Searching Windows Event Logs using PowerShell

For many people, it’s the last place you check while troubleshooting, but the Windows Event Log is always a good start to pinpoint issues on your system. In this blog post, I will show you how to search, find easily, and export Windows Event Log information.

How does the script work?

The script is a Windows PowerShell function that you can use with these parameters:

  • Computername allows you to connect to a remote computer or server. If not specified, it defaults to your local computer.
  • Hours allows you to set the number of hours back in time in which it searches for events. If not specified, it defaults to 1 hour.
  • EventID allows you to search for one or more specific EventID numbers. If not specified, it retrieves all events. (Separate EventIDs with commas) It can be used together with the EventLogName and Filter parameters.
  • EventLogName allows you to specify a specific Eventlog. For example, Application or Microsoft-Windows-AppReadiness/Admin. You can also specify multiple logs. For example, –EventLogName System, Security will scan both the System and the Security log. You can also use wildcards, -EventlogName *Hyper-V* will return events from all Hyper-V logs. It can be used together with the EventID and Filter parameters.
  • ExcludeLog allows you to exclude one or more EventLogs. For example, -ExcludeLog security will exclude the security log. -ExcludeLog security, application will exclude both security and application Eventlogs. (Note: No wildcards)
  • GridView allows you to show all the events found in an Out-GridView pane in which you can easily filter the results by typing in the Filter bar. GridView can’t be used together with OutCSV.
  • Filter allows you to search for a specific word or phrase, which can be used with the EventID and EventLogName parameters.
  • OutCSV allows you to save the results to a CSV file. For example, -OutCSV c:\data\events.csv. OutCSV can’t be used together with GridView.

Note: If -GridView and -Output were not used, the output will be shown on the screen if results were found.

Examples

Scan for specific EventID in the Security log on a remote server

Below is an example of retrieving all 4624 events on a remote server within the last 4 hours in a GridView:

Search-Eventlog -EventLogName Security -ComputerName w2k22member -EventID 4624 -Hours 4 -Gridview

Specified EventLog name System.String[] is valid on w2k22member, continuing...
[Eventlog 1/1] - Retrieving events from the Security Event log on w2k22member...
392 events found in the Security Event log on w2k22member

The screen output is like this:

Scan for all events on the local computer containing “KB2267602”

Below is an example of retrieving all events containing “KB2267602” on the local computer from the last 8 hours exported to a CSV file: (It scans 418 Event logs, so I omitted a few lines 😉 )

Search-Eventlog -Hours 8 -OutCSV C:\scripts\WindowsUpdate.csv -Filter 'KB2267602'
[Eventlog 1/418] - Retrieving events from the Active Directory Web Services Event log on W2K22DC...
[Eventlog 2/418] - Retrieving events from the Application Event log on W2K22DC...
[Eventlog 3/418] - Retrieving events from the DFS Replication Event log on W2K22DC...
[Eventlog 4/418] - Retrieving events from the Directory Service Event log on W2K22DC...
[Eventlog 5/418] - Retrieving events from the DNS Server Event log on W2K22DC...
[Eventlog 6/418] - Retrieving events from the ForwardedEvents Event log on W2K22DC...
No events found in ForwardedEvents within the specified time-frame (After 3-7-2023 08:25:58), EventID or Filter on W2K22DC, skipping...
.....
.....
[Eventlog 415/418] - Retrieving events from the System Event log on W2K22DC...
2 events found in the System Event log on W2K22DC
[Eventlog 416/418] - Retrieving events from the Windows Networking Vpn Plugin Platform/Operational Event log on W2K22DC...
No events found in Windows Networking Vpn Plugin Platform/Operational within the specified time-frame (After 3-7-2023 08:33:05), EventID or Filter on W2K22DC, skipping...
0 events found in the Windows Networking Vpn Plugin Platform/Operational Event log on W2K22DC
[Eventlog 417/418] - Retrieving events from the Windows Networking Vpn Plugin Platform/OperationalVerbose Event log on W2K22DC...
No events found in Windows Networking Vpn Plugin Platform/OperationalVerbose within the specified time-frame (After 3-7-2023 08:33:05), EventID or Filter on W2K22DC, skipping...
0 events found in the Windows Networking Vpn Plugin Platform/OperationalVerbose Event log on W2K22DC
[Eventlog 418/418] - Retrieving events from the Windows PowerShell Event log on W2K22DC...
0 events found in the Windows PowerShell Event log on W2K22DC
Exported results to C:\scripts\WindowsUpdate.csv

The output in the CSV file looks like this:

"Time";"Computer";"LogName";"ProviderName";"Level";"User";"EventID";"Message"
"03-07-2023 14:37";"W2K22DC";"System";"Microsoft-Windows-WindowsUpdateClient";"Information";"S-1-5-18";"43";"Installation Started: Windows has started installing the following update: Security Intelligence Update for Microsoft Defender Antivirus - KB2267602 (Version 1.391.3420.0)"
"03-07-2023 14:37";"W2K22DC";"System";"Microsoft-Windows-WindowsUpdateClient";"Information";"S-1-5-18";"19";"Installation Successful: Windows successfully installed the following update: Security Intelligence Update for Microsoft Defender Antivirus - KB2267602 (Version 1.391.3420.0)"

