Executive Summary:

Use Windows PowerShell to examine Windows Security event logs. With PowerShell you can retrieve Security events by type, narrow in on a list of properties, sort events, and retrieve and organize details about an event.

Every administrator knows that protecting security is a vital, but time-consuming, job. Windows collects a mountain of data in its Windows Security event logs; the task of sorting through all that data is something you’d want to automate. You can use the Windows PowerShell console to access the Windows Security event logs and then monitor the event logs to guard against network and asset intrusion. I’ll show you how to retrieve specific events and how to display information about those events. If you’re not familiar with using PowerShell to access the Security event log, take a look at my Windows VIP article, “PowerShell Makes Security Log Access Easy,” April 2008 (InstantDoc ID 98667). To run scripts against the Security event log, you must be logged on as administrator. (For more PowerShell resources, see the Learning Path.)

Retrieving Specific Events

Before retrieving events from the Security log, you should decide which events you want to view. You can easily retrieve all the Security events by using the command

  get-eventlog security

However, this command isn't usually very useful because the event log typically contains so many events. It's best to let PowerShell help you limit the number and types of events you retrieve. To limit the retrieved events to the most recent 20, for example, you can use the command

  get-eventlog security -newest 20

PowerShell also lets you retrieve specific types of events according to criteria you define. For example, you might decide to retrieve only those events whose EntryType value is FailureAudit. By taking this approach, you can view security events that have failed without having to sort through other types of events. To retrieve those events, you add a Where-Object cmdlet to your statement (referencing it by the where built-in alias), as in the following example:

  get-eventlog security -newest 100 |                                where \{$_.entrytype -eq `                                  "FailureAudit"\}

As you can see, the code pipes the data returned by the Get-EventLog command to a Where-Object cmdlet (referenced in the example by the where built-in alias), which specifies that the value in the EntryType property must equal FailureAudit. When you run the code, only failed events are returned to the PowerShell console. Figure 1 shows the type of information that the above statement returns. All the figures in this article show the results as they appear in Windows XP; the results might be slightly different in another Windows OS. For example, the event message is wordier in Windows Vista than in Windows XP; however, the information is essentially the same.

To retrieve a specific type of event, you need to specify only the property and its value. If you don’t know the exact name of the property you want, you can use the Get-Member cmdlet (or its built-in alias, gm) to retrieve property information:

  get-eventlog security |                                  gm -membertype *property* 

The -membertype parameter specifies that the returned types include the word “property.” I use asterisk (*) wildcards to ensure that all property-related member types, such as ScriptProperty (which you can see in Figure 2), are listed.

When you know the name of the property you want to see, you can just plug it into the Where-Object expression, as I demonstrated earlier. This doesn't work, however, if you don't know the exact property name. In some cases, you can use the -like operator and wildcards. The -like operator is a comparison operator that lets you use wildcards in the compared value, For instance, you can use an asterisk (*) to represent zero or more letters or numbers, as shown in the following example:

  get-eventlog security -newest 100 |                                where \{$_.entrytype -like "fail*"\}  

Because the -like operator and wildcard are used, the code will return any events whose EntryType property begins with “fail.” As you can see, PowerShell provides several ways to access information that you need.

The following set of statements separates events into different text files, based on their EntryType value. You might, for example, want to separate events so you can easily access one type of event without having to sort through all events. At the same time, saving the events to a file allows you to save the data indefinitely for analysis and comparison with other events.

  $events =                                  get-eventlog security -newest 20  
  $events | where \{$_.entrytype -eq `                                   
  $events | where \{$_.entrytype -eq `                                     "SuccessAudit"\} |                                 out-file c:\events\success.txt 

This code first uses a Get-EventLog command to retrieve the 20 most recent events from the Security log and assigns the results to the $events variable. In effect, this step takes a snapshot of the events at the time the variable is defined. Subsequent lines of code pipe the contents of the variable to the Where-Object cmdlet to direct failure events to an out file called fail.txt and success events to an out file named success.txt.

Sorting Events

When analyzing Security events, it's often useful to sort them by property value. To sort data, you use the Sort-Object cmdlet and specify one or more properties by which you want to sort. For example, the following code sorts events by the EventID property:

  $date = (get-date).adddays(-1)                                get-eventlog security |                                 where \{$_.timewritten -gt $date\} |                                 sort -property eventid  

The first statement (the first line) uses the Get-Date cmdlet to retrieve the current date. I then use the AddDays method available to the object returned by the Get-Date cmdlet. In this case, I retrieve a date 24 hours earlier than the current date. By retrieving this date, you’ll be able to search for all events that occurred in the last 24 hours.

In the second statement (the last three lines), I retrieve all security log events, pipe the events to a Where-Object cmdlet to sort out the events that were not written in the past 24 hours, pipe the events to the Sort-Object cmdlet (referenced by the sort built-in alias), and specify the -property parameter with the EventID argument to sort the results by EventID. Figure 3 shows the type of results you can expect from this command. Notice that the events are sorted by EventID, but the Index values are not in numerical order. To order the Index values as well, you can add the index argument (preceded by a comma) to the -property parameter:

  $date = (get-date).adddays(-1)                                 get-eventlog security |                                 where \{$_.timewritten -gt $date\} |                                 sort -property eventid, index  

In this case, I simply add a comma, followed by the Index property. Figure 4 shows the new results, which are sorted by index as well as by EventID.

Controlling the Type of Information an Event Returns

Up to this point, I’ve retrieved events based on specific property values. All these statements have returned the same type of information about each event. But you can also control the type of information that’s returned for the events. The easiest way to return specific information about an event is to use a ForEach statement. The ForEach statement is a looping structure that iterates through a collection of objects. As I loop through the objects, I concatenate the information to make it more readable. In this case, the objects in the collection are the events returned by the Get-EventLog cmdlet. The following example assigns the event objects to the $events variable, then uses that variable in the ForEach statement:

  $events =                                  get-eventlog security -newest 20 |                                 sort -property entrytype, index                                 foreach ($event in $events)                                 \{                                     $event.index.tostring() + " - " +                                     $event.entrytype                                     write-host                                 \}  

The ForEach statement begins by creating another variable ($event) to hold each object as the ForEach statement loops through the collection. You can choose any name for the variables, but you must follow the syntax that I’ve used here (i.e., $event in $events).

The next part of the ForEach statement is the expression in curly brackets, which defines the action to be taken each time the ForEach statement iterates through the collection. To return a specific property value, you specify the $event variable followed by a period and the name of the property you want to return (i.e., $event.index). Some property values, such as Index, are integers. Because I want to concatenate this value with string values, I use the ToStringmethod to convert the value to a string value. I then concatenate the resulting string with the necessary spaces and a hyphen, and then with the EntryType property. Finally, I include a Write-Host cmdlet to add a line between each event listing. Figure 5 shows how the data returned by this statement looks.

Retrieving Event Details

After you retrieve a list of events, you might want to learn more about a specific event. For instance, the list in Figure 5 shows only which events succeeded and which failed. Suppose you want to take a closer look at one of the failed events, such as event 86394. You can drill down into that event by piping the contents of the $events variable to a Where-Object command that specifies the Index property and the particular index value (86394) you're interested in:

  $events |                                  where \{$_.index -eq 86394\} |                                  fl *  

You can then pipe those results to a Format-List cmdlet (referenced by the fl built-in alias) and use a wildcard to indicate that all details about the event should be returned. Figure 6 shows sample results from the above command.

Putting It All Together

Up to this point, I’ve discussed using PowerShell to retrieve certain types of events, sort events, and return specific events. Now let’s put all those capabilities together. The following code returns the Index and Category values of the 20 most recent failed events:

  $events =                                get-eventlog security -newest 20 |                                where \{$_.entrytype -eq `                                  "failureaudit"\} |                                sort -property category, index                                write-host "INDEX   CATEGORY" write-host                                foreach ($event in $events)                                \{                                  $event.index.tostring() + "   " +                                  $event.category                                  write-host                                 \}  

You should recognize most of the elements in this example. The first statement returns a list of the 20 most recent failed events, sorted by Category and Index, and assigns those events to the $events variable. A Write-Host cmdlet then adds a line, which is followed by a heading (“INDEX CATEGORY”) and another Write-Host cmdlet. These three statements make the results more readable. Next, a ForEach loop returns the Index and Category values. Figure 7 shows what the results look like. Note that in Vista, categories are listed as numbers, not names.

Moving Ahead

Now that you know how to retrieve specific information from the Security event log, you can take a list of events and easily drill down into a specific event by using the Where-Object and Format-List cmdlets. (For more information about these or any other cmdlets, see the PowerShell Help files.) I encourage you to try retrieving different types of events and event information. The better you understand how to use PowerShell to retrieve the information you need, the more valuable PowerShell will become and the more efficiently you can work with the Security log.