Focusing on the printer! Printer Monitoring MP Supplement


The released version of the printer monitoring MP is available in the MP catalog and is an effective monitoring tool if you want to know about
1.  Printer performance
2.  Print server health
3.  Problems with ANY (key point here) of the printers attached to a Windows 2000, Windows 2003 or Windows 2008 print server.  While there is discovery for individual printers there is no monitoring for individual printer errors.

The Printer MP in the catalog is made up of a few components
Microsoft.Windows.Server.PrintServer.2008.mp
Microsoft.Windows.Server.PrintServer.mp
Microsoft.Windows.Server.PrintServer.Library.mp

Monitoring for Windows 2000 and 2003 print servers and hosted printers is done through the Microsoft.Windows.Server.PrintServer.mp.  This MP requires the backward compatible MP.  With this MP only collective printer monitoring is done – there is no ability to see problems on an individual printer level.  Monitoring for Windows 2008 print servers is done through the Microsoft.PrintServer.2008.mp.  This is a native MP but does not provide for any printer monitoring.

If you are OK with the more general monitoring available in the default MP’s they will work just fine.  If, however, you need to see errors on an individual printer level, the MP is not sufficient and is the reason I have created a supplemental MP to provide individual printer monitoring.  The term supplement is really a bad choice as the attached MP does NOT require the default printer MP from the catalog.  In fact, if you do have the original MP installed you will want to disable printer discovery via override as the attached MP has it’s own individual printer discovery.

image

Note also that the supplement MP does not do any monitoring of Windows 2000 print servers or hosted printers.  If you need Windows 2000 monitoring then you will need the printer MP from the catalog.

Printer MP Supplement
The focus for building out this MP supplement was to offer individualized printer monitoring.  Further, monitoring should include the ability to detect the 12 error conditions available from the printer MP in the catalog and each error condition should be configurable as to whether or not it is enabled and, if so, how long the error condition should persist before considering it to be a problem.  Lets walk through the MP.

Classes
The supplement MP includes the classes shown below.

image

Print Server Role – This is an abstract class that will display both Windows 2003 and Windows 2008 print servers

Windows 2003 Print Server Role – This class will contain all discovered Windows 2003 print servers

Windows 2008 Print Server Role – This class will contain all discovered Windows 2008 print servers

Custom Print Server Printer – This is an abstract class that will display all printers – whether hosted by Windows 2003 print servers or Windows 2008 print servers.

Windows 2003 print server printer – This class will contain all discovered printers on Windows 2003 print servers.

Windows 2008 print server printer – This class will contain all discovered printers on Windows 2008 print servers.

Discoveries
Populating these classes requires a discovery.  We need one discovery for each non-abstract class – so 4 discoveries total.  Note that the discoveries are all disabled by default.  You will need to either enable in general or, better, selectively enable as the MP is rolled to production. 

Note:  Always test in a lab first!

Note:  This MP is delivered in an unsealed format which means direct changes are allowed.  For production environments I recommend sealing and making adjustments via override – just like with any standard sealed MP.

image

In my lab I have simply enabled all discoveries.
image
Print Server Role
The discovery for the Windows 2003 and Windows 2008 print server role is similar – the only difference is in terms of the target.  The Windows 2003 print server role discovery targets Windows Server 2003 Computer class and the Windows 2008 print server role discovery targets the Windows Server 2008 Computer class.  That being the only difference, I will only describe one of the two discoveries – the Windows Server 2008 print server role discovery.

The general tab shows the discovery now enabled in my lab.
image

The discovered classes tab shows the associated class for the discovery.
image

The schedule tab shows the discovery runs daily – in general this frequency should not be changed in a production environment.
image

The discovery is driven by script.
image
Along with the required script based discovery parameters
image
This discovery merits a bit more discussion.  Determining whether a system is a print server or not is easy – simply connect to WMI, loop through all printers in the win32_printer class and if any show to be shared – as noted by shared=true – then the system should be flagged as a print server.  This is so straight forward that initially this discovery was built based on a WMI query instead of script – which is preferable as scripts do introduce a bit more overhead. 

During testing I quickly found this not to be effective as the operational environment had many servers with the spooler service disabled.  If the spooler service isn’t running then errors result when attempting to connect to Win32_printer in WMI which was causing the OpsMgr console to fill with related alerts. 

The spooler service by default is set to automatic.  Faced with a choice of fixing all of the servers – not a likely scenario – or fixing the discovery – I chose to fix the discovery and turn it into one based on a script.  The script itself is very easy – when running on a server the first check done is to see whether the spooler service is running or not.  Assuming the spooler service is running the script next checks to see if any printers are shared.  The commented script that is used is below.

‘Declare variables used by the script
Dim objWMINS, colItems, oPrinter, ErrorStateToString, oAPI, oExec, LOgEVentCOmmand, oArgs, SourceID
Dim ManagedEntityID, TargetComputer, oInst, oDiscoveryData, NetbiosName, oService, SpoolerStarted
Dim PrintServer

’Read in command line arguments passed to the script
Set oArgs = wscript.arguments
SourceId = oArgs(0)
ManagedEntityID = oArgs(1)
TargetComputer = oArgs(2)
NetbiosName = oArgs(3)

‘Instantiate objects needed by the script
Set oAPI = CreateObject("MOM.ScriptAPI")
Set oDiscoveryData = oAPI.CreateDiscoveryData(0, SourceId, ManagedEntityId)
Set objWMINS = GetObject("winmgmts://./root/cimv2")
Set colItems = objWMINS.ExecQuery("Select * from Win32_Service")

‘Set the variables to 0 – 0 indicates spooler not started and no printers shared
’respectively.

SpoolerStarted = 0
PrintServer = 0

‘Connect to WMI and verify whether the spooler service is running.  If so, set flag
’to 1
For each oService in colItems
    If oService.Name = "Spooler" and oService.Started = "True" Then
        SpoolerStarted = 1
    End If
Next

‘If flag is set to 1, indicating the spooler service is running, connect to Win32_Printer
’class in WMI and loop through looking for shared printers.  If a single shared printer
’is found then set the PrintServer flag to 1.
If SpoolerStarted = 1 Then
    Set colItems = objWMINS.ExecQuery("Select * from Win32_Printer")
    For Each oPrinter in colItems
        If oPrinter.Shared = "True" Then
            PrintServer = 1
        End If
    Next
End If

‘If both the SpoolerStarted and PrintServer flags are set to 1 then populate
’the discovery.
If SpoolerStarted = 1 and PrintServer = 1 Then
        Set oInst = oDiscoveryData.CreateClassInstance("$MPElement[Name=’Printer.Monitoring.Supplemental.Windows2008.printserver.role’]$")
        Call oInst.AddProperty("$MPElement[Name=’Windows!Microsoft.Windows.Computer’]/PrincipalName$",targetcomputer)
        Call oDiscoveryData.AddInstance(oInst)
End If

‘Return the property bag – the bag may be populated or empty depending on conditions
‘but needs to be returned either way.
Call oAPI.Return(oDiscoveryData)

The available overrides for the discovery are shown below.
image

Print Server Printer
The only difference in Print Server Printer discoveries is also the target class so only one of the two discoveries will be discussed – the Windows 2008 print server printer discovery.

The general tab shows my discovery is now enabled
image

Note the target class of this discovery is the print server role class just discussed.  This means that until the print server role class is populated this discovery will not be run.

The discovered classes tab shows the associated class for the discovery.
image

The schedule tab shows the discovery runs daily – in general this frequency should not be changed in a production environment.

image
The discovery is driven by script.
image

Along with the required script based discovery parameters
image

The script that drives the discovery is very simple – just connect to WMI, loop through and find any shared printers – adding them to the property bag as the script runs – and return the property bag at the end. 

If this discovery script runs then the spooler service, as discussed above, should have been found to be running so there is no need to check again. 

Don’t let the simplicity of this script fool you though.  Often print servers will host hundreds of printers.  In the most loaded scenario where this MP was tested we had print servers with right at 1000 printers each – and we had a couple of them.  While the script is simple it can cause some uptick in WMI load as it runs.  The frequency is once per day though so it shouldn’t be a big deal.  Also, with lots of printers we start to be concerned about the total size of the property bag returned by the script – which is why I haven’t included more attributes in the discovery – at least yet – I may add them later.  In current testing the resulting property bag is well under the 4 MB limit – weighing in at around 250 KB even on these heavily loaded print servers.  The commented discovery script is below.

‘Declare variables used by the script
Dim objWMIPrinters
Dim colItems
Dim oPrinter
Dim ErrorStateToString
Dim oAPI
Dim oExec
Dim LOgEVentCOmmand
Dim oArgs
Dim SourceID
Dim ManagedEntityID
Dim TargetComputer
Dim oInst
Dim oDiscoveryData
DIm NetbiosName