Scan for all Events on a remote server with EventID 105

Below is an example of retrieving all events with EventID 10 events on a remote server within the last hour:

Search-Eventlog -EventID 105 -ComputerName w2k22member 
[Eventlog 1/407] - Retrieving events from the Application Event log on w2k22member...
No events found in Application within the specified time-frame (After 3-7-2023 15:43:22), EventID or Filter on w2k22member, skipping...
0 events found in the Application Event log on w2k22member
[Eventlog 2/407] - Retrieving events from the ForwardedEvents Event log on w2k22member...
No events found in ForwardedEvents within the specified time-frame (After 3-7-2023 15:43:22), EventID or Filter on w2k22member, skipping...
0 events found in the ForwardedEvents Event log on w2k22member
[Eventlog 3/407] - Retrieving events from the HardwareEvents Event log on w2k22member...
No events found in HardwareEvents within the specified time-frame (After 3-7-2023 15:43:22), EventID or Filter on w2k22member, skipping...
0 events found in the HardwareEvents Event log on w2k22member
[Eventlog 4/407] - Retrieving events from the Internet Explorer Event log on w2k22member...
No events found in Internet Explorer within the specified time-frame (After 3-7-2023 15:43:22), EventID or Filter on w2k22member, skipping...
0 events found in the Internet Explorer Event log on w2k22member
....
....

The output will be shown on the screen because the -Gridview or -Output parameter was not used:

Eventlog 404/407] - Retrieving events from the System Event log on w2k22member...
No events found in System within the specified time-frame (After 3-7-2023 15:45:03), EventID or Filter on w2k22member, skipping...
0 events found in the System Event log on w2k22member
[Eventlog 405/407] - Retrieving events from the Windows Networking Vpn Plugin Platform/Operational Event log on w2k22member...
No events found in Windows Networking Vpn Plugin Platform/Operational within the specified time-frame (After 3-7-2023 15:45:03), EventID or Filter on w2k22member, skipping...
0 events found in the Windows Networking Vpn Plugin Platform/Operational Event log on w2k22member
[Eventlog 406/407] - Retrieving events from the Windows Networking Vpn Plugin Platform/OperationalVerbose Event log on w2k22member...
No events found in Windows Networking Vpn Plugin Platform/OperationalVerbose within the specified time-frame (After 3-7-2023 15:45:03), EventID or Filter on w2k22member, skipping...
0 events found in the Windows Networking Vpn Plugin Platform/OperationalVerbose Event log on w2k22member
[Eventlog 407/407] - Retrieving events from the Windows PowerShell Event log on w2k22member...
No events found in Windows PowerShell within the specified time-frame (After 3-7-2023 15:45:03), EventID or Filter on w2k22member, skipping...
0 events found in the Windows PowerShell Event log on w2k22member


