How fast is your print server working?

Author Message
mwalkowi

  • Total Posts : 1
  • Scores: 0
  • Reward points : 0
  • Joined: 3/31/2010
  • Status: offline
How fast is your print server working? Wednesday, March 31, 2010 8:47 AM (permalink)
0
At my company, we have a number of sites - some big, some small.  Each site has a "site server", at the small sites, each server does multiple things, but at the larger sites, we have multiple servers to handle each of the functions.  One of those functions is printing.
Because time is money, we want to know about a problem before the end user has to take the time and call us to inform us that we have a problem.
Our print servers have the standard monitoring enabled (can we ping the server, is the Spooler service running, is the IIS service running, do we have ample disk space) but that doesn't always tell you when the server is in a sour state.  Perhaps 50 huge jobs have come thru at the same time to 50 different printers, and the server is really busy, but is in fact working just fine (so standard monitors won't throw and alert).  Users would start calling saying nothing is printing, or jobs are taking 'forever' to print, but everything you look at tells you things should be working just fine.
I looked high and low for Perfmon counters that would give me some more detail, but nothing jumped out.  Even the counters for the Spooler service don't tell you much.  So I wrote a script.

You setup a printer on each server called PrintToFile - any job sent to that printer does just that, prints to a file.  The script will send a job to that printer, then use the job's output to determine just how long it took to print.

