Export (0) Print
Expand All

Enhanced WMI Monitoring Scripts

Microsoft® Windows® 2000 Scripting Guide

As previously explained, the WMI monitoring scripts presented in the introduction to this section can be easily adapted to monitor any WMI-managed resource. However, these scripts do have some limitations. In particular, they can only:

  • Specify the instance monitored with the value of a single property.

  • Handle a single event.

  • Handle a single type of event: creation, modification, or deletion.

  • Monitor a single type of resource.

  • Continue monitoring a resource as long as they are running. If the script stops for any reason, monitoring stops as well.

The following example scripts demonstrate how you can change the type of monitoring script presented in the introduction in order to overcome each of these limitations.

Targeting a Particular Resource

You can be more specific about the resource to monitor by enhancing the WHERE clause. The query in Listing 6.31 specifies that the Device ID property must have the value CPU0 and also specifies that the Load Percentage property must have a value greater than 90. You can include additional constraints on the values of any of the properties of the class, making use of the AND and OR keywords to combine the constraints.

Listing 6.31 Monitoring the First CPU for 90 Percent Load

  
1
2
3
4
5
6
7
8
9
10
11
12


Set objSWbemServices = _
 GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")

strWQL = "SELECT * FROM __InstanceModificationEvent " &_
 "WITHIN 5 " &_
 "WHERE TargetInstance ISA 'Win32_Processor' " &_
 "AND TargetInstance.DeviceID='CPU0' " &_
 "AND TargetInstance.LoadPercentage > 90"

Set objEventSource = objSWbemServices.ExecNotificationQuery(strWQL)
Set objEventObject = objEventSource.NextEvent()
Wscript.Echo "Load Percentage on CPU0 exceeded 90%."

Handling More than One Event

The scripts in Listing 6.29 and Listing 6.30 stop running after receiving a single event. You might want to have a script that continues to receive events even after the first event occurs. This requires only a minor modification to the scripts in Listing 6.29 and Listing 6.30. Simply encapsulate the call to the NextEvent method and the event notification message within an endless loop. Setting the condition statement for the loop to True ensures that the loop will never end.

So how do you stop the script when you no longer need it? If the script is running under CScript, either press CTRL+C or close the command window in which the script is running. If the script is running under WScript, you can terminate the Wscript.exe process by using Task Manager.

Listing 6.32 Continually Monitoring the First CPU for 90 Percent Load

  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16


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

strWQL = "SELECT * FROM __InstanceModificationEvent " & _
 "WITHIN 5 " & _
 "WHERE TargetInstance ISA 'Win32_Processor' " & _
 "AND TargetInstance.DeviceID='CPU0' " & _
 "AND TargetInstance.LoadPercentage > 90"

Set objSWbemEventSource = objSWbemServices.ExecNotificationQuery(strWQL)

While True
 Set objSWbemObject = objSWbemEventSource.NextEvent()
 WScript.Echo "Load Percentage on CPU0 exceeded 90%."
Wend

Handling More than One Type of Event

The script in Listing 6.29 handled only instance creation events; the script in Listing 6.30 handled only instance modification events. Suppose you want to know when a new instance of Notepad is started, when the priority of a running instance of Notepad is changed, or when an instance of Notepad is deleted. In other words, suppose you want to be notified when any changes involving Notepad occur. You can write three separate scripts, one for each event type, but there is an easier way to do it.

The __InstanceCreationEvent, __InstanceModificationEvent, and __InstanceDeletionEvent classes are all derived from the __InstanceOperationEvent class. Creation, modification, and deletion are just special cases of the more general action operation. If you handle instance operation events in your script by specifying the __InstanceOperationEvent class in your WQL notification query (line 7), your script will receive creation, modification, and deletion events.

You can also add code to determine which of the three possibilities actually occurred in a particular case. You do this by examining the class of the event object (line 14) and then deciding how to proceed based on the event that occurred, as shown in Listing 6.33.

Listing 6.33 Monitoring the Creation, Modification, and Deletion of Notepad.exe

  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21


strComputer = "."
Set objSWbemServices = GetObject("winmgmts:" &_
 "{impersonationLevel=impersonate}!" &_
 "\\" & strComputer & "\root\cimv2")

