Jump to content

Dynamic Program Uninstaller


Recommended Posts

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
Link to comment
Share on other sites

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
Link to comment
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.

Link to comment
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.

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

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...