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.
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
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:
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:
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:
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:
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