Set objEventSource = objSWbemServices.ExecNotificationQuery( _
 "SELECT * FROM __InstanceOperationEvent " &_
 "WITHIN 1 " &_
 "WHERE TargetInstance " &_
 "ISA 'Win32_Process' " &_
 "AND TargetInstance.Name = 'notepad.exe'")

Set objEventObject = objEventSource.NextEvent()
Select Case objEventObject.Path_.Class
 Case "__InstanceCreationEvent"
 Wscript.Echo "An instance of notepad.exe was just started."
 Case "__InstanceDeletionEvent"
 Wscript.Echo "An instance of notepad.exe was just stopped."
 Case "__InstanceModificationEvent"
 Wscript.Echo "An instance of notepad.exe was just modified."
End Select

Monitoring More than One Type of Managed Resource

The script in Listing 6.29 monitors a process and the script in Listing 6.30 monitors a service. It seems that each managed resource requires a separate script. As it turns out, however, you can create a single script that monitors two different types of resources. To do so, you have to make two modifications to scripts like those in Listing 6.29 and Listing 6.30, as shown in Listing 6.34.

First you have to modify the WQL by using logical ORs to register for notifications from each of the different resource types (lines 12-14).

Second you have to add code that examines the class of the TargetInstance, retrieved from the event object, to determine which of the resources the event came from, and then proceed accordingly (lines 17-22).

Listing 6.34 Monitoring Both the W3SVC Service and the Notepad.exe Process

  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21


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

Set objSWbemEventSource = objSWbemServices.ExecNotificationQuery( _
 "SELECT * FROM __InstanceModificationEvent " & _
 "WITHIN 1 " & _
 "WHERE (TargetInstance " & _
 "ISA 'Win32_Process' " & _
 "AND TargetInstance.Name = 'notepad.exe') " & _
 "OR (TargetInstance " & _
 "ISA 'Win32_Service' " & _
 "AND TargetInstance.Name='w3svc')")

Set objSWbemObject = objSWbemEventSource.NextEvent()
Select Case objSWbemObject.TargetInstance.Path_.Class
 Case "Win32_Process"
 WScript.Echo "An instance of notepad.exe was just modified."
 Case "Win32_Service"
 WScript.Echo "The state of the W3SVC service was just modified."
End Select

Monitoring Events by Using a Permanent Event Subscription

The WMI monitoring scripts presented to this point use temporary event subscriptions, which exist only as long as the scripts are running. If you want to monitor resources without perpetually running a script, you need to set up a permanent event subscription.

Suppose you want to monitor the free disk space available on the busiest Microsoft Exchange servers in your enterprise. You can write a script with a temporary event subscription. However, what if the process running the script terminates? What if someone reboots one of the servers and the script fails to restart?

Clearly, it would be useful to have a solution that is more permanent (and hence more reliable) than subscriptions tied to a running process. Permanent event subscriptions provide this more permanent solution. These event subscriptions are stored in the CIM repository; canceling a subscription involves deleting it from the CIM repository. There is no associated process that, if stopped, will interrupt the subscription.

The process of handling an event can be divided into two distinct subprocesses: 1) deciding which events to handle and 2) describing the actions to be taken in response to the event. There are WMI classes that correspond to each of these subprocesses. The __EventFilter class represents the process of deciding which events to handle, and the __EventConsumer class represents the process of describing the actions to be taken in response to particular events.

Three steps are involved in setting up a permanent event subscription:

  1. Create an __EventFilter class.

  2. Create a class derived from __EventConsumer.

  3. Associate the two classes with each other by creating a __FilterToConsumerBinding class.

In practice, creating the __EventFilter class is fairly straightforward. However, creating the __EventConsumer class (and the required associated WMI provider) is beyond the scope of this chapter. Fortunately, WMI provides prebuilt __EventConsumer classes that you can use. Before you can use the prebuilt __EventConsumer classes, you must register them in the CIM repository by using the mofcomp.exe tool.

The __EventFilter Class

Creating an instance of an __EventFilter class involves retrieving the class itself from the CIM repository by using the Get method and then calling the SpawnInstance_ method to create a "blank" instance of the class and storing a reference to it. After you have a reference to an instance of the class, you need to set the properties of the class and then use the Put_ method to actually store the instance in the CIM repository.

The most important property of __EventFilter class is its Query property. The Query property must be set to the WQL notification query that describes the events for which the instance of the __EventFilter class should filter, as shown in Listing 6.35.

Listing 6.35 Creating an Instance of the __EventFilter Class

  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15


