Sign in to follow this  
Followers 0
petesa

Dynamic Program Uninstaller

5 posts in this topic

Any help is really appreciated...

I am trying to write an AutoIt script that can search the uninstall area of the registry for a keyword (i.e. part of program name without need for the name of the exact registry entry) and then automatically uninstall all found programs. Eventually

I wanted to be able to provide the keyword to the compiled script via command line parameter.

The bad news is that I am just a beginner :shocked:

I am not sure if the approach that I am taking makes sense. The "sticking point" seems to be with arrays; I am attempting to build a new set of arrays based on a previous array and I am getting a "Array variable has incorrect number of subscripts or subscript dimension range exceeded.:" error.

Thank you in advance

Opt("MustDeclareVars", 1)
Local $a_DispName[10], $a_NameOfProg[10], $a_GetUninstallRunLine[10]
Global $DisplayName = 1, $NameOfProg = 1, $GetUninstallRunLine = 0, $UninstallRunLine = 0

_Main()
Func _Main()
    Local $a_subkeys = _RegEnumKeys(".", "HKLM", "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"), $x, $y, $a_keys
    If Not @error Then
        For $x = 0 To UBound($a_subkeys) - 1
            _DebugPrint($a_subkeys[$x])
            $a_keys = _RegEnumValues(".", "HKLM", "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\" & $a_subkeys[$x])
            If Not @error Then
                For $y = 0 To UBound($a_keys) - 1
                    ConsoleWrite($a_keys[$y][0] & @TAB & ":" & @TAB & $a_keys[$y][1] & @TAB & ":" & @TAB & $a_keys[$y][2] & @LF)                
                    $DisplayName = StringInStr($a_keys[$y][0], "DisplayName")
                    If $DisplayName <> 0 Then
                        ;Find application name in uninstall area in registry
                        $NameOfProg = StringInStr($a_keys[$y][1], "AutoIt")
                        If $NameOfProg <> 0 Then
                            $GetUninstallRunLine = 1
                            For $w = 0 To UBound($a_DispName, 1) - 1
                            ;Issue 1 how to get array data into new array for use in uninstall loop to uninstall multiple programs?
                            $a_DispName[$w] = ($a_keys[$y][0])
                            Next
                            For $v = 0 To UBound($a_NameOfProg, 1) - 1
                                $a_NameOfProg[$v]= ($a_keys[$y][1])
                            Next
                        EndIf
                    EndIf
                    $UninstallRunLine = StringInStr($a_keys[$y][0], "UninstallString")
                    If $UninstallRunLine <> 0 Then
                        If $GetUninstallRunLine = 1 Then
                            ;Issue 2 
                            MsgBox(0, "TEST", $a_DispName[$w], 10)
                            For $u = 0 To UBound($a_GetUninstallRunLine, 1) - 1
                                $a_GetUninstallRunLine[$u] = ($a_keys[$y][1])
                            Next
                            $GetUninstallRunLine = 0
                        EndIf
                    EndIf           
                Next
            EndIf
        Next
    EndIf
EndFunc   ;==>_Main

;Dim $sArrayString = _ArrayToString($MyArray, @TAB, 1, 7)
;MsgBox(4096, "_ArrayToString() Test", $sArrayString)

;~ Func _Main()
;~     Local $a_subkeys = _RegEnumKeys(".", "HKLM", "SOFTWARE\Microsoft\Windows\CurrentVersion"), $x, $y, $a_keys
;~     If Not @error Then
;~         For $x = 0 To UBound($a_subkeys) - 1
;~             _DebugPrint($a_subkeys[$x])
;~             $a_keys = _RegEnumValues(".", "HKLM", "SOFTWARE\Microsoft\Windows\CurrentVersion\" & $a_subkeys[$x])
;~             If Not @error Then
;~                 For $y = 0 To UBound($a_keys) - 1
;~                     ConsoleWrite($a_keys[$y][0] & @TAB & ":" & @TAB & $a_keys[$y][1] & @TAB & ":" & @TAB & $a_keys[$y][2] & @LF)
;~                 Next
;~             EndIf
;~         Next
;~     EndIf
;~ EndFunc   ;==>_Main

;===============================================================================
;
; Description:      _RegEnumValues
; Parameter(s):  computer name    - string of remote computer or "." for current computer
;                     registry tree  - contains the sSubKeyName path
;                     sub key name   - A path that contains the named values to be enumerated
; Requirement:      None
; Return Value(s):  Returns a multi-dimensional array ([0] = key name, [1] = key value, [2] = key type)
;                     If an error occurs @error is set and 0 is returned
; User CallTip:  _RegEnumValues(computer name, registry tree, sub key name) Enumerates the values of the given subkey
; Author(s):            Gary Frost (custompcs at charter dot net)
; Note(s):        A registry tree can be one of:
;                        "HKEY_LOCAL_MACHINE" ("HKLM")
;                        "HKEY_USERS" ("HKU")
;                        "HKEY_CURRENT_USER" ("HKCU")
;                        "HKEY_CLASSES_ROOT" ("HKCR")
;                        "HKEY_CURRENT_CONFIG" ("HKCC")
;
;===============================================================================
Func _RegEnumValues($strComputer, $s_hDefKey, $strKeyPath)
    Local $hDefKey, $x
    Enum $HKEY_CLASSES_ROOT = 0x80000000, $HKEY_CURRENT_USER, $HKEY_LOCAL_MACHINE, $HKEY_USERS, $HKEY_CURRENT_CONFIG
    If $strComputer = "." Then $strComputer = @ComputerName
    Switch StringUpper($s_hDefKey)
        Case "HKEY_LOCAL_MACHINE", "HKLM"
            $hDefKey = $HKEY_LOCAL_MACHINE
        Case "HKEY_USERS", "HKU"
            $hDefKey = $HKEY_USERS
        Case "HKEY_CURRENT_USER", "HKCU"
            $hDefKey = $HKEY_CURRENT_USER
        Case "HKEY_CLASSES_ROOT", "HKCR"
            $hDefKey = $HKEY_CLASSES_ROOT
        Case "HKEY_CURRENT_CONFIG", "HKCC"
            $hDefKey = $HKEY_CURRENT_CONFIG
        Case Else
            Return SetError(1, 1, 0)
    EndSwitch

    Local $a_Type[8] = [7, "REG_SZ", "REG_EXPAND_SZ", "REG_BINARY", "REG_DWORD", "", "", "REG_MULTI_SZ"]
    Local $arrValueNames, $arrValueTypes
    Local $oReg = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & $strComputer & "\root\default:StdRegProv")
    $oReg.EnumValues ($HKEY_LOCAL_MACHINE, $strKeyPath, $arrValueNames, $arrValueTypes)
    If Not IsArray($arrValueNames) Then Return SetError(2, 2, 0)
    Local $a_ret[UBound($arrValueNames) ][3]
    For $x = 0 To UBound($arrValueNames) - 1
        $a_ret[$x][0] = $arrValueNames[$x]
        $a_ret[$x][1] = RegRead($s_hDefKey & "\" & $strKeyPath, $arrValueNames[$x])
        $a_ret[$x][2] = $a_Type[$arrValueTypes[$x]]
    Next
    Return $a_ret
EndFunc   ;==>_RegEnumValues


;===============================================================================
;
; Description:      _RegEnumKeys
; Parameter(s):  computer name    - string of remote computer or "." for current computer
;                     registry tree  - contains the sSubKeyName path
;                     sub key name   - A path that contains the named values to be enumerated
; Requirement:      None
; Return Value(s):  Returns An array of subkey strings
;                     If an error occurs @error is set and 0 is returned
; User CallTip:  _RegEnumKeys(computer name, registry tree, sub key name) Enumerates the subkeys for a path
; Author(s):            Gary Frost (custompcs at charter dot net)
; Note(s):        A registry tree can be one of:
;                        "HKEY_LOCAL_MACHINE" ("HKLM")
;                        "HKEY_USERS" ("HKU")
;                        "HKEY_CURRENT_USER" ("HKCU")
;                        "HKEY_CLASSES_ROOT" ("HKCR")
;                        "HKEY_CURRENT_CONFIG" ("HKCC")
;
;===============================================================================
Func _RegEnumKeys($strComputer, $s_hDefKey, $strKeyPath)
    Local $hDefKey, $x
    Enum $HKEY_CLASSES_ROOT = 0x80000000, $HKEY_CURRENT_USER, $HKEY_LOCAL_MACHINE, $HKEY_USERS, $HKEY_CURRENT_CONFIG
    If $strComputer = "." Then $strComputer = @ComputerName
    Switch StringUpper($s_hDefKey)
        Case "HKEY_LOCAL_MACHINE", "HKLM"
            $hDefKey = $HKEY_LOCAL_MACHINE
        Case "HKEY_USERS", "HKU"
            $hDefKey = $HKEY_USERS
        Case "HKEY_CURRENT_USER", "HKCU"
            $hDefKey = $HKEY_CURRENT_USER
        Case "HKEY_CLASSES_ROOT", "HKCR"
            $hDefKey = $HKEY_CLASSES_ROOT
        Case "HKEY_CURRENT_CONFIG", "HKCC"
            $hDefKey = $HKEY_CURRENT_CONFIG
        Case Else
            Return SetError(1, 1, 0)
    EndSwitch

    Local $a_Type[8] = [7, "REG_SZ", "REG_EXPAND_SZ", "REG_BINARY", "REG_DWORD", "", "", "REG_MULTI_SZ"]
    Local $arrValueNames, $arrValueTypes
    Local $oReg = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & $strComputer & "\root\default:StdRegProv")
    $oReg.EnumKey ($HKEY_LOCAL_MACHINE, $strKeyPath, $arrValueNames)
    If Not IsArray($arrValueNames) Then Return SetError(2, 2, 0)
    Return $arrValueNames
EndFunc   ;==>_RegEnumKeys

Func _DebugPrint($s_text)
    $s_text = StringReplace($s_text, @LF, @LF & "-->")
    ConsoleWrite("!===========================================================" & @LF & _
            "!===========================================================" & @LF & _
            "-->" & $s_text & @LF & _
            "!===========================================================" & @LF)
EndFunc   ;==>_DebugPrint

Share this post


Link to post
Share on other sites



#3 ·  Posted (edited)

Thanks @Uten, your tutorial helped me with the array issue... Now I am working on some ObjGet Com issues, where not all registry values are returned.

That is a very nice "Wiki Arrays Tutorial"; good basic introduction, great AutoIt code examples, gradually goes into more complex examples...even an array within an array section!

FYI: The only thing that I noticed is a very minor grammar error: This makes sense in many situations as you now have a an array containing data with a an index starting at 1. Not really worth changing since this is a technical subject. :-)

