Jump to content

Uninstall with Autoit


31290
 Share

Recommended Posts

Hi guys :)

One of my project is to create an uninstaller GUI that list all app on a computer so  my techs can choose to remove apps without having to connect to his admin session (and loose time, especially while remotely controlling a domain machine).

I did succeeded by creating a version one but it's very slow so I decided to create a version 2 of it, speeding things up and bring improvements.

Here's my code so far:

Spoiler
#include <String.au3>
#include <Array.au3>
#include <Date.au3>
#include <InetConstants.au3>
#include <MsgBoxConstants.au3>
#include <WinAPIFiles.au3>
#include <WinAPISys.au3>
#include <TrayConstants.au3>
#include <ProgressConstants.au3>
#include <ScreenCapture.au3>
#include <StaticConstants.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>
#include <Date.au3>
#include <File.au3>
#Include <FontConstants.au3>
#include <GUIConstantsEx.au3>
#include <GuiEdit.au3>
#include <GuiListView.au3>
#include <GuiMenu.au3>
#include <Array.au3>
#include <ButtonConstants.au3>
#include <ColorConstants.au3>
#include <ComboConstants.au3>
#include <ListBoxConstants.au3>
#Include <EditConstants.au3>
#include <WinAPISys.au3>
#include <IE.au3>
#include <WinAPI.au3>
#include <Misc.au3>
#include <GuiListView.au3>
#include <MsgBoxConstants.au3>

#NoTrayIcon
Opt("TrayAutoPause", 0)
Opt('GUIOnEventMode', 1)
Opt('GUICloseOnEsc' , 1)
FileDelete ("Uninstall.txt")

Global $i
Global $sSft
Global $sGui = GUICreate('Select Programs You want to Uninstall:', 471, 650, -1, -1)
Global $sLvw = GUICtrlCreateListView('Program Name', 2, 2, 467, 580, -1, $LVS_EX_CHECKBOXES)
_ComputerGetSoftware($sSft)

For $i = 1 To ubound($sSft) - 1
    GUICtrlCreateListViewItem($sSft[$i], $sLvw)
Next
GUICtrlSendMsg($sLvw, 0x101E, 0, 450)
Local $exp = GUICtrlCreateButton('  Uninstall  ', 195, 590, 100, 55)
Local $clear_sel = GUICtrlCreateButton('  Clear Selection  ', 0, 600)
Local $g_exit = GUICtrlCreateButton('  Exit  ', 430, 600)
GUICtrlSetOnEvent($exp, '_Uninstall')
GUICtrlSetOnEvent($g_exit, '_AllExit')
GUISetOnEvent(-3, '_AllExit')
GUISetState(@SW_SHOW, $sGui)

While 1
    Sleep(1000)
WEnd

