This post is part of the #PSBlogWeek PowerShell blogging series. #PSBlogWeek is a regular event where anyone interested in writing great content about PowerShell is welcome to volunteer for. The purpose is to pool our collective PowerShell knowledge together over a 5-day period and write about a topic that anyone using PowerShell may benefit from. #PSBlogWeek is a Twitter hashtag so feel free to stay up to date on the topic on Twitter at the #PSBlogWeek hashtag. For more information on #PSBlogWeek or if you’d like to volunteer for future sessions, contact Adam Bertram (@adbertram) on Twitter.
Once you’re done getting schooled on everything this post has to offer head on over to the powershell.org announcement for links to the other four past and upcoming #PSBlogWeek articles this week!
Whether it’s an error report, a warning, or just an informational log, one of the most common places for Windows to write logging information is to the event logs. There are tons of reasons to open up Event Viewer and peruse the event logs. Some of the things I’ve had to do recently include:
Although Event Viewer is a handy tool, given today’s IT landscape, we should
always be looking for more efficient ways to consume data sources like the event
logs. That’s why we’re going to take a look at the Get-WinEvent
cmdlet in
PowerShell. This cmdlet is a powerful and flexible way of pulling data out of
the event logs, both in interactive sessions and in scripts.
Before we get started, don’t forget to launch your PowerShell session as Administrator, since some of the logs (like Security) won’t be accessible otherwise.
Like any good PowerShell cmdlet, Get-WinEvent
has excellent help, including
fourteen different examples. We’re going to review a lot of the important
points, but you can always use Get-Help Get-WinEvent -Online
to bring the full
help up in a browser window.
Without any parameters, Get-WinEvent
returns information about every single
event in the every single event log. To get to the specific events you want, you
need to pass one or more parameters to filter the output. Here are the most
common parameters of Get-WinEvent
and what they do:
-LogName
- Filters events in the specified log (think Application, Security,
System, etc.).-ProviderName
- Filters events created by the specified provider (this is
the Source column in Event Viewer).-MaxEvents
- Limits the number of events returned.-Oldest
- Sorts the events returned so that the oldest ones are first. By
default, the newest, most recent events are first.So, by using these basic parameters, we can build commands that do things like:
Get the last 10 events from the Application log.
Get-WinEvent -LogName Application -MaxEvents 10
Get the last 5 events logged by Outlook.
Get-WinEvent -ProviderName Outlook -MaxEvents 5
Get the oldest 50 events from the Application log.
Get-WinEvent -LogName Application -MaxEvents 50 -Oldest
The event logs have grown up quite a bit since the days when Application,
Security, and System were the only logs to look through. Now there are folders
full of logs. How are you going to know how to reference those logs when you’re
using Get-WinEvent
? You use the -ListLog
and -ListProvider
parameters.
For example, consider the log that PowerShell Desired State Configuration (DSC) uses. In Event Viewer, that log is located under:
Applications and Services Logs\Microsoft\Windows\Desired State Configuration\Operational
If I pass that name to the LogName
parameter of Get-WinEvent
, I get an
error. To find the name I need to use, I run the command:
Get-WinEvent -ListLog *PowerShell*
and see that there are a couple of options. Although there is one that mentions Desired State Configuration, it doesn’t sound like what I’m looking for. Let’s see if the name uses the abbreviation DSC.
Get-WinEvent -ListLog *DSC*
That looks like a much better fit. To be sure, you can always check the properties of a log in Event Viewer and look at the file name.
Bingo.
You can pass *
to the -ListLog
or -ListProvider
parameters to get all logs
or all providers.
The commonly used parameters are great for doing basic filtering, but if you’re
doing anything more complicated than a basic health, check you’re going to need
a more powerful search. That’s where the -FilterHashtable
parameter comes in.
First, a quick review of hash table syntax. A hash table can be specified on one line or on multiple lines. Both statements below produce the same hash table.
$Hashtable1 = @{Key = "Value"; Foo = "bar"; Bat = "baz"}
$Hashtable2 = @{
Key = "Value"
Foo = "bar"
Bat = "baz"
}
When passing a hash table to the FilterHashtable
parameter, here are some of
the keys you may find useful.
LogName
- Same as the -LogName
parameterProviderName
- Same as the ProviderName
parameterID
- Allows you to filter on the Event IDLevel
- Allows you to filter on the severity of the entry (You have to pass
a number: 4 = Informational, 3 = Warning, 2 = Error)StartTime
- Allows you to filter out events before a certain Date/TimeEndTime
- Allows you to filter out events after a certain Date/Time (You can
use StartTime and EndTime together)UserID
- Allows you to filter on the user that created the eventIf this does not provide the level of granularity that you need, don’t forget
that you can always pipe the results through Where-Object
to further refine
your results:
Get-WinEvent -FilterHashTable @{LogName = "Application"} -MaxEntries 50 | Where-Object -Property Message -Like "*success*"
Running one of the commands above might produce output that looks like this:
but what Get-WinEvent
actually returns are objects of type
[System.Diagnostics.Eventing.Reader.EventLogRecord]
. PowerShell is being nice
and picking just four common properties to show us, but there are more
properties that we can access by storing the results to a variable or using a
cmdlet like Select-Object
, Format-Table
, Format-List
, or even
Out-GridView
.
Here are some of the properties you might find useful:
Id
- Event IDLevel
- Numeric representation of the event levelLevelDisplayName
- Event level (Information, Error, Warning, etc.)LogName
- Log name (Application, Security, System, etc.)MachineName
- Name of the computer the event is fromMessage
- Full message of the eventProviderName
- Name of the provider (source) that wrote the eventYou can also dig into the message data attached to the event. Event log messages are defined by the Event ID, so all events with the same Event ID have the same basic message. Messages can also have placeholders that get filled in with specific values for each instance of that Event ID. These fill-in-the-blank values are called “insertion strings,” and they can be very useful.
For example, let’s say I grabbed an event out of the Application log and stored
it in a variable $x
. If I just examine $x
, I can see the full message of the
event is “The session ‘183c457c-733c-445d-b5d6-f04fc9623c8b’ was
disconnected”.
This is where things get interesting. Since Windows Vista, event logs have been
stored in XML format. If you run (Get-WinEvent -ListLog
Application).LogFilePath
you’ll see the .evtx extension on the file. The
EventLogRecord
objects that Get-WinEvent
returns have a ToXml
method that
I can use to get to the XML underneath the object; this is where the insertion
string data is stored.
By converting the event to XML and looking at the insertion strings, I can get direct access to the value that was inserted into the message without having to parse the full message and extract it. Here is the code to do that:
([xml]$x.ToXml()).Event.EventData.Data
The ToXml
method returns a string containing the XML, and putting the [xml]
accelerator in front of it tells PowerShell to read that string and create an
XML object from it. From there, I navigate the XML hierarchy to the place where
the insertion string data is stored.
The messages for different Event IDs can have different numbers of insertion strings, and you may need to explore a little to figure out exactly how to pull the specific piece of data you’re looking for, but all events for a given Event ID will be consistent. The example above uses a simple event on purpose, but one example of how I’ve used this in my automation is when pulling logon events from the Security log. Event 4624, which records a successful logon, contains insertion strings for which user is logging on, what domain they belong to, what kind of authentication they used, and more.
All the cool stuff we just covered above? You can do all of that on remote targets as well. There are two parameters you can use to have Get-WinEvent get values from a remote computer:
ComputerName
- Lets you specify which computer to connect to remotelyCredential
- Lets you specify a credential to use when connecting, in case
your current session is not running under an account with the appropriate
permissions.Get-WinEvent
does not use PSRemoting to get remote data; just the Event Log
Service. This requires TCP port 135 and a dynamically chosen port above 1024 to
be open in the firewall.
There is more to discover in using the Get-WinEvent
cmdlet and the data that
it returns but, hopefully, this introduction serves as a thorough foundation for
accessing the event logs from PowerShell. These techniques for discovering,
filtering, and extracting meaning from the event logs can be applied in an
interactive PowerShell session or an automated script. They can also be used to
read the event logs on your local machine or a remote target. It’s hard to know
what data you will be searching for to meet your requirements until you are
faced with them, but one thing is for sure: the event logs probably have at
least some of the data you need, and now you know how to get it!
Adam Platt is a technologist with more than a decade of experience across the full stack. His passion for technology and penchant for rendering complex technical ideas into simple terms have made him an in-demand speaker. His resume includes BriForum, the PowerShell Summit, teaching engagements and more.
He is one of the 10 types of people who understand binary and he can solve a Rubik’s Cube.
Adam Platt is a technologist with more than a decade of experience across the full stack. His passion for technology and penchant for rendering complex technical ideas into simple terms have made him an in-demand speaker. His resume includes BriForum, the PowerShell Summit, teaching engagements and more.
He is one of the 10 types of people who understand binary and he can solve a Rubik’s Cube.