Skip to content

Event Logs

Note

Query and filter Windows Event Logs with Get-WinEvent (modern) and Get-EventLog (legacy) to investigate errors, crashes, and system activity.

Overview

Windows records almost everything significant — service failures, logon attempts, application crashes, driver errors — into the Event Log. PowerShell gives you two ways in: Get-WinEvent, the modern, faster, and more flexible cmdlet that reads any log including the newer structured .evtx logs, and Get-EventLog, the older cmdlet limited to classic logs (Application, System, Security) but with a slightly simpler syntax. Use Get-WinEvent for new scripts; know Get-EventLog because you'll still see it in older code.

Basic Syntax

Get-WinEvent -LogName Application -MaxEvents 20
Get-WinEvent -FilterHashtable @{LogName='System'; Level=2}
Get-EventLog -LogName Application -Newest 20

Key Points

  • Get-WinEvent works on any event log, including application-specific and "Applications and Services Logs"; Get-EventLog only sees classic logs
  • -FilterHashtable on Get-WinEvent filters at the source — much faster than piping to Where-Object
  • Event Level: 1=Critical, 2=Error, 3=Warning, 4=Information, 5=Verbose
  • Reading the Security log requires an elevated session

Listing Available Logs

# All logs on the system, with basic stats
Get-WinEvent -ListLog * | Select-Object LogName, RecordCount, IsEnabled

# Only logs that actually have events (avoids empty ones cluttering output)
Get-WinEvent -ListLog * | Where-Object { $_.RecordCount -gt 0 } |
    Sort-Object RecordCount -Descending

Querying with Get-WinEvent

Basic Queries

# Most recent 20 events from the Application log
Get-WinEvent -LogName Application -MaxEvents 20

# Most recent errors only
Get-WinEvent -FilterHashtable @{LogName='Application'; Level=2} -MaxEvents 20

# Events from the last 24 hours
Get-WinEvent -FilterHashtable @{
    LogName   = 'System'
    StartTime = (Get-Date).AddHours(-24)
}

# Specific Event ID (e.g. 7034 = service crashed unexpectedly)
Get-WinEvent -FilterHashtable @{LogName='System'; Id=7034}

Output:

TimeCreated             ProviderName          Id LevelDisplayName Message
-----------             ------------          -- ---------------- -------
7/1/2026 8:42:15 AM     Service Control Man… 7034 Error            The Print Spooler service...
7/1/2026 8:12:03 AM     Service Control Man… 7036 Information      The Windows Update service...

Combining Filters

# Errors and warnings from a specific source, in the last 7 days
Get-WinEvent -FilterHashtable @{
    LogName      = 'Application'
    Level        = 2,3
    StartTime    = (Get-Date).AddDays(-7)
    ProviderName = 'MyApplication'
}

# Query an "Applications and Services" log (needs the full path-style name)
Get-WinEvent -LogName "Microsoft-Windows-PowerShell/Operational" -MaxEvents 50

-FilterHashtable Filters at the Source

# SLOW - reads every event, then filters in PowerShell
Get-WinEvent -LogName System -MaxEvents 5000 | Where-Object { $_.Id -eq 7034 }

# FAST - the Windows Event Log service does the filtering
Get-WinEvent -FilterHashtable @{LogName='System'; Id=7034}
-FilterHashtable pushes the query down to the event log provider itself instead of pulling everything into PowerShell first. On a busy system this is the difference between a query that takes seconds versus minutes.

Filtering by Message Content

# Text search across message bodies (slower - has to read and render each event)
Get-WinEvent -LogName Application -MaxEvents 500 |
    Where-Object { $_.Message -like "*timeout*" }

# XPath filtering for more precise, faster queries
Get-WinEvent -LogName Application -FilterXPath "*[System[(EventID=1000)]]"

Querying with Get-EventLog (Legacy)

# Newest 20 entries
Get-EventLog -LogName Application -Newest 20

# Only errors
Get-EventLog -LogName Application -EntryType Error -Newest 20

# Filter by source
Get-EventLog -LogName System -Source "Service Control Manager" -Newest 20

# Events within a time range
Get-EventLog -LogName System -After (Get-Date).AddDays(-1)

Get-EventLog Is Deprecated

Get-EventLog is not available in PowerShell 7+ on non-Windows platforms and Microsoft recommends Get-WinEvent for all new scripts — it's faster, supports more logs, and is the actively maintained cmdlet. Get-EventLog still works in Windows PowerShell 5.1 and PowerShell 7 on Windows, but don't build new tooling around it.

Working with Event Details

