Thursday, May 21, 2009

Crank 'em Up and Rip 'em Out

Ever wanted to batch remove software from computers on your network, but maybe you don't have SMS, or Altiris, or System Center, or OpenView, or Tivoli, or a band of Mexican gunslinging marauders with thumbdrives in their bandalaros?  Maybe you're dying for AppLocker in Windows 7 and Windows Server 2008 R2, but unfortunately: they're not released yet.

There's quite a few ways to do this.  One way which I have used in the past, which is also one of the laziest ways, is to use a computer start-up script and Group Policy.  Probably THE laziest way is to order one of your staff to walk around and do this manually.  But maybe on the bright side it would promote the perception of higher-quality customer service.  "Look, here comes that dorky IT guy.  I get to punch him first!"

Basically, you create a script and put it in a shared folder.  You grant permissions to the shared folder (NTFS and Share level) so the "Domain Computers" group will have READ access.  Then you create a Group Policy Object (GPO) with the requisite start-up script setting to point to the script in the shared folder path (always use the UNC path).  You can use almost any script tool.  I've used VBScript, BAT and KiXtart mostly, but you could use Perl, PowerShell or whatever works.  As always: TEST CAREFULLY on a FEW machines before you pull the pin and run screaming away.

This version is VBScript and uses an accompanying .TXT file with the same name.  The TXT file should reside in the same shared folder as the .VBS script file.  The code is actually a little more compact with KiXtart, but I haven't bothered porting it to any other languages so I don't know what that might look like.  Instead of "CSCRIPT /NOLOGO <PATH>\app_Uninstall.vbs" in the GPO setting, you can put that line into a .BAT file and have the GPO call the .BAT file instead.  That opens up other possibilities as well, but I'll shut up and dump the code here...

' Filename..: app_uninstall.vbs
' Author....:
' Date......: 02/11/2008
' Purpose...: uninstall applications using an input file listing
Option Explicit

Const inputFile = "app_remove_list.txt"
Const strComputer = "."
Const debugEnabled = True

Const ForReading = 1
Const ForWriting = 2

Dim objWMIService, objFSO, wmistring

wmistring = "winmgmts:{impersonationLevel=impersonate}!\\" & _
strComputer & "\root\cimv2"
Set objWMIService = GetObject(wmistring)

' comment:

Sub DebugPrint(s)
If debugEnabled = True Then
wscript.echo Now & vbTab & s
End If
End Sub

' comment:

Sub Uninstall(app)
Dim colSoftware, objSoftware, retval
DebugPrint "info: searching for " & Quote(app) & "..."
On Error Resume Next
Set colSoftware = objWMIService.ExecQuery("Select * from Win32_Product Where Name='" & app & "'")
If err.Number <> 0 Or (Lbound(colSoftware)=Ubound(colSoftware)) Or IsNull(colSoftware) Then
DebugPrint "info: " & Quote(app) & " is not installed"
Exit Sub
End If
DebugPrint "info: requesting removal of application..."
For Each objSoftware in colSoftware
retval = objSoftware.Uninstall()
If retval = 0 Then
DebugPrint "info: uninstall was successful"
DebugPrint "error: uninstall request failed!"
End If
End Sub

' comment:

Function Quote(s)
Quote = Chr(34) & s & Chr(34)
End Function

' comment:

Sub Main()
Dim objFile, appName, pathname, shortname, fullname, inputpath
fullname = Wscript.ScriptFullName
shortname = Wscript.ScriptName
pathname = Replace(fullname, shortname, "")
inputPath = pathname & inputfile
Set objFSO = Wscript.CreateObject("Scripting.FileSystemObject")
DebugPrint "info: searching for input file..."
If objFSO.FileExists(inputPath) Then
DebugPrint "info: loading applications list..."
Set objFile = objFSO.OpenTextFile(inputPath, ForReading)
DebugPrint "info: applications list loaded successfully"
Do While objFile.AtEndOfStream <> True
appName = Trim(objFile.ReadLine)
If appName <> "" And Left(appName, 1) <> ";" Then
Uninstall appName
End If
Set objFile = Nothing
DebugPrint "info: processing complete"
DebugPrint "error: input file not found = " & inputPath
End If
Set objFSO = Nothing
End Sub

' comment:


The .TXT file should contain the actual names of the applications as they would appear in the Add or Remove Programs list in Control Panel. You can fetch them from there, or from the registry by going under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall. Each application is listed as a sub-key and you would query the DisplayName value for each. There's lots of ways to do that, so I won't bother with that. But here's an example .TXT file to play with...

; Application Removal List
Stupid Application 2009
Farm Animals Calendar 2007
Visual Sewer Unclogger v10

Lines which are empty or begin with a semi-colon (;) are ignored by the script.  The script processing output (if DebugMode is set to True) would look like the following if the applications are not found on a given computer...

5/20/2009 8:43:40 PM	info: searching for input file...
5/20/2009 8:43:40 PM info: loading applications list...
5/20/2009 8:43:40 PM info: applications list loaded successfully
5/20/2009 8:43:40 PM info: searching for "Stupid Application 2009"...
5/20/2009 8:43:40 PM info: "Stupid Application 2009" is not installed
5/20/2009 8:43:40 PM info: searching for "Farm Animals Calendar 2007"...
5/20/2009 8:43:40 PM info: "Farm Animals Calendar 2007" is not installed
5/20/2009 8:43:40 PM info: searching for "Visual Sewer Unclogger v10"...
5/20/2009 8:43:40 PM info: "Visual Sewer Unclogger v10" is not installed
5/20/2009 8:43:40 PM info: processing complete

If you want to take this a step further (or farther?), you can capture the output to another text file and then push it up to another shared folder (remember to grant "Domain Computers" to allow CHANGE access, share and NTFS).  That way you can come in the next morning to look at who rebooted and what happened.  If you want to force it, kill the building power overnight and turn it back on.  Drastic, of course, but at least you'll know the computers had to be rebooted.

Post a Comment