Use PowerShell Cmdlet to Filter Event Log for Easy Parsing

ScriptingGuy1

 

Summary: Learn how to use the Get-WinEvent Windows PowerShell cmdlet to filter the event log prior to parsing it.

Hey, Scripting Guy! Question Hey, Scripting Guy! I am confused. I have enjoyed using the Get-EventLog Windows PowerShell cmdlet. It is fast, and easy to use. However, I do not always like the way it seems to return all the records from a remote computer before I can parse it with the Where-Object cmdlet. Why does it not support a –filter parameter?

— RD

Hey, Scripting Guy! Answer Hello RD,

Microsoft Scripting Guy Ed Wilson here. After SQL Saturday in Tampa, Florida, Dr. Scripto and I decided to head to the beach so we could play a little volleyball. The following action shot captures Dr. Scripto in peak beach volleyball form.

Image of Dr. Scripto in action on beach

Speaking of things that seem to bounce around, Windows PowerShell 2.0 introduces a new cmdlet to permit filtering of an event log prior to returning it to the workstation for additional parsing. I will admit that the Get-EventLog Windows PowerShell cmdlet is extremely easy to use. In Windows PowerShell 2.0, it even has a computername parameter that provides easy access to remote event logs. There are a couple of problems with the Get-EventLog cmdlet. The first is that it must first return the log entries before they can be parsed with the Where-Object cmdlet. When working on a local computer, this might not be a huge issue, but when connecting across the network, it is better to filter the events at the remote computer before returning them to the local machine. The second issue with the Get-EventLog cmdlet is that it does not allow one to query the ETL type of logs; it is limited to the so-called “traditional event logs” such as the system, application, and security logs. The last problem with Get-EventLog is it is limited to online logs. When the event log is archived, Get-EventLog cannot access it. All of these problems are addressed with the Get-WinEvent cmdlet.

Unfortunately, Get-WinEvent is not as easy to use as the Get-EventLog cmdlet. Confusion with Get-WinEvent begins with its name—it sounds as if it would have something to do with Windows events such as a shutdown event instead of event logs. It extends to the use of hash tables for filter mechanisms, and concludes with reading the event logs backward. But do not let these quirks scare you away from using an extremely powerful cmdlet.

If I want to look at the most recent event from the application log on my computer, I use the logname parameter and specify a value for maxevents. In the example that follows, I use the number 1 to retrieve the most recent event in the application log (1 maximum event is the most recent event). I illustrate this technique with the code that appears here.

PS C:\> Get-WinEvent -LogName application -MaxEvents 1

TimeCreated                     ProviderName                       Id          Message

———–                            ————                              —          ——-

1/16/2011 11:41:11 AM    Windows Error Reporting     1001      Fault bucket , type 0…

PS C:\>

If I want to see all of the entries in a particular event log (or ETL log), I do not specify a value for maxevents. An example of doing that is shown here:

PS C:\> Get-WinEvent -LogName system

TimeCreated                         ProviderName                       Id           Message

———–                                ————                              —           ——-

1/16/2011 12:00:00 PM         EventLog                             6013      The system uptime is …

1/16/2011 11:47:53 AM         Service Control Manager     7036       The Application Exper…

1/16/2011 11:47:20 AM         Microsoft-Windows-Tim…     129         NtpClient was unable …

1/16/2011 11:43:34 AM         Service Control Manager      7036       The Multimedia Class …

<output truncated>

When I use a hash table to filter events prior to returning them, the power of the cmdlet begins to show. A hash table uses the syntax of key = value, and each key must be unique. If I use the FilterHashTable parameter, I am not able to supply a value for the LogName parameter. I discovered this by examining the parameter sets that appear in the Get-Help Get-WinEvent help topic. The two applicable parameter sets appear here:

Get-WinEvent [-LogName] <string[]> [-ComputerName <string>] [-Credential <PSCredential>] [-Filt

erXPath <string>] [-Force <switch>] [-MaxEvents <int64>] [-Oldest] [<CommonParameters>]

Get-WinEvent -FilterHashTable <Hashtable[]> [-ComputerName <string>] [-Credential <PSCredential

>] [-Force <switch>] [-MaxEvents <int64>] [-Oldest] [<CommonParameters>]

What this means is that I must include the log name in my hash table filter when I execute the command. The following table details the permitted key names and the associated data type of that associated value. Only two of the value fields accept wildcard characters. The * key represents a named event data field.

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

Suppose I am concerned with events that are coming from Capi2 with the EventID of 4107. When developing these types of filters, I always like to look at the actual event log record so that I can test my results to ensure the accuracy of my efforts. The particular event log entry I am interested in obtaining is shown in the following image.

To use the Get-WinEvent cmdlet to query the application log for event ID 4107, I create a hash table that will be supplied to the FilterHashTable parameter. The key names (from the table above) do not need to be placed in quotation marks. The value data types that are listed as String or SID will need the quotation marks around it. The ID data type is an int32 and therefore does not need quotation marks around it. The resulting command appears here, along with the associated output.

