Event Log Queries Using PowerShell


Summary: Ed Wilson, Microsoft Scripting Guy, talks about using Windows PowerShell to query event logs.

Microsoft Scripting Guy, Ed Wilson, is here. Today I talk a bit more about using Windows PowerShell to make queries from the event log. Although most large enterprises already have an event log monitoring application, at times it is useful to do these types of queries on your own.

Keep in mind that this can generate a lot of network traffic and a decent amount of load if you are not cognizant of what is really going on. As I mentioned yesterday, this can be an area of hidden danger, such as the alligator that the Scripting Wife and I saw over the weekend.

This photo is a different gator than the one I showed you yesterday, and because this dude was lying right on the grass, not in the water, I nearly tripped over him. It might have surprised us both.

Photo of alligator

So, just as it is important to watch where you are going when hiking out in the swamp lands, it is also important to watch what you are doing when querying event logs from remote servers on a widely distributed network.

As I mentioned yesterday, the easiest way to do this (at least for me) is to use a filter hash table. Unfortunately, parameter completion or Tab expansion does not work for this method, so I need to keep a reference in mind. Here is the chart I like to keep nearby:

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

    Note  For more information about the basics of this technique, see Filtering Event Log Events with PowerShell.

Specify multiple log names

One of the way cool features of the Get-WinEvent cmdlet is that it will accept an array of log names. This means that I can query for events from the application, the system, and even from the security log at the same time. This makes it really easy to correlate events that may occur at nearly the same time.

I often like to look at what happened today. Usually that means that I type a date. But you know what? I hate typing numbers. Even with a number pad and NumLock turned on, I still hate typing numbers. I never got good at touch typing numbers (although I am great at letters). So if I can avoid typing in numbers, it is so much the better. Luckily, there is a static property from the DateTime object:

PS C:\> [datetime]::Today

Tuesday, October 20, 2015 12:00:00 AM

Image of Dr. Scripto

   Dr. Scripto says: Don’t forget that beginning with Windows PowerShell 4.0, you can use Tab expansion for
   .NET Framework class names. So you can type [date … and press Tab to get the type accelerator.

From the chart, I see that the LogName keyword accepts an array of strings. That is what string[] means. To specify two logs, I simply use LogName =, and then I specify each log separated by a comma. This is shown here:

@{logname='application','system'}

If I use my trick about returning a single event, the –maxevents 1, I will not really know if I am getting anything from both event logs:

PS C:\> Get-WinEvent @{logname='application','system'} -MaxEvents 1

   ProviderName: Microsoft-Windows-Security-SPP

TimeCreated                     Id LevelDisplayName Message

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

10/20/2015 2:52:39 PM          903 Information      The Software Protection servi...

In fact, even if I specify two events, it doesn’t help:

PS C:\> Get-WinEvent @{logname='application','system'} -MaxEvents 2

   ProviderName: Microsoft-Windows-Security-SPP

TimeCreated                     Id LevelDisplayName Message

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

10/20/2015 2:52:39 PM          903 Information      The Software Protection servi...

10/20/2015 2:52:39 PM        16384 Information      Successfully scheduled Softwa...

How do I know if my query is working properly? One thing I can do is limit the events to those that happened today. I use my [datetime]::Today technique. I can then pipe the output to the Group-Object cmdlet to see how many events each log contains. The command is shown here:

Get-WinEvent @{logname='application','system';starttime=[datetime]::today } |

 group logname –NoElement

Here is the command and its associated output:

Image of command output

What about errors that occurred today in both logs? I add level=2 to my query:

Get-WinEvent @{logname='application','system';starttime=[datetime]::today;level=2 } |

group logname –NoElement

The command and its output are shown here:

Image of command output

That is a small enough number that it bears investigating. So I remove Group-Object and look at the output:

Get-WinEvent @{logname='application','system';starttime=[datetime]::today;level=2 }

Here is the command and its output:

Image of command output

OK. But it doesn’t tell me the log names. So I change things a bit to show the log names. Also, because I am specifically filtering errors, I remove that field from the output. The command is shown here:

Get-WinEvent @{logname='application','system';starttime=[datetime]::today;level=2 } |

select logname, timecreated, id, message

Here is the command and its output:

Image of command output

It is now obvious that the crypto service failing and the user data access events have nothing to do with each other. Cool. Now I just need to find out what is causing the errors—but I now know what is not causing the error.

That is all there is to using Windows PowerShell to query event logs. Join me tomorrow when I will talk about measuring the efficiency of different types of queries.

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 

Comments (2)

  1. go4 says:

    thank you very much for this blogpost. i tried this and it works when executed on my local machine, but when i wrap it into an invoke-command to execute remotely i get an error like "the eventlog "application system" could not be found". what do i need
    to change to achieve that? (windows7/8,psversion4)

  2. Chris says:

    go4: Get-WinEvent supports the -ComputerName parameter so you don’t need to use Invoke-Command.

Skip to main content