strComputer = "."
Set objSWbemServices = GetObject("winmgmts:" _
 & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")

Set objEventFilterClass = objSWbemServices.Get("__EventFilter")
Set objEventFilter = objEventFilterClass.SpawnInstance_()

objEventFilter.Name = "WebServiceStateModFilter"
objEventFilter.QueryLanguage = "WQL"
objEventFilter.Query = "SELECT * FROM __InstanceModificationEvent " &_
 "WITHIN 600 WHERE TargetInstance " &_
 "ISA 'Win32_Service' " &_
 "AND TargetInstance.Name = 'W3SVC'"

objEventFilter.Put_()

The Prebuilt __EventConsumer Classes

As mentioned previously, creating an __EventConsumer-derived class is beyond the scope of this chapter. However, WMI includes a number of prebuilt consumer classes that you can use. These standard consumer classes are listed and described in Table 6.11.

Table 6.11 Standard Event Consumer Classes

Class

Description

ActiveScriptEventConsumer

Runs a script when an event is delivered to it

SMTPEventConsumer

Sends an e-mail message by using SMTP when an event is delivered to it

CommandLineEventConsumer

Runs a program in the local system context when an event is delivered to it

NTEventLogEventConsumer

Logs a message to the Windows event log when an event is delivered to it

LogFileEventConsumer

Writes strings to a text file when an event is delivered to it

ScriptingStandardConsumerSetting

Provides registration data common to all instances of the ActiveScriptEventConsumer consumer


The standard consumer classes are not available for use until they have been registered in the CIM repository. For example, you will need to run the following command to register the ActiveScriptEventConsumer, which will be used in Listing 6.36.

mofcomp -N:root\default %SYSTEMROOT%\system32\wbem\scrcons.mof

Assuming the command completes successfully, you should see output similar to the following:



Parsing MOF file: C:\WINNT2\system32\wbem\scrcons.mof
MOF file has been successfully parsed
Storing data in the repository...
Done!

Registration needs to be performed only once unless the information about ActiveScriptEventConsumer that was added to the CIM repository is explicitly removed.

Following registration of a standard consumer class, creating an instance of this class uses code similar to that used in Listing 6.35 (where an instance of the __EventFilter class was created), as shown in Listing 6.36.

Listing 6.36 Creating an Instance of the __EventConsumer Class

  
1
2
3
4
5
6
7
8
9
10
11
12
13


strComputer = "."
strComputer = "."
Set objSWbemServices = GetObject("winmgmts:" _
 & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")

Set objConsumerClass = objSWbemServices.Get("ActiveScriptEventConsumer")
Set objConsumer = objConsumerClass.SpawnInstance_()

objConsumer.Name = "RunResponseScript"
objConsumer.ScriptFileName = "C:\scripts\response.vbs"
objConsumer.ScriptingEngine = "VBScript"

objConsumer.Put_()

The __FilterToConsumerBinding Class

The purpose of the __FilterToConsumerBinding class is to associate an __EventFilter with an __EventConsumer. After that association is established, any events that the __EventFilter instance intercepts are handed off to the __EventConsumer instance so that it can act upon them.

Creating an instance of the __FilterToConsumerBinding class requires the same steps as creating instances of the __EventFilter and __EventConsumer classes. The two properties of the class that need to be set are Filter and Consumer, which are the relative object paths of the __EventFilter and __EventConsumer classes being associated, as shown in Listing 6.37.

Listing 6.37 Creating an Instance of the __FilterToConsumerBinding Class

  
1
2
3
4
5
6
7
8
9
10
11


strComputer = "."
Set objSWbemServices = GetObject("winmgmts:" _
 & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")

Set objBindingClass = objSWbemServices.Get("__FilterToConsumerBinding")
Set objBindingInstance = objBindingClass.SpawnInstance_()

objBindingInstance.Filter = "WebServiceStateModFilter"
objBindingInstance.Consumer = "RunResponseScript"

objBindingInstance.Put_()


After the __EventFilter-derived and __EventConsumer-derived instances have been created in the CIM repository and have been bound together by the __FilterToConsumerBinding class, the final step is to create the script that will run in response to a Web service status modification. This can simply be a script that displays a message when invoked by the Active Script Event Consumer.

Was this page helpful?
(1500 characters remaining)
Thank you for your feedback
Show:
© 2014 Microsoft