PS C:\> Get-WinEvent -FilterHashtable @{logname=’application’; id=4107}

TimeCreated                           ProviderName                       Id             Message

———–                                 ————                               —             ——-

1/17/2011 8:18:27 AM            Microsoft-Windows-CAPI2    4107        Failed extract of thi…

1/16/2011 11:32:02 AM          Microsoft-Windows-CAPI2    4107        Failed extract of thi…

1/15/2011 9:23:30 AM            Microsoft-Windows-CAPI2    4107        Failed extract of thi…

<truncated output>

If I want to limit the output to events from the current day, I add the StartTime key. The StartTime key expects a datetime object. I therefore use the Get-Date Windows PowerShell cmdlet to retrieve the current date and time. I then specify that I only want today’s date from the cmdlet. I do this by placing parentheses around the Get-Date cmdlet, and then using dotted notation to retrieve only the date property from the System.DateTime object that is returned by Get-Date. I knew which properties were available from the System.DateTime object because I used the Get-Member cmdlet to examine the properties. This is illustrated here:

PS C:\> get-date | Get-Member -MemberType property

TypeName: System.DateTime

Name                     MemberType                           Definition

—-                         ———-                                   ———-

Date                       Property                                  System.DateTime Date {get;}

Day                         Property                                  System.Int32 Day {get;}

DayOfWeek            Property                                   System.DayOfWeek DayOfWeek {get;}

DayOfYear              Property                                   System.Int32 DayOfYear {get;}

Hour                       Property                                   System.Int32 Hour {get;}

Kind                        Property                                   System.DateTimeKind Kind {get;}

Millisecond              Property                                   System.Int32 Millisecond {get;}

Minute                    Property                                   System.Int32 Minute {get;}

Month                     Property                                   System.Int32 Month {get;}

Second                   Property                                   System.Int32 Second {get;}

Ticks                       Property                                   System.Int64 Ticks {get;}

TimeOfDay              Property                                    System.TimeSpan TimeOfDay {get;}

Year                        Property                                    System.Int32 Year {get;}

Next, I tested the command to ensure it returned what I expected. This technique is shown here:

PS C:\> (get-date).date

Monday, January 17, 2011 12:00:00 AM

PS C:\>

After I had confirmed that the command worked as I expected, I incorporated it into my previous hash table filter. This is shown here, along with the associated output:

PS C:\> Get-WinEvent -FilterHashtable @{logname=’application’; id=4107; StartTime=(Get-Date).date}

TimeCreated                        ProviderName                       Id              Message

———–                              ————                               —              ——-

1/17/2011 8:18:27 AM        Microsoft-Windows-CAPI2      4107         Failed extract of thi…

PS C:\>

I then decided to try an experiment. Because the StartTIme key expects a DateTime data type, I wondered if I could give it a string and have it cast it to a System.DateTime object for me. I knew that I could do something like the following command and that I would receive a DateTime object:

PS C:\> [datetime]”1/17/11″

Monday, January 17, 2011 12:00:00 AM

PS C:\> ([datetime]”1/17/11″).GetType()

IsPublic              IsSerial      Name              BaseType

——–                ——–        —-                  ——–

True                   True           DateTime         System.ValueType

PS C:\>

However, I was not certain that Windows PowerShell was smart enough to perform the conversion for me. Therefore, I decided to test it out. As you can see, the command worked out great:

PS C:\> Get-WinEvent -FilterHashtable @{logname=’application’; id=4107; StartTime=”1/17/11″}

TimeCreated                    ProviderName                      Id          Message

———–                           ———–                              —           ——-

1/17/2011 8:18:27 AM     Microsoft-Windows-CAPI2   4107      Failed extract of thi…

PS C:\>

When I had the previous command working, I decided to see if I could use the same technique to retrieve a range of records. To do this, I used both the StartTime key and the EndTime key. The command and associated output appear here:

PS C:\> Get-WinEvent -FilterHashtable @{logname=’application’;id=4107;StartTime=”1/15/11″;EndTime=”1

/17/11″}

TimeCreated                    ProviderName                        Id          Message

———–                           ————                               —          ——-

1/16/2011 11:32:02 AM   Microsoft-Windows-CAPI2     4107     Failed extract of thi…

1/15/2011 9:23:30 AM     Microsoft-Windows-CAPI2     4107     Failed extract of thi…

1/15/2011 8:28:07 AM     Microsoft-Windows-CAPI2     4107     Failed extract of thi…

1/15/2011 8:27:32 AM     Microsoft-Windows-CAPI2     4107     Failed extract of thi…

PS C:\>

RD, that is all there is to using the Get-WinEvent cmdlet. Neglected Cmdlet Week will continue tomorrow when I will talk about using the Get-WinEvent cmdlet to query offline event logs.

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

 

 

0 comments

Discussion is closed.

Feedback usabilla icon