Use FilterHashTable to Filter Event Log with PowerShell

Use FilterHashTable to Filter Event Log with PowerShell

  • Comments 2
  • Likes

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using a filter hash table to filter the event log with Windows PowerShell.

Microsoft Scripting Guy, Ed Wilson, is here. The weather here in Charlotte, North Carolina has turned hot and humid. As a result, the Scripting Wife decided to migrate north for a while. Actually, she is attending a conference in Cincinnati, Ohio. This has given me a bit of extra time to play around with Windows PowerShell and to work on my laptop.

The most powerful way to filter event and diagnostic logs by using Windows PowerShell is to use the Get-WinEvent cmdlet. Introduced in Windows PowerShell 2.0, the Get-WinEvent cmdlet is not new technology. But most people do not use the Get-WinEvent cmdlet because it seems to be more difficult to use. The Get-EventLog cmdlet that I used yesterday is easy-to-use, and for a lot of things, it works just fine.

But Get-WinEvent has several ways to filter the left side of the pipeline. When working with large logs, grabbing everything and sending it down the pipeline to a Where-Object cmdlet is not the most efficient thing to do. It fact, it can be downright slow. An example of this sort of slow command is shown here:

Get-EventLog -LogName application | where source -match 'defrag'

Get-WinEvent the easy way

The easiest way to perform powerful queries by using the Get-WinEvent cmdlet is to use the FilterHashTable parameter. As the parameter name might imply, it accepts a hash table as a filter. A hash table is made up of key/value pairs. Therefore, the trick is to know the permissible key names and what an acceptable value for that key might look like. Here is a table that shows the key names, the data type it accepts, and whether it will accept a wildcard character for that data value.

Key name

Value data type

Accepts wildcard characters?

 LogName

 <String[]>

 Yes

 ProviderName

 <String[]>

 Yes

 Path

 <String[]>

 No

 Keywords

 <Long[]>

 No

 ID

 <Int32[]>

 No

 Level

 <Int32[]>

 No

 StartTime

 <DateTime>

 No

 EndTime

 <DataTime>

 No

 UserID

 <SID>

 No

 Data

 <String[]>

 No

 *

 <String[]>

 No

One thing I like to do when I build a query using Get-Winevent is to take it a step at a time. I begin with the LogName. As shown here, this first query is the same as typing Get-EventLog –LogName Application:

Get-WinEvent -FilterHashtable @{logname='application'}

The next thing I want to specify (I do not have to use the order that is presented in my previous table) is the ProviderName. This example returns entries generated by the .NET RunTime source, in the Application log:

Get-WinEvent -FilterHashtable @{logname='application'; providername='.Net Runtime' }

The ProviderName is the name that appears in the Source field in the Event Viewer. This is shown here:

Image of menu

I use the –path parameter when I am working with archived event logs. I wrote a good blog post about that: Use PowerShell to Parse Saved Event Logs for Errors.

In my hash table, the next key is the Keywords key name. This sounds like you would be able to use keywords to filter out event log events. But the Data Type field holds an array made up of the [long] value type, and a [long] value type holds a really large number. Here is the maximum value:

PS C:\> [long]::MaxValue

9223372036854775807

Therefore, what Windows PowerShell wants is a number, not a keyword (such as Security). I can use the GUI to see what permissible keywords are feasible. This is shown here:

Image of menu

The problem is that when I attempt to use one of these keywords, I get an error message. This is because these are string values, and not long numbers. So when I have a potential list of keywords that have associated numeric values, I think enumeration. In fact, these are the StandardEventKeywords enumeration, as shown here:

PS C:\> [System.Diagnostics.Eventing.Reader.StandardEventKeywords] | gm -s -MemberType property

   TypeName: System.Diagnostics.Eventing.Reader.StandardEventKeywords

Name             MemberType Definition

----             ---------- ----------

AuditFailure     Property   static System.Diagnostics.Eventing.Reader.StandardEventKey...

AuditSuccess     Property   static System.Diagnostics.Eventing.Reader.StandardEventKey...

CorrelationHint  Property   static System.Diagnostics.Eventing.Reader.StandardEventKey...

CorrelationHint2 Property   static System.Diagnostics.Eventing.Reader.StandardEventKey...

EventLogClassic  Property   static System.Diagnostics.Eventing.Reader.StandardEventKey...

None             Property   static System.Diagnostics.Eventing.Reader.StandardEventKey...

ResponseTime     Property   static System.Diagnostics.Eventing.Reader.StandardEventKey...

Sqm              Property   static System.Diagnostics.Eventing.Reader.StandardEventKey...

WdiContext       Property   static System.Diagnostics.Eventing.Reader.StandardEventKey...

WdiDiagnostic    Property   static System.Diagnostics.Eventing.Reader.StandardEventKey...

This enumeration is documented on MSDN (StandardEventKeywords Enumeration), but it does not display the enumeration numeric values. For a function that will do this, take a look at my series of blog posts about enumerations, and in particular, read Enumerations and Values. In fact, my Get-EnumAndValues function is so helpful that it is a function I have in my Windows PowerShell profile. When I use the Get-EnumAndValues function, I retrieve the following results:

Name                           Value                                          

----                           -----                                          

AuditFailure                   4503599627370496                               

AuditSuccess                   9007199254740992                               

CorrelationHint2               18014398509481984                              

EventLogClassic                36028797018963968                              

Sqm                            2251799813685248                               

WdiDiagnostic                  1125899906842624                               

WdiContext                     562949953421312                                

ResponseTime                   281474976710656                                

None                           0                                            

Now the query looks like the following (this is a one-line command that is wrapped for readability):

Get-WinEvent -FilterHashtable @{logname='application'; providername='.Net Runtime'; keywords=36028797018963968}

Because this is an enumeration, I can also use the actual enumeration static property, but I have to convert it to the value by calling the value__ property, and not to the returned string. To do this, I might use the following script:

$c = [System.Diagnostics.Eventing.Reader.StandardEventKeywords]::EventLogClassic

Get-WinEvent -FilterHashtable @{logname='application'; providername='.Net Runtime'; keywords=$c.value__}

As I have been running my commands, I have been getting increasingly shorter outputs of event log records. From that list, I select the particular event ID, which in FilterHashTable becomes the keyword ID. This command is shown here:

Get-WinEvent -FilterHashtable @{logname='application'; providername='.Net Runtime'

; keywords=36028797018963968; ID=1023}

I now decide that I want to filter out only the errors. This is the Level property. But when I use the command shown here, it generates an error message.

PS C:\> Get-WinEvent -FilterHashtable @{logname='application'; providername='.Net Runtime'

; keywords=36028797018963968; ID=1023; level='error'}

I go back to my has table, and sure enough, I see that Level needs an Int32, or an array of Int32s. So it wants another number, and not the standard error, warning, information that I am used to using. This smells like another enumeration.

I look back at the MSDN page I had open for the previous enumeration, and I discover that there is a StandardEventLevel Enumeration. It works the same way as the previous enumeration. I can create the class, use the Get-Member with –Static, and use my enumeration value function. Here are the enumeration member names and their associated values:

Name                           Value                                           

----                           -----                                          

Verbose                        5                                              

Informational                  4                                              

Warning                        3                                              

Error                          2                                              

Critical                       1                                              

LogAlways                      0        

Armed with this information, I know that an error is level 2. So here is the modified command:

Get-WinEvent -FilterHashtable @{logname='application'; providername='.Net Runtime'; keywords=36028797018963968; ID=1023; level=2}

That is all there is to using Get-WinEvent to look at event log keywords. Event Log Week will continue tomorrow when I will talk about more way cool stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment