'========================================================================================================================== ' NAME: CleanComputerFromBadTS_vX.x.vbs ' ' AUTHOR: Mathias Haas, Fidelity Consulting AB. ' mathias.haas@fidelityconsulting.se ' DATE : 2013-10-16 ' Version : 1.6 ' COMMENT: This script removes a faulty TS from the client, kills the TS-process and removes the Paused-SoftwareDist-flag. ' ARGUMENTS : Computername or /CheckAll '========================================================================================================================== Option Explicit 'dim connection,key, SiteDic, i, sSiteServer, sSiteCode Dim swbemLocator, swbemconnection, providerLoc, Location Dim swbemServices Dim sUserName, sUserPassword Dim sLogFile,sDataFile,sAnswerFile Dim sComputername Dim sTSKilled Dim sCheckAll, sNonPingableOnly, colNamedArguments Dim sAnswerFileData, sDataFileData Const sConnect = "YourSCCMServer" '<----------- Change This ! sLogFile = Replace(WScript.ScriptFullName,WScript.ScriptName,"") & Replace (WScript.ScriptName,".vbs","") & ".log" sDataFile = Replace(WScript.ScriptFullName,WScript.ScriptName,"") & "CheckedComputers.log" sAnswerFile = Replace(WScript.ScriptFullName,WScript.ScriptName,"") & "DoesntAnswer.log" sUserName = "" sUserPassword = "" If WScript.Arguments.Count = 0 Then Call LogToFile(Now() & " - Arguments needed. Either or /CheckAll to check ALL computers.") WScript.Quit (1) Else If InStr(UCase(WScript.Arguments(0)),"CHECKALL") > 0 Then sCheckAll = True ElseIf InStr(UCase(WScript.Arguments(0)),"NONPINGABLEONLY") > 0 Then sNonPingableOnly = True Else sComputername = WScript.Arguments(0) End If End If If sCheckAll = True Or sNonPingableOnly = True Then Call AllComputers() If sCheckAll = False Then Call CheckComputer(sComputername) Call LogToFile(Now() & " - Finished!") Wscript.Quit ''''''''''''''''''''''''''''' ' FUNCTIONS ' ''''''''''''''''''''''''''''' '---- ConnectToSCCM ---- Function ConnectToSCCM() On Error Resume Next Set swbemLocator = CreateObject("WbemScripting.SWbemLocator") Set swbemconnection = swbemLocator.ConnectServer(sConnect, "root\sms") Set providerLoc = swbemconnection.InstancesOf("SMS_ProviderLocation") For Each Location In providerLoc If location.ProviderForLocalSite = True Then Set swbemconnection = swbemLocator.ConnectServer(Location.Machine, "root\sms\site_" + Location.SiteCode) Exit For End If Next If Err.Number <> 0 Then Wscript.echo "Unable to connect to the SCCM provider. " & _ "Check the connection and / or the settings in the script!" & _ "The script will be stopped now." WScript.Quit End If On Error GoTo 0 End Function Function AllComputers() Dim obj, Computers Call ConnectToSCCM() Set Computers = swbemconnection.ExecQuery("Select * From SMS_R_System where name like 'B%' and Active = '1' and Client = '1' and Decommissioned = '0' and Obsolete = '0'") sAnswerFileData = ReadDataList(sAnswerFile) sDataFileData = ReadDataList(sDataFile) For each obj in Computers sComputername = obj.Name 'WScript.Echo sComputername If sNonPingableOnly = True And instr(sAnswerFileData,sComputername) > 0 And instr(sDataFileData,sComputername) = False Then 'WScript.Echo "NONpingable" Call CheckComputer(sComputername) ElseIf sNonPingableOnly <> True And instr(sDataFileData,sComputername) = False And instr(sAnswerFileData,sComputername) = False Then Call CheckComputer(sComputername) End If Next end Function Function CheckComputer(ComputerName) Call Ping (ComputerName) If Ping(ComputerName) = True Then Call LogToFile(Now() & " - " & ComputerName & " ### Ping successfull.") '### DO ALL THE REPAIR TASKS HERE... Call KillTSProcess(ComputerName,"TSManager.exe") Call DeleteTSFolder(ComputerName,"c:\_SMSTaskSequence") Call DeleteTSFolder(ComputerName,"c:\SMSTSLog") if sTSKilled = False Then Call CleanPausedRegKey(ComputerName) if sTSKilled = False Then Call ConnectToClientWMI(ComputerName) if sTSKilled = False Then Call KillTSAdv(ComputerName) if instr(sDataFileData,ComputerName) = 0 Then Call WriteDataList(ComputerName,sDataFile) Else Call LogToFile(Now() & " - " & ComputerName & " !!! Doesn't answer to Ping.") If InStr(sAnswerFileData,ComputerName) = 0 Then Call WriteDataList(ComputerName,sAnswerFile) End If End Function Function ReadDataList(file) Dim fso, sPath, fsotxt, sData, sDatatxt Const ForReading = 1 Set fso = CreateObject("Scripting.FileSystemObject") If fso.FileExists (file) then set sData = fso.OpenTextFile(file,ForReading) sDatatxt = sData.ReadAll 'WScript.Echo "Read " & file sData.Close ReadDataList = sDatatxt Else ReadDataList = "" End If End Function Function WriteDataList(ComputerName,file) Dim fso, sPath, fsotxt Const ForAppending = 8 Set fso = CreateObject("Scripting.FileSystemObject") if (fso.FileExists(file)) Then Set fsotxt = fso.OpenTextFile(file, ForAppending, True) Else Set fsotxt = fso.CreateTextFile(file, False) End If fsotxt.WriteLine ComputerName WScript.Echo "Wrote to Logfile:" & file fsotxt.close End Function Function DeleteTSFolder(ComputerName,folder) Dim fso, sPath, fsotxt Set fso = CreateObject("Scripting.FileSystemObject") If InStr (folder,":") Then folder = Replace (folder,":","$") If fso.FolderExists ("\\"&ComputerName &"\"& folder) Then fso.DeleteFolder "\\"&ComputerName &"\"& folder,True Call LogToFile(Now() & " - " & ComputerName & " ### Deleted folder " & folder) End If End Function Function CleanPausedRegKey(ClientName) Dim sRegVal sRegVal = ReadReg(ClientName,"SOFTWARE\Wow6432Node\Microsoft\SMS\Mobile Client\Software Distribution\State","Paused") If sRegVal = 1 Then Call LogToFile(Now() & " - " & ClientName & " - Paused: " & sRegVal) Call WriteReg(ClientName,"SOFTWARE\Wow6432Node\Microsoft\SMS\Mobile Client\Software Distribution\State","Paused") Call WriteReg(ClientName,"SOFTWARE\Wow6432Node\Microsoft\SMS\Mobile Client\Software Distribution\State","PausedCookie") Call LogToFile(Now() & " - " & sComputername & " ### Cleaned Reg Values.") 'Else ' Call LogToFile(ClientName & " - Software Dist. was not paused. Key = " & sRegVal) End If End Function Function ConnectToClientWMI(ClientName) Dim net Dim localConnection Dim swbemLocator 'Dim swbemServices Dim providerLoc Dim location Set swbemLocator = CreateObject("WbemScripting.SWbemLocator") swbemLocator.Security_.AuthenticationLevel = 6 'Packet Privacy ' If the server is local, don't supply credentials. Set net = CreateObject("WScript.NetWork") ' Connect to the Client. On Error Resume Next Set swbemServices= swbemLocator.ConnectServer _ (ClientName, "Root\ccm\SoftMgmtAgent",sUserName,sUserPassword) If Err.Number<>0 Then Call LogToFile(Now() & " !!! Couldn't connect: " + Err.Description) Connect = Null If Err.Number<>0 Then Call LogToFile(Now() & " !!! Call to connect failed") : WScript.Quit(1) End If End If Set Connect = Null ' Failed to connect. On Error GoTo 0 End Function Function KillTSAdv(ClientName) Dim intProgramFlags, objProgram Dim oTSExecutionReq, oValue Set oTSExecutionReq = swbemServices.ExecQuery("Select * from CCM_TSExecutionRequest where State = 'Completed' And CompletionState = 'Failure'",,48) For Each oValue In oTSExecutionReq If oValue.State = "Completed" And oValue.CompletionState = "Failure" Then 'Delete the Advertisement Call LogToFile(Now() & " ### Removed the faulty TS-Advertisement: " & oValue.AdvertID & ", " & oValue.MIFPackageName) oValue.delete_ End If Next End Function Function KillTSProcess(Computername,Process) Dim objWMIService, colProcessList,objProcess On Error Resume Next Set objWMIService = GetObject("winmgmts:\\" & Computername & "\root\cimv2") Set colProcessList = objWMIService.ExecQuery ("SELECT * FROM Win32_Process WHERE Name = '"&Process&"'") For Each objProcess in colProcessList objProcess.Terminate() Call LogToFile(Now() & " ### Terminated " & Process & " , ProcessID=" & objProcess.processid & " on " & sComputername) sTSKilled = True 'If we kill the TSManager.exe -process everything else will be fixed automagically. Next On Error GoTo 0 End Function Function ReadReg(sComputername,key,value) Const HKEY_LOCAL_MACHINE = &H80000002 Dim oRegistry, dwValue On Error Resume Next Set oRegistry = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & sComputername & "\root\default:StdRegProv") oRegistry.GetDWORDValue HKEY_LOCAL_MACHINE, key , value, dwValue ReadReg = dwValue If dwValue = Null Then dwValue = "0" On Error GoTo 0 End Function Function WriteReg(sComputername,key,value) Const HKEY_LOCAL_MACHINE = &H80000002 Dim oRegistry Set oRegistry = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & sComputername & "\root\default:StdRegProv") oRegistry.SetDWORDValue HKEY_LOCAL_MACHINE, key , value, 0 Call LogToFile(sComputername & " - Set Paused to 0.") End function Function Ping(myHostName) Dim colPingResults, objPingResult, strQuery ' Define the WMI query strQuery = "SELECT * FROM Win32_PingStatus WHERE Address = '" & myHostName & "'" ' Run the WMI query Set colPingResults = GetObject("winmgmts://./root/cimv2").ExecQuery( strQuery ) ' Translate the query results to either True or False For Each objPingResult In colPingResults If Not IsObject( objPingResult ) Then Ping = False ElseIf objPingResult.StatusCode = 0 Then Ping = True Else Ping = False End If Next Set colPingResults = Nothing End Function Function LogToFile(txt2log) Dim fso, sPath, fsotxt Const ForAppending = 8 Set fso = CreateObject("Scripting.FileSystemObject") if (fso.FileExists(sLogfile)) Then Set fsotxt = fso.OpenTextFile(sLogfile, ForAppending, True) Else Set fsotxt = fso.CreateTextFile(sLogfile, False) fsotxt.WriteLine("Log from " & WScript.ScriptName & ".") End If On Error Resume Next fsotxt.WriteLine txt2log On Error GoTo 0 WScript.Echo txt2log fsotxt.close End Function