Edited by petesa

Share this post


Link to post
Share on other sites

Simple question: If you got the uninstallstring, why don't you use it directly?

Here is a sample I created some time ago to delete all java-stuff from a machine. At least it worked here. :shocked:

For $k = 1 To 1000
    $Key = RegEnumKey("HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", $k)
    If @error <> 0 Then ExitLoop
    $DContact = RegRead("HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\" & $Key, 'Contact')
    If StringInStr($DContact, 'java') Then
        $MSI = RegRead("HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\" & $Key, 'UninstallString')
        $MSI = StringTrimLeft($MSI, 14)
        RunWait(@ComSpec & ' /c start /wait MsiExec.exe /X' & $MSI & ' /qn', 'C:', @SW_HIDE)
    EndIf
Next

The part I would like to point to is the runwait-line.

Share this post


Link to post
Share on other sites

:shocked: Thanks dabus, I was not aware of that there was a "built-in" RegEnumKey function! That is a great help. I tested a variation of your RegEnumKey function example and it works great!

I had not considered running the "uninstallstring" directly (nested) because I thought that there may be more than one keyword match. The intention was to make a general use utility that accepts command line parameters. I will also need to detect different uninstallstring types (i.e. quiet, MSI, .exe, etc ), parse based on what is found, then do a RunWait to perform the uninstall. When I have it all working I will post the code here.

Thank you again for responding.

Share this post


Link to post
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
Sign in to follow this  
Followers 0