Func _ComputerGetSoftware(ByRef $aSoftwareInfo)
    Local Const $UnInstKey = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"
    Local $i = 1
    Dim $aSoftwareInfo[1]
      For $j = 1 To 500
        $AppKey = RegEnumKey($UnInstKey, $j)
        If @error <> 0 Then Exitloop
        If RegRead($UnInstKey & "\" & $AppKey, "DisplayName") = '' Then ContinueLoop
        ReDim $aSoftwareInfo[UBound($aSoftwareInfo) + 1]
        $aSoftwareInfo[$i] = StringStripWS(RegRead($UnInstKey & "\" & $AppKey, "DisplayName"), 1)
        $i = $i + 1
    Next
    $aSoftwareInfo[0] = UBound($aSoftwareInfo, 1) - 1
    Return _ArraySort($aSoftwareInfo)
EndFunc

Func _ClearSel()

EndFunc

Func _AllExit()
    GUIDelete($sGui)
    FileDelete ("Uninstall.txt")
    Exit
EndFunc

Func _Uninstall()
    Local Const $iCount = _GUICtrlListView_GetItemCount($sLvw)
    For $i = 1 To $iCount
        If _GUICtrlListView_GetItemChecked($sLvw, $i - 1) Then
            $sAppToUninstall = _GUICtrlListView_GetItemText($sLvw, $i - 1)
        Endif
    Next
    Global $g_Confirm = Msgbox (52, "WARNING", "Your're about to uninstall " & $sAppToUninstall & @CRLF & @CRLF & "Continue?")
; If $g_Confirm = $IDYES Then
; GuiSetState (@SW_DISABLE, $g_UninstallGUI)

;---------
    ; Local Const $iCount = _GUICtrlListView_GetItemCount($sLvw)
    ; FileOpen("Uninstall.txt", 2)
    ; For $i = 1 To $iCount
        ; If _GUICtrlListView_GetItemChecked($sLvw, $i - 1) Then
        ; FileWrite("Uninstall.txt", _GUICtrlListView_GetItemText($sLvw, $i - 1) & @CRLF)
        ; EndIf
    ; Next
        ; FileClose ("Uninstall.txt")
        ; ShellExecute("Uninstall.bat")
        ; Exit
EndFunc

 

Problems are:

1/ If I click 2 items, only the last one is taken into account when I click the "uninstall" button (the msgbox is for testing outputs ATM)

2/ I can't figure out how to make the "Clear Selection" button to work (this may be a dumb question)

3/ I'd like to queue un-installations according to what the tech checked, in your opinion, what is best? (Make the script generating and executing a sort of .bat file for each selection? / Make the script running "RunAsWait($sT0_AdminUserName, "DOMAIN" ,$sT0_AdminUserPassword, 2, "WMIC.exe product where ""name like '" & $sAppToUninstall& "'"" call uninstall /nointeractive","",@SW_HIDE) for each selection? /  write the selection in a .txt file and make the script read it line after line?, Other ideas? ^^)

4/ How can I exclude some programs in the soft list? I mean, I don't want the tech to see all Security Update blablabla crap and other things in the list (as the Anti Virus..)

Thanks a lot for those who can help, 

Cheers,

31290

~~~ Doom Shall Never Die, Only The Players ~~~

Link to comment
Share on other sites

  • Moderators

@31290 a couple of suggestions. I recently did something similar for a customer using WMI to query the machine (note, some crapware will not be seen through WMI, so I have on occasion had to do a mixture of WMI calls and searching through the registry):

#include <Array.au3>

Local $oWMI, $oProducts, $sApp, $aApps[1] = [""]

$oWMI = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
$oProducts = $oWMI.ExecQuery("Select * from Win32_Product")
    If IsObj($oProducts) Then
        If $oProducts.Count <> 0 Then
            For $sApp in $oProducts
                _ArrayAdd($aApps, $sApp.Name)
            Next
            $aApps[0] = UBound($aApps) - 1
        EndIf
    EndIf

    If $aApps[0] > 0 Then _ArrayDisplay($aApps)

You could then parse the array, using an if statement to weed out any programs you don't want to appear, and use this to populate your GUI.

;pseudo

For $a = 1 To $aApps[0]
   If Not (StringInStr($aApps[$a], "<criteria>")) Then
      ;add to listview on GUI
   EndIf
Next

As for the uninstall, there are a couple of different options. You could again use WMI and just call the uninstall() function:

;pseudo

$sAppName = ;Name returned from your GUI
$oWMI = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
$oProducts = $oWMI.ExecQuery("Select * from Win32_Product Where Name LIKE '%" & $sAppName & "%'")
    If IsObj($oProducts) Then
        If $oProducts.Count <> 0 Then
            For $sApp In $oProducts
                If $sApp.Name == $sAppName Then ;Match Name exactly, so as not to mistakenly uninstall any close matches 
                    $app.Uninstall()
                EndIf
            Next
        EndIf
    EndIf

Or, as I am doing at a job right now, use the AppName to cycle through the registry and get the application's uninstall string:

Local $sSubkey, $sAppName = "<name pulled from GUI>"
Local $sKey = "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" ;Have to account for HKLM64 if running against both 32 and 64bit machines

    For $a = 1 To 200
        $sSubkey = RegEnumKey($sKey, $a)
            If @error Then
                ExitLoop
            Else
                If StringInStr(RegRead($sKey & "\" & $sSubkey, "DisplayName"), $sAppName) Then
                        $sUninstall = RegRead($sKey & "\" & $sSubkey, "UninstallString")
                EndIf
            EndIf
    Next

 

"Profanity is the last vestige of the feeble mind. For the man who cannot express himself forcibly through intellect must do so through shock and awe" - Spencer W. Kimball

How to get your question answered on this forum!

Link to comment
Share on other sites

JLogan3o13, 

Thanks a lot for the reply. This will help me a lot for sure. 

21 hours ago, JLogan3o13 said:

For $a = 1 To $aApps[0]    If Not (StringInStr($aApps[$a], "<criteria>")) Then       ;add to listview on GUI    EndIf Next

Do I have to type the entire name of the apps I don't want to be shown in the list? Because I tested with some programs and they still appears in the list. 

 

~~~ Doom Shall Never Die, Only The Players ~~~

Link to comment
Share on other sites

  • Moderators

StringinStr is going to find any substring that you define in the criteria. So, for example, if you did this:

Local $oWMI, $oProducts, $sApp

$oWMI = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
$oProducts = $oWMI.ExecQuery("Select * from Win32_Product")
    If IsObj($oProducts) Then
        If $oProducts.Count <> 0 Then
            For $sApp in $oProducts
                If StringInStr($sApp.Name, "Microsoft Office") Then ConsoleWrite($sApp.Name & @CRLF)
            Next
        EndIf
    EndIf

You're going to pick up everything that matches that. On my machine it returns the following:

Microsoft Office Professional Plus 2016
Microsoft Office 32-bit Components 2016
Microsoft Office Shared 32-bit MUI (English) 2016
Microsoft Office OSM MUI (English) 2016
Microsoft Office OSM UX MUI (English) 2016
Microsoft Office Shared Setup Metadata MUI (English) 2016
Microsoft Office Proofing (English) 2016
Microsoft Office Shared MUI (English) 2016
Microsoft Office Proofing Tools 2016 - English
Herramientas de corrección de Microsoft Office 2016: español
Outils de vérification linguistique 2016 de Microsoft Office - Français

So you have to narrow the criteria down as far as you can. If I was looking for the main application, for example, I would set my criteria to something like " Office Professional Plus", so I capture only that app and none of the others.

"Profanity is the last vestige of the feeble mind. For the man who cannot express himself forcibly through intellect must do so through shock and awe" - Spencer W. Kimball

How to get your question answered on this forum!

Link to comment
Share on other sites

I have found that WMIC command was ungodly slow, so i created a different method which is about 5x + faster than wmic. The catch is you have to know where things live in the registry and the uninstall silent switches. Its a bit more work, but in the end the time it takes to run wmic vs what I wrote below is hugely significant.

I created something that will uninstall any Java runtimes, but leave anything with 'Development' or Javascript' alone as we needed something to push through Altiris and also create a set up for add java site exceptions for all users when re-installing.

Below is the piece that removes Java runtimes; both 64 bit and 32 bit as an example to work off of. You will of course have to determine the reg location of the uninstall string and the silent uninstall command. This code took about 30 seconds or less to find and uninstall both 32 and 64 bit java on my machine but leave any Java development alone.

Hope it will help or add to a list off suggestions for anyone else.

#RequireAdmin

Global $sBase_x64 = "HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\"
Global $sBase_x32 = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\"
SplashTextOn("Progress", "", 220, 60, -1, -1, 16, "Tahoma", 10)
ControlSetText("Progress", "", "Static1", "Uninstalling Java, please be patient could take a few minutes", 2)
Call('step1')
Call('u')
Call('z')
Exit

Func U()
    $iEval = 1
    $sSearch = "Java"
    While 1
        $sUninst = ""
        $sDisplay = ""
        $sCurrent = RegEnumKey($sBase_x32, $iEval)
        If @error Then ExitLoop
        $sKey = $sBase_x32 & $sCurrent
        $sDisplay = RegRead($sKey, "DisplayName")
        If StringRegExp($sDisplay, "(?i).*" & $sSearch & ".*") Then
            If StringRegExp($sDisplay, "(?i).*" & "Development" & ".*") Then
                $iEval += 1
                ContinueLoop
            ElseIf StringRegExp($sDisplay, "(?i).*" & "javascript" & ".*") Then
                $iEval += 1
                ContinueLoop
            Else
                $sUninst1 = StringSplit(RegRead($sKey, "UninstallString"), "/X", 1)
                $sUninst = $sUninst1[1] & ' /QN' & ' /X' & $sUninst1[2]
                ControlSetText("Progress", "", "Static1", "Uninstalling " & $sDisplay, 2)
                RunWait($sUninst)
                Call('u')
            EndIf
        EndIf
        $iEval += 1
    WEnd
EndFunc   ;==>U

Func z()
    $iEval = 1
    $sSearch = "Java"
    While 1
        $sUninst = ""
        $sDisplay = ""
        $sCurrent = RegEnumKey($sBase_x64, $iEval)
        If @error Then ExitLoop
        $sKey = $sBase_x64 & $sCurrent
        $sDisplay = RegRead($sKey, "DisplayName")
        If StringRegExp($sDisplay, "(?i).*" & $sSearch & ".*") Then
            If StringRegExp($sDisplay, "(?i).*" & "Development" & ".*") Then
                $iEval += 1
                ContinueLoop
            ElseIf StringRegExp($sDisplay, "(?i).*" & "javascript" & ".*") Then
                $iEval += 1
                ContinueLoop
            Else
                $sUninst1 = StringSplit(RegRead($sKey, "UninstallString"), "/X", 1)
                $sUninst = $sUninst1[1] & ' /QN' & ' /X' & $sUninst1[2]
                ControlSetText("Progress", "", "Static1", "Uninstalling " & $sDisplay, 2)
                RunWait($sUninst)
                Call('z')
            EndIf
        EndIf
        $iEval += 1
    WEnd
EndFunc   ;==>z


Func step1()

    $iEval = 1
    $sSearch = "Java Auto Updater"
    While 1
        $sUninst = ""
        $sDisplay = ""
        $sCurrent = RegEnumKey($sBase_x64, $iEval)
        If @error Then ExitLoop
        $sKey = $sBase_x64 & $sCurrent
        $sDisplay = RegRead($sKey, "DisplayName")
        If StringRegExp($sDisplay, "(?i).*" & $sSearch & ".*") Then
            RegDelete($sKey)
        EndIf
        $iEval += 1
    WEnd
EndFunc   ;==>step1

 

Link to comment
Share on other sites

Everyone :)

Thanks a lot for your inputs, much appreciated and really helped. 

But ( :( )

In my code, how to combine both x32 and x64 reg paths on a x64 based arch? I can only see applications located in the x32 reg path...

Spoiler
Func _ComputerGetSoftware(ByRef $aSoftwareInfo)
    If @OSArch = "x86" Then 
        Local Const $UnInstKey = "HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
        Local $i = 1
        Dim $aSoftwareInfo[1]
          For $j = 1 To 500
            $AppKey = RegEnumKey($UnInstKey, $j)
            If @error <> 0 Then Exitloop
            If RegRead($UnInstKey & "\" & $AppKey, "DisplayName") = '' Then ContinueLoop
            ReDim $aSoftwareInfo[UBound($aSoftwareInfo) + 1]
            $aSoftwareInfo[$i] = StringStripWS(RegRead($UnInstKey & "\" & $AppKey, "DisplayName"), 1)
            $i = $i + 1
        Next
        $aSoftwareInfo[0] = UBound($aSoftwareInfo, 1) - 1
        Return _ArraySort($aSoftwareInfo)
    ElseIf @OSArch = "x64" Then
            Local Const $UnInstKey = "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"
        Local $i = 1
        Dim $aSoftwareInfo[1]
          For $j = 1 To 500
            $AppKey = RegEnumKey($UnInstKey, $j)
            If @error <> 0 Then Exitloop
            If RegRead($UnInstKey & "\" & $AppKey, "DisplayName") = '' Then ContinueLoop
            ReDim $aSoftwareInfo[UBound($aSoftwareInfo) + 1]
            $aSoftwareInfo[$i] = StringStripWS(RegRead($UnInstKey & "\" & $AppKey, "DisplayName"), 1)
            $i = $i + 1
        Next
        $aSoftwareInfo[0] = UBound($aSoftwareInfo, 1) - 1
        Return _ArraySort($aSoftwareInfo)
    EndIf
EndFunc

 

I tried to play with:

Spoiler
If @OSArch = "X64" Then
    $UnInstKey = 'HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall\|' & _
            'HKLM64\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\|' & _
            'HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\'
ElseIf @OSArch = "X86" Then
    $UnInstKey = 'HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall\|' & _
            'HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\|' & _
            'HKLM64\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\'
EndIf

 

But now, I have nothing in my list. Any thoughts / directions / help?

Thanks :D

EDIT: In fact, I already created an uninstaller but WMIC are too long for my techs needs. So I really need to speed it up (by reading reg paths depending on the OSArch) and add the possibility to queue uninstallations (I thought of writing their choices in a text file and then perform some RunAsWait wmic uninstall functions).
I thought replacing the combobox by a listbox with check boxes but apparently this is not easy as I thought it would be...

Spoiler
#include <Array.au3>
#include <GuiComboBox.au3>
#include <ButtonConstants.au3>
#include <ColorConstants.au3>
#include <ComboConstants.au3>
#Include <Constants.au3>
#include <Date.au3>
#include <File.au3>
#Include <FontConstants.au3>
#include <GUIConstantsEx.au3>
#include <GuiEdit.au3>
#include <GuiListView.au3>
#include <GuiMenu.au3>
#include <Misc.au3>
#include <MsgBoxConstants.au3>
#include <ProgressConstants.au3>
#include <ScreenCapture.au3>
#include <StaticConstants.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>
#include <StringConstants.au3>
#include <AD.au3>

Opt("GUIOnEventMode", 1)

Global $Resources = "C:\SAC_IS\SEE_Uninstaller\Resources"
DirCreate($Resources)

FileInstall ("C:\Users\h74033\Google Drive\ZZZ_Main Resources\SAClogo.jpg", $resources & "\SAClogo.jpg", 1)

f_UninstallerMainGUI()

While 1
    Sleep(10)
Wend

Func f_UninstallerMainGUI()
    Global $g_UninstallGUI =  GuiCreate ("SEE UNINSTALLER", 400, 500)
    GUISetBkColor ($Color_White)
    GUICtrlCreatePic ($Resources & "\SAClogo.jpg", 80, 10, 240, 80)
    $g_DescLabel = GUICtrlCreateLabel("-- SEE UNINSTALLER --", 135, 105)
    GUICtrlSetFont (-1, 8.5, 700, 0)
    GUICtrlCreateSeparator(0, 5, 130, 2, 390)
    GUICtrlCreateLabel("*** Current Computer: " & @ComputerName & " ***", 100, 140, 250, 20)
    GUICtrlSetFont (-1, 8.5, 700, 0)
    GUICtrlSetColor (-1, $COLOR_PURPLE)
    GuiCtrlCreateLabel ("Click the above button to list Applications that can be uninstalled:", 5, 180, 370)
    GUICtrlSetFont (-1, 8.5, 700, 0)
    Global $g_AppList = GUICtrlCreateButton ("Populate list", 160, 200, 75, 50)
    GuiCtrlSetOnEvent (-1, "f_ListApps")
    GUISetOnEvent($GUI_EVENT_CLOSE, "_exit")
    GuiSetState()
EndFunc

Func f_ListApps()
    GuiSetState (@SW_DISABLE, $g_UninstallGUI)
    SplashTextOn  ("", "Getting Apps, please wait...", 700, 100, -1, -1,  33, -1, -1, 700)
    RunWait(@ComSpec & ' /c ' & 'wmic /node:' & @Computername &' product get name > %temp%\model.txt' ,"", @SW_HIDE)
    Global $comboBox = GUICtrlCreateCombo(" Select App from the List", 5, 270, 395, 300, BitOR($CBS_DROPDOWN, $CBS_AUTOHSCROLL, $WS_VSCROLL, $CBS_SORT))
    $file =(@TempDir & "/model.txt")
    $fileread = FileRead($file)
    $aFileArray = FileReadToArray($file)
    _ArrayDelete($aFileArray, 0)
    For $i = 0 To UBound($aFileArray, 1) - 1
        $aFileArray[$i] = StringStripWs($aFileArray[$i], $STR_STRIPTRAILING)
         GUICtrlSetData($comboBox,$aFileArray[$i])
    Next
    $sText = " Select App from the List"
    _GUICtrlComboBox_SelectString ($comboBox, $sText)
    GuiCtrlCreateButton ("Proceed to Application Uninstallation", 110, 300, -1, 50)
    GuiCtrlSetOnEvent (-1, "f_Uninstall")
    GuiCtrlCreateLabel ("TIP: You can type the first letters of the Application and press the Down arrow " & @CRLF &  "to go faster.", 5, 370)
    SplashOff()
    GuiSetState (@SW_ENABLE, $g_UninstallGUI)
    FileDelete(@TempDir & "/model.txt")
EndFunc

Func f_Uninstall() ;can't be used in this example.
    $sAppToUninstall = GUICtrlRead ($comboBox)
    If $sAppToUninstall = " Select App from the List" Then
        MsgBox (16, "Error", "You can't do that")
    Else
        $g_Confirm = Msgbox (52, "WARNING", "Your're about to uninstall " & $sAppToUninstall & @CRLF & @CRLF & "Continue?")
    If $g_Confirm = $IDYES Then
        GuiSetState (@SW_DISABLE, $g_UninstallGUI)
        SplashTextOn  ("", "Uninstalling " & $sAppToUninstall & ", please wait...",700, 100, -1, -1,  33, -1, -1, 700)
        RunAsWait($sT0_AdminUserName, "MYDOMAIN" ,$sT0_AdminUserPassword, 2, "WMIC.exe product where ""name like '" & $sAppToUninstall& "'"" call uninstall /nointeractive","",@SW_HIDE)
        SplashOff()
        GuiSetState (@SW_ENABLE, $g_UninstallGUI)
        $g_AnotherApp = Msgbox (36, "INFORMATION", $sAppToUninstall & " has been successfully uninstalled from the system!" & @CRLF & @CRLF & "Uninstall another Application? -- Script will be reloaded --")
    If $g_AnotherApp = $IDYES Then
        RestartScript()
    ElseIf $g_AnotherApp = $IDNO Then
        _exit()
    EndIf
    ElseIf $g_Confirm = $IDNO Then
        Msgbox (64, "INFORMATION", "Application won't be uninstalled!")
    EndIf
    Endif
EndFunc

    ;Separator Creation
Func GuiCtrlCreateSeparator($Direction, $Left, $Top, $Width=3, $Lenght=25)
    Switch $Direction
        Case 0
            GUICtrlCreateLabel("", $Left, $Top, $Lenght, $Width, $SS_SUNKEN)
        Case 1
            GUICtrlCreateLabel("", $Left, $Top, $Width, $Lenght, $SS_SUNKEN)
    EndSwitch
EndFunc

Func RestartScript()
    If @Compiled = 1 Then
        Run(FileGetShortName(@ScriptFullPath))
    Else
        Run(FileGetShortName(@AutoItExe) & " " & FileGetShortName(@ScriptFullPath))
    EndIf
    _exit()
EndFunc

Func f_closeGUI()
    GUIdelete()
    GuiSetState (@SW_ENABLE, $g_UninstallGUI)
    GuiSetState (@SW_RESTORE, $g_UninstallGUI)
EndFunc

Func _exit()
    Exit
EndFunc

 

Thanks for the help you can provide. 

Edited by 31290

~~~ Doom Shall Never Die, Only The Players ~~~

Link to comment
Share on other sites

  • Moderators

@31290 from the help file:

When running on 64-bit Windows if you want to read a value specific to the 64-bit environment you have to suffix the HK... with 64 i.e. HKLM64.

Have you tried this?

"Profanity is the last vestige of the feeble mind. For the man who cannot express himself forcibly through intellect must do so through shock and awe" - Spencer W. Kimball

How to get your question answered on this forum!

Link to comment
Share on other sites

8 minutes ago, JLogan3o13 said:

@31290 from the help file:

When running on 64-bit Windows if you want to read a value specific to the 64-bit environment you have to suffix the HK... with 64 i.e. HKLM64.

Have you tried this?

Yes, In my previous post I defined a variable 

If @OSArch = "X64" Then
    $UnInstKey = 'HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall\|' & _
            'HKLM64\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\|' & _
            'HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\'
ElseIf @OSArch = "X86" Then
    $UnInstKey = 'HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall\|' & _
            'HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\|' & _
            'HKLM64\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\'
EndIf

Because on x64, I have to look mix both reg path. For example, I have an X64 version of iTunes and 7zip and they don't show in my list whereas it works with the first version of my soft (code on previous post). When looking at the regedit, many soft are installed in the x86 HKLM place and some in the x64 one (iTunes and 7Zip for example). that's why I need both of them in the same variable to populate my list...

Thanks for your input btw :)

~~~ Doom Shall Never Die, Only The Players ~~~

Link to comment
Share on other sites

  • Moderators

I understand what you're saying, but if I do this:

#include <Array.au3>

Local $sSubkey, $ax86[1] = [""], $ax64[1] = [""]
Local $sKey = "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"
Local $sx64Key = "HKLM64\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"

    For $a = 1 To 1000
        $sSubkey = RegEnumKey($sKey, $a)
            If @error Then
                ExitLoop
            Else
                _ArrayAdd($ax86, $sSubkey)
            EndIf
    Next

    For $b = 1 To 1000
        $sSubkey = RegEnumKey($sx64Key, $b)
            If @error Then
                ExitLoop
            Else
                _ArrayAdd($ax64, $sSubkey)
            EndIf
    Next

    $ax86[0] = UBound($ax86) - 1
    $ax64[0] = UBound($ax64) - 1

    _ArrayDisplay($ax86, "Keys Under Wow6432Node")
    _ArrayDisplay($ax64, "Keys Under " & $sx64Key)

it enumerates the different keys just fine. If, as in your example, I am looking for 7zip, I could do something like this:

#include <Array.au3>

Local $sSubkey, $a7Zip[1] = [""]
Local $sKey = "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\"
Local $sx64Key = "HKLM64\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\"

    For $a = 1 To 1000
        $sSubkey = RegEnumKey($sKey, $a)
            If @error Then
                ExitLoop
            ElseIf StringInStr(RegRead($sKey & $sSubkey, "DisplayName"), "7-Zip") Then
                _ArrayAdd($a7Zip, $sKey & $sSubkey)
            EndIf
    Next

    If @OSArch = "X64" Then
        For $b = 1 To 1000
            $sSubkey = RegEnumKey($sx64Key, $b)
                If @error Then
                    ExitLoop
                ElseIf StringInStr(RegRead($sx64Key & $sSubkey, "DisplayName"), "7-Zip") Then
                    _ArrayAdd($a7Zip, $sx64Key & $sSubkey)
                EndIf
        Next
    EndIf

    $a7Zip[0] = UBound($a7Zip) - 1
    If $a7Zip[0] > 0 Then _ArrayDisplay($a7Zip, "All instances of 7-Zip")

Is this not working for you?

"Profanity is the last vestige of the feeble mind. For the man who cannot express himself forcibly through intellect must do so through shock and awe" - Spencer W. Kimball

How to get your question answered on this forum!

Link to comment
Share on other sites

Hi ;)

Sorry for the late response.

Yes, this is working, but it's how to implement that to my current script to speed it up?

I'm not good at all with arrays and despite reading help file, I still can't get it.

Thanks

 

~~~ Doom Shall Never Die, Only The Players ~~~

Link to comment
Share on other sites

  • 4 years later...

I needed this code today and.
I think the code given by @JLogan3o13 will scan both x86 and x64 systems, if I am wrong, please warn me or notify me.
Doesn't it make more sense to look at the OSArch value first for this?

#include <Array.au3>

Local $a = 0, $b = 0
Local $sSubkey, $a7Zip[1] = [""]
Local $sKey = "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\"
Local $sx64Key = "HKLM64\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\"

If @OSArch = "X64" Then
    While 1
        $a += 1
        $sSubkey = RegEnumKey($sx64Key, $a)
        If @error Then ExitLoop
        If StringInStr(RegRead($sx64Key & $sSubkey, "DisplayName"), "7-Zip") Then
            _ArrayAdd($a7Zip, $sx64Key & $sSubkey)
        EndIf
    WEnd
Else
    While 1
        $b += 1
        $sSubkey = RegEnumKey($sKey, $b)
        If @error Then ExitLoop
        If StringInStr(RegRead($sKey & $sSubkey, "DisplayName"), "7-Zip") Then
            _ArrayAdd($a7Zip, $sKey & $sSubkey)
        EndIf
    WEnd
EndIf

$a7Zip[0] = UBound($a7Zip) - 1
If $a7Zip[0] > 0 Then _ArrayDisplay($a7Zip, "All instances of 7-Zip")

 

Link to comment
Share on other sites

  • Moderators

@youtuber the point of the code that I posted (5 years ago, you have been around long enough to know better) was to always search the x86 hive for software. And, if it is a 64-bit system (which 5 years later you are almost guaranteed it will be) also search the 64bit hive. The point of doing so is many applications, at that time, were still 32bit. So you could have 7zip, for example, install in either Program Files or Program Files (x86) on a 64bit system, and the OP needed a way to find the software regardless of the bitness installed.

Your code will indeed search the 64bit hive for the application. However, if a 32-bit version was installed for some reason (still happens, though not as much as in 2016), you would miss it.

"Profanity is the last vestige of the feeble mind. For the man who cannot express himself forcibly through intellect must do so through shock and awe" - Spencer W. Kimball

How to get your question answered on this forum!

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...