Hey, Scripting Guy! Question

Hey, Scripting Guy! How can I receive notification any time something is printed to a particular printer?

-- IL

SpacerHey, Scripting Guy! AnswerScript Center

Hey, IL. You know, one of the Scripting Guys once had a summer job in an organization where the only decent printer in the entire building was kept in the administrative assistant’s office. We can attest, from painful experience, that it didn’t take much effort to receive a … notification … any time you printed something to that printer.

Of course, that kind of notification involves a good deal of yelling and screaming. Fortunately, there’s a more peaceful and civilized way to receive notification any time something is printed to a particular printer. In fact, all you need is a WMI event notification script similar to this:

strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

Set colPrintJobs = objWMIService. _ 
    ExecNotificationQuery("Select * From __InstanceCreationEvent " _ 
        & "Within 10 Where TargetInstance ISA 'Win32_PrintJob'")

Do While True
    Set objPrintJob = colPrintJobs.NextEvent
    If InStr(objPrintJob.TargetInstance.Name, "atl-color-printer-1") Then 
        Wscript.Echo objPrintJob.TargetInstance.Document, Now
    End If
Loop

This quieter, gentler form of notification starts off by connecting to the WMI service on the local computer. Note that you easily modify this script to connect to the WMI service on a remote computer: just assign the variable strComputer the name of that computer. Note, too that you do not have to connect to the print server; this script works on any computer that has a connection to the printer being monitored (in this case, a printer named atl-color-printer).

After making the connection to the WMI service we then run this line of code:

Set colPrintJobs = objWMIService. _ 
    ExecNotificationQuery("Select * From __InstanceCreationEvent " _ 
        & "Within 10 Where TargetInstance ISA 'Win32_PrintJob'")

This is the actual event notification query: we’re asking WMI to inform us any time a new instance of the Win32_PrintJob class is created. Why? Well, each time someone prints a new document a new instance of the Win32_PrintJob class is created; by receiving notification each time a new Win32_PrintJob instance is created we’ll know that someone is printing a document.

Note. What does the Within 10 mean? That simply means that we’re going to check every 10 seconds to see if there are any new print jobs; if there aren’t, then the script will go into temporary hibernation and re-emerge 10 seconds later in order to make another check. If you aren’t sure what terminology like Within 10, TargetInstance, and ISA means, then you might want to check out the Scripting Guys Scripting Week 2 webcast on WMI events.

We should clarify one thing here: if all we have is the event notification query then our script will be informed any time a document is printed; however, we won’t be informed. If we want to know what’s going on (and, obviously, we do), we have to add in code that will send us a notification of some type. For this example script we’re going to use a very simple form of notification: we’ll just echo back the name of the document being printed and the time that printing began. Here’s what that code looks like:

Do While True
    Set objPrintJob = colPrintJobs.NextEvent
    If InStr(objPrintJob.TargetInstance.Name, "atl-color-printer-1") Then 
        Wscript.Echo objPrintJob.TargetInstance.Document, Now
    End If
Loop

What we do here is set up a Do Loop that will run forever (Do While True basically means that the loop should continue to run as long as True is equal to True). Why do we do that? Well, we’re assuming you want to constantly monitor the printer and thus receive a notification each and every time a document is printed. The easiest way to do that is to put the notification code inside an endless loop.

Next we have this line of code:

Set objPrintJob = colPrintJobs.NextEvent

When the script encounters this line of code it stops dead in its tracks and waits for the NextEvent to occur. The event we are awaiting, of course, is the creation of a new instance of the Win32_PrintJob class. If no documents are ever printed (and thus no new instances of this class created) the script will simply sit on this line forever, dutifully waiting for the next event to take place.

So what happens when this next event does occur and someone does print a document? Well, the first thing we do is check to see if the document is being printed on the target printer:

If InStr(objPrintJob.TargetInstance.Name, "atl-color-printer-1") Then

We use the InStr function here because the print job Name (at least on network printers) is likely to look like this: \\\\atl-ps-01\\atl-color-printer-1, 226 (a big, long string that represents the network path to the printer plus the job ID -226 - assigned to the individual print job). All we’re doing is checking to see if the string atl-color-printer-1 appears anywhere within the print job Name. If it does, then that means the document is being printed to the printer atl-color-printer-1.

Note. If you only have one printer connection on the computer where the script is running, then you can skip this If-Then statement. After all, in a case like that there’s only one possible printer that the document could be printed to.

If the InStr function returns true (meaning the string atl-color-printer-1 was found), then we echo back the name of the document and the time that printing began:

Wscript.Echo objPrintJob.TargetInstance.Document, Now

And that’s it: we then loop around and wait for the next event. If we ever decide to stop monitoring all we need to do is terminate the process (either Cscript.exe or Wscript.exe) that the script is running in.

And, yes, instead of echoing back the fact that a document was being printed we could have written the script so that it plays a .WAV file that yells at you. But you’re on your own for that one. You know what they say: been there, done that. Our ears are still ringing, even after all these years.