Get Windows Event Log Entries using Powershell

2015-09-19T18:00:00Z

Whilst rolling an upgrade to Microsoft Server 2012 r2 in a VMWare VSphere virtualized cluster, we encountered a problem where-by individual servers would periodically lose network connectivity over one or both of their network adapters. Whilst the actual problem remains under investigation, I felt it might be useful to write a bit of PowerShell that could be used to quickly retrieve all the event logs written on a machine during a given period.

Invoke-Command -ComputerName <RemoteComputerName> -ScriptBlock {
    Get-WinEvent -ListLog * |`
        Where-Object {$_.recordcount -gt 0 -and`
            $_.lastwritetime -gt [datetime](Get-Date 2015-09-22T15:54:00)} |`
        Foreach-Object {Get-WinEvent -LogName $_.logname} |`
        Where-Object {($_.TimeCreated -gt [datetime](get-date 2015-09-22T15:54:00)) -and`
            ($_.TimeCreated -lt [datetime](get-date 2015-09-22T15:56:00))} |`
        Sort -Property TimeCreated |`
        Format-Table TimeCreated, ID, ProviderName, Message -AutoSize -Wrap
}

This bit of PowerShell will retrieve all the event logs a remote computer specified by "<RemoteComputerName>", created between 15:54 and 15:56 on 22nd September 2015. The command can be broken down into several parts. The "Invoke-Command" statement allows us to run an abitrary piece of powershell inside a scriptblock on another host via PowerShell remoting. Here's another simpler example:

Invoke-Command -ComputerName <RemoteComputerName> -ScriptBlock { Get-ChildItem -Path C:\ }

The first part of the command retrieves all the available Windows Event Logs. This we can do with Get-WinEvent. Some logs will be empty so we pipe the results into "Where-Object" to eliminate those. We can narrow down the result set further still by adding a second condition to this "Where-Object" statement. Adding a condition that evaluates LastWriteTime means that we can narrow the scope further too by filtering out event logs which have not been written to since before the start of our time period.

Get-WinEvent -ListLog * |`
    Where-Object {$_.recordcount -gt 0 -and 
        $_.lastwritetime -gt [datetime](Get-Date 2015-09-22T15:54:00)}

So at this point we have a list of logs that we're interested in. We need to check each event log and retrieve each relevant entry it contains. This is where our next statement, the Foreach-Object comes in.

Foreach-Object {Get-WinEvent -LogName $_.logname}

This statement simplay says, for each object (event log) still in our pipeline from calling "Get-WinEvent -ListLog *", retreive all the events associated with that object. Finally, all we need to do is filter out the events in that log that occured before and after our time period. We can achieve this using a "Where-Object" statement, similar to that which we used earlier:

 Where-Object {($_.TimeCreated -gt [datetime](get-date 2015-09-22T15:54:00)) -and`
    ($_.TimeCreated -lt [datetime](get-date 2015-09-22T15:56:00))}

Finally we use "Sort-Object" and "Format-Table" just to make a little more sense of our output. Putting it all together gives us the command I introduced earlier, which used to retrieve log entries on a computer named "homer" would look like:

Invoke-Command -ComputerName homer -ScriptBlock {
    Get-WinEvent -ListLog * |`
        Where-Object {$_.recordcount -gt 0 -and`
            $_.lastwritetime -gt [datetime](Get-Date 2015-09-22T15:54:00)} |`
        Foreach-Object {Get-WinEvent -LogName $_.logname} |`
        Where-Object {($_.TimeCreated -gt [datetime](get-date 2015-09-22T15:54:00)) -and`
            ($_.TimeCreated -lt [datetime](get-date 2015-09-22T15:56:00))} |`
        Sort -Property TimeCreated |`
        Format-Table TimeCreated, ID, ProviderName, Message -AutoSize -Wrap

}