When an operating system crashes, a server stops responding to ping, or a simple PowerShell DSC configuration needs to be debugged, where's the first place a sysadmin goes? The event log. The Windows event log records a wealth of information. Let's see how we can automate log reviews.
On a typical Windows server, you'll find dozens of event logs recording events of all shapes and sizes. Having this kind of information is valuable, but it's only as useful as the ability to parse through it and find actionable information. We have the tried-and-true event viewer that's been around for a long time that allows you to sift through all of these events. It even has an excellent filtering option for each log.
This is fine if you're working on a single machine, but many sysadmins don't have that luxury. Also, a sysadmin might simply need all events from a particular timeframe from all event logs. At this point, the usefulness of the event viewer starts to erode. You need to build some kind of automation tool around this. In this article, we'll cover how to use PowerShell to create such a tool.
For this tool, I'd like to build something that I can point at one or more servers and that either finds all events in all event logs matching a particular event ID or all events in all event logs in a specific time window. Both of these requirements are great use-cases for troubleshooting purposes.
Let's first build a tool to automate log reviews of the event logs on multiple servers. We'll then build upon this and add more functionality as we go along.
function Find-TroubleshootingEvent
{
[OutputType()]
[CmdletBinding()]
param
(
[Parameter()]
[ValidateNotNullOrEmpty()]
[string[]]$ComputerName = (hostname)
)
try
{
@($ComputerName).foreach({
$getEventParams = @{
ComputerName = $_
}
$logNames = @(Get-WinEvent @getEventParams -ListLog *).where({ $_.RecordCount }).LogName
Write-Verbose -Message "Found log names: [$($logNames -join ',')]"
})
}
catch
{
$PSCmdlet.ThrowTerminatingError($_)
}
}
PS> Find-TroubleshootingEvent
You can see the output is ugly, but it is, in fact, reading all of the event logs on my local machine. Let's now add the ability to find specific event IDs by adding this criterion to Get-WinEvent's FilterHashTable parameter. This requires adding another parameter called EventId so we can optionally limit results by event ID and including the logic in the function to add this criterion to the FilterHashTable if necessary.
We will add this parameter:
[Parameter()]
[ValidateNotNullOrEmpty()]
[int]$EventId
…and add the logic to check for the parameter EventId:
if ($PSBoundParameters.ContainsKey('EventId'))
{
$filterHashTable.Id = $EventId
}
Now when Get-WinEvent runs, it's going to also include the event ID as criteria and limit results to that. Below you can see that I can specify the event ID and only get events from all event logs that contain that specific ID.
PS> Find-TroubleshootingEvent –EventId 7040
This is a great start but what if we have multiple servers that we need to scour? Let's add a few of them in the query. To do that is easy. Simply use the ComputerName parameter and specify multiple comma-separated names.
PS> Find-TroubleshootingEvent –EventId 7040 –ComputerName 'MEMBERSRV1','LABSQL'
This works fine, but now we can't tell what server the result came from. Let's change that and add a ServerName property to the output. I'll do this by using calculated properties with Select-Object.
$selectProperties = @('*',@{Name = 'ServerName'; Expression = {$computer}})
Get-WinEvent @getEventParams -FilterHashTable $filterHashTable | Select-Object -Property $selectProperties
PS> Find-TroubleshootingEvent –EventId 7040 –ComputerName 'MEMBERSRV1','LABSQL' | Format-Table –Property ServerName,Id,Message -AutoSize
I had to pass the results to Format-Table this time in order to get a decent-looking output. This is because PowerShell understands the default output of Get-WinEvent and applies its own formatting, but since this is a new object, we had to add our own rudimentary formatting.
If you liked this approach, you can download this script from Github. To learn more about PowerShell and building a tool like we have here, check out Understanding PowerShell Toolmaking.
Get our latest blog posts delivered in a weekly email.