Wednesday, July 13, 2011

SCCM/SMS Client Uninstall Script

Forgive the sloppy code but I'm just posting this in response to a post on TechNet in regards to someone trying to mass uninstall the SCCM client.

This script was hastily/sloppily written to address a major problem we had migrating from SMS 2003 to SCCM 2007 where the clients didn't like being reassinged to a new site. The fix action ended up being a myraid of things:

  1. Hung 'ccmexec' service due to the process not terminating
  2. The uninstall didn't fully complete
  3. Duplicate GUID problems
  4. ...etc

You may have to change some parts around:

On Error Resume Next

Set objShell = CreateObject("WScript.Shell")
Set objFSO = CreateObject("Scripting.FileSystemObject")

strOutputFile = "CCMOutputFile.txt"
strComputerFile = "computers.txt"
strSMSCfgFile = "c$\Windows\smscfg.ini"
strSMSDelCertString = "c:\temp\ccmdelcert.exe"
strSMSUninstallString = "c:\windows\system32\ccmsetup\ccmsetup.exe /uninstall"
strSMSCleanString = "c:\temp\ccmclean.exe /all /q"
strSCCMServer = "SCCMSERVERNAME"
strSMSServiceName = "ccmexec"

iComputersSuccess = 0
iComputersOffline = 0
iComputersTotal = 0



arrComputers = Split(getTextFile(strComputerFile), vbCrLf)

If IsArray(arrComputers) Then
 For Each strComputer In arrComputers
  strComputer = Trim(strComputer)
  If strComputer <> "" Then 
   WScript.Echo "Pinging " & strComputer & " to see if it is online."
   If Ping(strComputer) Then
    WScript.Echo "Binding to " & strComputer & " via WMI."
    Set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
    If Err.Number <> 0 Then
     displayError("Binding error to WMI on:  " & strComputer)
     Err.Clear
    End If
    
    If Not objWMI Is Nothing Then
    
     WScript.Echo "Copying pertinent files to c:\temp"
     If Not objFSO.FileExists("\\" & strComputer & "\c$\" & strSMSUninstallString) Then
      objFSO.CopyFile "\\" & strSCCMServer & "\SCCM Client Tools\*", "\\" & strComputer & "\c$\temp\", true
     End If
     
     killProcess strComputer, "ccmexec.exe"

     Set objWMIProcess = GetObject("winmgmts:\\" & strComputer & "\root\cimv2:Win32_Process") 
     
     WScript.Echo "Running delcert process on remote host."
     If objFSO.FileExists("\\" & strComputer & "\c$\temp\ccmdelcert.exe") Then
      spawnProcess strComputer, strSMSDelCertString
     Else
      WScript.Echo "Unable to locate delcert executable for execution."
     End If
     
     WScript.Echo "Running ccmsetup /uninstall process on remote host."
     If objFSO.FileExists("\\" & strComputer & "\c$\windows\system32\ccmsetup\ccmsetup.exe") Then
      spawnProcess strComputer, strSMSUninstallString
     Else
      WScript.Echo "Unable to locate ccmsetup executable for execution."
     End If
     
     WScript.Echo "Running ccmclean process on remote host."
     If objFSO.FileExists("\\" & strComputer & "\c$\temp\ccmclean.exe") Then
      spawnProcess strComputer, strSMSCleanString
     Else
      WScript.Echo "Unable to locate ccmclean executable for execution."
     End If
           
     iComputersSuccess = iComputersSuccess + 1
    Else    
     WScript.Echo "Error binding to WMI using the syntax:  winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2"
    End If
   Else
    iComputersOffline = iComputersOffline + 1
   End If
   iComputersTotal = iComputersTotal + 1
  End If
  If iComputersTotal Mod 5 = 0 Then
   WScript.Echo ""
   WScript.Echo "STATUS UPDATE:"
   WScript.Echo vbTab & "Hosts Successfully Uninstalled:  " & iComputersSuccess
   WScript.Echo vbTab & "Hosts Offline:  " & iComputersOffline
   WScript.Echo vbTab & "Total Hosts Evaluated:  " & iComputersTotal
   WScript.Echo ""
  Else
   WScript.Echo ""
  End If
 Next
End If



' ***********************************************************************************

Sub displayError(strMessage)
    'Display custom message and information from VBScript Err object.

    strError = VbCrLf & "ERROR:  " & strMessage & VbCrLf & _
      "Number (dec) : " & Err.Number & VbCrLf & _
      "Number (hex) : &H" & Hex(Err.Number) & VbCrLf & _
      "Description  : " & Err.Description & VbCrLf & _
      "Source       : " & Err.Source
    Err.Clear
    WScript.Echo strError

End Sub

Function Ping(strComputer)
 Dim objPing, strPing

 Set objPing = objShell.Exec("ping -n 1 -w 2000 " & strComputer & "")
 
 strPing = objPing.StdOut.ReadAll()
 
 If Instr(strPing, "Reply") <> 0 Then
  Ping = True
 Else
  Ping = False
 End If
End Function


Function getTextFile(strFilePath)
 If Not objFSO.FileExists(strFilePath) Then
  WScript.Echo "Could not locate text file:  " & strFilePath
  WScript.Quit
 End If
 
 Set objTextFile = objFSO.OpenTextFile(strFilePath, 1)
 strTemp = objTextFile.ReadAll
 objTextFile.Close
 
 getTextFile = strTemp
End Function

Sub killProcess(strComputer, strProcess)
 Set objSWbemLocator = CreateObject("WbemScripting.SWbemLocator") 
 objSWbemLocator.Security_.privileges.addasstring "sedebugprivilege", true
 Set objWMIService = objSWbemLocator.ConnectServer(strComputer, "root\CIMV2")
 Set colProcesses = objWMIService.ExecQuery("Select * From Win32_Process Where Name = '" & strProcess & "'")
 
 If colProcesses.Count = 0 Then
  log("Process not found to be running:  " & strProcess & vbCrLf)
 ElseIf colProcesses.Count > 0 Then
  For Each objProcess in colProcesses
   intReturn = objProcess.Terminate()
   log("Attempting to kill process (" & strProcess & ") returned error code:  " & intReturn & vbCrLf)
  Next
 Else
  log(".Count method returned an unexpected value while attempting to kill:  " & strProcess & vbCrLf)
 End If
End Sub

Sub spawnProcess(strComputer, strExec)
 intReturn = objWMIProcess.Create(strExec)
 Select Case intReturn
  Case 0 WScript.Echo "Process creation was a success"
  Case 2 WScript.Echo "Process creation returned Access Denied"
  Case 3 WScript.Echo "There were insufficient priviledges to complete the process"
  Case 8 WScript.Echo "Unknown failure"
  Case 9 WScript.Echo "Path not found"
  Case 21 WScript.Echo "Invalid Parameter"
  Case Else WScript.Echo "Process creation returned an unrecognized parameter"
 End Select
End Sub