’Read in command line arguments passed to the script
Set oArgs = wscript.arguments
SourceId = oArgs(0)
ManagedEntityID = oArgs(1)
TargetComputer = oArgs(2)
NetbiosName = oArgs(3)

‘Instantiate objects needed by the script
Set oAPI = CreateObject("MOM.ScriptAPI")
Set oDiscoveryData = oAPI.CreateDiscoveryData(0, SourceId, ManagedEntityId)
Set objWMIPrinters = GetObject("winmgmts://./root/cimv2")
Set colItems = objWMIPrinters.ExecQuery("Select * from Win32_Printer")
‘Set WshShell = CreateObject("Wscript.Shell")

‘Loop through WMI finding printers that are shared.  For each printer found to be
’shared, add it to the property bag and continue with the loop until done.
For each oPrinter in colItems
    If oPrinter.Shared = 0 Then
        wscript.echo "printer " & oPrinter.name & " is not shared"
    Else
        wscript.echo "printer " & oPrinter.name & " – " & ErrorStateToString
        Set oInst = oDiscoveryData.CreateClassInstance("$MPElement[Name=’Printer.Monitoring.Supplemental.Windows2008.printserver.printer’]$")
        Call oInst.AddProperty("$MPElement[Name=’Windows!Microsoft.Windows.Computer’]/PrincipalName$", targetcomputer)
        Call oInst.AddProperty("$MPElement[Name=’Printer.Monitoring.Supplemental.Windows2008.printserver.printer’]/PrinterName$", oPrinter.name) ‘Key Attribute & " (" & NetbiosName & ")") ‘Key Attribute
        Call oInst.AddProperty("$MPElement[Name=’Printer.Monitoring.Supplemental.Windows2008.printserver.printer’]/PrintServerHost$", targetcomputer)
        Call oDiscoveryData.AddInstance(oInst)
    End If
Next

‘Return the property bag
Call oAPI.Return(oDiscoveryData)

The available overrides for the discovery are shown below
image

Results of Discovery
The results of our discovery should be that every print server and every printer hosted by a print server in the environment is found.  My lab environment is very simple so I only show a couple of servers and a couple of printers.

Looking at discovered inventory for the Windows 2008 Print Server Role class I see two printers are displayed
image
In my Windows 2008 print server printer class I have found a single printer so far – hosted by one of my Windows 2008 print serves.
image

Monitoring
OK, so all that discovery stuff is out of the way…on to the good stuff – monitoring.  Actually, the monitoring done in the MP is very simple- there is a monitor to check the status of the spooler service on discovered print servers and a monitor to check each discovered printer individually to determine error state. 

image

image

There are two of each monitor – one targeting Windows 2003 and one targeting Windows 2008.  Like before, only one of each will be shown since they are identical except for target.  Let’s take them in order.

Spooler Service Check
This monitor runs a script to check the status of the spooler service.  Let’s wakk through the configuration.

On the general tab we see the monitoring is enabled by default

image

The schedule tab shows this monitor runs a check every 2 hours.

image

The script tab shows the default timeout of the script is 5 minutes.  You will note that the script is visible for this monitor – this is not the case with every monitor, depending on the complexity.  The script for the printer state monitor – discussed next – is not visible on the monitor properties.

image

No parameters are needed for the script.

image

The script, shown below, simply connect to WMI, checks the status of the spooler service and if it is started a status of OK si returned – if not, a status of Error is returned.  The commented script is below.

‘Declare variables needed by the script
Dim oAPI, oService, oBag, oWMIServices, colItems

‘Don’t fail on error
On Error Resume Next

‘Instantiate objects needed by the script
Set oAPI = CreateObject("MOM.ScriptAPI")
set oWMIServices = GetObject("winmgmts://./root/cimv2")
Set colItems = oWMIServices.ExecQuery("Select * from win32_service where name = ‘spooler’")

‘Loop through services listed in WMI looking for the spooler service.  When spooler is found, check
’to see if the status of started – true, if so return an OK property bag – if not, return an Error property
’bag
For each oService in colItems
    If oService.Started = "True" Then
        WritePropertyBag("OK")
    Else
        WritePropertyBag("Error")
    End If
Next

