WMI Event Monitoring

The information in this article was written against the second Community Technology Preview (CTP2) of Windows PowerShell 2.0. This information is subject to change in future releases of Windows PowerShell 2.0.

Monitoring WMI Events with the Register-WMIEvent Cmdlet

Event monitoring and event subscriptions, particularly WMI event subscriptions, have become a standard tool for system administration scripters. Need to be notified any time free disk space falls below a specified amount? WMI events can help you with that. Need to be alerted any time a particular process gets started or stopped? WMI events can help you with that. Want to know if a new file has been added to a folder or if a new USB device has been plugged into a computer? That’s right: WMI events can help you with all that, too. And with much, much more.

Using the initial release of Windows PowerShell it’s possible to subscribe to and monitor WMI events. Unfortunately, though, this can be done only by going through the .NET Framework and relying on a trio of System.Management classes. The resulting script works, but it isn’t pretty, and it’s hardly in the “improving the world one-line at a time” spirit of Windows PowerShell:

$a = 0

$timespan = New-Object System.TimeSpan(0, 0, 1)
$scope = New-Object System.Management.ManagementScope("\\.\root\cimV2")
$query = New-Object System.Management.WQLEventQuery `
    ("__InstanceDeletionEvent",$timespan, "TargetInstance ISA 'Win32_Process'" )
$watcher = New-Object System.Management.ManagementEventWatcher($scope,$query)

do
    {
        $b = $watcher.WaitForNextEvent()
        $b.TargetInstance.Name
    }
while ($a -ne 1)

So has all this changed with the Windows PowerShell 2.0 of Windows PowerShell? You better believe it has.

The latest iteration of Windows PowerShell includes a full-blown eventing infrastructure. In all honesty, the Scripting Guys haven’t had much time to explore this infrastructure and figure out what makes it tick. However, we have had a chance to play around a bit with WMI events; needless to say, we liked what we saw.

For example, suppose you’d like to keep tabs on new processes that are created on a computer. The following one-line PowerShell command lets you do just that:

Register-WMIEvent -query "Select * From __InstanceCreationEvent within 3 Where TargetInstance ISA 'Win32_Process'" `
-messageData "A new process has started." -sourceIdentifier "New Process"

As you can see all we’re doing is calling a single cmdlet, the new Register-WMIEvent cmdlet. In addition, we’re passing Register-WMIEvent three parameters:

  • -query. This is a standard WMI event query. (If you aren’t familiar with writing these kinds of queries you might take a look at the Scripting Guys Webcast An Ounce of Prevention: An Introduction to WMI Events.) In this case we’re asking the script (or command) to check every 3 seconds (Within 3) to see if any new instances of the __InstanceCreationEvent class have been created; as the name implies, instances of this class are created any time something new (or at least something new that WMI is aware of) takes place on a computer. Of course, lots of new things take place on a computer; we’re interested only in new processes starting up. Therefore, we included a Where clause that limits our event subscription to new processes (that is, items that are members of the Win32_Process class).

  • -messageData. Any time a subscribed-to event occurs, PowerShell records information about that event. (Note that this information is retained only during the current PowerShell session. The moment you terminate the session this data disappears.) The –messageData parameter simply specifies the message we want written to the PSEvent queue. In this case it’s a simple enough message: A new process has started.

  • -sourceIdentifier. The Source Identifier is nothing more than the name we want to give our event subscription. Again, we’ve gone all out in coming up with a name for our command that watches for the creation of new processes: New Process.

Note. Yes, hard as it is to believe they do pay us to come up with names like that.

So what happens when you run this Register-WMIEvent command? Well, nothing, or so it would seem; after a second or two you’re simply returned to the PowerShell command prompt. Ah, but try this: start a new process (it doesn’t matter what; just start up Notepad or Calculator or any other application) and then run this command:

Get-PSEvent

In return, you should see something similar to this:

EventIdentifier  : 1
Sender           : System.Management.ManagementEventWatcher
SourceEventArgs  : System.Management.EventArrivedEventArgs
SourceArgs       : {System.Management.ManagementEventWatcher, System.Management. EventArrivedEventArgs}
SourceIdentifier : New Process
TimeGenerated    : 4/25/2008 9:15:11 AM
MessageData      : A new process has started.

Start another process and run the Get-PSEvent cmdlet a second time; now you should see both events listed in the queue:

EventIdentifier  : 1
Sender           : System.Management.ManagementEventWatcher
SourceEventArgs  : System.Management.EventArrivedEventArgs
SourceArgs       : {System.Management.ManagementEventWatcher, System.Management. EventArrivedEventArgs}
SourceIdentifier : New Process
TimeGenerated    : 4/25/2008 9:15:11 AM
MessageData      : A new process has started.

EventIdentifier  : 2
Sender           : System.Management.ManagementEventWatcher
SourceEventArgs  : System.Management.EventArrivedEventArgs
SourceArgs       : {System.Management.ManagementEventWatcher, System.Management. EventArrivedEventArgs}
SourceIdentifier : New Process
TimeGenerated    : 4/25/2008 9:17:14 AM
MessageData      : A new process has started.

Etc. etc.

If you have a whole bunch of events in the PSEvent queue you can use Get-PSEvent’s –sourceIdentifier parameter to retrieve just the events pertaining to a specific event subscription:

Get-PSEvent -sourceIdentifier "New Process"

Or, use Where-Object to filter data using some other criteria:

Get-PSEvent | Where-Object {$_.MessageData -like "*process*"}

Of course, you might not want to repeatedly check the PSEvent queue just to see if any events of interest have occurred; you might want more immediate notification. Here’s a simple way to get Windows PowerShell to write a message to the console window any time a new process has been created:

Register-WMIEvent -query "Select * From __InstanceCreationEvent within 3 Where TargetInstance ISA 'Win32_Process'" `
-sourceIdentifier "NewProcess" -action {Write-Host "A new process has started."}

This time around we’ve left off the –messageData parameter and substituted the –action parameter in its place. The –action parameter lets us specify a scriptblock to be executed any time the subscribed-to event occurs; in this case, any time a new process is created we’re going to use the Write-Host cmdlet to write the message “A new process has started.” to the console window.

Note. Don’t worry: this message will not be written to the screen if you’re in the middle of another command. You’ll see the message only if the console window is currently idle.

Incidentally, if you specify an action to take place any time an event occurs then the event will not be recorded in the event queue; instead, the specified action will take place. Just something to keep in mind.

And what if you no longer want, or need, a particular event subscription? No problem; just use the Unregister-PSEvent cmdlet to cancel your subscription:

Unregister-PSEvent "New Process"

Which brings up a good point: what if you can’t remember the names of your event subscriptions, assuming you even have any event subscriptions? That’s what this command is for:

Get-PSEventSubscriber

In turn, you should get back information similar to this:

SubscriptionId   : 1
SourceObject     : System.Management.ManagementEventWatcher
EventName        : EventArrived
SourceIdentifier : New Process
Action           :
SupportEvent     : False

Cool, huh?

Admittedly this is a somewhat cursory overview of the new eventing infrastructure built into PowerShell, and it’s an overview that touches only on WMI events; there are other kinds of events that you can monitor – and raise – as well. But this article is designed simply to whet your appetite for PowerShell eventing; we’ll explore some of these other possibilities later on.