{"id":41,"date":"2008-10-21T03:40:50","date_gmt":"2008-10-20T18:40:50","guid":{"rendered":"http:\/\/www.jhouseconsulting.com\/?p=41"},"modified":"2009-02-04T03:33:06","modified_gmt":"2009-02-03T19:33:06","slug":"print-spooler-self-healing-20","status":"publish","type":"post","link":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/2008\/10\/21\/print-spooler-self-healing-20-41","title":{"rendered":"Print Spooler Self Healing 2.0"},"content":{"rendered":"<p>I was driven to write this script for a client that was using Novell&#8217;s iPrint.\u00a0iPrint was causing some threads to hang, ending the spoolsv.exe process, and therefore stopping the Print Spooler service. Those of you that are using such poor printing solutions would no doubt have clocked up a considerable number of headaches. The good news is that this script will provide you with some much deserved pain relief. Let&#8217;s call it the &#8220;Asprin for iPrint&#8221;. I&#8217;ll have to register a trade mark for that one \ud83d\ude09<\/p>\n<p>So why is this script so good? Glad you asked!<!--more--><\/p>\n<p>It\u00a0monitors the spoolsv.exe process. If the process ends, it then checks to see if the service has cleanly stopped with an &#8220;Exit Code&#8221; of 0. If it hasn&#8217;t, it will clean out the spooler folder and then restart the Spooler service, including\u00a0any dependants that are not running, such as the &#8220;Citrix Print Manager&#8221; service. The cool thing is that it time stamps the events, writes messages to the Event Logs, and sends e-mail alerts. Very cool for monitoring a problematic printing environment.<\/p>\n<p>The script does a whole lot more, specifically around iPrint, and can really be adapted for any printing solution. The important thing is that it quickly and neatly restarts the Spooler service, preventing any user interruptions what so ever.<\/p>\n<p>I&#8217;m currently running the script from the good\u00a0old\u00a0&#8220;autoexnt&#8221; Resouce Kit tool, so it runs at Startup as the System account. But you could also run it as a Startup Script from a Group Policy Object.<\/p>\n<p>It is executed by the Autoexnt.bat using the following line&#8230;<\/p>\n<pre name=\"code\" class=\"vb.net\">\r\nstart cscript \/\/nologo \"%SystemRoot%\\System32\\MonitorProcess.vbs\" spoolsv.exe spooler\r\n<\/pre>\n<p>It&#8217;s worth mentioning here that I use the FREE w3 JMail COM Object from <a href=\"http:\/\/www.dimac.net\/\" target=\"_blank\">Dimac<\/a> to send SMTP messages from within VBScripts. And as such, you will see how I create an instance of the jmail.message object <strong>set objJMail = CreateOBject(&#8220;JMail.Message&#8221;)<\/strong> and then specify the sender, recipient, subject, body and mail server. Therefore, this script will fail as is if you do not install JMail, or at least place a copy of the jmail.dll on the server and register it. Alternatively, you can comment out any calls to the SendMail subroutine.<\/p>\n<p>MonitorProcess.vbs<\/p>\n<pre name=\"code\" class=\"vb.net\">\r\n' The purpose of this script is to monitor the spoolsv.exe process. If it ends, restart the Spooler service.\r\n' I have tried to make this as generic as possible so that it can be used to monitor other processes and\r\n' services.\r\n\r\n' This was specifically written for a client who had implemented Novell's iPrint into their Citrix XenApp 4.5\r\n' environment. iPrint was causing a lot of grief when adding printer objects by ending the spoolsv.exe process.\r\n\r\n' Version 1.0\r\n' Written by Jeremy@jhouseconsulting.com on 14th July 2008.\r\n\r\nOption Explicit\r\n\r\nDim objArgs, strProcess, strFile, strService, j, k, blnFirstRun, strComputer\r\nDim objWMIService, colProcesses, blnDebugger, intDebugRuns\r\n\r\nstrComputer = \".\"\r\nSet objArgs = WScript.Arguments\r\n\r\n' Check to make sure we received arguments.\r\nif objArgs.Count = 0 Then\r\n\u00a0 WScript.Echo \"USAGE: cscript \/\/nologo ''MonitorProcess.vbs'' ''&lt;process&gt;'' ''&lt;service&gt;''\" &amp; VbCr &amp; VbCr &amp; _\r\n               \"Where 'process' is the process you wish to monitor, and 'service' is the\" &amp; VbCr &amp; _\r\n               \"short name of the service that needs to be restarted.\" &amp; VbCr &amp; VbCr &amp; _\r\n               \"For Example:\"  &amp; VbCr &amp; _\r\n               \"cscript \/\/nologo MonitorProcess.vbs spoolsv.exe spooler\"\r\n  WScript.Quit(0)\r\nEnd If\r\n\r\nSet objWMIService = GetObject(\"winmgmts:\\\\\" &amp; strComputer &amp; \"\\root\\cimv2\")\r\n\r\n' Check to make sure the script is not already running, as only one copy of this script should be running at\r\n' any time.\r\nSet colProcesses = objWMIService.ExecQuery _\r\n  (\"SELECT commandline FROM Win32_Process WHERE commandline LIKE '%\" &amp; wscript.scriptname &amp; \"%'\")\r\nIf colProcesses.Count &gt; 1 Then\r\n  Set objArgs = Nothing\r\n  Set objWMIService = Nothing\r\n  Set colProcesses = Nothing\r\n  wscript.quit(0)\r\nEnd If\r\n\r\nblnFirstRun = True\r\n\r\n' Setting this value to True will trigger the user mode debugger.\r\nblnDebugger = True\r\n\r\n' This value represents the number of times the debugger should run.\r\nintDebugRuns = 5\r\n\r\nDo Until j = 999\r\n' Note how we never increment j. Therefore, it takes on the default value of 0, and never increments, meaning\r\n' that this will loop forever.\r\n  strProcess = objArgs(0)\r\n  strFile = objArgs(0) &amp; \" monitoring.txt\"\r\n\r\n  if objArgs.Count &gt; 1 Then\r\n    strService = objArgs(1)\r\n  End If\r\n\r\n  If blnFirstRun Then\r\n    wscript.echo Now() &amp; vbTab &amp; \"The script has initiated.\"\r\n  End If\r\n\r\n  Call MonitorProcess(strProcess,strService,strFile,blnFirstRun,blnDebugger)\r\n  blnFirstRun = False\r\n\r\n  If K = intDebugRuns-1 Then\r\n    blnDebugger = False\r\n  End If\r\n  k = k + 1\r\nLoop\r\n\r\nSet objArgs = Nothing\r\nSet objWMIService = Nothing\r\nSet colProcesses = Nothing\r\n\r\nWScript.Quit(0)\r\n\r\nSub MonitorProcess(strProcess,strService,strFile,blnFirstRun,blnDebugger)\r\n\r\n' This subroutine will monitor the process.\r\n\r\n  Dim objWMIService, colProcesses, objProcess, strTimeStamp, strMessage\r\n  Dim strComputer, strProcessPath, process, i, objFSO, intExitCode, strServiceMessage\r\n\r\n  Const HKEY_LOCAL_MACHINE = &amp;H80000002\r\n\r\n  strComputer = \".\"\r\n\r\n  Set objWMIService = GetObject(\"winmgmts:\\\\\" &amp; strComputer &amp; \"\\root\\cimv2\")\r\n  Set objFSO = CreateObject(\"Scripting.FileSystemObject\") \r\n\r\n' Check to see if the process is running.\r\n  Set colProcesses = objWMIService.ExecQuery _\r\n  (\"SELECT * FROM Win32_Process WHERE Name = '\" &amp; strProcess &amp; \"'\")\r\n  If colProcesses.Count &gt; 0 Then\r\n\r\n  If blnDebugger Then\r\n    Call RunDebugger(strProcess,blnFirstRun)\r\n  End If\r\n\r\n'   Get the path of the running process.\r\n    for each process in colProcesses\r\n      strProcessPath = Left(process.ExecutablePath, InstrRev(process.ExecutablePath, \"\\\"))\r\n'     wscript.echo strProcessPath\r\n    Next\r\n    strFile = strProcessPath &amp; strFile\r\n\r\n    If blnFirstRun Then\r\n      If objFSO.FileExists(strFile) Then\r\n        objFSO.DeleteFile(strFile), True\r\n      End If\r\n    End If\r\n\r\n'   Wait for the process to end.\r\n    Set colProcesses = objWMIService.ExecNotificationQuery _\r\n      (\"Select * From __InstanceDeletionEvent \" _\r\n              &amp; \"Within 1 Where TargetInstance ISA 'Win32_Process'\")\r\n\r\n    Do Until i = 999\r\n'   Note how we never increment i. Therefore, it takes on the default value of 0,\r\n'   and never increments, meaning that this will loop forever until the process ends.\r\n    Set objProcess = colProcesses.NextEvent\r\n      If lcase(objProcess.TargetInstance.Name) = lcase(strProcess) Then\r\n        Exit Do\r\n      End If\r\n    Loop\r\n\r\n    intExitCode=ServiceExitCode(strService)\r\n    If intExitCode &lt;&gt; 0 Then\r\n      strTimeStamp=\"on \" &amp; Date() &amp; \" at \" &amp; Time()\r\n      strMessage=\"Process: \" &amp; strProcess &amp; VbCr &amp; \"Status: Ended\" &amp; VbCr &amp; \"Timestamp: \" &amp; strTimeStamp\r\n      wscript.echo Now() &amp; vbTab &amp; \"Process has ended.\"\r\n    Else\r\n      wscript.echo Now() &amp; vbTab &amp; \"Process has ended because the service was cleanly stopped.\"\r\n    End If\r\n\r\n  Else\r\n      strTimeStamp=\"on \" &amp; Date() &amp; \" at \" &amp; Time()\r\n      strMessage=\"Process: \" &amp; strProcess &amp; VbCr &amp; \"Status: Not running\" &amp; VbCr &amp; \"Timestamp: \" &amp; strTimeStamp\r\n      wscript.echo Now() &amp; vbTab &amp; \"Process not running.\"\r\n      Call WaitForProcessToStart(strProcess)\r\n  End If\r\n  If intExitCode &lt;&gt; 0 Then\r\n    Call WriteToEventLog(strMessage)\r\n    wscript.echo Now() &amp; vbTab &amp; \"Message written to event log.\"\r\n    Call WriteToLogFile(strFile,strMessage)\r\n    wscript.echo Now() &amp; vbTab &amp; \"Message written to log file.\"\r\n    Call SendMail(\"Process\",strMessage)\r\n    wscript.echo Now() &amp; vbTab &amp; \"E-mail alert sent.\"\r\n    If strService &lt;&gt; \"\" Then\r\n      Call RestartService(strService,strFile)\r\n    End If\r\n  End If\r\n\r\n  set objWMIService = Nothing\r\n  Set objFSO = Nothing\r\n  Set colProcesses = Nothing\r\n\r\nEnd Sub\r\n\r\nFunction ServiceExitCode(strService)\r\n\r\n' This function gets the exit code for the service and passes it back as a return value so that we know if the\r\n' service has cleanly stopped.\r\n\r\n  Dim strComputer, objWMIService, colListOfServices, objService\r\n  strComputer = \".\"\r\n  Set objWMIService = GetObject(\"winmgmts:\" _\r\n    &amp; \"{impersonationLevel=impersonate}!\\\\\" &amp; strComputer &amp; \"\\root\\cimv2\")\r\n  Set colListOfServices = objWMIService.ExecQuery _\r\n        (\"Select * from Win32_Service where Name='\" &amp; strService &amp; \"'\")\r\n  For Each objService in colListOfServices\r\n    ServiceExitCode=objService.ExitCode\r\n  Next\r\n  Set objWMIService = Nothing\r\n  Set colListOfServices = Nothing\r\nEnd Function\r\n\r\nSub WaitForProcessToStart(strProcess)\r\n\r\n' This subroutine waits for the process to start\r\n\r\n  Dim strComputer, objWMIService, colMonitoredProcesses, l, objLatestProcess, strTimeStamp, strMessage\r\n  strComputer = \".\"\r\n  Set objWMIService = GetObject(\"winmgmts:\" _\r\n    &amp; \"{impersonationLevel=impersonate}!\\\\\" &amp; strComputer &amp; \"\\root\\cimv2\")\r\n  Set colMonitoredProcesses = objWMIService. _\r\n    ExecNotificationQuery(\"select * from __instancecreationevent \" _\r\n        &amp; \" within 1 where TargetInstance isa 'Win32_Process'\")\r\n  Do Until l = 999\r\n    Set objLatestProcess = colMonitoredProcesses.NextEvent\r\n    If lcase(objLatestProcess.TargetInstance.Name) = lcase(strProcess) Then\r\n      strTimeStamp=\"on \" &amp; Date() &amp; \" at \" &amp; Time()\r\n      strMessage=\"Process: \" &amp; strProcess &amp; VbCr &amp; \"Status: Started\" &amp; VbCr &amp; \"Timestamp: \" &amp; strTimeStamp\r\n      wscript.echo Now() &amp; vbTab &amp; \"Process started.\"\r\n      Exit Do\r\n    End If\r\n  Loop\r\n  Set objWMIService = Nothing\r\n  Set colMonitoredProcesses = Nothing\r\n  Set objLatestProcess = Nothing\r\nEnd Sub\r\n\r\nSub RestartService(strService,strFile)\r\n\r\n' This subroutine will restart the service if it has terminated abnormally, and will\r\n' attempt to start any other stopped services that have this service set as a dependency.\r\n\r\n  Dim strComputer, objWMIService, objItem, objService, colListOfServices, return, strTimeStamp\r\n  Dim strMessage, objServiceList, objDependService\r\n  strComputer = \".\"\r\n  Set objWMIService = GetObject(\"winmgmts:\\\\\" &amp; strComputer &amp; \"\\root\\cimv2\")\r\n  Set colListOfServices = objWMIService.ExecQuery _\r\n  (\"Select * from Win32_Service Where Name ='\" &amp; strService &amp; \"'\")\r\n  If colListOfServices.count &gt; 0 Then\r\n    For Each objService in colListOfServices\r\n      If (lcase(objService.State)=\"stopped\") AND (objService.ExitCode&lt;&gt;0) Then\r\n'       As an example, when the spoolsv.exe process ends, the exit code for the spooler\r\n'       service is 1067, which means that the process terminated unexpectedly.\r\n        wscript.echo Now() &amp; vbTab &amp; \"The Service has stopped with an exit code of \" &amp; objService.ExitCode &amp; \".\"\r\n      Else\r\n        return=objService.StopService()\r\n        If return=0 Then\r\n          wscript.echo Now() &amp; vbTab &amp; \"Service successfully stopped.\"\r\n          strTimeStamp=\"on \" &amp; Date() &amp; \" at \" &amp; Time()\r\n          strMessage=\"Service: \" &amp; objService.Name &amp; VbCr &amp; \"Status: Stopped\" &amp; VbCr &amp; \"Timestamp: \" &amp; strTimeStamp\r\n          Call WriteToEventLog(strMessage)\r\n          wscript.echo Now() &amp; vbTab &amp; \"Message written to event log.\"\r\n          Call WriteToLogFile(strFile,strMessage)\r\n          wscript.echo Now() &amp; vbTab &amp; \"Message written to log file.\"\r\n          Call SendMail(\"Service\",strMessage)\r\n          wscript.echo Now() &amp; vbTab &amp; \"E-mail alert sent.\"\r\n        End If\r\n      End If\r\n\r\n      Select Case LCase(strService)\r\n        Case \"spooler\"\r\n          Call CleanOutSpoolerFolder()\r\n          Call CheckforiPrint()\r\n      End Select\r\n\r\n      return=objService.StartService()\r\n      If return=0 Then\r\n        wscript.echo Now() &amp; vbTab &amp; \"The \" &amp; objService.Name &amp; \" service successfully started.\"\r\n      End If\r\n      strTimeStamp=\"on \" &amp; Date() &amp; \" at \" &amp; Time()\r\n      strMessage=\"Service: \" &amp; objService.Name &amp; VbCr &amp; \"Status: Started\" &amp; VbCr &amp; \"Timestamp: \" &amp; strTimeStamp\r\n      Call WriteToEventLog(strMessage)\r\n      wscript.echo Now() &amp; vbTab &amp; \"Message written to event log.\"\r\n      Call WriteToLogFile(strFile,strMessage)\r\n      wscript.echo Now() &amp; vbTab &amp; \"Message written to log file.\"\r\n      Call SendMail(\"Service\",strMessage)\r\n      wscript.echo Now() &amp; vbTab &amp; \"E-mail alert sent.\"\r\n\r\n'     Start dependent services\r\n      Set objServiceList = objWMIService.ExecQuery(\"Associators of \" _\r\n                 &amp; \"{Win32_Service.Name='\" &amp; strService &amp; \"'} Where \" _\r\n                 &amp; \"AssocClass=Win32_DependentService \" &amp; \"Role=Antecedent\" )\r\n      For Each objDependService In objServiceList\r\n        If objDependService.State = \"Stopped\" Then\r\n          return=objDependService.StartService()\r\n          If return=0 Then\r\n            wscript.echo Now() &amp; vbTab &amp; \"The \" &amp; objDependService.Name &amp; \" service successfully started.\"\r\n          End If\r\n          strTimeStamp=\"on \" &amp; Date() &amp; \" at \" &amp; Time()\r\n          strMessage=\"Service: \" &amp; objDependService.Name &amp; VbCr &amp; \"Status: Started\" &amp; VbCr &amp; \"Timestamp: \" &amp; strTimeStamp\r\n          Call WriteToEventLog(strMessage)\r\n          wscript.echo Now() &amp; vbTab &amp; \"Message written to event log.\"\r\n          Call WriteToLogFile(strFile,strMessage)\r\n          wscript.echo Now() &amp; vbTab &amp; \"Message written to log file.\"\r\n          Call SendMail(\"Service\",strMessage)\r\n          wscript.echo Now() &amp; vbTab &amp; \"E-mail alert sent.\"\r\n        End If\r\n      Next\r\n\r\n    Next\r\n  Else\r\n    strTimeStamp=\"on \" &amp; Date() &amp; \" at \" &amp; Time()\r\n    strMessage=\"Service: \" &amp; strService &amp; VbCr &amp; \"Status: Not found\" &amp; VbCr &amp; \"Timestamp: \" &amp; strTimeStamp\r\n    Call WriteToEventLog(strMessage)\r\n    wscript.echo Now() &amp; vbTab &amp; \"Message written to event log.\"\r\n    Call WriteToLogFile(strFile,strMessage)\r\n    wscript.echo Now() &amp; vbTab &amp; \"Message written to log file.\"\r\n    wscript.quit 0\r\n  End If\r\n  Set objWMIService  = Nothing\r\n  Set colListOfServices = Nothing\r\n  Set objServiceList = Nothing\r\nEnd Sub\r\n\r\nSub WriteToEventLog(strMessage)\r\n\r\n' This subroutine will write an alert to the event logs.\r\n\r\n  Dim WshShell\r\n  Set WshShell = CreateObject(\"WScript.Shell\")\r\n  WshShell.LogEvent 2, strMessage\r\n  Set WshShell = Nothing\r\nEnd Sub\r\n\r\nSub WriteToLogFile(strFile,strMessage)\r\n\r\n' This subroutine will write the entries to a text file\r\n\r\n  Dim objFSO, objFile\r\n  Const ForAppending = 8\r\n  Set objFSO = CreateObject(\"scripting.filesystemobject\")\r\n  Set objFile = objFSO.OpenTextFile(strFile,ForAppending,True,0)\r\n  strMessage = Replace(strMessage,VbCr,vbCrLf) &amp; vbCrLf\r\n  objFile.WriteLine strMessage\r\n  objFile.Close\r\n  Set objFile = Nothing\r\nEnd Sub\r\n\r\nSub SendMail(strServiceorProcess,strMessage)\r\n\r\n' This subroutine will send off an e-mail alert using the JMail COM Object from www.Dimac.net\r\n\r\n  Dim WshNetwork, sComputerName, strSMTPServer, strReceipent1, strSubject, strBody\r\n  Dim objJMail\r\n\r\n  Set WshNetwork = WScript.CreateObject(\"WScript.Network\")\r\n  sComputerName = WshNetwork.ComputerName\r\n\r\n  strSMTPServer = \"smtp.mydomain.com\"\r\n  strReceipent1 = \"CitrixAlerts@mydomain.com\"\r\n  strSubject = \"A \" &amp; strServiceorProcess &amp; \" has changed state on \" &amp; sComputerName &amp; \".\"\r\n\r\n  strBody = Replace(strMessage,VbCr,vbCrLf)\r\n\r\n  set objJMail = CreateOBject(\"JMail.Message\")\r\n\r\n  objJMail.From = \"server.alerts@mydomain.com\"\r\n  objJMail.FromName = \"Server Alerts\"\r\n\r\n  objJMail.AddRecipient strReceipent1\r\n  objJMail.Subject = strSubject\r\n  objJMail.Body = strBody\r\n\r\n  objJMail.Send(strSMTPServer)\r\n\r\n  Set WshNetwork = Nothing\r\n  set objJMail = Nothing\r\nEnd Sub\r\n\r\nSub CleanOutSpoolerFolder()\r\n\r\n' This subroutine will clean put the Spooler folder.\r\n\r\n  Dim oReg, strComputer, objFSO, strKeyPath, strValueName, strValue, objFolder, Subfolder\r\n\r\n  Const HKEY_LOCAL_MACHINE = &amp;H80000002\r\n  StrComputer=\".\"\r\n\r\n  Set oReg = GetObject(\"winmgmts:{impersonationLevel=impersonate}!\\\\\" &amp; _\r\n  strComputer &amp; \"\\root\\default:StdRegProv\")\r\n  Set objFSO = CreateObject(\"Scripting.FileSystemObject\") \r\n\r\n  strKeyPath = \"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Printers\"\r\n  strValueName = \"DefaultSpoolDirectory\"\r\n  oReg.GetStringValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strValue\r\n  Wscript.Echo Now() &amp; vbTab &amp; \"The spooler folder is: \" &amp; strValue\r\n\r\n  objFSO.DeleteFile(strValue &amp; \"\\*.*\"), True\r\n  Set objFolder = objFSO.GetFolder(strValue)\r\n  For Each Subfolder in objFolder.SubFolders\r\n    objFSO.DeleteFolder Subfolder.Path, True\r\n  Next\r\n  Wscript.Echo Now() &amp; vbTab &amp; \"Deleted the contents of the spooler folder.\"                   \r\n\r\n  Set objFolder = Nothing\r\n  Set oReg = Nothing\r\n  Set objFSO = Nothing\r\nEnd Sub\r\n\r\nSub CheckforiPrint()\r\n\r\n' This subroutine checks for the existence of iPrint.\r\n' If it's installed it checks to see if Trace is enabled.\r\n' If Trace is enabled it checks for the Trace file.\r\n' If the Trace file exists, it renames it before restarting the Spooler service.\r\n' NOTE that iPrint should be doing this, but I found that it was unreliable. It\r\n' was perhaps a timing issue!\r\n\r\n  Dim oReg, strComputer, objFSO, strKeyPath, strValueName, dwValue\r\n  Dim WshShell, sRegValue, sRegKey, strSystemDrive\r\n\r\n  Const HKEY_LOCAL_MACHINE = &amp;H80000002\r\n  StrComputer=\".\"\r\n\r\n  Set WshShell = CreateObject(\"WScript.Shell\")\r\n  Set oReg = GetObject(\"winmgmts:{impersonationLevel=impersonate}!\\\\\" &amp; _\r\n  strComputer &amp; \"\\root\\default:StdRegProv\")\r\n  Set objFSO = CreateObject(\"Scripting.FileSystemObject\")\r\n  strSystemDrive = WshShell.ExpandEnvironmentStrings(\"%SystemDrive%\")\r\n\r\n  sRegKey = \"HKLM\\SOFTWARE\\Novell-iPrint\"\r\n  sRegValue = \"HKLM\\SOFTWARE\\Novell-iPrint\\Settings\\TraceOn\" \r\n\r\n  If RegKeyExists(sRegKey) Then\r\n    Wscript.Echo Now() &amp; vbTab &amp; \"iPrint is installed.\"\r\n    If RegValueExists(sRegValue) Then\r\n'     Check to see if Trace is enabled\r\n      strKeyPath = \"SOFTWARE\\Novell-iPrint\\Settings\"\r\n      strValueName = \"TraceOn\"\r\n      oReg.GetDWORDValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,dwValue\r\n      Select Case dwValue\r\n        Case 0\r\n          Wscript.Echo Now() &amp; vbTab &amp; \"iPrint Trace is disabled.\"\r\n        Case 1\r\n          Wscript.Echo Now() &amp; vbTab &amp; \"iPrint Trace is enabled.\"\r\n'         Check for existance Trace file.\r\n          If objFSO.FolderExists(strSystemDrive &amp; \"\\NDPS\") Then\r\n            If objFSO.FileExists(strSystemDrive &amp; \"\\NDPS\\ippTrace.txt\") Then\r\n              Wscript.Echo Now() &amp; vbTab &amp; \"An iPrint Trace File exists.\"\r\n              If objFSO.FileExists(strSystemDrive &amp; \"\\NDPS\\ippTrace.previous.txt\") Then\r\n                objFSO.DeleteFile strSystemDrive &amp; \"\\NDPS\\ippTrace.previous.txt\", 1\r\n              End If\r\n              objFSO.MoveFile strSystemDrive &amp; \"\\NDPS\\ippTrace.txt\", strSystemDrive &amp; \"\\NDPS\\ippTrace.previous.txt\"\r\n              Wscript.Echo Now() &amp; vbTab &amp; \"Renamed iPrint Trace file to \" &amp; strSystemDrive &amp; \"\\NDPS\\ippTrace.previous.txt\"\r\n            Else\r\n              Wscript.Echo Now() &amp; vbTab &amp; \"The iPrint Trace file is missing.\"\r\n            End If\r\n          End If\r\n        Case Else\r\n          Wscript.Echo Now() &amp; vbTab &amp; \"iPrint Trace setting is invalid.\"\r\n      End Select\r\n    End If\r\n  Else\r\n    Wscript.Echo Now() &amp; vbTab &amp; \"iPrint is not installed.\"\r\n  End If\r\n  Set WshShell = Nothing\r\n  Set oReg = Nothing\r\n  Set objFSO = Nothing\r\nEnd Sub\r\n\r\nFunction RegKeyExists(ByVal sRegKey) \r\n\r\n' Returns True or False based on the existence of a registry key.\r\n\r\n  Dim sDescription, oShell\r\n  Set oShell = CreateObject(\"WScript.Shell\")\r\n  RegKeyExists = True\r\n  sRegKey = Trim (sRegKey)\r\n  If Not Right(sRegKey, 1) = \"\\\" Then\r\n    sRegKey = sRegKey &amp; \"\\\"\r\n  End If\r\n  On Error Resume Next\r\n  oShell.RegRead \"HKEYNotAKey\\\"\r\n  sDescription = Replace(Err.Description, \"HKEYNotAKey\\\", \"\")\r\n  Err.Clear\r\n  oShell.RegRead sRegKey\r\n  RegKeyExists = sDescription &lt;&gt; Replace(Err.Description, sRegKey, \"\")\r\n  On Error Goto 0\r\n  Set oShell = Nothing\r\nEnd Function\r\n\r\nFunction RegValueExists(sRegValue) \r\n\r\n' Returns True or False based of the existence of a registry value. \r\n\r\n  Dim oShell, RegReadReturn\r\n  Set oShell = CreateObject(\"WScript.Shell\")\r\n  RegValueExists = True  ' init value\r\n  On Error Resume Next\r\n  RegReadReturn = oShell.RegRead(sRegValue)\r\n  If Err.Number &lt;&gt; 0 Then\r\n    RegValueExists = False\r\n  End if\r\n  On Error Goto 0\r\n  Set oShell = Nothing\r\nEnd Function \r\n\r\nSub RunDebugger(strProcess,blnFirstRun)\r\n\r\n' ADPlus is a vbscript included with the Debugging Tools for Windows. To enable the\r\n' monitoring of a process and Wait for a crash, use the following command:\r\n' ADPlus will only provide a user mode dump. Refer to KB article 286350 for further\r\n' information.\r\n\r\n  Dim WshShell, objFSO, strSystemDrive, strProgramFiles, strCommandLine\r\n  Set WshShell = CreateObject(\"WScript.Shell\")\r\n  Set objFSO = CreateObject(\"Scripting.FileSystemObject\")\r\n  strSystemDrive = WshShell.ExpandEnvironmentStrings(\"%SystemDrive%\")\r\n  strProgramFiles = WshShell.ExpandEnvironmentStrings(\"%ProgramFiles%\")\r\n  If objFSO.FileExists(strProgramFiles &amp; \"\\Debugging Tools for Windows\\adplus.vbs\") Then\r\n  If blnFirstRun Then\r\n    If objFSO.FolderExists(strSystemDrive &amp; \"\\\" &amp; strProcess &amp; \"_dumps\\\") Then\r\n      objFSO.DeleteFolder strSystemDrive &amp; \"\\\" &amp; strProcess &amp; \"_dumps\", True\r\n    End If\r\n  End If\r\n  If NOT objFSO.FolderExists(strSystemDrive &amp; \"\\\" &amp; strProcess &amp; \"_dumps\\\") Then\r\n      objFSO.CreateFolder(strSystemDrive &amp; \"\\\" &amp; strProcess &amp; \"_dumps\")\r\n    End If\r\n    strCommandLine = \"cscript \" &amp; chr(34) &amp; strProgramFiles &amp; \"\\Debugging Tools for Windows\\adplus.vbs\" &amp; chr(34) &amp; \" -quiet -crash -pn \" &amp; strProcess &amp; \" -o \" &amp; strSystemDrive &amp; \"\\\" &amp; strProcess &amp; \"_dumps\"\r\n    WshShell.Run strCommandLine, 1, FALSE\r\n    wscript.echo Now() &amp; vbTab &amp; \"Running the debugger to monitor for a \" &amp; strProcess &amp; \" crash using the following command line...\" &amp; VbCrLf &amp; strCommandLine\r\n  End If\r\n  Set WshShell = Nothing\r\n  Set objFSO = Nothing\r\nEnd Sub\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>I was driven to write this script for a client that was using Novell&#8217;s iPrint.\u00a0iPrint was causing some threads to hang, ending the spoolsv.exe process, and therefore stopping the Print Spooler service. Those of you that are using such poor printing solutions would no doubt have clocked up a considerable number of headaches. The good &#8230; <a title=\"Print Spooler Self Healing 2.0\" class=\"read-more\" href=\"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/2008\/10\/21\/print-spooler-self-healing-20-41\" aria-label=\"Read more about Print Spooler Self Healing 2.0\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"footnotes":""},"categories":[55,57,5],"tags":[83,82,84],"class_list":["post-41","post","type-post","status-publish","format-standard","hentry","category-novell","category-printing","category-scripting","tag-monitor-spooler","tag-monitor-spoolsvexe","tag-spoolsvexe"],"aioseo_notices":[],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/posts\/41","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/comments?post=41"}],"version-history":[{"count":23,"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/posts\/41\/revisions"}],"predecessor-version":[{"id":75,"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/posts\/41\/revisions\/75"}],"wp:attachment":[{"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/media?parent=41"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/categories?post=41"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.jhouseconsulting.com\/jhouseconsulting\/wp-json\/wp\/v2\/tags?post=41"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}