‘Return the property bag
oAPI.ReturnItems

‘’Subroutine to create the property bag
PUblic Sub WritePropertyBag(PBState)
    set oBag = oAPI.CreatePropertyBag()
    oBag.AddValue "State",PBState
    oAPI.AddItem oBag
End Sub

The script returns either OK to indicate healthy or Error to indicate unhealthy so our monitor needs to be configured to handle these conditions.  The unhealthy expression tab defines the error condition.

image

The health expression tab defines the health expression

image

The health tab ties these to the specific health state.

image
When a problem is seen an alert is generated.

image

Finally, the overrides tab lists configurations that can be changed via override.

image

If the spooler service is found to be down an alert will be generated and the system will show up in an unhealthy state.  The state screenshot is an initial look at the views that are included with the management pack.

image

image

Printer State Check
OK, now the meat of monitoring – checking the state of individual printers.  Like the spooler check, this is a simple state based monitor with some added complexities of a unique data source and condition detection modules that operate behind the scenes.  This extra detail (other than the script) will not be discussed here but will be discussed but will be discussed in a future blog post I will write showing how to write monitoring scripts that support cookdown.  If you don’t know what cookdown is – I describe it here.  On to the monitor.

The general tab of this monitor shows us that the monitoring is enabled by default and also gives a description that describes how to customize the monitor to meet the requirements of each specific environment.

image

This is a simple state monitor but notice the health and unhealthy expressions tabs are not present – they are actually handled behind the scenes in the condition detection.  You can view this condition detection if you load the MP into the authoring console.

The next tab visible is for health.  A printer with an error will always be considered a warning.

image

The script that drives this monitor is not visible in the properties of the monitor – it is defined as a data source that the monitor calls.  The data source is visible if you load the MP into the authoring console.  The script that is executed is shown below with comments.  Note that this script allows the administrator to configure whether to test for each error condition and – if the error condition should be tested – how long to wait before generating an alert.  Both of these configurations are handled by command line but are configured on the monitor itself – shown shortly.  One note here.  A typical approach for this type of scenario would be to use the available consolidation modules.  Because some evaluation times can be long and because consolidation information does not persist through an agent restart this script makes use of the registry to store state data for comparison purposes.

‘Declare variables to be used with the script
Dim objWMIPrinters, colItems, oPrinter, ErrorStateToString, oAPI, oBag, WshShell, oEventCreateCmd, PrinterState
Dim PrinterStateRegPath, DataIn, DataOut, SLength, PrinterError, ErrorTime, ErrorandDate, StateRegPath
Dim PBState, PrinterName, DetectedError, oArgs
Dim Err1Enabled, Err1Threshold, Err2Enabled, Err2Threshold, Err3Enabled, Err3Threshold, Err4Enabled, Err4Threshold
Dim Err5Enabled, Err5Threshold, Err6Enabled, Err6Threshold, Err7Enabled, Err7Threshold, Err8Enabled, Err8Threshold
Dim Err9Enabled, Err9Threshold, Err10Enabled, Err10Threshold, Err11Enabled, Err11Threshold, Err12Enabled, Err12Threshold

‘Don’t fail on script error
On Error Resume Next

‘Instantiate wscript object to read in command line variables
Set WshShell = CreateObject("WScript.Shell")

‘Read in variables from command line to determine which printer checks are relevant and the associated time frame for alerting
Set oArgs = wscript.Arguments
Err1Enabled = oArgs(0)
Err1Threshold = oArgs(1)
Err2Enabled = oArgs(2)
Err2Threshold = oArgs(3)
Err4Enabled = oArgs(6)
Err4Threshold = oArgs(7)
Err5Enabled = oArgs(8)
Err5Threshold = oArgs(9)
Err6Enabled = oArgs(10)
Err6Threshold = oArgs(11)
Err7Enabled = oArgs(12)
Err7Threshold = oArgs(13)
Err8Enabled = oArgs(14)
Err8Threshold = oArgs(15)
Err9Enabled = oArgs(16)
Err9Threshold = oArgs(17)
Err10Enabled = oArgs(18)
Err10Threshold = oArgs(19)
Err11Enabled = oArgs(20)
Err11Threshold = oArgs(21)
Err12Enabled = oArgs(22)
Err12Threshold = oArgs(23)

