Windows Management Instrumentation (WMI) is a Microsoft implementation of Web-Based Enterprise Management (WBEM), an industry initiative that establishes management infrastructure standards. WMI provides you with the tools to discover, understand, and use various system resources, devices, and applications of your Windows 2000 or Windows NT system. WMI includes a rich eventing infrastructure that enables efficient and scalable monitoring, data collection, and problem detection.
In the article "Understanding WMI Eventing," September 2000, I discussed WMI's data model, eventing infrastructure, and different event-subscription methods. Now, I walk you through three examples of how to use WMI scripting to monitor your mission critical applications and to automatically restart those applications if they terminate. Although the examples use VBScript, you can use any scripting language that Windows Script Host (WSH) supports, including JScript and Perl.
Suppose that your server is running a mission-critical application and you need to know immediately if that application terminates. In the WMI data model, an instance of the Win32_Process class represents each running application. The termination of applications causes the deletion of those instances that represent them; _Instance-DeletionEvent is a generic event class that represents the deletion of any instance. Listing 1 shows how you can write a script that uses this event to monitor that application and display a message if it terminates.
In the script, you use the GetObject function to connect to WMI. The moniker (winmgmts:\\) you pass to GetObject specifies the server and namespace to which you want to connect. In this example, you want to connect to the local machine (which the period after the double backslashes represents) in the namespace root\cimv2, which is the standard location for the classes describing the local machine's current state.
The GetObject function returns a Connection object called SWbemServices. You can use this object's ExecNotificationQuery method to request events of a particular type. In this case, you're requesting _InstanceDeletionEvent events. The WITHIN 4 clause specifies that you want the object manager to poll instances of the Win32_Process class every 4 seconds to check for the _InstanceDeletionEvent event. Because _InstanceDeletionEvent is a generic class that applies to all objects, you use the WHERE clause to specify particular objects of interest. The TargetInstance ISA Win32_Process clause specifies that only objects of class Win32_Process or its subclasses are of interest. The condition TargetInstance.Name = 'MyCriticalApplication' narrows the selection to the object that represents a particular process. If the event occurs, the Do...Loop statement retrieves that object and displays the message Program MyCriticalApplication terminated, where MyCriticalApplication is the name of your crucial program.
The script in Listing 1 will notify you when your application terminates as long as the script is running. In other words, the script is creating a temporary event subscription.
Suppose your server is an unattended machine running 24 * 7, so you need to guarantee that any abnormally terminated application automatically restarts. Because of possible system reboots or other failures, you can't rely on a script that uses temporary event subscriptions. Instead, you need to use permanent event subscriptions, such as those in Listing 2. In this script, the Managed Object Format (MOF) syntax specifies a filter for the application termination event and creates a permanent event subscription by creating instances of three classes in the schema repository: _EventFilter, ActiveScriptEventConsumer, and _FilterToConsumerBinding.
The _EventFilter class object defines the event filter that specifies the event's parameters. This object performs a role similar to that of the ExecNotificationQuery call in Listing 1, except that the object is permanently stored in the repository. The ActiveScriptEventConsumer class object is a logical consumer. Logical consumers define actions that the WinMgmt service performs when it receives events associated with the consumers. In this case, you want WinMgmt to execute a script, so you need to use the scripting consumer, one of WMI's standard consumers. The _FilterToConsumerBinding class object links _EventFilter and ActiveScriptEventConsumer and activates the subscription. When an event occurs that matches the filter specification, the scripting consumer receives the event object and executes the specified script.
Because the _EventFilter, ActiveScriptEventConsumer, and _FilterToConsumerBinding class objects already exist in the repository, you just need to use the instance definition syntax to create instances of those classes. The code at callout A in Listing 2 creates an instance of the _EventFilter class. The instance defines the parameters of the event you're watching for. The Name property contains a unique string to identify this event-filter instance. The Query property contains the event query. In this case, the query watches for the termination of a process. Termination causes the deletion of the object for that process. The filter specifies that the event will only fire when the object representing the process MyCriticalApp is deleted. The WITHIN 4 clause in the query specifies that WMI will check for this deletion every 4 seconds. This setting guarantees that WMI will report the event no later than 4 seconds after the actual termination. The QueryLanguage property specifies the query language you want to use. Currently, WMI Query Language (WQL) is the only query language that you can use in the event filters.
The code at callout B in Listing 2 creates an instance of the ActiveScriptEventConsumer class. This instance specifies the script you want to run when WinMgmt service receives the specific event. The Name property is key because it uniquely identifies this instance among other instances of the same class (you might be executing different scripts for different events). The ScriptingEngine property is set to VBScript because that is the scripting language I'm using in the example, but in other instances, you might set this property to JScript or Perl. The ScriptText property fills with the text of the script you want to execute when the event arrives. (The ScriptText property is for short scripts. When a script is longer, you use the ScriptFile property to point to the file containing the script.) This script executes the Create method to create an instance of the Win32_Process class. By using TargetEvent.TargetInstance.Name as the name of the process, you guarantee that the terminated process restarts.
The code at callout C in Listing 2 defines the _FilterToConsumerBinding instance. At this point, you've defined the event (process termination event) and the action you want to take (execute a script to restart the same process) if that event occurs. Now, you just need to link the _EventFilter and ActiveScriptEventConsumer instances to activate the subscription. You can create this link by creating an instance of the _FilterToConsumerBinding class. To define the _FilterToConsumerBinding instance, you need to specify three properties: Consumer, Filter, and DeliverSynchronously. In the Consumer property, you specify $CONS, which represents the ActiveScriptEventConsumer instance you previously defined. In the Filter property, you specify $FILT, which represents the _EventFilter instance you previously defined. In the DeliverSynchronously property, you specify FALSE, which means you want the events sent asynchronously.
You're responsible for the operation of the 24 * 7 server in the previous example, so you want to configure a subscription that not only automatically restarts the terminated application but also sends an email message notifying you when the application terminates and successfully restarts. The script in Listing 3 shows how you can extend your subscription in Listing 2 to perform these additional actions.
The script in Listing 3 uses another WMI standard consumer: the SMTP consumer. Note that you must have an SMTP server on your network to use the SMTP consumer. The SMTPEventConsumer class represents the consumer. Each instance of this Class object defines the parameters of the email message you want to send in response to an event.
The first instance at callout A in Listing 3 defines the SMTPEventConsumer object, which generates an email message when the application terminates. This class has many properties, but this example only fills in those properties required to do the job. The rest of the properties will be left empty. The Name property uniquely identifies this instance among other instances of the class. (You might be sending email to several different people for different events.) The ToLine and Subject properties are the recipient's email address and the message's subject line, respectively. The Message property contains what you want to say in the body of the email message. You can use the standard %% delimiters to include property values from the event in the message. In this case, the email message body includes the name of the terminated process. Finally, the SMTPServer property specifies the name of your email server. The consumer needs this information so that it knows where to send the email message.
The termination email message is triggered by the same instance deletion event you defined at callout A in Listing 2. Because you now have the same event triggering two different actions, you need to create a separate _FilterToConsumerBinding object to bind the new logical consumer instance to the existing filter. The code after callout A in Listing 3 registers the binding object. You need to set the Filter property to $FILT, which represents the filter for the process termination event (see callout A in Listing 2).
The second instance of the SMTPEventConsumer class at callout B in Listing 3 defines another logical consumer that sends an email message when the application successfully restarts. This instance is similar to the first instance of the same class at callout A in Listing 3, but it specifies a different subject and message body to notify the systems administrator about the process restart. The instance also uses a different unique name as the key.
Because the restart results in the creation of a new instance of the Win32_ Process class, you need to define a new filter for process-activation events. The code at callout C in Listing 3 registers this filter. The Query property defines parameters of the event that watches for the activation of the MyCriticalApp process. Because process activation causes the creation of an instance for the process, the query includes the _InstanceCreationEvent class. The TargetInstance ISA Win32_Process clause specifies that only the creation of instances of the Win32_Process or its subclasses are of interest. The event will only fire when the object representing MyCriticalApp is created. Again, you set the WITHIN clause to 4 to guarantee that WMI will report the event no later than 4 seconds after the activation. The QueryLanguage property specifies WQL as the query language.
To activate this subscription, you need to bind the consumer and the filter. The code after callout C in Listing 3 creates the binding as an instance of the _FilterToConsumerBinding. This instance definition is similar to the code at callout C in Listing 2.
Using the Scripts
To use the scripts in Listings 2 and 3, you need to set up the scripting consumer and SMTP consumer. (Although all versions of Win2K ship with both, the consumers aren't set up by default.) Follow these steps to set up the consumer:
- Type or copy the code in Listings 2 and 3 into Notepad, and save it in the \winnt\system32\wbem folder as myactions.mof.
- Fill in the appropriate properties in the instance definitions with the existing process name, SMTP server name, email address, and so on. Save the changes.
- At the command prompt, change the directory to \winnt\system32wbem.
- To register the SMTP and scripting consumers with WMI, type
MOFCOMP N:root\cimv2 smtpcons.mof MOFCOMP N:root\cimv2 scrcons.mofat the command prompt. MOFCOMP is a standard tool that comes with WMI. This tool reads MOF files and places the schema within them into the WMI repository.
- To compile your event subscription registration, type
MOFCOMP N:root\cimv2 myactions.mofat the command prompt.
After you complete these steps, WMI will start to monitor your process. To test the operation, you can use the Task Manager to terminate your process. WMI will send the termination email message, and in about 4 seconds, the process will restart and WMI will send the activation email message. Because this registration is permanent, the subscriptions will remain active until you remove them. In "Understanding WMI Eventing," I introduced a simple script that deletes a registration object. You can find that script in the Code Library on the Win32 Scripting Journal Web site at http://www .win32scripting.com/. After you download the script, you can modify it so that it removes the objects that myactions.mof creates.
Efficiently Monitor Your System
This article concludes the short series about WMI eventing. I hope the examples in the series will help you better understand WMI eventing so that you can use WMI to build powerful and efficient scripting solutions to monitor and troubleshoot your system.
Printed with permission from Microsoft.