Notify with WMI

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:

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.)

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:

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:

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.