Notify with WMI

Find out how to use Windows Management Instrumentation (WMI) for system notifications without having to write scripts.

I recently got a request from an administrator with a printer issue. In his office, the sales staff sends work orders to a printer sitting in the warehouse. Fulfillment team members check the printer's output tray every once in a while for work orders. The admin wanted a way to notify the fulfillment team by e-mail when a work order prints to eliminate delay.

I suppose he and I could've come up with a quick-and-dirty solution to this problem, or a modification to the work process. But in the long run it seemed best to implement a strategic solution that could be applied to this and any other case involving system operations requiring notification or other automated action. This solution requires no investment (other than a bit of configuration time) and no additional software on the servers.

How, you ask? Through Windows Management Instrumentation (WMI). Yes, I know you've dabbled with writing WMI scripts and found them to be inordinately complex, with documentation showing a bazillion different ways to do things, none of which seem to work as promised. Don't worry—you don't need scripts to use WMI for system notifications.

Installing a WMI Event Consumer
Just about every component on a Windows machine has drivers that contribute information to WMI. This information gets stored in the Common Information Model (CIM) Repository. When a change occurs to something in the CIM Repository, WMI creates an "event," so getting notified of these changes requires configuring a WMI event handler.

This handler has two elements: a WMI Event Filter and a WMI Event Consumer. A Filter watches for something to happen and a Consumer does something once the event occurs. If you were to use WMI Events to drive a car, for example, a Filter would watch for a traffic light to change from red to green, and a Consumer would accelerate the car through the intersection.

In this printing scenario, the Consumer would send an e-mail to the Fulfillment team whenever the Filter detects a new print job. Windows XP and Windows Server 2003 come with a pre-packaged SMTP Event Consumer that can send e-mails. On Windows 2000, the files for installing the SMTP Event Consumer are included but not compiled into the WMI database. You'll need to do this manually.

Constructing a WMI Search Query
Before you can build a WMI Event Filter, you need to know a bit about doing WMI searches. Searches in WMI use a stripped-down version of SQL called WMI Query Language, or WQL.

Because WMI typically classifies information based on its source, you can usually extract information about a given component by formulating a short WQL statement using the associated WMI class. For example, here's a scripted query that lists printer names on a server:

Set wmi = GetObject
("WinMgmts://./root/cimv2")
wql = "SELECT * FROM Win32_Printer"
Set rs = wmi.ExecQuery(wql)
For Each item In rs
  WScript.echo item.name
Next

You can get the same information in an XP or Windows 2003 machine—without scripts—using WMIC as follows: wmic printer get name

Print jobs are represented in WMI by the Win32_PrintJob class. Each print job has a property called DriverName that contains the name of the printer that created the job. By using the printer name received from WMIC as a selection criteria for DriverName, you can construct a WQL statement that collects properties from all print jobs queued for a specified printer. The WHERE term defines selection criteria:

SELECT * FROM Win32_PrintJob WHERE DriverName = 'HP Deskjet 6122'

This statement can only collect properties if a print job exists. However, the real power of WMI comes from its ability to notice status changes, which is just another way of saying "event."

WMI has an object class called __InstanceCreationEvent (that's a double underscore) for use in working with events. When a WMI provider such as a printer driver creates a new WMI object—in this case, a Win32_ PrintJob object—WMI creates a new __InstanceCreationEvent object. To look for new print jobs, then, the WQL statement would look for new __InstanceCreationEvent objects originating from Win32_PrintJob. The statement looks like this:

SELECT * FROM __Instance
CreationEvent WITHIN .1 WHERE
TargetInstance ISA 'Win32_PrintJob'

The WITHIN term defines a polling interval. I used a very short interval because small print jobs don't last very long. The ISA term defines the source class, which in this case is Win32_PrintJob.

To get notifications only when print jobs originate from a specific printer, add the printer name to the selection criteria (be sure to substitute a printer name that actually exists at your server):

SELECT * FROM __Instance
CreationEvent WITHIN .1 WHERE
TargetInstance ISA 'Win32_PrintJob' AND TargetInstance.DriverName='HP LaserJet 4'

A query like this forms the basis of a WMI Event Filter. All you need to do is add the appropriate entries into the WMI database. Let's see how that works.

Configure an Event Filter
There are several ways to cram information about Event Filters and Consumers into the WMI database. Some use scripts. Others use Managed Object Format (MOF) files. But if you don't like messing about with code, Microsoft provides a super-cool utility called the WMI Event Viewer that simplifies the process of setting up Event Filters and Consumers. The WMI Event Viewer comes as part of a set of WMI Tools, downloadable from http://snipurl.com/bces.

After installing the WMI Tools, from the Start menu, launch the WMI Event Viewer.

In the toolbar of the main Event Viewer window, click the Register For Events button. (It's decorated with a pen.)

When the Connect To Namespace popup opens, enter the path root\subscription if you're running XP or Windows 2003, and root\cimv2 if you're running Win2K. Click OK to connect using your login credentials (you'll need Administrator rights on the server.)

The WMI Event Registration Editor window opens. The editor has three options, selectable from a dropdown box in the upper left corner:

  • Filters
  • Consumers
  • Timers

Select Filters. The left pane now shows an __EventFilter icon.

Right-click the __EventFilter icon and select New Instance from the flyout menu. This opens the Edit new instance properties window, shown in Figure 1, below. Enter the following configuration information:

  • Event Namespace: Use root\cimv2 regardless of the Windows version you're running. This tells the Event Filter to look in the main path of the CIM repository for the specified object classes.
  • Name: Identify the filter with a friendly name such as PrintJobMonitor. You can't change the name after the filter has been created.
  • Query Language: Enter the letters WQL. (The entry is not case-sensitive.)
  • Query: Enter the WQL statement shown earlier. Pay particular attention to spaces, quotes and spelling. The statement is not case sensitive.

No other entries are required. Click OK to save the filter.

Figure 1. Create a custom Event Filter.
Figure 1. The "Edit new instance properties" window is where you create a custom Event Filter. (Click image to view larger version.)

Configure an SMTP Event Consumer
Now it's time to configure the SMTP Event Consumer to send e-mail to the appropriate individuals or distribution lists.

  • In the Registration Editor, select Consumers from the dropdown box. The left pane now shows a __EventConsumer icon.
  • Expand the tree to show the SMTPEventConsumer icon. (If this icon isn't present, you either selected the wrong path when you launched the Registration Editor or neglected to compile the SMTPCons.mof file on Win2K.)
  • Right-click the SMTPEventConsumer icon and select New Instance from the flyout menu. This opens the "Edit new instance properties" window.
  • The entries in this window determine who gets e-mail notification. Put a comma or semicolon between multiple e-mail addresses on the same line. Entries delimited by "%%" extract information from the print job and put them in the e-mail. Here are sample entries:
    • FromLine: %TargetInstance DriverName%@company.com
    • Message: NOTICE: %TargetInstance.DriverName% printed a job with JobID % TargetInstance.JobID%
    • Name: PrintJobNotification
    • SMTPServer: smtp_server.company.com
    • Subject: Print Job Notification
    • ToLine: [email protected]; [email protected], [email protected]
    • Click OK to close the Edit New Instance Properties window and return to the Event Registration Editor.

Figure 2. If configured correctly, this link will show.
Figure 2. If you've configured everything correctly, the WMI Event Registration Editor will show this link between custom Event Filter and new SMTP Event Consumer. (Click image to view larger version.)

Link the Filter and Consumer
These final and critical steps link the new Event Filter to the SMTP Event Consumer you just configured.

  • Highlight the new SMTP Event Consumer instance. The right pane of the window populates with Event Filters.
  • Highlight the custom Event Filter you created, then click the Register button. (It's decorated with a big green checkmark.) This links the filter to the event. Figure 2 above shows an example.
  • Close the Registration Editor and close the Event Viewer. The entries made to the WMI database remain and will survive a reboot.
  • Test the event entries by sending a print job to the specified printer then make sure you get an e-mail.

There's More …
You can use WMI Events in thousands of different ways. For more information, check out Developing WMI Solutions by Craig Tunstall and Gwyn Cole and also the Windows 2000 Scripting Guide by the Microsoft Scripting Guys.

More Information

Manually Compile the Consumer Files into the WMI Database:
Open a console prompt and navigate to %windir%\System32\WBEM. This folder holds configuration files for WMI, some of which have a .mof extension. (MOF stands for Managed Object Format.) The SMTPCons.mof file holds the instructions for the SMTP Consumer. Inserting the mof entries into the WMI database is called “compiling a mof.” To compile SMTPCons.mof, enter the following command:

mofcomp /n:root\cimv2 smtpcons.mof

You'll get a result similar to the following:

Microsoft (R) 32-bit MOF Compiler Version 5.2.3790.0
Copyright (c) Microsoft Corp. 1997-2001. All rights reserved.
Parsing MOF file: smtpcons.mof
MOF file has been successfully parsed
Storing data in the repository...
Done!

The /n:root\cimv2 entry represents the path within the Common Information Model (CIM) repository where the consumer gets registered. The CIM repository acts as a database for WMI. In XP and Win2003, prepackaged event consumers and filters are registered in the root\subscription path. Windows 2000 uses the root\cimv2 path. Keep this in mind, because later on you'll need to navigate within the CIM.

To use the SMTP Event Consumer, you'll need to know the name of an SMTP server on your network. Most SMTP servers accept anonymous connections if the messages are addressed to someone within your organization. If you want to send a message to an address outside your organization, you'll need to make special relaying provisions that fall outside the scope of this discussion.

Featured