PowerShell Answers

Adventures in PowerShell

About the author

Author Name is someone.
E-mail me Send mail

Recent posts

Recent comments

Don't show

Authors

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2008

Launching PowerShell Scripts in Response to WMI Events

This turns out to very straightforward, the key is to use the CommandLineEventConsumer class. It allows you to launch any program in response to a WMI event. In order to use it you only need to set two properties (although there are many more to explore)

  1. Name - a unique name for your class instance
  2. CommandLineTemplate - the command you want to run

As we want to launch a PowerShell script the command line would need to be something like

powershell.exe -command C:\temp\myscript.ps1

This would run the script myscript.ps1 and pass it any parameters that are added to the command line. Within the script you can access the parameters via the $args array.

A Working Example

Lets say that we wanted to stop people running Solitaire on their PCs - it's mean but hey, we're admins! The PowerShell cmdlet stop-process will kill a process if we supply the process ID so we'll pass that out from WMI to the script and pick it up via $args.

stop-process $args[0]

As before you need to create a filter and a consumer and join them together. So this code creates a filter that looks for instances of Solitaire starting up

$EFClass = [wmiclass]"\root\subscription:__EventFilter"
$ef = $EFClass.CreateInstance()
$ef.Name = "NewProcessFilter"
$ef.Querylanguage = "WQL"
$ef.Query = "select * from __InstanceCreationEvent within 5 where targetinstance isa 'Win32_Process' and targetinstance.name = 'Solitaire.exe'"
$ef.EventNamespace = "root\cimv2"
$ef.put()

Next we create a consumer, using the CommandLineEventConsumer class. %TargetInstance.Handle% picks up the process ID from the win32_process object that triggered the event and adds it onto the end of the PowerShell command line.

$CLECClass = [wmiclass]"\root\subscription:CommandLineEventConsumer"
$clec = $CLECClass.CreateInstance()
$clec.Name = "RunPowerShell"
$clec.CommandLineTemplate = "powershell.exe -command C:\temp\myscript.ps1 %TargetInstance.Handle%"
$clec.put()

and finally join them together with an instance of the __FilterToConsumerBinding class

$FCBClass = [wmiclass]"\root\subscription:__FilterToConsumerBinding"
$fcb = $FCBClass.createinstance()
$fcb.Consumer = $clec.__Path
$fcb.Filter = $ef.__Path
$fcb.put()

Now every time you start Solitaire the PowerShell script myscript.ps1 will run and Solitaire will be terminated :-)

Note

You might get the same errors that I noted in an earlier post when you invoke the put method. This is a known bug in PowerShell 1.0 and will be fixed in v2.0. The workaround for now is to keep invoking put until it works.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: events | PowerShell | WMI
Posted by tb on Monday, January 07, 2008 3:41 AM
Permalink | Comments (0) | Post RSSRSS comment feed

A first look at WMI events

Event notification is built into WMI and if you open up CIM Studio (one of the tools in the WMI Toolkit) and navigate to '__SystemClass\__IndicationRelated' you will find all of the classes related to event handling. There are two types of event that you can use -

Intrinsic Events

These are generated by WMI in response to changes in the CIM repository and further breakdown into events related to namespaces, classes, instances and timers. You can see these by navigating to '__SystemClass\__IndicationRelated\__Event' where you will find

  • __NamespaceOperationEvent and its children
  • __ClassOperationEvent and its children
  • __InstanceOperationEvent and its children
  • __TimerEvent

If you poke around under these classes you'll see that there are various events that fire when something interesting happens in the CIM repository. The timer event is different as this lets you set up an event that fires on a regular basis or at a scheduled time.

Extrinsic Events

Providers

Extrinsic events are fired into WMI by providers. Providers allow third parties to plug in to WMI and make their management information available. You'll probably have a whole bunch of these registered on your systems. They are often created as DLLs with an accompanying MOF file. You can find some provider related files in '%windir%\system32\wbem'. Look for any files with 'prov' in their names. Alternatively running these commands will give you an exhaustive list of the providers installed in the 'root\CIMv2' namespace from WMIs perspective.


get-wmiobject -class "__InstanceProviderRegistration" | select-object -property Provider
get-wmiobject -class "__ClassProviderRegistration" | select-object -property Provider
get-wmiobject -class "__EventProviderRegistration" | select-object -property Provider
get-wmiobject -class "__MethodProviderRegistration" | select-object -property Provider
get-wmiobject -class "__PropertyProviderRegistration" | select-object -property Provider
get-wmiobject -class "__EventConsumerProviderRegistration" | select-object -property Provider
and Events

In order to list all of the extrinsic events available on a system you need to recurse through all of the namespaces in WMI listing out all of the '__ExtrinsicEvent' classes that you find. This next piece of code does exactly that. It uses a couple of functions -

Get-ExtrinsicEvents
runs a query against all of the classes in a particular namespace and lists only the '__ExtrinsicEvent' classes. Specifying 'meta-class' causes Get-WmiObject to retrieve class rather than instance objects from the repository.
ExamineNamespace
recurses through a namespace hierarchy calling Get-ExtrinsicEvents

function Get-ExtrinsicEvents( [string]$ns )
{
Get-WmiObject -class meta_class
-namespace $ns
-filter "__this isa '__ExtrinsicEvent'" |
select-object Name | Format-Table -HideTableHeaders
}

function ExamineNamespace( [string]$ns )
{
write-host "==================" $ns
Get-ExtrinsicEvents $ns

foreach ($n in (Get-WmiObject -Class "__NAMESPACE" -namespace $ns))
{
ExamineNamespace ($n.__NAMESPACE + "\" + $n.Name)
}
}

ExamineNamespace "ROOT"

In my next post I'll look at how you register you interest in specific WMI events and how you can launch PowerShell scripts in response to WMI events.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: events | PowerShell | WMI
Posted by tb on Monday, January 07, 2008 2:32 AM
Permalink | Comments (0) | Post RSSRSS comment feed

WMI events and PowerShell

I see on the Powershell Team blog Kapil Mathur is writing about his experience with WMI and Powershell. I find when I'm out and about teaching and consulting that very few people have explored WMI and even fewer make use of it.

I think WMI is one of the most useful technologies to be able to script against and over the next week or two I'm going to look at the WMI event model and how to use WMI to invoke Powershell scripts in response to WMI events. I'll also look at how you can use Powershell to audit all of the events handlers that have been registered on your systems.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: PowerShell | WMI
Posted by tb on Monday, January 07, 2008 2:31 AM
Permalink | Comments (0) | Post RSSRSS comment feed