PowerShell WMI events

In my previous post ( http://richardsiddaway.spaces.live.com/blog/cns!43CFA46A74CF3E96!2598.entry  or http://richardsiddaway.spaces.live.com/blog/cns!43CFA46A74CF3E96!2598.entry ) I started to look at WMI events in PowerShell v2.  The win32_process class was used but all that showed us was that a process had started. We need a bit more information.  A bit of digging brought up the Win32_ProcessStartTrace class that seems to do what we want. 

Register-WMIEvent allows us to specify the class we want to use rather than a query – however if we try that we don’t get anything returned  - oops.

Looking through the help for Register-WMIEvent shows that we have the possibility of performing an action when the event occurs.  The action scriptblock can use a number of variables including $Event, $EventSubscriber, $Sender, $SourceEventArgs, and $SourceArgs automatic variables.  Wanting to understand these variables I tried dumping it though get-member. 

PS> Register-WmiEvent -Query "Select * FROM Win32_ProcessStartTrace" -Action {$Event | gm}

Id              Name            State      HasMoreData     Location             Command
--              ----            -----      -----------     --------             -------
2               c1016218-f80... NotStarted False                                $Event | gm

The subscription runs as a PowerShell job. Using the opening of Notepad to trigger the event we can see that data is returned.

PS> Get-Job

Id              Name            State      HasMoreData     Location             Command
--              ----            -----      -----------     --------             -------
2               c1016218-f80... Running    True                                 $Event | gm

And see that we have a few properties to play with.  ComputerName may come in useful if we are dealing with remote machines.

PS> Receive-Job -Id 2

   TypeName: System.Management.Automation.PSEventArgs

Name             MemberType Definition
----             ---------- ----------
Equals           Method     bool Equals(System.Object obj)
GetHashCode      Method     int GetHashCode()
GetType          Method     type GetType()
ToString         Method     string ToString()
ComputerName     Property   System.String ComputerName {get;}
EventIdentifier  Property   System.Int32 EventIdentifier {get;}
MessageData      Property   System.Management.Automation.PSObject MessageData {get;}
RunspaceId       Property   System.Guid RunspaceId {get;}
Sender           Property   System.Object Sender {get;}
SourceArgs       Property   System.Object[] SourceArgs {get;}
SourceEventArgs  Property   System.EventArgs SourceEventArgs {get;}
SourceIdentifier Property   System.String SourceIdentifier {get;}
TimeGenerated    Property   System.DateTime TimeGenerated {get;}

The properties look similar to those we saw in the last post.  Lets dig into SourceEventArgs

PS> Register-WmiEvent -Query "Select * FROM Win32_ProcessStartTrace" -Action {$Event.SourceEventArgs | gm}

Id              Name            State      HasMoreData     Location             Command
--              ----            -----      -----------     --------             -------
3               8d4246a5-5f8... NotStarted False                                $Event.SourceEventArgs...

PS> Get-Job

Id              Name            State      HasMoreData     Location             Command
--              ----            -----      -----------     --------             -------
3               8d4246a5-5f8... Running    True                                 $Event.SourceEventArgs...

PS> Receive-Job -Id 3

   TypeName: System.Management.EventArrivedEventArgs

Name        MemberType Definition
----        ---------- ----------
Equals      Method     bool Equals(System.Object obj)
GetHashCode Method     int GetHashCode()
GetType     Method     type GetType()
ToString    Method     string ToString()
Context     Property   System.Object Context {get;}
NewEvent    Property   System.Management.ManagementBaseObject NewEvent {get;}

 

Only thing here that look interesting is NewEvent

PS> Register-WmiEvent -Query "Select * FROM Win32_ProcessStartTrace" -Action {$Event.SourceEventArgs.NewEvent | gm}

Id              Name            State      HasMoreData     Location             Command
--              ----            -----      -----------     --------             -------
4               0857a744-1d3... NotStarted False                                $Event.SourceEventArgs...

PS> Receive-Job -Id 4

   TypeName: System.Management.ManagementBaseObject#\Win32_ProcessStartTrace

Name                MemberType Definition
----                ---------- ----------
ParentProcessID     Property   System.UInt32 ParentProcessID {get;set;}
ProcessID           Property   System.UInt32 ProcessID {get;set;}
ProcessName         Property   System.String ProcessName {get;set;}
SECURITY_DESCRIPTOR Property   System.Byte[] SECURITY_DESCRIPTOR {get;set;}
SessionID           Property   System.UInt32 SessionID {get;set;}
Sid                 Property   System.Byte[] Sid {get;set;}
TIME_CREATED        Property   System.UInt64 TIME_CREATED {get;set;}
__CLASS             Property   System.String __CLASS {get;set;}
__DERIVATION        Property   System.String[] __DERIVATION {get;set;}
__DYNASTY           Property   System.String __DYNASTY {get;set;}
__GENUS             Property   System.Int32 __GENUS {get;set;}
__NAMESPACE         Property   System.String __NAMESPACE {get;set;}
__PATH              Property   System.String __PATH {get;set;}
__PROPERTY_COUNT    Property   System.Int32 __PROPERTY_COUNT {get;set;}
__RELPATH           Property   System.String __RELPATH {get;set;}
__SERVER            Property   System.String __SERVER {get;set;}
__SUPERCLASS        Property   System.String __SUPERCLASS {get;set;}

 

Now we have got to the information we need.  So how can we use this.  Up to now we have just allowed the job to run and then picked the data from the job.  One option is to write the data to the prompt as shown in this example  http://blogs.msdn.com/powershell/archive/2009/08/30/exploring-wmi-with-powershell-v2.aspx.  A lot of this digging was because I didn’t understand how this was put together.  PowerShell really is the best way to discover how to use PowerShell!!

This gets us to this script which is modified from the PowerShell Team blog

 

001
002
003
004
005
006
007
008
009
010
011
## query
$q = "Select * from Win32_ProcessStartTrace"
## action script block
$a = {
    $eSEANE = $Event.SourceEventArgs.NewEvent
    $str = 'Computer {0},ID {1}, Name "{2}", Time {3}, Source {4}' 
    $data = $str -f $Event.Sender.Scope.Path.Server, $eSEANE.ProcessId, `
      $eSEANE.ProcessName, $Event.TimeGenerated, $Event.SourceIdentifier
    Write-Host $data
}
Register-WmiEvent -Query $q -SourceIdentifier "Process Start" -Action $a

 

Turns out the ComputerName parameter doesn’t work but a comment on the blog shows how Jeffrey Hicks solved the problem.

What we get now is a listing at our PowerShell prompt  when a new process starts. We can keep working and the data comes through when the prompt is idle.

Next we will look at closing a process and recording the data in a log

Technorati Tags: ,,
Published Sat, Nov 7 2009 21:29 by RichardSiddaway

Comments

# Watching the file system

We saw how to watch for WMI events msmvps.com/.../powershell

Monday, November 09, 2009 2:15 AM by Richard Siddaway's Blog

Leave a Comment

(required) 
(required) 
(optional)
(required)