‘Instantiate objects and declare variables needed in the script
Set oAPI = CreateObject("MOM.ScriptAPI")
Set objWMIPrinters = GetObject("winmgmts://./root/cimv2")
Set colItems = objWMIPrinters.ExecQuery("Select * from Win32_Printer")
StateRegPath = oAPI.GetScriptStateKeyPath("PrinterState")
PrinterStateRegPath = "HKLM\" & StateRegPath

‘Loop through all printers and handle individually.
For each oPrinter in colItems
    ‘Instantiate a new printerstateclass for each printer we are testing

    Set PrinterState = New PrinterStateClass
       
    ‘If this is not a shared printer then no need to evaluate – simply flag as not shared.
    If oPrinter.Shared = 0 Then
        Call PrinterState.PutState(oPrinter.Name, "Not Shared")
    Else

        ‘If this is a shared printer, check to see what error condition has been reported in WMI
        Select Case (oPrinter.DetectedErrorState)
            Case 1: ErrorStateToString = "Unknown"
            Case 2: ErrorStateToString = "Other"
            Case 3: ErrorStateToString = "No Error"
            Case 4: ErrorStateToString = "Low Paper"
            Case 5: ErrorStateToString = "No Paper"
            Case 6: ErrorStateToString = "Low Toner"
            Case 7: ErrorStateToString = "No Toner"
            Case 8: ErrorStateToString = "Door Open"
             Case 9: ErrorStateToString = "Jammed"
              Case 10: ErrorStateToString = "Offline"
              Case 11: ErrorStateToString = "Service Requested"
              Case 12: ErrorStateToString = "Output Bin Full"
              Case Else: ErrorStateToString = "No Error"
        End Select

        wscript.echo ErrorStateToSTring

        ‘Depending on the error state detected, report an appropriate property bag
        If (ErrorStateToString = "No Error") Then
            ‘Put state in the registry and add data to the property bag

            Call PrinterState.PutState(oPrinter.Name, "OK")
            Call WritePropertyBag("OK", oPrinter.Name, "No Error")
        Else
           ‘If an error state is detected try to read the previously stored value from the registry
           ‘and compare to see if it’s time to alert.  It’s possible no state has yet been stored in
           ‘the registry which normally would cause an error – since the script is set to ‘on error resume
           ‘next’ the error will not cause failure and will be handled.

            DataOut = PrinterState.GetState (oPrinter.Name) 
                                                             ‘If DataOut somehow equals OK or a string
                                                             ‘without the date attached functions will fail.  Further, if
                                                            ‘DataOut doesn’t find a match to rinter name it will
                                                            ‘simply return empty which is why the test below is done
            ‘If we get blank data (meaning no data was in the registry) or we get a status of
            ‘OK from the registry then we need to update – the fact we are here means that an
            ‘error condition has been detected.  Write the udpated info to the registry
            If DataOut = "" or DataOut = "OK" Then
                wscript.echo DataOut
                ErrorandDate = ErrorStateToString & "-" & Now
                Call PrinterState.PutState(OPrinter.Name, ErrorandDate)
            Else
               ‘If we don’t get a null response or an OK response that must mean we have detected a 
               ‘pre-existing error condition in the registry – parse and pull apart to see if we should alert
                sLength = InStr(DataOut, "-")
                PrinterError = Left(DataOut, sLength-1)
                ErrorTime = Right(DataOut, Len(Dataout)-sLength)
                PrinterError =LTrim(PrinterError)
                PrinterError = RTrim(PrinterError)
                ErrorTime = LTrim(ErrorTime)
                ErrorTime = RTrim(ErrorTime)
               
                wscript.echo PrinterError
                
                ‘We have the error – now test based on the command line input to see if its time to alert
                Select Case (PrinterError)
                    Case "Unknown"
                        If Err1Enabled = 1 and (cint(abs(DateDiff("h",now,ErrorTime))) > cint(Err1Threshold)) Then
                            Call WritePropertyBag("WARNING", oPrinter.name, PrinterError)
                        Else
                            PrinterError = "ErrorNoAlert"
                            Call WritePropertyBag("OK", oPrinter.name, PrinterError)
                        End If
                    Case "Other"
                        If Err2Enabled = 1 and (cint(abs(DateDiff("h",now,ErrorTime))) > cint(Err2Threshold)) Then
                            Call WritePropertyBag("WARNING", oPrinter.name, PrinterError)
                        Else
                            PrinterError = "ErrorNoAlert"
                            Call WritePropertyBag("OK", oPrinter.name, PrinterError)
                        End If
                    ‘Including here but we should never hit this section in the event of no error condition being detected so
                    ‘commenting out for now   
                    ‘Case "No Error"
                    ‘    If Err3Enabled = 1 and (cint(abs(DateDiff("h",now,ErrorTime))) > cint(Err3Threshold)) Then
                    ‘        Call WritePropertyBag("WARNING", oPrinter.name, PrinterError)
                    ‘    Else
                    ‘        PrinterError = "ErrorNoAlert"
                    ‘        Call WritePropertyBag("OK", oPrinter.name, PrinterError)
                    ‘    End If
                    Case "Low Paper"
                        If Err4Enabled = 1 and (cint(abs(DateDiff("h",now,ErrorTime))) > cint(Err4Threshold)) Then
                            Call WritePropertyBag("WARNING", oPrinter.name, PrinterError)
                        Else
                            PrinterError = "ErrorNoAlert"
                            Call WritePropertyBag("OK", oPrinter.name, PrinterError)
                        End If
                    Case "No Paper"
                        If Err5Enabled = 1 and (cint(abs(DateDiff("h",now,ErrorTime))) > cint(Err5Threshold)) Then
                            Call WritePropertyBag("WARNING", oPrinter.name, PrinterError)
                        Else
                            PrinterError = "ErrorNoAlert"
                            Call WritePropertyBag("OK", oPrinter.name, PrinterError)
                        End If
                    Case "Low Toner"
                        If Err6Enabled = 1 and (cint(abs(DateDiff("h",now,ErrorTime))) > cint(Err6Threshold)) Then
                            Call WritePropertyBag("WARNING", oPrinter.name, PrinterError)
                        Else
                            PrinterError = "ErrorNoAlert"
                            Call WritePropertyBag("OK", oPrinter.name, PrinterError)
                        End If                   
                    Case "No Toner"
                        If Err7Enabled = 1 and (cint(abs(DateDiff("h",now,ErrorTime))) > cint(Err7Threshold)) Then
                            Call WritePropertyBag("WARNING", oPrinter.name, PrinterError)
                        Else
                            PrinterError = "ErrorNoAlert"
                            Call WritePropertyBag("OK", oPrinter.name, PrinterError)
                        End If                   
                    Case "Door Open"
                        If Err8Enabled = 1 and (cint(abs(DateDiff("h",now,ErrorTime))) > cint(Err8Threshold)) Then
                            Call WritePropertyBag("WARNING", oPrinter.name, PrinterError)
                        Else
                            PrinterError = "ErrorNoAlert"
                            Call WritePropertyBag("OK", oPrinter.name, PrinterError)
                        End If                   
                    Case "Jammed"
                        If Err9Enabled = 1 and (cint(abs(DateDiff("h",now,ErrorTime))) > cint(Err9Threshold)) Then
                            Call WritePropertyBag("WARNING", oPrinter.name, PrinterError)
                        Else
                            PrinterError = "ErrorNoAlert"
                            Call WritePropertyBag("OK", oPrinter.name, PrinterError)
                        End If                   
                    Case "Offline"
                        If Err11Enabled = 1 and (cint(abs(DateDiff("h",now,ErrorTime))) > cint(Err10Threshold)) Then
                            Call WritePropertyBag("WARNING", oPrinter.name, PrinterError)
                        Else
                            PrinterError = "ErrorNoAlert"
                            Call WritePropertyBag("OK", oPrinter.name, PrinterError)
                        End If                   
                    Case "Service Requested"
                        If Err12Enabled = 1 and (cint(abs(DateDiff("h",now,ErrorTime))) > cint(Err11Threshold)) Then
                            Call WritePropertyBag("WARNING", oPrinter.name, PrinterError)
                        Else
                            PrinterError = "ErrorNoAlert"
                            Call WritePropertyBag("OK", oPrinter.name, PrinterError)
                        End If
                    Case "Output Bin Full"
                        If Err13Enabled = 1 and (cint(abs(DateDiff("h",now,ErrorTime))) > cint(Err12Threshold)) Then
                            Call WritePropertyBag("WARNING", oPrinter.name, PrinterError)
                        Else
                            PrinterError = "ErrorNoAlert"
                            Call WritePropertyBag("OK", oPrinter.name, PrinterError)
                        End If   
                End Select
            End If
        End IF
    End If