Time         : 03-07-2023 16:45
Computer     : w2k22member
LogName      : Microsoft-Windows-Kernel-Cache/Operational
ProviderName : Microsoft-Windows-Kernel-Cache
Level        : Information
User         : S-1-5-18
EventID      : 105
Message      : Volume Periodic Cache Write Latency Information:

                                      Device GUID: {75e374b9-21e1-4e3c-84cc-cdfbb74634ca}
                                      Period Duration (microseconds): 3645937940

                                      Latency Bucket Values:  [256us, 1ms, 4ms, 16ms, 64ms, 128ms, 256ms, 2000ms, 6000ms, 10000ms, 20000ms, 20000+ms]

                                      Synchronous Write IO Counts: [26213, 255, 57, 29, 2, 0, 0, 0, 0, 0, 0, 0]
                                      Synchronous Write IO Total Latencies (us): [29072, 116015, 100398, 248976, 42342, 0, 0, 0, 0, 0, 0, 0]
                                      Synchronous Write Non-Blocking IO Counts: [102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
                                      Synchronous Write Non-Blocking IO Total Latencies (us): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

The “1 events found” message was not shown in the output above but was in the screen output:

[Eventlog 168/407] - Retrieving events from the Microsoft-Windows-Kernel-Cache/Operational Event log on w2k22member...
1 events found in the Microsoft-Windows-Kernel-Cache/Operational Event log on w2k22member

The script

Below is the contents of the script. Copy and paste the contents, for example, in c:\scripts\Search-EventLog.ps1, and run it in Visual Studio Code or PowerShell ISE to make it available in your session. Afterward, you can use Search-EventLog with the parameters specified above in the first chapter.

To make it available in all your PowerShell sessions, you can also add it to your profile like this:

notepad $profile
Add ". c:\scripts\Search-Eventlog.ps1"
Quit/Save and start a new PowerShell session, the Search-Eventlog function is available then
#-Requires RunAsAdministrator
function Search-Eventlog {
    [CmdletBinding(DefaultParameterSetName = 'All')]
    param (
        [Parameter(Mandatory = $false, HelpMessage = "Name of remote computer")][string]$ComputerName = $env:COMPUTERNAME,
        [Parameter(Mandatory = $false, HelpMessage = "Number of hours to search back for")][double]$Hours = 1 ,
        [Parameter(Mandatory = $false, HelpMessage = "EventID number")][int[]]$EventID,
        [Parameter(Mandatory = $false, HelpMessage = "The name of the eventlog to search in")][string[]]$EventLogName,
        [Parameter(Mandatory = $false, HelpMessage = "Output results in a gridview", parameterSetName = "GridView")][switch]$Gridview,
        [Parameter(Mandatory = $false, HelpMessage = "String to search for")][string]$Filter,
        [Parameter(Mandatory = $false, HelpMessage = "Output path, e.g. c:\data\events.csv", parameterSetName = "CSV")][string]$OutCSV,
        [Parameter(Mandatory = $false, HelpMessage = "Exclude specific logs, e.g. security or application, security")][string[]]$ExcludeLog
    )

    #Convert $Hours to equivalent date value
    [DateTime]$hours = (Get-Date).AddHours(-$hours)

    #Set EventLogName if available
    if ($EventLogName) {
        try {
            $EventLogNames = Get-WinEvent -ListLog $EventLogName -ErrorAction Stop | Where-Object LogName -NotIn $ExcludeLog
            Write-Host ("Specified EventLog name {0} is valid on {1}, continuing..." -f $($EventLogName), $ComputerName) -ForegroundColor Green
        }
        catch {
            Write-Warning ("Specified EventLog name {0} is not valid or can't access {1}, exiting..." -f $($EventLogName), $ComputerName)
            return
        }
    }

    #Create array of logs for Eventlogname if not specified, exclude specific EventLogs if specified by Excludelog parameter
    if (-not $EventLogName) {
        try {
            $EventLogNames = Get-WinEvent -ListLog * -ComputerName $ComputerName | Where-Object LogName -NotIn $ExcludeLog
        }
        catch {
            Write-Warning ("Can't retrieve Eventlogs on {0}, exiting..." -f $ComputerName)
            return
        }
    }

    #Retrieve events
    $lognumber = 1
    $total = foreach ($log in $EventLogNames) {
        $foundevents = 0
        Write-Host ("[Eventlog {0}/{1}] - Retrieving events from the {2} Event log on {3}..." -f $lognumber, $EventLogNames.count, $log.LogName, $ComputerName) -ForegroundColor Green  
        try {
            #Specify different type of filters
            $FilterHashtable = @{
                LogName   = $log.LogName
                StartTime = $hours
            } 

            if ($EventID) {
                $FilterHashtable.Add('ID', $EventID)
            }

            #Retrieve events
            $events = Get-WinEvent -FilterHashtable $FilterHashtable -ErrorAction Stop

            #Loop through events
            foreach ($event in $events) {
                if (-not $Filter -or $event.Message -match $Filter) {
                    [PSCustomObject]@{
                        Time         = $event.TimeCreated.ToString('dd-MM-yyy HH:mm')
                        Computer     = $ComputerName
                        LogName      = $event.LogName
                        ProviderName = $event.ProviderName
                        Level        = $event.LevelDisplayName
                        User         = if ($event.UserId) {
                            "$($event.UserId)"
                        }
                        else {
                            "N/A"
                        }
                        EventID      = $event.ID
                        Message      = $event.Message
                    }
                    $foundevents++
                }
            }  
            Write-Host ("{0} events found in the {1} Event log on {2}" -f $foundevents, $log.LogName, $ComputerName) -ForegroundColor Green
            $lognumber++
        }
        catch {
            Write-Host ("No events found in {0} within the specified time-frame (After {1}), EventID or Filter on {2}, skipping..." -f $log.LogName, $Hours, $ComputerName)
        }
    }

    #Output results to GridView
    if ($Gridview -and $total) {
        return $total | Sort-Object Time, LogName | Out-GridView -Title 'Retrieved events...'
    }

    #Output results to specified file location
    if ($OutCSV -and $total) {
        try {
            $total | Sort-Object Time, LogName | 
            export-csv -NoTypeInformation -Delimiter ';' -Encoding UTF8 -Path $OutCSV -ErrorAction Stop
            Write-Host ("Exported results to {0}" -f $OutCSV) -ForegroundColor Green
        }
        catch {
            Write-Warning ("Error saving results to {0}, check path or permissions. Exiting...")
            return
        }
    }
    
    #Output to screen is Gridview or Output were not specified
    if (-not $OutCSV -and -not $Gridview -and $total) {
        return $total | Sort-Object Time, LogName
    }

    #Return warning if no results were found
    if (-not $total) {
        Write-Warning ("No results were found on {0}..." -f $ComputerName)
    }
}

Download the script(s) from GitHub here

One thought on “Searching Windows Event Logs using PowerShell

  1. Pingback: PowerShell is fun :)2023 overview

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.