This script also demonstrates some interesting things, such as:
-Quickly PING a server (via WMI) to see if it will respond (does not use ping.exe)
-Connect to the print server and validate the Spooler service is running
-Print a test page to a remote printer via printui.dll (originally I was using WMI, however with servers that have many printers (over 200+) enumerating all the printers took way too long and caused the server to work harder than it needed to)
-An 'Alert' process that uses a file to determine previous state.  I don't want to be alerted over and over for one problem.  I do want to be alerted when the state changes (good -> bad, bad -> good)
-Sending an e-mail

  
 ':: PrintSpeedTest.vbs'
 ':: Assumptions:'
 '::   This script assumes the following:'
 '::   -There is a printer on the Print Server named PrintToFile'
 '::   -The output of the printer is a file named E:\PrintToFile.txt'
 '::    (if another path is used, stipulate that as a second argument)'
 '::   -The driver used is a Xerox WorkCentre 245 PS (however, any PS driver will probably do)'
 ':: Prerequisits:'
 '::   Setup a printer on print server that will print to a file.'
 '::   -Launch Add Printer Wizard'
 '::   -Add a local printer'
 '::   -Create a new port, Local Port'
 '::   -Name the port the path of the output file - E:\PrintToFile.txt'
 '::   -Assign a PS driver to the printer (Xerox WorkCentre245 PS) as PS files are easy to read'
 '::    The headder of the PS file is used to determine how long the job took to process'
 '::  Usage:'
 '::   -Fill out PrintShare, MailTo, MailFrom and TimeoutValue values'
 '::   -Also fill out the SMTP server info inside the vbSendMail sub'
 '::   -cscript PrintSpeedTest.vbs <PrintServer> [<Path to Output file>]'
 
 Const PrintShare = "PrintToFile" 
 Const MailTo = <Alert Email> 
 Const MailFrom = <From Email> 
 Const TimeoutValue = 60 'seconds 
 
 ':: Process Arguments'
 ':: Only acceptable arguments are 'print server name' and 'path to output file' 
 ':: If 'path to output file' is omitted, it defaults to E$'
 Set objArgs = WScript.Arguments 
 If objArgs.Count < 1 Or objArgs.Count > 2 Then 
   WScript.Echo "Usage: cscript PrintSpeedTest.vbs <PrintServer> [<Path to Output file>]" 
   WScript.Quit(0) 
 End If 
 
 PrintServer = UCase(objArgs(0)) 
 If objArgs.Count = 2 Then PathToOutfile = objArgs(1) Else PathToOutfile = "E$" 
 OutputFile = "\\" & PrintServer & "\" & PathToOutfile & "\PrintToFile.txt" 
 
 ':: Setup standard variables for this particular instance 
 ScriptName = WScript.ScriptName 
 Subject = ScriptName & "-" & PrintServer 
 
 fileUP = ScriptName & "-" & PrintServer & "-UP.check" 
 fileDN = ScriptName & "-" & PrintServer & "-DN.check" 
 
 ':: Define and setup variables used outside the Main Sub 
 Dim TestPassed, msg, tTIME 
 TestPassed = False 
 msg = ScriptName & vbCrLf 
 msg = msg & "Print Monitor for " & PrintServer & vbCrLf & vbCrLf 
 
 ':: Ok, lets get started with some real work 
 Call Main(PrintServer, PrintShare, OutputFile, TimeoutValue) 
  ':: If the value returned for the total time taken to print the job has a length less than one, substitute '-1' 
  ':: Since this script could also be used to chart total time over time (MRTG), write out this value 
  If Len(tTIME) < 1 Then tTIME = "-1" 
  WScript.Echo tTIME 
 
 ':: Pass results thru Alert. If state changes (Good -> Bad, Bad -> Good) send an alert 
 ':: Otherwise simply update the current state file with current results 
 ':: fileUP or fileDN (located in the same folder as this script) are used to keep track of the current state 
 Call Alert(TestPassed, fileUP, fileDN, Subject, MailTo, MailFrom, msg) 
 
 WScript.Quit 
 
 
 '__________________________________________________________________________________ 
 Sub Main(SERVER, PRINTER, OUTFILE, TIMEOUT) 
   ':: PreTest: Ping Server 
   If Ping(SERVER) <> True Then 
     msg = msg & "Unable to ping server " & SERVER & vbCrLf 
     TestPassed = False 
     Exit Sub 
   End If 
 
   ':: PreTest: Delete previous print output file 
   Set fso = CreateObject("Scripting.FileSystemObject") 
   If fso.FileExists(OUTFILE) Then fso.DeleteFile OUTFILE, True 
   If fso.FileExists(OUTFILE) Then 
     msg = msg & "Unable to delete " & OUTFILE & ": " & Err.Description & vbCrLf 
     TestPassed = False 
     Err.Clear 
     Exit Sub 
   End If 
    
   ':: PreTest: Connect to WMI 
   On Error Resume Next 
   Set objWMI = GetObject("winmgmts:\\" & SERVER) 
   If Err.Number Then 
     msg = msg & "Cannot connect to WMI service on " & SERVER & ": " & Err.Description 
     TestPassed = False 
     Err.Clear 
     Exit Sub 
   End If 
   On Error Goto 0 
 
   ':: PreTest: Verify Spooler service is running 
   strQueryService = "Select * From Win32_Service Where Name = 'Spooler'" 
   Set colServices = objWMI.ExecQuery(strQueryService) 
   For Each objService In colServices 
     If objService.State <> "Running" Then 
       msg = msg & "Spooler service not running. Current state: " & objService.State & vbCrLf 
       TestPassed = False 
       Exit Sub 
     End If 
   Next 
 
   ':: PreTest: Verify we find one and only one printer 
   Set WshShell = CreateObject("WScript.Shell") 
   cmdNetView = "cmd /c net view \\" & SERVER & " | findstr " & PRINTER & " " 
   Set objNetView = WshShell.Exec(cmdNetView) 
   strNetView = objNetView.StdOut.ReadAll 
   asdf = Err.Number 
   If Len(strNetView) = 0 Then 
     msg = msg & "Printer " & PRINTER & " not found on server " & SERVER & vbCrLf 
     TestPassed = False 
     Exit Sub 
   End If 
 
   ':: All pre-tests passed!  No reason the job shouldn't print at this point. 
   cmdPrintTest = "cmd /c rundll32 printui.dll,PrintUIEntry /k /n " & Chr(34) & "\\" & SERVER & "\" & PRINTER & Chr(34) 
   sTIME = Now() 
   Set objPrintTest = WshShell.Exec(cmdPrintTest) 
   strPrintTest = objPrintTest.StdOut.ReadAll 
 
   ':: Print sent, now lets see if it successfully printed 
   ':: Give the system two seconds to catch up 
   WScript.Sleep 2000 
    
   ':: Test: Look for Output file 
   If Not fso.FileExists(OUTFILE) Then 
     msg = msg & OUTFILE & " not found after sending print job." & vbCrLf 
     TestPassed = False 
     Exit Sub 
   End If 
    
   ':: Test: Make sure Output file looks like a PostScript print job 
   If Left(fso.OpenTextFile(OUTFILE).ReadLine, 13) <> "%-12345X@PJL" Then 
     msg = msg & OUTFILE & " not a valid PostScript file. Missing '%-12345X@PJL' at top" & vbCrLf 
     TestPassed = False 
     Exit Sub 
   End If 
    
   ':: All tests passed! 
   ':: Determine how long the whole process took 
   Set fsoOutput = fso.OpenTextFile(OUTFILE) 
   Do Until fsoOutput.AtEndOfStream 
     L = fsoOutput.ReadLine 
     ':: Look for the following line: %%CreationDate: 1/1/2010 12:00:00 and derive elapsed time 
     If Left(L, 16) = "%%CreationDate: " Then 
       fTIME = CDate(Split(L, " ", 2)(1)) 
       Exit Do 
     End If 
   Loop 
   tTIME = DateDiff("s", sTIME, fTIME) 
   If tTIME > TIMEOUT Then 
     msg = msg & "Print job to server " & SERVER & " took more than " & TIMEOUT & " seconds" 
     TestPassed = False 
     Exit Sub 
   End If 
 
   msg = msg & "All tests passed." & vbCrLf 
   msg = msg & "Elapsed Time: " & tTIME & " seconds" & vbCrLf 
   TestPassed = True 
   Exit Sub 
 End Sub 
 
 
 '__________________________________________________________________________________ 
 Sub Alert(CheckState, fileUP, fileDN, Subject, MailTo, MailFrom, msg) 
   Set fso = CreateObject("Scripting.FileSystemObject") 
   If CheckState = True Then 
     If fso.FileExists(fileUP) Then 
       Set fsoUp = fso.OpenTextFile(fileUP, 8) 
       fsoUp.WriteLine GetDateTime() & "-StillGood " & "(" & tTIME & " sec)" 
       fsoUp.Close 
     Else 
       If fso.FileExists(fileDN) Then 
         If fso.FileExists(fileDN & "." & GetDateTime()) Then fso.DeleteFile fileDN & "." & GetDateTime(), True 
         fso.MoveFile fileDN, fileDN & "." & GetDateTime() 
       End If 
       Set fsoUP = fso.OpenTextFile(fileUP, 2, True) 
       fsoUP.WriteLine msg 
       fsoUP.WriteLine GetDateTime() & "-Good " & "(" & tTIME & " sec)" 
       fsoUP.Close 
 
       Set fsoMail = fso.OpenTextFile(fileUP, 1) 
       strMsg = fsoMail.ReadAll 
       fsoMail.Close 
       vbSendMail Subject, MailTo, MailFrom, msg 
     End If 
   Else 
     If fso.FileExists(fileDN) Then 
       Set fsoUp = fso.OpenTextFile(fileDN, 8) 
       fsoUp.WriteLine GetDateTime() & "-StillBad " & "(" & tTIME & " sec)" 
       fsoUp.Close 
     Else 
       If fso.FileExists(fileUP) Then 
         If fso.FileExists(fileUP & "." & GetDateTime()) Then fso.DeleteFile fileUP & "." & GetDateTime(), True 
         fso.MoveFile fileUP, fileUP & "." & GetDateTime() 
       End If 
       Set fsoDN = fso.OpenTextFile(fileDN, 2, True) 
       fsoDN.WriteLine msg 
       fsoDN.WriteLine GetDateTime() & "-Bad " & "(" & tTIME & " sec)" 
       fsoDN.Close 
 
       Set fsoMail = fso.OpenTextFile(fileDN, 1) 
       strMsg = fsoMail.ReadAll 
       fsoMail.Close 
       vbSendMail Subject, MailTo, MailFrom, msg 
     End If 
   End If 
   Set fso = Nothing 
 End Sub 
 
 
 '__________________________________________________________________________________ 
 Private Sub vbSendMail(SUBJECT, MAILTO, MAILFROM, MESSAGE) 
   Const SMTP = <SMTP Server> 
   Dim objCDOSYSCon, objCDOSYSMail 
   Set objCDOSYSMail = CreateObject("CDO.Message") 
   Set objCDOSYSCon = CreateObject ("CDO.Configuration") 
   objCDOSYSCon.Fields("http://schemas.microsoft.com/cdo/configuration/smtpserver") = SMTP 
   objCDOSYSCon.Fields("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25 
   objCDOSYSCon.Fields("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2 
   objCDOSYSCon.Fields("http://schemas.microsoft.com/cdo/configuration/smtpconnectiontimeout") = 10 
   objCDOSYSCon.Fields.Update 
   Set objCDOSYSMail.Configuration = objCDOSYSCon 
   'WScript.Echo "Type of objCDOSYSMail is " & TypeName(objCDOSYSMail) 
 
   objCDOSYSMail.From = MAILFROM 
   objCDOSYSMail.To = MAILTO 
   objCDOSYSMail.Subject = SUBJECT 
   objCDOSYSMail.TextBody = MESSAGE 
   objCDOSYSMail.Send 
 End Sub 
 
 
 '__________________________________________________________________________________ 
 Function Ping(strHostname) 
   Ping = False 
   strQuery = "SELECT * FROM Win32_PingStatus WHERE Address = '" & strHostname & "'" 
   Set colPingResults = GetObject("winmgmts://./root/cimv2").ExecQuery(strQuery) 
   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 GetDateTime() 
   strDate = FormatDateTime(Date, 2) 
   strTime = FormatDateTime(Time, 3) 
    
   strDateY = Mid(strDate, InStrRev(strDate, "/") +1) 
   strDateD = Mid(strDate, InStr(strDate, "/") +1, InStrRev(strDate, "/") - InStr(strDate, "/") -1) 
   strDateM = Mid(strDate, 1, InStr(strDate, "/") -1) 
    If Len(strDateD) < 2 Then strDateD = "0" & strDateD 
    If Len(strDateM) < 2 Then strDateM = "0" & strDateM 
   strTimeH = Mid(strTime, 1, InStr(strTime, ":") -1) 
   strTimeN = Mid(strTime, InStr(strTime, ":") +1, InStrRev(strTime, ":") - InStr(strTime, ":") -1) 
   strTimeS = Mid(strTime, InStrRev(strTime, ":") +1, InStrRev(strTime, " ") - InStrRev(strTime, ":")) 
    If Len(strTimeH) < 2 Then strTimeH = "0" & strTimeH 
     
   GetDateTime = Trim(strDateY & "." & strDateM & strDateD & "." & strTimeH & strTimeN & strTimeS) 
 End Function 
 
 

<message edited by mwalkowi on Wednesday, March 31, 2010 1:54 PM>
 
#1

    Online Bookmarks Sharing: Share/Bookmark

    Jump to:

    Current active users

    There are 0 members and 2 guests.

    Icon Legend and Permission

    • New Messages
    • No New Messages
    • Hot Topic w/ New Messages
    • Hot Topic w/o New Messages
    • Locked w/ New Messages
    • Locked w/o New Messages
    • Read Message
    • Post New Thread
    • Reply to message
    • Post New Poll
    • Submit Vote
    • Post reward post
    • Delete my own posts
    • Delete my own threads
    • Rate post

    2000-2012 ASPPlayground.NET Forum Version 3.9