Next

‘Return a property bag always
oAPI.ReturnItems

‘Subroutine to handle adding items to the property bag
PUblic Sub WritePropertyBag(PBState, PrinterName, DetectedError)
    set oBag = oAPI.CreatePropertyBag()
    oBag.AddValue "State",PBState
    oBag.AddValue "PrinterName", PrinterName
    oBag.AddValue "Error Condition", DetectedError
    oAPI.AddItem oBag
End Sub

‘Class for placing printer state in the registry
class PrinterStateClass
    public Sub PutState(stateName, val)
        call WshShell.RegWrite (PrinterStateRegPath & "\" & stateName, val, "REG_SZ")
    End Sub
   
    public function GetState(stateName)           
        GetState = WshShell.RegRead(PrinterStateRegPath & "\" & stateName)
    end function
       
End Class

If it’s time to alert then one will be generated – specifically calling out the error condition of the printer along with the printer having the error
image

On the Configuration tab we see the settings that are passed to the script – these settings determine whether a particular condition should be evaluated and the threshold for alerting.  If running the MP unsealed these valued can be changed on this tab.  If not, they are configurable via override.

image

image

Views
And that’s it for monitoring.  The last item is the default views I’ve build into the MP.  You can add more if needed.  I’ve build out a few state views and a few alert views – the alert views will categorize the printers having specific error conditions by error.

image

That’s it – the MP is attached.  Let me know of any feedback and how this works for you!

Printer.Monitoring.Supplemental – revision 2.zip

Comments (31)

  1. Layne says:

    Thanks Steve, this is great!  One problem I've had trying to monitor printer state with WMI is that on a cluster, WMI doesn't work well.  Do you know if this MP will monitor printers on a cluster?

  2. steverac says:

    I haven't actually tested the MP on a cluster yet but I know of folks using it that do run clustered print servers.  So far I haven't heard of any issues – but no promises! :)

  3. Michael says:

    Awesome mp Steve, have been looking for this quite a while. The discoveries work, but i am not able to see each printer (i have both 2003 and 2008). I have try opening the door, remove all paper etc, to see if i get any alerts. How is the alerts set up? I cannot see any in the Authoring console.

    Thanks!

  4. Michael says:

    Hi

    Looking really good. All my printers are getting discovered, but the alerting part does not seem to be working as it should. I have received two alerts last night at 03.00 about paper jam, and one for no paper. As you can imagine the printers are not being used at that time. I have a printer on my table. I am taking out the paper, toner, opening the door etc – no alerts.

    Regarding the cluster the printers are getting discovered perfectly.

    Thanks!

  5. steverac says:

    Hey Michael – the discoveries in the MP are all disbled by default – you will need to enable the ones you care about – 4 total.  From there the discoveries run once every 24 hours and will show all discovered printers in the discovered inventory view for the specific class.  Make sure you are looking at the class I defined in my MP – it's easy to get them confused with the default printer MP from the catalog.  In the object view sort for supplemental and you will see all of my classes.  Once everything is discovered (and discovery requires that you have printers shared and the spooler service started) then monitoring will take place hourly.  There are 12 error conditions that are monitored – some are disabled by default – others aren't.  Check the printer state monitor to see all of the available choices and individual configuration available.

  6. steverac says:

    One other thing I forgot to add.  One of the configurations is a delay period between which the problem is detected and an alert is reported.  I have set the threshold at various levels based on my needs – your needs may be different.  Some of the error conditions require no delay, some wait for 2 hours, one for 15 hours and one for 45 hours.  Just adjust them to 0 if you want alerting to happen immediately.

  7. Mark says:

    Hi Steve

    Just wondering is the "Windows 2008 print server role discovery" targetted at the right class. I am showing it pointing to "Windows Server 2008 Computer" when the 2003 versions points to "Windows 2003 print server role"?

  8. Steverac says:

    The discoveries are pointing to the right target – look again!  ::)

  9. Steverac says:

    FYI – I have posted an updated version of the MP.  The state monitoring check was not picking up on printers that were offline so had to fix that.  I also added a few more attributes to the discoveries.

  10. Dave F says:

    Thank you VERY much for the MP.  PLease, what bis the version of the revised MP that detects off-line printers?  I have 1.0.2.9.

  11. steverac says:

    FYI – I have posted an second updated version of the MP.  This version changes the way errors are handled and also fixes a bug I found in unknown printer detection logic.  In this version the last error noted is detected and the threshold timer set accordingly.  If one error is detected and then the error changes, such as the printer going offline, the last error will win.  Also, if a printer is detected as offline that wins over any other detected error.  The new version is 1.0.2.12.

  12. jmayrand says:

    Have you considered using a consensus scan of registry values instead of a WMI query for initial discovery?  It's a lot lighter… Once you know which servers have the spooler service active then query WMI for the other stuff.

  13. steverac says:

    No, I didn't think of doing that – just used the WMI/Registry stuff – it's light weight too.  If you prefer your method feel free to modify.

  14. googletalk says:

    I've done the same with SNMP probes a year ago. It saved me much time if only I had found it at that time.

    Great Work!

  15. Andy says:

    Great work!  Does this MP support 2008 R2 print servers?  If no, is it possible to modify the MP to allow it to work on that version of Windows?

  16. steverac says:

    I didn't specifically build this got 3008 R2 but the MP can be modified quite easily to do that – feel free to adjust as needed!

  17. Remstar says:

    Hi,

    Can you explain how to modify the MP to discover the 2008 R2 Printer role

    I'm a happy man

  18. Joep says:

    Hello Steve,

    I've created an override for the monitor (Windows 2003 print server printer state) with the parameter OfflineErrorDetectionEnabled set to 0. But when a printer is offline I still get a warning. How can I disable the alerts when a printer is offline?

  19. Remco says:

    Can you provide us on the details who to modify the MP to see 2008 R2 print managers

  20. Naveed Anjum says:

    Hello Steve –

    Thanks for this wonderful MP. I've imported this MP and have enabled all 4 discoveries. Printer Servers for Windows 2008 are discovered. However, none of the printers on this print server is getting discovered. It's been more than an hour since we've imported the MP.

    We're depending only on supplemental printer MP for printer monitoring. We do not have released Windows 2000/2003/2008 Printer MP imported in our environment.

    Is there something I'm missing ?

    Naveed Anjum

  21. steverac says:

    This is an MP Supplement – it requires you have the base Printer MP imported.

  22. Naveed Anjum says:

    Thanks for your response Steve. I'll import the base printer MP as well.

    Just to clarify, what do you mean by the following statement at the start of this post. Because, this is what made me believe that supplement MP would be enough to monitor the printers,

    "The term supplement is really a bad choice as the attached MP does NOT require the default printer MP from the catalog.  In fact, if you do have the original MP installed you will want to disable printer discovery via override as the attached MP has it’s own individual printer discovery."

    Naveed

  23. steverac says:

    Yep, sorry – that statement is absolutely true – you don't need the MP from the catalog with the version of the MP I have posted on this blog.  Too many things going on and was thinking of something else.

  24. Vijay H says:

    Hello Steve,

    This is a very nice post. I have already imported print server MP from catalog and was really looking for individual printer monitoring too, this is really a good one which help me a lot. I just want to confirm with you that with print server MP from catalog i import this MP, will create any abnormal behaviour in my environment.

    Regards,

    Vijay

  25. Vijay says:

    Hello Steve,

    I've created an override for the monitor (Windows 2003 print server printer state) with the parameter OfflineErrorDetectionEnabled set to 0. But when a printer is offline I still get a warning. How can I disable the alerts when a printer is offline?

    Regards,

    Vijay

  26. Steve Bernard says:

    Does this MP work with Server 2008 R2 printers as well?

  27. Chiel says:

    Anyone made this pack running for 2008 R2 and 2012 R2?

  28. Chiel says:

    Has there been someone made the adjustments foor 2008 R2 already?

  29. Phil A says:

    Steve I've edited the MP to work with 2008 R2. So far so good I'm discovering 2008 R2 print servers and Printers. (I just changed the targeted class, I haven't renamed all of the display string to R2 Life's too short)

    The only Issue I've seen so far is the Error Codes are one out.

    The MSDN reference for DetectedErrorState start at 0 whereas your case statement starts at 1.

    I'm testing this edit now to see if it all matches up. This is my first delve into Visual Studio MP authoring (In this instance Editing really)

    IF this works (No promises people) are you happy for me to share this on my blog with credit to you as original author a link back to here?

  30. steverac says:

    @Phil, sure, feel free to post.

  31. Vladimir says:

    Phil please share your MP. I really want to test it for my W2008R2