# Pull specific properties out of events
Get-WinEvent -FilterHashtable @{LogName='System'; Id=7034} |
    Select-Object TimeCreated, Id, LevelDisplayName, Message

# Access structured event data (XML) for events with custom properties
$event = Get-WinEvent -FilterHashtable @{LogName='System'; Id=7034} -MaxEvents 1
[xml]$xml = $event.ToXml()
$xml.Event.EventData.Data

# Export a set of events to CSV for further analysis
Get-WinEvent -FilterHashtable @{LogName='Application'; Level=2} -MaxEvents 100 |
    Select-Object TimeCreated, Id, ProviderName, Message |
    Export-Csv -Path "C:\Reports\app-errors.csv" -NoTypeInformation

Remote Event Log Queries

# Query a remote computer's event log
Get-WinEvent -ComputerName "SERVER01" -LogName System -MaxEvents 20

# Query multiple servers and tag results with the source machine
$servers = @("SERVER01", "SERVER02")
foreach ($server in $servers) {
    Get-WinEvent -ComputerName $server -FilterHashtable @{LogName='System'; Level=2} -MaxEvents 10 |
        Select-Object @{N="Server";E={$server}}, TimeCreated, Id, Message
}

Important Parameters

Parameter Type Description Example
-LogName String Which log to query -LogName Application
-FilterHashtable Hashtable Server-side filter (LogName, Id, Level, StartTime, etc.) @{LogName='System'; Level=2}
-MaxEvents Int Limit the number of results -MaxEvents 20
-Id Int[] Get-EventLog: filter by Event ID (via Where-Object) n/a for Get-EventLog directly
-EntryType String Get-EventLog: Error, Warning, Information -EntryType Error
-ComputerName String Query a remote machine -ComputerName "SRV01"
-FilterXPath String Advanced XPath-based filtering "*[System[(EventID=1000)]]"

Common Patterns

# Pattern 1: Errors in the last N hours across two core logs
$since = (Get-Date).AddHours(-6)
@('Application', 'System') | ForEach-Object {
    Get-WinEvent -FilterHashtable @{LogName=$_; Level=2; StartTime=$since} -ErrorAction SilentlyContinue
}

# Pattern 2: Count events by ID to spot noisy repeat errors
Get-WinEvent -LogName Application -MaxEvents 1000 |
    Group-Object Id | Sort-Object Count -Descending | Select-Object -First 10 Count, Name

# Pattern 3: Daily error summary email body
$errors = Get-WinEvent -FilterHashtable @{LogName='Application'; Level=2; StartTime=(Get-Date).Date}
"$($errors.Count) errors logged today" | Out-String

Real-World Examples

Example: Daily Crash Report

Scenario: Every morning, summarize application crashes (Event ID 1000, .NET/native crash reporting) from the previous day into a report.

$yesterday = (Get-Date).Date.AddDays(-1)
$today = (Get-Date).Date

$crashes = Get-WinEvent -FilterHashtable @{
    LogName   = 'Application'
    Id        = 1000
    StartTime = $yesterday
    EndTime   = $today
} -ErrorAction SilentlyContinue

if ($crashes) {
    $summary = $crashes | Group-Object { ($_.Message -split "`n")[0] } |
        Sort-Object Count -Descending |
        Select-Object Count, Name

    $summary | Format-Table -AutoSize | Out-String |
        Set-Content -Path "C:\Reports\crash-report-$(Get-Date -Format 'yyyy-MM-dd').txt"
}

Explanation: -FilterHashtable with StartTime/EndTime scopes the query to exactly yesterday, and grouping by the first line of the message rolls up repeat crashes from the same faulting application into a single count instead of a wall of duplicate rows.

Tips & Tricks

Find Which Event IDs Are Most Common First

Get-WinEvent -LogName System -MaxEvents 500 | Group-Object Id | Sort-Object Count -Descending | Select-Object -First 10
Before writing a targeted filter, this quickly shows you what's actually flooding a log — useful for figuring out which Event IDs are worth alerting on versus which are just noise.

-FilterHashtable Level Numbers Aren't What You'd Guess

# This looks like it should mean "level 2 out of something" but it's a specific enum
Get-WinEvent -FilterHashtable @{LogName='System'; Level=2}   # Level 2 = Error
Level values: 1=Critical, 2=Error, 3=Warning, 4=Information, 5=Verbose. There's no Level 0 in practice for most providers. Double-check this mapping — mixing up Warning (3) and Error (2) in an alerting script is an easy mistake.

  • Services Management - Event ID 7034/7036/7031 track service state changes
  • Process Management - Application crashes show up as both a process exit and an event log entry
  • Logging - Building your own application logs alongside the system event log

Additional Resources