Exploring WMI with PowerShell V2

I was messing around with my son’s computer today trying to figure out why one of his programs wouldn’t work.  I was going to use ProcMon to monitor the processes but wasn’t sure what the processes where.  So first I had to figure out what processes were getting started when I ran his program.  I guessed that there was a WMI event for this but as always with WMI – WHAT IS THE NAME OF THE EVENT?

In the past, this is where things stopped.  WMI was awesome but god help you if you didn’t know exactly what you wanted.  We made this a ton easier in PowerShell V2 so I decided to give it a try.  First thing I did was to LIST all the WMIOBJECTS that had the term PROCESS in the name.  I did that with this:

PS> Get-WMIObject -NameSpace root -Recurse -List  *Process*             

 

 

That gave me too many results to wade through so I needed to filter it down some more.  Every WMI object as a property called __Derivation which is a list of strings showing the class hierarchy for that object.  The point of that is that all WMI Event classes will contain the string “__Event” in this property.  So then I did this:

PS> Get-WMIObject -NameSpace root -Recurse -List  *Process* |Where {$_.Derivation -contains "__Event"}            

   NameSpace: ROOT\CIMV2

Name                                Methods              Properties                                          
—-                                ——-              ———-                                          
Win32_ProcessTrace                  {}                   {ParentProcessID, ProcessID, ProcessName, SECURITY…

Win32_ProcessStartTrace             {}                   {ParentProcessID, ProcessID, ProcessName, SECURITY…

Win32_ProcessStopTrace              {}                   {ExitStatus, ParentProcessID, ProcessID, ProcessNa…

   NameSpace: ROOT\WMI

Name                                Methods              Properties                                          
—-                                ——-              ———-                                          
ProcessorCStateEvent                {}                   {Active, InstanceName, SECURITY_DESCRIPTOR, TIME_C…

ProcessorPerfStateEvent             {}                   {Active, HighestState, InstanceName, SECURITY_DESC…

ProcessorThrottleStateEvent         {}                   {Active, HighestState, InstanceName, SECURITY_DESC…

PortCls_IrpProcessing               {}                   {SECURITY_DESCRIPTOR, TIME_CREATED}                 

 

 

 

 

That made it pretty easy to figure out that I wanted to look at Win32_ProcessStartTrace.  Just to make sure I got the class using the –Amended parameter.  This adds documentation to the returned object in the QUALIFIERS property.  This information is normally not provided because it can be expensive to retrieve so WMI only provides it if/when you ask for it.

$Class = Get-WmiObject -List Win32_ProcessStartTrace -Amended            
$Class.Qualifiers |ft Name,Value -auto            

This returned:

Name                                                                         Value

—-                                                                         —–

abstract                                                                      True

Description The ProcessStartTrace event class indicates a new process has started.

Locale                                                                        1033

 

 

 

With that I was ready to go.  I used the new Register-WMIEvent class to solve the problem.  This takes a WMI query and can optionally take an ACTION.  I decided to format the event and write the results to the host whenever a process was started.  This looks a little chewy but is actually pretty straight forward.

$Query = 'SELECT * FROM Win32_ProcessStartTrace'            
$action = {            
    $e = $Event.SourceEventArgs.NewEvent            
    $fmt = 'ProcessStarted: (ID={0,5}, Parent={1,5}, Time={2,20}, Name="{3}")'            
    $msg = $fmt -f $e.ProcessId, $e.ParentProcessId, $event.TimeGenerated, $e.ProcessName            
    Write-host -ForegroundColor Red $msg            
}            
Register-WmiEvent -Query $Query -SourceIdentifier ProcessStart -Action $Action             

 

This then worked a treat.  Every time a process was created, I got output like this on my host:

ProcessStarted: (ID= 8740, Parent= 1140, Time=8/30/2009 3:41:54 PM, Name="Magnify.exe")

ProcessStarted: (ID=13748, Parent= 1068, Time=8/30/2009 3:41:54 PM, Name="Utilman.exe")

ProcessStarted: (ID=11964, Parent=13748, Time=8/30/2009 3:41:54 PM, Name="Magnify.exe")

ProcessStarted: (ID= 9872, Parent= 1068, Time=8/30/2009 3:41:58 PM, Name="Utilman.exe")


This worked a treat.  When I was done, I just unregistered from the event.

Unregister-Event -SourceIdentifier ProcessStart            

 

 

 

I love to tell the story from years ago about a customer that told me they had a love/hate relationship with WMI. 
When I asked them why they loved  it, they said, “Everything you could ever want to know is available in WMI”.

When I asked them why they hated it, they said, “We can’t FIND IT!”

 

I strongly encourage you to spend some time learning and using the new WMI cmdlets we put into PowerShell V2, they will pay you back over and over again.

 

Enjoy!

Jeffrey Snover [MSFT]

Distinguished Engineer

Visit the Windows PowerShell Team blog at:    http://blogs.msdn.com/PowerShell

Visit the Windows PowerShell ScriptCenter at:  http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx