Contents
- Introduction
- WQL Event Queries
- Event Helper Classes
- WITHIN and GROUP Clauses
- Temporary Event Consumers
- Permanent Event Subscription
- Using WMI Tools
- ActiveScriptEventConsumer Class
- Note about Strings
- TargetEvent and TargetInstance
- SMTPEventConsumer Class
- LogFileEventConsumer Class
- CommandLineEventConsumer Class
- Win32_LocalTime Class
- Final Note
- Useful Links
1. Introduction
The WMI Event Subsystem allows you to subscribe to WMI events. WMI events represent changes in WMI data: if you start Notepad, an instance of the
Win32_Process
WMI class is created, and an instance creation WMI event is also created. If you delete a file from the disk, an instance of the CIM_DataFile
class is deleted, and an instance deletion WMI event is created. In fact, any change in WMI data can be used to create an event, so it is easy to see how WMI events can be useful in system administration.
WMI will not create events for you unless you subscribe to them. Applications that register their interest in WMI events are called event consumers.
There are two types of event consumers: temporary and permanent. Temporary event consumers are typically applications that use the .NET Framework and its
System.Management
namespace or WMI scripting library to receive WMI events, which means that they receive events only when they are started by a user. Permanent event consumers are different - they are designed to receive events at all times. Both temporary and permanent event consumers use WMI event queries to subscribe to events they are interested in.2. WQL Event Queries
Just like other WMI queries, WMI event queries are issued using WQL (WMI Query Language). There are several differences between event queries and other query types, but the most significant one is that WMI event queries use WMI event classes. A WMI class is an event class if it is derived from the
__Event
system class. So, in order to see what tasks can be accomplished using WMI events, you first need to examine the WMI event classes. But, how can you do that? Since all event classes are derived from the __Event
system class, you can use a query like this one:
Collapse | Copy Code
Select * From Meta_Class Where __This Isa "__Event"
Although this query includes a reference to the
__Event
class, it is not an event query. Actually, it is a WMI schema query - it uses Meta_Class
, a special class that represents all classes in a WMI namespace. Since you don't want all the classes, but just the __Event
derived classes, you also need to add the WHERE
clause. When issued, the query returns a list of WMI classes that looks like this:
Collapse | Copy Code
. . .
MSFT_WMI_GenericNonCOMEvent
MSFT_WmiSelfEvent
Msft_WmiProvider_OperationEvent
Msft_WmiProvider_ComServerLoadOperationEvent
Msft_WmiProvider_InitializationOperationFailureEvent
Msft_WmiProvider_LoadOperationEvent
Msft_WmiProvider_OperationEvent_Pre
Msft_WmiProvider_DeleteClassAsyncEvent_Pre
Msft_WmiProvider_GetObjectAsyncEvent_Pre
Msft_WmiProvider_AccessCheck_Pre
Msft_WmiProvider_CreateClassEnumAsyncEvent_Pre
Msft_WmiProvider_ExecQueryAsyncEvent_Pre
Msft_WmiProvider_CreateInstanceEnumAsyncEvent_Pre
Msft_WmiProvider_NewQuery_Pre
Msft_WmiProvider_DeleteInstanceAsyncEvent_Pre
Msft_WmiProvider_CancelQuery_Pre
Msft_WmiProvider_PutInstanceAsyncEvent_Pre
. . .
On my test Windows XP SP2 machine, the query returns a total of 136 classes. The number may be different on your computer, but if you examine the list closely, you'll notice that most commonly used WMI classes like
Win32_Process
or Win32_Service
are not on it.3. Event Helper Classes
So, the classes that you are really interested in are not derived from the
__Event
class, but it is still possible to use them in WMI event queries. You can use all WMI classes in event queries, only not directly. In order to use a class that is not derived from __Event
in an event query, you need to use one of the helper classes like:__InstanceCreationEvent
__InstanceModificationEvent
__InstanceDeletionEvent
All of the above classes are derived from
__InstanceOperationEvent
, and have a TargetInstance
property, which is a reference to the class instance you want to receive event notifications from. So, if you use a query like this:
Collapse | Copy Code
Select * From __InstanceCreationEvent
Where TargetInstance Isa "Win32_Process"
the
TargetInstance
property of the returned event will contain a reference to the Win32_Process
instance that was created. If you want to refer to the Win32_Process.ExecutablePath
property, use the__InstanceCreationEvent.TargetInstance.ExecutablePath
property. In addition, the__InstanceModificationEvent
class has the PreviousInstance
property that contains a reference to a copy of the WMI class instance before it was modified. Classes derived from __InstanceOperationEvent
and theirTargetInstance
property enable you to use all WMI classes in event queries.4. WITHIN and GROUP Clauses
The WMI event subsystem uses a polling mechanism for event delivery. To specify the polling interval, use the
WITHIN
keyword followed by the polling interval (in seconds):
Collapse | Copy Code
Select * From Win32_Process
Within 10
Where TargetInstance Isa "Win32_Process"
In this example, WMI initially enumerates all
Win32_Process
instances, and polls for changes every ten seconds. This means that it is possible to miss some events: if a process is created and destroyed in less than ten seconds, it will not raise an event.
The
Group
clause causes WMI to create only one event notification to represent a group of events. For example, this query:
Collapse | Copy Code
Select * From __InstanceModificationEvent
Within 10
Where TargetInstance Isa
"Win32_PerfFormattedData_PerfOS_Processor"
Group Within 5
Having NumberOfEvents > 3
will create one event that represents all the modification events for
Win32_PerfFormattedData_PerfOS_Processor
that occurred within 5 seconds, but only if the number of events is greater than 3.
To summarize:
- WQL event queries use classes derived from the
__Event
system class. - WQL event queries use
Within
andGroup
clauses. - WQL event queries use the
Isa
keyword to specify classes to receive events from. - WQL event queries use
TargetInstance
andPreviousInstance
to access WMI data of interest.
5. Temporary Event Consumers
A temporary event consumer is any application that requests event notifications from WMI. In most cases, it is a VBScript or code that uses the
System.Management
namespace. Here is a sample VBScript that subscribes to theWin32_Process
creation events:
Collapse | Copy Code
' VBScript source code
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "\\" & strComputer & "\root\cimv2")
Set colMonitoredProcesses = objWMIService. _
ExecNotificationQuery("select * from __InstanceCreationEvent " _
& " Within 1 Where TargetInstance isa 'Win32_Process'")
Do
Set objLatestProcess = colMonitoredProcesses.NextEvent
Wscript.Echo objLatestProcess.TargetInstance.Name
Loop
Although this code works, it has at least three disadvantages:
- The script process needs to run all the time. The above script will receive WMI events only while it is running, and while it is running, it consumes system resources. This may become a problem if you have multiple scripts running at the same time.
- The process can be easily interrupted. Scripts such as the above are typically run from the Command Prompt, so they can easily be interrupted, either by closing the Command Prompt box, or by pressing Ctrl+C.
- Even if the CScript process is interrupted, the event notification is not canceled. This may be the most serious disadvantage.
Here is a sample of the third case:
Collapse | Copy Code
' VBScript source code
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "\\" & strComputer & "\root\cimv2")
Set colEvents = objWMIService.ExecNotificationQuery _
("Select * From __InstanceCreationEvent Within 2" _
& "Where TargetInstance Isa 'Win32_Directory' " _
& "And TargetInstance.Path = '\\Scripts\\'")
Do
Set objEvent = colEvents.NextEvent()
WScript.Echo objEvent.TargetInstance.Name
Loop
Scripts like this one are typically run from the Command Prompt. But, even if you stop the script, the event notification is not canceled - you can easily observe that, because the floppy disk drive is still flashing every two seconds (I call this the 'FDD Light Show'). This is true not only of the file system monitoring scripts, but every other. The only way to cancel the event notification in this case is to stop the Winmgmt service itself, using:
Collapse | Copy Code
net stop winmgmt
The Windows Firewall service depends on Winmgmt, so it is easy to imagine a situation where this can become a problem.
6. Permanent Event Subscription
WMI permanent event subscription can remedy all these problems. It doesn't depend on a running process (save forsvchost.exe that hosts the Winmgmt service). To interrupt it, you need knowledge of WMI, so it is not easy to stop it accidentally, and you can cancel it anytime, without having to restart the Winmgmt service. In its basis, permanent event subscription is a set of static WMI classes stored in a CIM repository. Of course, you can use VBScript or the .NET Framework
System.Management
classes to create these instances and set up a permanent event subscription, but the easiest way is (at least in my opinion) to use MOF. Here is a sample MOF that you can use as a template for creating permanent event subscriptions:
Collapse | Copy Code
// 1. Change the context to Root\Subscription namespace
// All standard consumer classes are
// registered there.
#pragma namespace("\\\\.\\root\\subscription")
// 2. Create an instance of __EventFilter class
// and use it's Query property to store
// your WQL event query.
instance of __EventFilter as $EventFilter
{
Name = "Event Filter Instance Name";
EventNamespace = "Root\\Cimv2";
Query = "WQL Event query text";
QueryLanguage = "WQL";
};
// 3. Create an instance of __EventConsumer
// derived class. (ActiveScriptEventConsumer
// SMTPEventConsumer etc...)
instance of __EventConsumer derived class as $Consumer
{
Name = "Event Consumer Instance";
// Specify any other relevant properties.
};
// 4. Join the two instances by creating
// an instance of __FilterToConsumerBinding
// class.
instance of __FilterToConsumerBinding
{
Filter = $EventFilter;
Consumer = $Consumer;
};
To create a permanent WMI event subscription, you need to follow these steps:
- Change the WMI context to the
Root\Subscription
namespace. Starting with Windows XP, it is Microsoft's recommendation to store all permanent event subscriptions there. - Create an instance of the
__EventFilter
class. The__EventFilter
class is derived from the__IndicationRelated
system class, and its main purpose is to hold a WQL event query. To create an instance of__EventFilter
, use 'instance of
' keywords. First, you give the class instance a unique name using itsName
property. Second, specify itsEventNamespace
property - typically, this will be theRoot\Cimv2
namespace, as the majority of useful classes are located there. Third, set itsQuery
property to the WQL event query you want to use. - Create an instance of the
__EventConsumer
derived class. This is the instance that represents the event consumer. Although it is possible to create custom__EventConsumer
derived classes, this requires creating a COM object that reacts to the specified event, which is probably not a viable solution for most system administrators. Luckily, Microsoft provides a set of standard event consumer classes, likeActiveScriptEventConsumer
,LogFileEventConsumer
, etc. In this article, I will use only standard event consumer classes. - Associate the instances of
__EventFilter
and__EventConsumer
derived classes by creating an instance of the__FilterToConsumerBinding
class. ItsFilter
property is a reference to the previously created instance of the__EventFilter
class, and itsConsumer
property is a reference to one of the standard event consumer class instances.
In the rest of this article, I will attempt to walk you through several samples of permanent event subscription that use standard event consumer classes.
7. Using WMI Tools
A tool named WMI Event Registration is included with WMI Tools, and it is very helpful when working with permanent subscription: it allows you to explore existing filters, consumers, or timers, and also create new ones using a user-friendly interface. You can also cancel event subscriptions using this tool.
When this tool is first opened, you are offered to connect to the
Root\Cimv2
namespace, but connect toRoot\Subscription
instead - this is where you will create most of the permanent event subscriptions. Once connected, if you select 'Consumers' from the leftmost dropdown, you will see a list of all available standard event consumer classes listed in the left hand pane, as they are already registered there.
If an instance of any of the standard event consumer classes already exists, by selecting it, you can view the available
__EventFilter
instances in the right hand pane. If any of the __EventFilter
instances is joined with the selected consumer instance, it is checked, so, the green checkmark actually represents an instance of the__FilterToConsumerBinding
class.
All permanent event subscription samples presented here are created using MOF - you need a tool calledmofcomp.exe to store instance definitions contained in a MOF file into the CIM repository. Mofcomp.exe is stored in the Windows directory (typically C:\Windows\System32\Wbem\) and its basic syntax is:
Collapse | Copy Code
mofcomp FileName.mof
8. ActiveScriptEventConsumer Class
The
ActiveScriptEventConsumer
class is one of the standard event consumer classes: it allows you to run ActiveX script code whenever an event is delivered to it. To create an instance of theActiveScriptEventConsumer
class, you need to assign values to its properties:Name
: Gives a unique name to an instance ofActiveScriptEventConsumer
.ScriptingEngine
: This is the name of the scripting engine that will be used. Although the documentation states that this can be any arbitrary scripting engine, the only ones I have used are 'VBScript' and 'JScript'.ScriptText
: This is a string property that contains a VBScript or JScript code to be executed when an event is delivered to theActiveScriptEventConsumer
instance.ScriptFileName
: This property holds the full path to the VBScript or JSCript file to be executed on event arrival.ScriptText
andScriptFileName
properties are mutually exclusive.
As a test, you can create an event consumer that executes some arbitrary VBScript code whenever an instance of
Win32_Process
named 'notepad.exe' is created. To create a permanent event subscription that usesActiveScriptEventConsumer
:- Change the current WMI namespace to
Root\Subscription
:Collapse | Copy Code#pragma namespace("\\\\.\\root\\subscription")
- Create an instance of the
__EventFilter
class to monitor theWin32_Process
creation:Collapse | Copy Codeinstance of __EventFilter as $EventFilter { EventNamespace = "Root\\Cimv2"; Name = "New Process Instance Filter"; Query = "Select * From __InstanceCreationEvent Within 2" "Where TargetInstance Isa \"Win32_Process\" " "And Targetinstance.Name = \"notepad.exe\" "; QueryLanguage = "WQL"; };
In this case, you will receive a__InstanceCreationEvent
class instance, but from theRoot\Cimv2
namespace, as theWin32_Process
class is located there. - Create an instance of the
ActiveScriptEventConsumer
class:Collapse | Copy Codeinstance of ActiveScriptEventConsumer as $Consumer { Name = "TestConsumer"; ScriptingEngine = "VBScript"; ScriptText = "Set objFSO = CreateObject(\"Scripting.FileSystemObject\")\n" "Set objFile = objFSO.OpenTextFile(\"c:\\log.txt\", 8, True)\n" "objFile.WriteLine Time & \" \" & \" Notepad started\"\n" "objFile.Close\n"; };
The VBScript code that is assigned to itsScriptText
property simply logs the time of the notepad.exeprocess creation to a text file. - Bind the two previously created instances using the
__FilterToConsumerBinding
class:Collapse | Copy Codeinstance of __FilterToConsumerBinding { Consumer = $Consumer; Filter = $EventFilter; }
When you compile the above MOF using mofcomp.exe, every time Notepad is opened, the time of the notepad.exeprocess creation is logged to the c:\log.txt file. If the file doesn't already exist, it is created when the first event notification is received.
Instead of
ScriptText
, you can also use the ScriptFileName
property:
Collapse | Copy Code
instance of ActiveScriptEventConsumer as $Consumer
{
Name = "ExternalScriptConsumer";
ScriptingEngine = "VBScript";
ScriptFileName = "C:\\Consumer.vbs";
};
In that case, you also need an external script file: c:\Consumer.vbs.
When creating VBScript or JScript scripts to use with
ActiveScriptEventCosumer
, you need to be aware of some limitations:ActiveScriptEventConsumer
doesn't use the Windows Script Host (WSH), which is widely used in system administration scripts. This means that you can not use theWScript
object or any of its properties and methods (likeWScript.CreateObject
,WScript.Sleep
etc.).- The script can not generate any screen output, which means that you can not use the VBScript
MsgBox
function. - The script does not have network access.
- The script can't use any user specific data, such as environment variables or network shares.
9. Note about Strings
When setting up a permanent event subscription, it is likely that you will need to use strings, so here is a quick note:
An MOF string is a sequence of characters enclosed in double quotes. Successive strings are joined together, so this:
Collapse | Copy Code
"Select * From __InstanceCreationEvent "
"Within 30 "
becomes:
Collapse | Copy Code
"Select * From __InstanceCreationEvent Within 30 "
You can also use the following escape sequences:
Collapse | Copy Code
\b backspace
\t horizontal
\n linefeed
\f form feed
\r carriage return
\" double quote
\' single quote
\\ backslash
10. TargetEvent and TargetInstance
A script executed by an
ActiveScriptEventConsumer
instance can access an environment variable calledTargetEvent
, which holds a reference to the event class:
Collapse | Copy Code
instance of ActiveScriptEventConsumer as $Consumer
{
Name = "TargetEventConsumer";
ScriptingEngine = "VBScript";
ScriptText =
"Const ForReading = 1\n"
"Const ForWriting = 2\n"
"\n"
"Set objFso = CreateObject(\"Scripting.FileSystemobject\")\n"
"Set objStream = objFso.OpenTextFile( _\n"
" TargetEvent.TargetInstance.Name, ForReading, False)\n"
"\n"
"strContent = objStream.ReadAll()\n"
"objStream.Close\n"
"\n"
"Set objStream = objFso.OpenTextFile( _\n"
" TargetEvent.TargetInstance.Name, ForWriting, False)\n"
"\n"
"objStream.Write( _\n"
" Replace(strContent, \"127.0.0.1\", \"Localhost\"))\n"
"objStream.Close\n";
};
The event class is typically one of various
__InstanceOperationEvent
derived classes, whose TargetInstance
property, in turn, is a reference to the actual class instance of what was created. If that class is, for example,CIM_DataFile
, you need to use the following to access its Name
property:
Collapse | Copy Code
TargetEvent.TargetInstance.Name
11. SMTPEventConsumer Class
This class sends an e-mail message each time an event is delivered to it. To create an instance of the
SMTPEventConsumer
class, assign values to its properties:Name
: Gives a unique name to the instance.SMTPServer
: Name of the SMTP server through which the message will be sent.ToLine
: To line of the e-mail message.FromLine
: From line of the e-mail message.Subject
: Subject line of the mail message.Message
: The body of the e-mail message.
As an example, set up a permanent event subscription that uses the
SMTPEventConsumer
class to send an e-mail message each time a printer status changes. To use SMTPEventConsumer
in permanent event subscription:- Change the context to the
Root\Subscription
namespace:Collapse | Copy Code#pragma namespace("\\\\.\\root\\subscription")
- Create an instance of the
__EventFilter
class:Collapse | Copy Codeinstance of __EventFilter as $EventFilter { EventNamespace = "Root\\Cimv2"; Name = "SMTPEventFilter"; Query = "Select * From __InstanceModificationEvent " "Within 2 " "Where TargetInstance Isa \"Win32_Printer\" " "And (TargetInstance.PrinterStatus = 1 " "Or TargetInstance.PrinterStatus = 2) " "And Not (PreviousInstance.PrinterStatus = 1 " "Or PreviousInstance.PrinterStatus = 2)"; QueryLanguage = "WQL"; };
With the above WQL query, you subscribe to modification events of theWin32_Printer
class instances. Note the usage of the__InstanceModificationEvent.PreviousInstance
property, which contains a copy of theWin32Printer
instance before it was changed. It is useful for comparing the instance properties before and after it was modified. In this case, we are only interested in the events in which theWin32_Printer.PrinterStatus
value is changed from anything else to 1 or 2. - Create an instance of the
SMTPEventConsumer
class:Collapse | Copy Codeinstance of SMTPEventConsumer as $Consumer { Name = "Printer Error Event Consumer"; SMTPServer = "SMTPServerName"; ToLine = "Recipient@nn.com"; FromLine = "Sender@nn.com"; Subject = "Printer Error!"; Message = "An error is detected in one of the printers!\n" "Printer Name: %TargetInstance.Name%\n" "Server: %TargetInstance.__Server%\n" "Event Date: %TIME_CREATED%"; };
If you look at theSMTPEventConsumer
class MOF code, you will see that most of its properties are marked with aTemplate
qualifier. This means that you can use WMI standard string templates when setting their values. Using standard string templates, you can access the event class properties, just as you can use theTargetEvent
environment variable withActiveScriptEventConsumer
. So, for example, ifTargetInstance
isWin32_Printer
, this:
Collapse | Copy Code"Printer Name: %TargetInstance.Name%"
will be translated into something like:
Collapse | Copy Code"Printer Name: HP LaserJet III PostScript Plus v2010.118"
Also, this:
Collapse | Copy Code"Event Date: %TIME_CREATED%"
will become:
Collapse | Copy Code"Event Date: 128611400690000000"
__InstanceModificationEvent.Time_Created
is the number of 100-nanosecond intervals after January 1, 1601, so if you want to convert it to a readable format, it will probably take a bit of work. - Bind the two instances by creating an instance of the
__FilterToConsumerBinding
class:Collapse | Copy Codeinstance of __FilterToConsumerBinding { Consumer = $Consumer; Filter = $EventFilter; };
12. LogFileEventConsumer Class
The
LogFileEventConsumer
class writes customized strings to a text file each time an event is delivered to it. Significant properties:Name
: Gives a unique name to the instance.Text
: Contains the text to be written to the log file when an event arrives. You can use standard string templates to compose it.Filename
: Path to the text file where the value of theText
property is to be written.
A sample usage of
LogFileEventConsumer
could be to log changes in a Windows service's state. To useLogFileEventConsumer
with permanent event subscription:- Change the context to the
Root\Subscription
namespace:Collapse | Copy Code#pragma namespace("\\\\.\\root\\subscription")
- Create an instance of the
__EventFilter
class that monitors theWin32_Service
modification events:Collapse | Copy Codeinstance of __EventFilter as $EventFilter { EventNamespace = "Root\\Cimv2"; Name = "Service State Event Filter"; Query = "Select * From __InstanceModificationEvent " "Within 2 " "Where TargetInstance Isa \"Win32_Service\" " "And TargetInstance.State <> " "PreviousInstance.State"; QueryLanguage = "WQL"; };
- Create an instance of
LogFileEventConsumer
:Collapse | Copy Codeinstance of LogFileEventConsumer as $Consumer { Name = "Service State Log Consumer"; Filename = "c:\\scripts\\ServiceStateLog.csv"; IsUnicode = true; Text = "\"%TargetInstance.Name%\"," "\"%PreviousInstance.State%\"," "\"%TargetInstance.State%\"," "\"%TIME_CREATED%\""; };
- Bind the two instances using the
__FilterToConsumerBinding
class:Collapse | Copy Codeinstance of __FilterToConsumerBinding { Consumer = $Consumer; Filter = $EventFilter; };
When assigning value to the
LogFileEventConsumer.Text
property, use WMI standard string templates to access event-related data.13. CommandLineEventConsumer Class
The
CommandLineEventConsumer
class launches an arbitrary process when an event is delivered to it. Important properties are:Name
: Gives a unique name to the instance.ExecutablePath
: Path to the executable. This property can beNull
, but even if you assign a value to it, you still need to include the executable path at the beginning of theCommandLineTemplate
property.CommandLineTemplate
: Standard string template that specifies the executable to be launched, followed by any command line arguments. You can use standard string templates when creating it.
Here is a sample of a
CommandLineEventConsumer
MOF that monitors PNP device changes. To create a permanent event subscription that uses CommandLineEventConsumer
:- Change the WMI context to the
Root\Subscription
namespace:Collapse | Copy Code#pragma namespace("\\\\.\\root\\subscription")
- Create an instance of the
__EventFilter
class that detects theWin32_PNPEntity
instance creation:Collapse | Copy Codeinstance of __EventFilter as $EventFilter { EventNamespace = "Root\\Cimv2"; Name = "Test Command Line Event Filter"; Query = "Select * From __InstanceCreationEvent " "Within 2 " "Where TargetInstance Isa \"Win32_PNPEntity\" "; QueryLanguage = "WQL"; };
- Create an instance of the
CommandLineEventConsumer
class:Collapse | Copy Codeinstance of CommandLineEventConsumer as $Consumer { Name = "Test CommandLine Event Consumer"; RunInteractively = false; CommandLineTemplate = "cmd /c " "WMIC /Output:" "C:\\HWLogs\\PNPDeviceLog%TIME_CREATED%.html " "Path Win32_PNPEntity " "Get Caption, DeviceId, PNPDeviceId " "/Format:HTable.xsl"; };
ThisCommandLineEventConsumer
instance uses the WMI command line utility (WMIC) to create a simple HTML file that contains a list of allWin32_PNPEntity
instances each time a newWin32_PNPEntity
instance is created. - Bind the instances using
__FilterToConsumerBinding
:Collapse | Copy Codeinstance of __FilterToConsumerBinding { Consumer = $Consumer; Filter = $EventFilter; };
14. Win32_LocalTime Class
The
Win32_LocalTime
class is an exception: it is not derived from the __Event
class, but you can still use it in WQL event queries, which means that you can also use it to set up a permanent event subscription. An interesting use of the Win32_LocalTime
class can be to mimic the Windows Scheduler service. To create a permanent event subscription that subscribes to Win32_LocalTime
events:- Change the context to the
Root\Subscription
namespace:Collapse | Copy Code#pragma namespace("\\\\.\\root\\subscription")
- Create an instance of the
__EventFilter
class:Collapse | Copy Codeinstance of __EventFilter as $EventFilter { EventNamespace = "Root\\Cimv2"; Name = "Sample Timer Event Filter"; Query = "Select * From __InstanceModificationEvent " "Where TargetInstance Isa \"Win32_LocalTime\" " "And TargetInstance.Hour = 18 " "And TargetInstance.Minute = 10 " "And TargetInstance.Second = 30"; QueryLanguage = "WQL"; };
Use this filter to subscribe toWin32_LocalTime
modification events. In the query, you can use any combination ofWin32_LocalTime
properties:Day
,DayOfWeek
,Hour
,Milliseconds
,Minute
,Month
,Quarter
,Second
,WeekInMonth
, andYear
. - Create an instance of a
__EventConsumer
derived class:Collapse | Copy Codeinstance of CommandLineEventConsumer as $Consumer { Name = "Test CommandLine Event Consumer"; RunInteractively = false; CommandLineTemplate = "cmd /c " "C:\\Backup\\LocalBackup.bat"; };
In this case, it is an instance of theCommandLineEventConsumer
class, but it can be any of the standard consumer classes. - Bind
__EventFilter
andCommandLineEventConsumer
instances by creating an instance of the__FilterToConsumerBinding
class:Collapse | Copy Codeinstance of __FilterToConsumerBinding { Consumer = $Consumer; Filter = $EventFilter; };
15. Final Note
Permanent event subscription has several advantages over temporary event subscription, but it also has one disadvantage: temporary event subscription is easier to debug. If you are using the
System.Management
namespace to create an application that subscribes to WMI events, you have all Visual Studio debugging tools at your disposal. If you are using VBScript, you can test WQL event queries separately from the rest of the code, and you receive meaningful (at least sometimes) error messages from WMI. While you are testing permanent event subscription, the only source of debugging information is the WMI event subsystem log file, named Wbemess.log (it is typically located in the C:\Windows\System32\Wbem\Logs\ directory) - all errors detected both in the event filter and the event consumer instances are logged there, and the messages are not always easy to decipher. So, it is probably better to test WQL queries you want to use for permanent event subscription using System.Management
or VBScript first.
Permanent event subscription can be useful, but if you don't use it carefully, it can consume too much system resources and become inefficient. There are two ways to deal with this:
- Increase the polling interval using the
Within
clause. In the samples presented here, I used very short polling intervals, but, depending on your requirements, you can increase it at your will. - Make WQL queries more selective using the
Where
clause. For example, this query:Collapse | Copy CodeSelect * From __InstanceCreationEvent Where TargetInstance Isa "CIM_DataFile" And TargetInstance.Path = "\\Logs\\"
will be less efficient than this one:
Collapse | Copy CodeSelect * From __instanceCreationEvent Where TargetInstance Isa "CIM_DataFile" And TargetInstance.Drive = "C:" And TargetInstance.Path = "\\Logs\\" And TargetInstance.Extension = "Log"
Queries that include file system classes like
CIM_DataFile
or Win32_Directory
can be very resource consuming, in general: a query that monitors a couple of hundreds of files can slow down your system noticeably.
WQL is a version of SQL, and for SQL queries, it is often recommended not to select all fields in a table (using '*') unless you really need all of them. I haven't tested this recommendation with WQL queries, but I don't think this advice applies to WQL.
16. Useful Links
There is not much documentation concerning permanent event subscription, but you can find some in MSDN:
No comments:
Post a Comment