Thursday, May 21, 2009

Crank 'em Up, and Rip 'em Out (Selectively)

My previous post was kind of broad.  Somewhat like duck hunting with a shotgun. Swatting flies with a boat paddle.  Hauling trash with a dragster.  Well, you get the idea.  This post takes that previous pile of code and tweaks it a little to allow you to get fancy-shmancy with the input file.  Rather than just specify a name, this will make it possible to remove applications by Name, Caption, Description, Vendor, PackageCache, and so on.

'****************************************************************
' Filename..: app_uninstall.vbs
' Author....: skatterbrainz.blogspot.com
' Date......: 05/21/2009
' Purpose...: uninstall applications using an input file listing
'****************************************************************
Option Explicit

Const inputFile = "app_uninstall.txt"
Const strComputer = "."
Const RunVerbose = True ' False = run quietly, no output
Const TestMode = True ' False = enable it to run
Const ForReading = 1
Const ForWriting = 2

Dim objWMIService, objFSO, wmistring

'----------------------------------------------------------------
' comment:
'----------------------------------------------------------------

Sub Echo(s)
If RunVerbose = True Then
wscript.echo Now & vbTab & s
End If
End Sub

'----------------------------------------------------------------
' comment:
'----------------------------------------------------------------

Sub Uninstall(query)
Dim colItems, objItem, retval
On Error Resume Next
Set colItems = objWMIService.ExecQuery(query,,48)
If err.Number <> 0 Then
Echo "info: wmi query failure"
Exit Sub
ElseIf IsNull(colItems) Then
Echo "info: application not found"
Exit Sub
End If

For Each objItem in colItems
If TestMode <> True Then
Echo "info: requesting removal of application..."
retval = objItem.Uninstall()
If retval = 0 Then
Echo "info: uninstall was successful"
Else
Echo "error: uninstall request failed!"
End If
Else
Echo "test: caption = " & objItem.Caption
End If
Next
End Sub

'----------------------------------------------------------------
' comment:
'----------------------------------------------------------------

Sub Main()
Dim objFile, appName, pathname, shortname, fullname, inputpath
Dim appData, wmiField, wmiValue, strQuery, strLine

fullname = Wscript.ScriptFullName
shortname = Wscript.ScriptName
pathname = Replace(fullname, shortname, "")
inputPath = pathname & inputfile

Set objFSO = Wscript.CreateObject("Scripting.FileSystemObject")

wmistring = "winmgmts:{impersonationLevel=impersonate}!\\" & _
strComputer & "\root\cimv2"
On Error Resume Next
Set objWMIService = GetObject(wmistring)
If err.Number <> 0 Then
Wscript.Echo "error: " & err.Number & " = " & err.Description
err.Clear
Wscript.Quit(1)
End If

Echo "info: searching for input file..."
If objFSO.FileExists(inputPath) Then
Echo "info: loading applications list..."
Set objFile = objFSO.OpenTextFile(inputPath, ForReading)
Echo "info: applications list loaded successfully"
Do While objFile.AtEndOfStream <> True
strLine = Trim(objFile.ReadLine)
If Left(strLine,1) <> ";" And strLine <> "" Then
If InStr(1, strLine, "=") > 0 Then
appData = Split(strLine, "=")
wmiField = Trim(appData(0)) 'name of field to match
wmiValue = Trim(appData(1)) 'value to match against
Echo "info: wmiField [" & wmiField & "] wmiValue [" & wmiValue & "]"
strQuery = WMIQuery(wmiField, wmiValue)
Uninstall strQuery
End If
End If
Loop
objFile.Close
Set objFile = Nothing
Echo "info: processing complete"
Else
Echo "error: input file not found = " & inputPath
End If
Set objFSO = Nothing
End Sub

'----------------------------------------------------------------
' comment:
'----------------------------------------------------------------

Function wmiQuery(strField, strValue)
Dim retval : retval = ""
Dim tmp : tmp = "SELECT * FROM Win32_Product WHERE XFIELD='XVALUE'"
Const fieldList = "Caption Description IdentifyingNumber InstallLocation Name PackageCache Vendor"
If InStr(1, Lcase(fieldList), Lcase(strField)) <> 0 Then
retval = Replace(Replace(tmp, "XFIELD", strField), "XVALUE", strValue)
Else
Echo "error: invalid wmi class fieldname requested: " & strField
End If
wmiQuery = retval
End Function

'----------------------------------------------------------------
' comment: call the code to do the dirty work
'----------------------------------------------------------------
Main()


And below is an updated example of the input .TXT file. It borrows from the standard .INI format where you have keynames on the left and a value on the right (separated by an equal sign).



TEXT FILE EXAMPLE:

; application removal list
; WMI-FieldName=Value to match
; lines which begin with semi-colon are ignored
; blanks are ignored
Name=Autodesk DirectConnect 2.0
Name=MSXML 4.0 SP2 (KB954430)
PackageCache=C:\WINDOWS\Installer\b564880.msi


You can expand upon this in many ways. As I said before, and probably too-often: this is simply ONE way to skin this kitty. If you have a better way, that's great too. Drop a feedback comment if you have something to share or a question to ask. Thanks!

No comments: