no way to compare when less than two revisions
Differences
This shows you the differences between two versions of the page.
— | monitors:listprn [2012/05/04 08:28] (current) – created - external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== listprn.vbs ====== | ||
+ | |||
+ | ^ Author | [[ goldfndr@gmail.com | Richard Finegold ]] | | ||
+ | ^ Compatibility | Xymon/ | ||
+ | ^ Requirements | VBScript and (BBWin or BBNT) on client | | ||
+ | ^ Download | None | | ||
+ | ^ Last Update | 2012-05-03 | | ||
+ | |||
+ | ===== Description ===== | ||
+ | This lists TCP/ | ||
+ | |||
+ | ===== Installation ===== | ||
+ | === Client side === | ||
+ | * Confirm that the client is actually being used as a print server. On Windows XP, one would check by opening Printers, File/Server Properties, and on the Ports tab, check that IP_* ports (typically described as " | ||
+ | * Copy listprn.vbs (below) to your BBWin' | ||
+ | * Customize the IPpattern and MYDOMAIN values to match your network' | ||
+ | * Optionally try running it at the command line (cscript listprn.vbs), | ||
+ | * Edit your BBWin' | ||
+ | * Add a line in the '' | ||
+ | <load value=" | ||
+ | </ | ||
+ | * If the externals agent was disabled in the '' | ||
+ | <load name=" | ||
+ | </ | ||
+ | |||
+ | === Server side === | ||
+ | Optionally add a composite script that makes a report of all printers. prntx.sh depends on prnt.sh; run something like the following:< | ||
+ | == prnt.sh == | ||
+ | If the listing isn't long enough to warrant stand-alone versions of Combined/ | ||
+ | <hidden onHidden=" | ||
+ | <code bash> | ||
+ | COLUMN=prnt | ||
+ | LOGFILE=/ | ||
+ | |||
+ | #Filter out some totals | ||
+ | echo "< | ||
+ | <script src=\" | ||
+ | < | ||
+ | for S in `$BB localhost " | ||
+ | s=`echo $S | tr a-z A-Z` | ||
+ | echo "| <a href=\"# | ||
+ | done | ||
+ | #NOTE: If the length of this isn't enough to warrant stand-alone pages | ||
+ | #NOTE: then remove the links to prnt-{combined|ports|jobs}.html and prnt-names.txt here | ||
+ | #NOTE: and don't bother using prntx.sh. | ||
+ | echo "</ | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | <li> | <a href=prnt-names.txt> | ||
+ | </ | ||
+ | |||
+ | <a name=each>< | ||
+ | |||
+ | #The output of this is essentially identical to what one would get if `cat`-ing the $BBLOGS if | ||
+ | # " | ||
+ | for S in `$BB localhost " | ||
+ | |||
+ | #Get each list of printers, including first line of status | ||
+ | sed ' | ||
+ | /Printers list/,/ | ||
+ | /Printers list/ | ||
+ | s/ | ||
+ | s/ | ||
+ | s/ | ||
+ | s/& | ||
+ | s/& | ||
+ | s/ | ||
+ | s/& | ||
+ | s/ | ||
+ | s/& | ||
+ | #s/table border=1/ | ||
+ | s/< | ||
+ | s/< | ||
+ | ' $LOGFILE | ||
+ | |||
+ | #Calculate some statistics | ||
+ | S=`awk ' /Printers list/ { | ||
+ | shares += substr($9, | ||
+ | MACs += $12; | ||
+ | unassigned+=$14; | ||
+ | ports+=$17; | ||
+ | jobs+=$20 | ||
+ | } END { | ||
+ | print " | ||
+ | }' $LOGFILE` | ||
+ | |||
+ | #Get each list of printers, but rather than listing each separately, combine into one table | ||
+ | #S=`sed '/ | ||
+ | echo "< | ||
+ | |||
+ | <a name=combined>< | ||
+ | `echo $S | sed 's/\; [0-9]* jobs//' | ||
+ | <table border=1 class=sortable>< | ||
+ | sed ' | ||
+ | /Printers list/,/ | ||
+ | /< | ||
+ | s/& | ||
+ | s/& | ||
+ | s/& | ||
+ | s/& | ||
+ | ' $LOGFILE | ||
+ | echo "</ | ||
+ | |||
+ | #Get each list of print jobs, but rather than listing each separately, combine into one table | ||
+ | echo "< | ||
+ | |||
+ | <a name=jobs>< | ||
+ | `echo $S | sed ' | ||
+ | <table border=1 class=sortable>< | ||
+ | sed ' | ||
+ | s/... DATA TRUNCATED .../... DATA TRUNCATED ...\ | ||
+ | < | ||
+ | / | ||
+ | #Put a non-breaking space in the date/time stamp | ||
+ | s/ | ||
+ | /< | ||
+ | s/& | ||
+ | s/& | ||
+ | s/& | ||
+ | s/& | ||
+ | s/& | ||
+ | s/ UNKNOWN/ | ||
+ | ' $LOGFILE | ||
+ | echo "</ | ||
+ | |||
+ | #More statistics (for ports list) | ||
+ | S=`sed ' | ||
+ | s/... DATA TRUNCATED .../... DATA TRUNCATED ...\ | ||
+ | < | ||
+ | / | ||
+ | /< | ||
+ | ' $LOGFILE | wc -l` | ||
+ | |||
+ | #Get each list of ports | ||
+ | echo "< | ||
+ | |||
+ | |||
+ | <a name=ports>< | ||
+ | Total: `echo $S` ports | ||
+ | <table border=1 class=sortable>< | ||
+ | sed ' | ||
+ | s/... DATA TRUNCATED .../... DATA TRUNCATED ...\ | ||
+ | < | ||
+ | / | ||
+ | /< | ||
+ | s/& | ||
+ | s/& | ||
+ | s/& | ||
+ | s/public, 1/ | ||
+ | ' $LOGFILE | ||
+ | echo "</ | ||
+ | echo "< | ||
+ | echo "</ | ||
+ | </ | ||
+ | </ | ||
+ | == prntx.sh == | ||
+ | Customize as you like; at this company, we use a convention of // | ||
+ | <hidden onHidden=" | ||
+ | <code bash> | ||
+ | echo "< | ||
+ | <script src=\" | ||
+ | |||
+ | < | ||
+ | `sed '/ | ||
+ | </ | ||
+ | |||
+ | echo "< | ||
+ | <script src=\" | ||
+ | |||
+ | < | ||
+ | `sed '/ | ||
+ | </ | ||
+ | |||
+ | echo "< | ||
+ | <script src=\" | ||
+ | |||
+ | < | ||
+ | `sed '/ | ||
+ | </ | ||
+ | |||
+ | echo " | ||
+ | sed ' | ||
+ | echo " | ||
+ | Counts of printer base names" >> $BBHOME/ | ||
+ | sed ' | ||
+ | echo " | ||
+ | |||
+ | Notes: | ||
+ | * This excludes the following duplicate entries: | ||
+ | *-PS names (e.g. 5 named COPIER1-PS would give 14 instead of 9 COPIER1) | ||
+ | *-PCL* (usually PCL5 or PCL6, mostly at PDX) | ||
+ | *-Universal (a duplicate using the HP Universal driver, all in ONT) | ||
+ | " >> $BBHOME/ | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | ===== Source ===== | ||
+ | ==== listprn.vbs ==== | ||
+ | |||
+ | <hidden onHidden=" | ||
+ | <code vb> | ||
+ | Option Explicit | ||
+ | 'List printers (for Xymon/ | ||
+ | 'Note: This script assumes that one uses Share names identical to Printer names. (WMIC Printer GET Name, | ||
+ | '(If printer names have spaces, they will defy pinging, and the print jobs ping column will be less useful.) | ||
+ | ' | ||
+ | |||
+ | Dim TimerStart : TimerStart = Timer | ||
+ | Dim FSO : Set FSO = CreateObject(" | ||
+ | Dim WSH : Set WSH = CreateObject(" | ||
+ | Dim WMI, wmiq, p : Set WMI = GetObject(" | ||
+ | 'Dim me : me = WSH.Environment(" | ||
+ | const ssfSYSTEM = 37 | ||
+ | Dim SHA : Set SHA = CreateObject(" | ||
+ | Const dhcplog = " | ||
+ | |||
+ | const dbg=true | ||
+ | |||
+ | Dim subcolor, color : color = " | ||
+ | Const td = "< | ||
+ | Const th = "< | ||
+ | Const D = "< | ||
+ | Const IPpattern = " | ||
+ | Const MYDOMAIN = " | ||
+ | Const DHCPDescriptions = True | ||
+ | |||
+ | |||
+ | ' | ||
+ | Phase " | ||
+ | 'Note: This check assumes that the DHCP server is in the DNS search path. | ||
+ | 'Note: Duplication will result if there are multiple print servers within one DHCP subnet. | ||
+ | 'Note: The user that this script runs under needs permissions to do remote netsh checks. | ||
+ | 'Note: DNS Search Order should be either null (no DNS) or an array; null might be from a virtual adapter. | ||
+ | Dim dhcpserver : dhcpserver = "" | ||
+ | Set wmiq = WMIQuery(" | ||
+ | & "; Win32_NetworkAdapterConfiguration Where IPEnabled = True") | ||
+ | ' | ||
+ | Dim t, f : For each p in wmiq | ||
+ | For each t in p.IPAddress | ||
+ | wscript.echo "IP Address=" | ||
+ | 'if t = p.DHCPServer then dhcpserver = "" | ||
+ | ' | ||
+ | If IsArray(p.DNSServerSearchOrder) then | ||
+ | For each f in p.DNSServerSearchOrder | ||
+ | wscript.echo "DNS Server=" | ||
+ | if t = f then ' | ||
+ | dhcpserver = "" | ||
+ | exit for | ||
+ | end if | ||
+ | if "" | ||
+ | Next | ||
+ | End If | ||
+ | Next | ||
+ | Next | ||
+ | wscript.echo " | ||
+ | ' | ||
+ | |||
+ | ' | ||
+ | Phase "Dump DHCP " & dhcpserver | ||
+ | t = " | ||
+ | if "" | ||
+ | WSH.Run " | ||
+ | Phase "Parse DHCP, gathering Ports (IP Addresses), MAC Addresses, and Reservations (Reserved Names)" | ||
+ | ' | ||
+ | Dim ports : Set ports = CreateObject(" | ||
+ | Dim macs : Set macs = CreateObject(" | ||
+ | Dim reservations : Set reservations = CreateObject(" | ||
+ | Dim resdescriptions : Set resdescriptions = CreateObject(" | ||
+ | Dim tcpips : Set tcpips = CreateObject(" | ||
+ | Dim pingables : Set pingables = CreateObject(" | ||
+ | |||
+ | if FSO.GetFile(dhcplog).Size Then | ||
+ | Set f = FSO.OpenTextFile(dhcplog, | ||
+ | Do | ||
+ | Dim s : s = f.ReadLine | ||
+ | t = Split(s) | ||
+ | ports.Item(t(7)) = t(7) | ||
+ | macs.Item(t(7)) = t(8) | ||
+ | dim reservation : reservation = Mid(t(9), 2, len(t(9)) - 2) | ||
+ | reservations.Item(t(7)) = reservation | ||
+ | ' | ||
+ | if Instr(4, reservation, | ||
+ | reservations.Item(t(7)) = left(reservation, | ||
+ | end if | ||
+ | resdescriptions.Item(t(7)) = Split(s, """ | ||
+ | Loop until f.AtEndOfStream | ||
+ | f.Close | ||
+ | End If | ||
+ | |||
+ | Dim ErrorStateTxt : ErrorStateTxt = Array("", | ||
+ | , "Low Toner", | ||
+ | Dim ErrorStateVal : ErrorStateVal = Array(0, 1, 0, 1, 2, 1, 2, 2, 2, 2, 2, 2) ' | ||
+ | Dim PrinterStatusTxt : PrinterStatusTxt = Array("", | ||
+ | , " | ||
+ | Dim colors : colors = Array(" | ||
+ | |||
+ | |||
+ | Dim exps : Set exps = CreateObject(" | ||
+ | Dim drivers : Set drivers = CreateObject(" | ||
+ | Dim processors : Set processors = CreateObject(" | ||
+ | Dim datatypes : Set datatypes = CreateObject(" | ||
+ | Dim totals(3) : totals(0) = 0 : totals(1) = 0 : totals(2) = 0 : totals(3) = 0 | ||
+ | Dim versions : Set versions = CreateObject(" | ||
+ | |||
+ | Dim LINE : LINE = "" | ||
+ | |||
+ | ' | ||
+ | Phase " | ||
+ | WMI.Security_.Privileges.AddAsString " | ||
+ | Set wmiq = WMIQuery(" | ||
+ | ' | ||
+ | For Each p in wmiq | ||
+ | t = "< | ||
+ | & td & p.HostAddress & td & "&" | ||
+ | & td & MACs(p.HostAddress) & td | ||
+ | Select Case p.Protocol | ||
+ | Case 1: t = t & "Raw, " | ||
+ | if p.PortNumber <> 9100 then _ | ||
+ | t = t & "< | ||
+ | Case 2: t = t & "LPR, " & p.Queue | ||
+ | if p.ByteCount then t = t & " < | ||
+ | Case Else: t = t & "< | ||
+ | End Select | ||
+ | t = t & td | ||
+ | if p.SNMPEnabled then t = t & p.SNMPCommunity & ", " & p.SNMPDevIndex | ||
+ | wscript.echo t | ||
+ | tcpips(p.HostAddress) = t | ||
+ | next | ||
+ | |||
+ | |||
+ | Phase " | ||
+ | dim productversion, | ||
+ | Set f = SHA.NameSpace(ssfSYSTEM) | ||
+ | For t = -1 to 50 | ||
+ | if " | ||
+ | if "file version" | ||
+ | Next | ||
+ | |||
+ | Function DriverVersion(p) | ||
+ | 'The logic in here is from analysis of HP and Canon drivers. YMMV. | ||
+ | wscript.echo " | ||
+ | Dim f, v : f = FSO.GetFileName(p.DriverPath) | ||
+ | if UCase(f) <> " | ||
+ | v = ProductVer(p.DriverPath) | ||
+ | ' | ||
+ | else | ||
+ | f = FSO.GetFileName(p.ConfigFile) | ||
+ | if UCase(f) <> " | ||
+ | v = ProductVer(p.ConfigFile) | ||
+ | if len(v) >= 3 then v = v & " (" & Replace(LCase(f), | ||
+ | end if | ||
+ | ' | ||
+ | if UCase(f) = " | ||
+ | wscript.echo " | ||
+ | v = DependentFilesVersion(p.DependentFiles) | ||
+ | if len(v) < 3 then | ||
+ | wscript.echo "Still no version, getting date of " & p.DataFile | ||
+ | f = FSO.GetFile(p.DataFile).DateLastModified | ||
+ | v = " | ||
+ | & Year(f) & " | ||
+ | end if | ||
+ | end if | ||
+ | end if | ||
+ | |||
+ | f = Left(p.Name, | ||
+ | |||
+ | ' | ||
+ | DriverVersion = Array(v, f) | ||
+ | ' | ||
+ | End Function | ||
+ | |||
+ | |||
+ | Private Function DependentFilesVersion(df) ' | ||
+ | ' | ||
+ | Dim a, fn : a = Filter(df, " | ||
+ | if UBound(a) >= 0 then | ||
+ | fn = a(0) | ||
+ | a = Filter(a, " | ||
+ | if UBound(a) >= 0 then | ||
+ | fn = a(0) | ||
+ | a = Filter(a, " | ||
+ | if UBound(a) >= 0 then | ||
+ | fn = a(0) | ||
+ | end if | ||
+ | end if | ||
+ | else | ||
+ | DependentFilesVersion = "" | ||
+ | Exit Function | ||
+ | end if | ||
+ | |||
+ | wscript.echo " | ||
+ | Dim v : v = ProductVer(fn) | ||
+ | if Instr(v, "," | ||
+ | if len(v) >= 3 then v = v & " [" & LCase(FSO.GetBaseName(fn)) & " | ||
+ | DependentFilesVersion = v | ||
+ | End Function | ||
+ | |||
+ | |||
+ | Function ProductVer(filename) | ||
+ | Dim nmsp : Set nmsp = SHA.Namespace(FSO.GetParentFolderName(FSO.GetAbsolutePathName(filename))) | ||
+ | Productver = nmsp.GetDetailsOf(nmsp.ParseName(FSO.GetFileName(filename)), | ||
+ | End Function | ||
+ | |||
+ | Function FileVer(filename) | ||
+ | Dim nmsp : Set nmsp = SHA.Namespace(FSO.GetParentFolderName(FSO.GetAbsolutePathName(filename))) | ||
+ | Filever = nmsp.GetDetailsOf(nmsp.ParseName(FSO.GetFileName(filename)), | ||
+ | End Function | ||
+ | |||
+ | ' | ||
+ | Set wmiq = WMIQuery(" | ||
+ | & "; Win32_PrinterDriver" | ||
+ | Phase " | ||
+ | ' | ||
+ | For Each p in wmiq | ||
+ | dim a : a = DriverVersion(p) : f = a(1) | ||
+ | if versions.exists(f) then | ||
+ | versions(f) = versions(f) & "< | ||
+ | else | ||
+ | versions(f) = "" | ||
+ | end if | ||
+ | versions(f) = versions(f) & Mid(p.SupportedPlatform, | ||
+ | Next | ||
+ | |||
+ | |||
+ | Function DontShout(drivername) ' | ||
+ | DontShout = drivername | ||
+ | Dim s : for each s in Split(" | ||
+ | DontShout = Replace(DontShout, | ||
+ | next | ||
+ | End Function | ||
+ | |||
+ | Function ShareStatus(ps, | ||
+ | ShareStatus = PrinterStatusTxt(ps) & Replace(", | ||
+ | ShareStatus = Replace(ShareStatus, | ||
+ | if "<" | ||
+ | End Function | ||
+ | |||
+ | |||
+ | ''''''''''''''''''''''''''''''''''''''''''''''''''''''''' | ||
+ | 'The WMI Query line is where servers sometimes get stuck. | ||
+ | 'It is similar to the command: | ||
+ | 'One could check WMI goodness with: wmic server | ||
+ | 'Note: restarting Print Spooler service doesn' | ||
+ | ''''''''''''''''''''''''''''''''''''''''''''''''''''''''' | ||
+ | ' | ||
+ | Set wmiq = WMIQuery(" | ||
+ | Phase " | ||
+ | ' | ||
+ | For each p in wmiq | ||
+ | Phase "Check printer port " & p.PortName | ||
+ | totals(0) = totals(0) + 1 | ||
+ | ' | ||
+ | 'if len(p.ShareName) then | ||
+ | dim c : c = "" | ||
+ | if not IsNull(p.CapabilityDescriptions) then | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | Phase "Check port " & p.PortName & " capabilities" | ||
+ | for each t in p.CapabilityDescriptions | ||
+ | ' | ||
+ | if t <> " | ||
+ | next | ||
+ | c = Replace(Trim(c), | ||
+ | end if | ||
+ | dim port : port = p.PortName | ||
+ | dim mac : mac = "" | ||
+ | if " | ||
+ | port = Mid(p.PortName, | ||
+ | if not ports.Exists(port) then ports(port) = port | ||
+ | if macs.Exists(port) then | ||
+ | mac = macs(port) | ||
+ | ' | ||
+ | ' | ||
+ | end if | ||
+ | end if | ||
+ | dim ping : ping = pingable(port) | ||
+ | Phase "Check printer' | ||
+ | subcolor = colors(ErrorStateVal(p.DetectedErrorState)) | ||
+ | dim res : res = p.HorizontalResolution | ||
+ | if res <> p.VerticalResolution then res = res & " | ||
+ | Dim errtxt : errtxt = ErrorStateTxt(p.DetectedErrorState) | ||
+ | exps(port) = "< | ||
+ | & td & p.ShareName _ | ||
+ | & td & port _ | ||
+ | & td & res _ | ||
+ | & td & DontShout(p.DriverName) & td & versions(p.DriverName) _ | ||
+ | & td & p.PrintProcessor _ | ||
+ | & td & c _ | ||
+ | & td & ShareStatus(p.PrinterStatus, | ||
+ | & td & "&" | ||
+ | & td & "&" | ||
+ | & td & p.Comment _ | ||
+ | & Replace(td, "<", | ||
+ | |||
+ | if dbg then wscript.echo port & vbTab & exps(port) | ||
+ | if " | ||
+ | if 9 = p.DetectedErrorState then ' | ||
+ | if p.Status = " | ||
+ | LINE = LINE & "& | ||
+ | & ", hallmarks of Spooler service restart required." | ||
+ | color = " | ||
+ | else | ||
+ | LINE = LINE & "& | ||
+ | & " but claims " & errtxt & "; restart Spooler service?" | ||
+ | if color <> " | ||
+ | end if | ||
+ | end if | ||
+ | end if | ||
+ | Phase "Add share " & p.ShareName & " to drivers list" | ||
+ | drivers(p.ShareName) = p.DriverName | ||
+ | Phase "Add share " & p.ShareName & " to processors list" | ||
+ | processors(p.ShareName) = p.PrintProcessor | ||
+ | Phase "Add share " & p.ShareName & " to datatypes list" | ||
+ | datatypes(p.ShareName) = p.PrintJobDataType | ||
+ | Phase " | ||
+ | 'end if | ||
+ | Next | ||
+ | |||
+ | |||
+ | ' | ||
+ | Set wmiq = WMIQuery(" | ||
+ | Phase " | ||
+ | ' | ||
+ | For Each p in wmiq | ||
+ | Phase "Check printer MAC" | ||
+ | Phase "Check printer MAC " & p.PortName | ||
+ | 'if len(p.ShareName) then | ||
+ | port = Mid(p.PortName, | ||
+ | if macs.Exists(port) then | ||
+ | Phase "Check printer MAC for " & port | ||
+ | totals(2) = totals(2) + 1 | ||
+ | macs.Remove(port) | ||
+ | reservations.Remove(port) | ||
+ | end if | ||
+ | 'end if | ||
+ | Next | ||
+ | |||
+ | |||
+ | ' | ||
+ | Phase "List each printer share with its expansion" | ||
+ | ' | ||
+ | if len(LINE) > 1 then LINE = LINE & vbCRLF | ||
+ | LINE = LINE & "< | ||
+ | & "< | ||
+ | & | ||
+ | 'if Instr(th, "<" | ||
+ | LINE = LINE & th | ||
+ | LINE = LINE & " | ||
+ | for each p in ports.Keys | ||
+ | ' | ||
+ | |||
+ | if len(exps(p)) then LINE = LINE & exps(p) | ||
+ | next | ||
+ | LINE = LINE & vbCRLF & "</ | ||
+ | |||
+ | |||
+ | 'Some credit to http:// | ||
+ | Function CULng(ByVal x) | ||
+ | If x < 0 Then CULng = x + 2^32 Else CULng = x | ||
+ | End Function | ||
+ | |||
+ | |||
+ | |||
+ | ' | ||
+ | Dim jobs : jobs = "" | ||
+ | Set wmiq = WMIQuery(" | ||
+ | Phase " | ||
+ | ' | ||
+ | For Each p in wmiq | ||
+ | totals(3) = totals(3) + 1 | ||
+ | Dim eltime : eltime = "" | ||
+ | if not IsNull(p.ElapsedTime) then | ||
+ | eltime = CLng(Left(p.ElapsedTime, | ||
+ | if 0 = eltime then eltime="" | ||
+ | end if | ||
+ | Select case p.Status | ||
+ | Case " | ||
+ | LINE = "& | ||
+ | & vbCRLF & LINE | ||
+ | Case " | ||
+ | Case " | ||
+ | Case " | ||
+ | Case Else: | ||
+ | ' | ||
+ | End Select | ||
+ | jobs = jobs & "< | ||
+ | if p.Owner <> p.Notify then | ||
+ | jobs = jobs & | ||
+ | else | ||
+ | jobs = jobs & | ||
+ | end if | ||
+ | 'Some print jobs are over 2 GB, so make sure the size is an Unsigned Long. | ||
+ | jobs = jobs & | ||
+ | & | ||
+ | Dim k, pinged : pinged = "& | ||
+ | If Instr(exps(k), | ||
+ | ' | ||
+ | pinged = "&" | ||
+ | End If | ||
+ | next | ||
+ | ' | ||
+ | if pinged = "& | ||
+ | jobs = jobs & td & pinged & " &" & pingable(Replace(p.HostPrintQueue, | ||
+ | |||
+ | Dim notes : notes = "" | ||
+ | if p.PagesPrinted > 0 then notes = notes & D & " | ||
+ | if len(p.StartTime) > 0 then notes = notes & D & " | ||
+ | if len(eltime) > 0 then notes = notes & D & " | ||
+ | if len(p.UntilTime) <> 0 then notes = notes & D & " | ||
+ | if len(p.Parameters) > 0 then notes = notes & D & " | ||
+ | if p.Priority <> 1 then notes = notes & D & " | ||
+ | if len(p.JobStatus) > 0 then notes = notes & D & " | ||
+ | if p.StatusMask <> 0 then notes = notes & D & " | ||
+ | if len(p.InstallDate) <> 0 then notes = notes & D & " | ||
+ | |||
+ | 'We have the expected processor/ | ||
+ | dim sn : sn = left(p.Description, | ||
+ | if p.PrintProcessor <> processors(sn) then notes = notes & D & " | ||
+ | if p.DriverName <> drivers(sn) then notes = notes & D & " | ||
+ | if p.DataType <> datatypes(sn) then notes = notes & D & " | ||
+ | |||
+ | if len(notes) > 0 then notes = Mid(notes, 1+len(D)) ' | ||
+ | jobs = jobs & | ||
+ | Next | ||
+ | |||
+ | ' | ||
+ | Phase "If there are any print jobs then add them to the report" | ||
+ | ' | ||
+ | if len(jobs) > 0 then LINE = LINE & "< | ||
+ | & "< | ||
+ | & th & " | ||
+ | & th & " | ||
+ | & th & " | ||
+ | |||
+ | |||
+ | |||
+ | ' | ||
+ | Phase " | ||
+ | ' | ||
+ | Dim r : set r = New RegExp | ||
+ | r.Pattern = IPpattern | ||
+ | for each p in macs.Keys | ||
+ | 'set c = r.Execute(p) : wscript.echo vbTab & c.Count & vbTab & p | ||
+ | if r.Execute(p).Count > 0 then | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | if 0 = len(tcpips(p)) then | ||
+ | tcpips(p) = "< | ||
+ | & td & p & td & "&" | ||
+ | & divright(" | ||
+ | end if | ||
+ | else | ||
+ | if ports.Exists(p) then ports.Remove(p) | ||
+ | end if | ||
+ | if dbg then wscript.echo vbTab & p & vbTab & """" | ||
+ | next | ||
+ | |||
+ | |||
+ | ' | ||
+ | Phase " | ||
+ | ' | ||
+ | LINE = LINE & vbCRLF & vbCRLF & "< | ||
+ | & "< | ||
+ | & th & "TCP, Port|LPR, Name" & th & " | ||
+ | for each p in tcpips.Keys | ||
+ | wscript.echo vbTab & p & vbTab & tcpips(p) | ||
+ | if len(tcpips(p)) then | ||
+ | LINE = LINE & vbCRLF & tcpips(p) | ||
+ | if len(exps(p)) then | ||
+ | LINE = LINE & td & Split(exps(p), | ||
+ | else | ||
+ | LINE = LINE & td & divright(" | ||
+ | end if | ||
+ | end if | ||
+ | next | ||
+ | LINE = LINE & vbCRLF & "</ | ||
+ | |||
+ | |||
+ | Function divright(s) | ||
+ | divright = "< | ||
+ | End Function | ||
+ | |||
+ | |||
+ | |||
+ | ' | ||
+ | Phase " | ||
+ | ' | ||
+ | WriteStatus " | ||
+ | & totals(0) & " shares on " & totals(2) & " MACs, " _ | ||
+ | & totals(1) & " unassigned MACs; " & ports.Count & " ports total; " & totals(3) & " jobs)", | ||
+ | 'if dbg then wscript.echo LINE | ||
+ | |||
+ | Function dt(t) ' | ||
+ | dt = "" | ||
+ | if not IsNull(t) then | ||
+ | Dim dtt : dtt = CLng(Left(t, | ||
+ | Dim d : d = Now : d = 10000 * Year(d) + 100 * Month(d) + Day(d) | ||
+ | Select Case d - dtt | ||
+ | Case 0 : dt = "& | ||
+ | Case 1 : dt = "& | ||
+ | Case 2,3,4,5,6 : dt = "& | ||
+ | Case Else : dt = "& | ||
+ | End Select | ||
+ | dt = dt & dtt & " " & Mid(t, 9, 6) & Right(t,4) | ||
+ | end if | ||
+ | End Function | ||
+ | |||
+ | Function pingable(ip) | ||
+ | if not IsNumeric(Left(ip, | ||
+ | pingable = " | ||
+ | Exit Function | ||
+ | end if | ||
+ | if pingables.Exists(ip) then | ||
+ | Phase " | ||
+ | pingable = pingables(ip) | ||
+ | exit function | ||
+ | end if | ||
+ | ' | ||
+ | Phase "Try to ping " & ip | ||
+ | 'Dim WMI_ : Set WMI_ = GetObject(" | ||
+ | 'The following should be a WMI Get rather than a query, as only one response is usable | ||
+ | Dim pings : Set pings = WMI.ExecQuery(" | ||
+ | Dim pi : for each pi in pings | ||
+ | pingables(ip) = " | ||
+ | if 0 <> pi.StatusCode then pingables(ip) = " | ||
+ | pingable = pingables(ip) | ||
+ | exit function | ||
+ | next | ||
+ | End Function | ||
+ | |||
+ | '###################################################################### | ||
+ | 'Write out the status; depends on FSO and WSH; will use TimerStart if available for duration | ||
+ | Sub WriteStatus(column, | ||
+ | 'Why so long? Assume that client might collect file while writing, so make temp file and rename it. | ||
+ | '###################################################################### | ||
+ | Dim FSO : Set FSO = CreateObject(" | ||
+ | Dim WSH : Set WSH = CreateObject(" | ||
+ | Dim HKLMSoft : HKLMSoft=" | ||
+ | if WSH.Environment(" | ||
+ | Const LEAKYMAX = 8500, BBWinreg = " | ||
+ | Const Questreg = " | ||
+ | On error resume next | ||
+ | ' | ||
+ | Dim colfn, src, leaky : colfn = "" | ||
+ | If "" | ||
+ | If "" | ||
+ | colfn = colfn & " | ||
+ | Dim tmpfn : tmpfn = colfn & " | ||
+ | If FSO.FileExists(tmpfn) Then WScript.Quit 183 ' | ||
+ | Phase " | ||
+ | With FSO.CreateTextFile(tmpfn, | ||
+ | if err then WScript.Quit err ' | ||
+ | if Len(quickie) + Len(line) > LEAKYMAX and src = " | ||
+ | leaky = True | ||
+ | .Write " | ||
+ | end if | ||
+ | .WriteLine color & " " & WeekdayName(Weekday(Now), | ||
+ | & Mid(Now, | ||
+ | & " [" & WSH.Environment(" | ||
+ | .WriteLine line | ||
+ | .Write "< | ||
+ | FSO.GetFile(WScript.ScriptFullName).DateLastModified)) | ||
+ | if not IsNull(TimerStart) then .Write "; run time " & Timer - TimerStart & " | ||
+ | .Close | ||
+ | End With | ||
+ | With FSO.OpenTextFile(tmpfn, | ||
+ | .Write "; len ~" & FSO.GetFile(tmpfn).Size + 29 & " | ||
+ | .Close | ||
+ | End With | ||
+ | ' | ||
+ | ' | ||
+ | 'Or send directly with bbwincmd.exe if over LEAKYMAX and using bbwin | ||
+ | ' | ||
+ | Phase " | ||
+ | on error goto 0 | ||
+ | ' | ||
+ | if leaky then ' | ||
+ | Dim XML : Set XML = CreateObject(" | ||
+ | If XML.Load(WSH.RegRead(HKLMSoft & " | ||
+ | Phase " | ||
+ | Dim x, s : for each x in XML.SelectNodes("// | ||
+ | s = x.Attributes.GetNamedItem(" | ||
+ | Phase " | ||
+ | WSH.Run " | ||
+ | next | ||
+ | Else | ||
+ | WScript.Echo "Error parsing " & WSH.RegRead(HKLMSoft & " | ||
+ | End If | ||
+ | FSO.DeleteFile tmpfn | ||
+ | else | ||
+ | if FSO.FileExists(colfn) then FSO.DeleteFile(colfn) | ||
+ | FSO.MoveFile tmpfn, colfn | ||
+ | end if | ||
+ | End Sub | ||
+ | |||
+ | 'If the script gets stuck, we can use Process Explorer to examine its environment | ||
+ | Sub Phase(n) | ||
+ | if dbg then wscript.echo vbTab & n | ||
+ | CreateObject(" | ||
+ | End Sub | ||
+ | |||
+ | Function WMIQuery(ByVal s) | ||
+ | Phase "WMI Query: " & s | ||
+ | if Instr(s, ";" | ||
+ | Set WMIQuery = WMI.ExecQuery(s) ' | ||
+ | Phase "WMI Queried: " & s | ||
+ | End Function | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | ===== Known Bugs and Issues ===== | ||
+ | * Figure out what credentials are required to remotely retrieve a DHCP server' | ||
+ | * Determine why a WMI query for Win32_Printer sometimes gets stuck. | ||
+ | |||
+ | ===== To Do ===== | ||
+ | * Confirm that changing td/th to tabs actually does produce readable (non-HTML) output. | ||
+ | * Figure out why the server sometimes claims a printer has gone offline when it hasn' | ||
+ | * Perhaps find more methods that printer driver creators use to embed the version numbers in their drivers. | ||
+ | |||
+ | ===== Credits ===== | ||
+ | (see source code) | ||
+ | |||
+ | ===== Changelog ===== | ||
+ | |||
+ | * **2012-05-03** | ||
+ | * Initial release | ||