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!