How to read and clear Windows Event Logs with PowerShell





Windows Event Logs accumulate fast. On a busy server, the Application and System logs can hold hundreds of thousands of entries within days. PowerShell gives you two tools for dealing with this: Get-WinEvent for reading and filtering events with precision, and Clear-EventLog or wevtutil for clearing logs safely — with an export step before wiping anything. This article focuses on the patterns that come up during real troubleshooting and maintenance, not on every parameter in the documentation.

If you need the CMD equivalent for the same operations, see the wevtutil command guide. This article focuses on the PowerShell side: structured output, time-based filtering, exporting to files, and clearing logs with a proper backup step.


Quick answer

Get the last 20 errors from the System log:

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

Export the Application log and clear it:

wevtutil epl Application C:\bat\Application-backup.evtx
Clear-EventLog -LogName Application

Two cmdlets, one use case each

PowerShell has two ways to read Event Logs: the older Get-EventLog and the newer Get-WinEvent. Use Get-WinEvent — it is faster, supports all log channels including operational logs, and handles large logs without performance issues. Get-EventLog is limited to classic logs and is significantly slower on large datasets.

CmdletPurposeUse
Get-WinEventRead and filter events from any log channel or .evtx fileAlways prefer this
Get-EventLogRead classic logs only (System, Application, Security)Avoid — legacy
Clear-EventLogClear a classic log channelUse with export first
wevtutil eplExport any log channel to .evtx before clearingAlways run before clear
Note: Reading System and Application logs does not require elevation. Reading the Security log and clearing any log requires an elevated PowerShell prompt (Run as Administrator).

Practical examples

1. Get recent errors from a log channel

The problem: Something failed on a server — a service crashed, an application threw an error, a scheduled task did not run. You need to see what the Event Log recorded in the last hour without opening Event Viewer and clicking through filters manually.

The solution: Get-WinEvent with a filter hashtable is the fastest way to query a log channel with multiple conditions at once. The filter hashtable is more efficient than piping to Where-Object because the filtering happens before events are loaded into memory.

# Get errors (Level 2) from the System log in the last 2 hours
# Level 1 = Critical, Level 2 = Error, Level 3 = Warning
Get-WinEvent -FilterHashtable @{
    LogName   = 'System'
    Level     = 2
    StartTime = (Get-Date).AddHours(-2)
} | Select-Object TimeCreated, Id, Message

Example output:

TimeCreated          Id  Message
-----------          --  -------
4/20/2026 8:14:33   7034 The Print Spooler service terminated unexpectedly...
4/20/2026 7:58:11   7031 The Windows Update service terminated unexpectedly...

To include both errors and warnings, use an array for Level:

# Get both errors and warnings from the Application log in the last 24 hours
Get-WinEvent -FilterHashtable @{
    LogName   = 'Application'
    Level     = 2, 3
    StartTime = (Get-Date).AddHours(-24)
} | Select-Object TimeCreated, Id, LevelDisplayName, Message | Format-Table -AutoSize
Get-WinEvent PowerShell command output showing System log errors with TimeCreated and Event ID

2. Filter events by Event ID

The problem: You know the specific Event ID you are looking for — failed logons (4625), account lockouts (4740), service crashes (7034), or a custom application event. You want only those events, not everything in the log.

The solution: Add Id to the filter hashtable. Multiple IDs can be passed as an array.

# Get failed logon events (4625) from the Security log — requires elevation
Get-WinEvent -FilterHashtable @{
    LogName = 'Security'
    Id      = 4625
} -MaxEvents 50 | Select-Object TimeCreated, Message
# Get both failed logon (4625) and account lockout (4740) events
Get-WinEvent -FilterHashtable @{
    LogName = 'Security'
    Id      = 4625, 4740
} -MaxEvents 50 | Select-Object TimeCreated, Id, Message
# Get service crash events (7034) from System log in the last week
Get-WinEvent -FilterHashtable @{
    LogName   = 'System'
    Id        = 7034
    StartTime = (Get-Date).AddDays(-7)
} | Select-Object TimeCreated, Message
Note: The Security log on an active domain machine can contain millions of events. Always use -MaxEvents or a StartTime filter when querying it — without a limit, the query will run for several minutes and return an unmanageable amount of data.

3. Query events from a remote machine

The problem: A server in another location is generating errors and you need to check its Event Log without opening an RDP session or asking someone to physically access it.

The solution: Get-WinEvent accepts a -ComputerName parameter. The query runs against the remote machine’s Event Log service over the network. Requires admin rights on the remote machine and RPC connectivity.

# Query the System log on a remote machine for errors in the last hour
Get-WinEvent -ComputerName SRV-PROD-01 -FilterHashtable @{
    LogName   = 'System'
    Level     = 2
    StartTime = (Get-Date).AddHours(-1)
} | Select-Object TimeCreated, Id, Message
# Query with explicit credentials when the current session lacks remote admin rights
$cred = Get-Credential
Get-WinEvent -ComputerName SRV-PROD-01 -Credential $cred -FilterHashtable @{
    LogName = 'System'
    Level   = 2
} -MaxEvents 20 | Select-Object TimeCreated, Id, Message
Note: Get-Credential opens a secure prompt for username and password — credentials are never stored in the script or command history. This is the correct pattern for interactive remote queries.

4. Export events to a file for analysis or handoff

The problem: You need to share Event Log data with another admin, attach it to a ticket, or keep a record of what was in the log before making changes. Copying terminal output loses formatting and is hard to read.

The solution: Export to CSV for structured data that can be opened in Excel, or export as an .evtx file to preserve all event metadata and allow re-querying with Get-WinEvent or Event Viewer later.

# Export filtered events to CSV — easy to open in Excel or share via email
Get-WinEvent -FilterHashtable @{
    LogName   = 'System'
    Level     = 2
    StartTime = (Get-Date).AddDays(-7)
} | Select-Object TimeCreated, Id, LevelDisplayName, Message |
    Export-Csv -Path C:\bat\system-errors-last-7-days.csv -NoTypeInformation
# Export the entire Application log as .evtx — preserves all metadata
# wevtutil is faster and more reliable for full log exports than PowerShell
wevtutil epl Application C:\bat\Application-$(Get-Date -Format 'yyyy-MM-dd').evtx
# Query events from a saved .evtx file — same syntax as a live channel
Get-WinEvent -Path C:\bat\Application-2026-04-20.evtx -FilterXPath "*[System[Level=2]]" |
    Select-Object TimeCreated, Id, Message
PowerShell Export-Csv command exporting Event Log data to a CSV file in C:\bat

5. Export and clear a log safely

The problem: A log channel is full or filling up fast — older events are being overwritten before they can be reviewed, or disk space on a server is getting tight. You need to clear the log but cannot lose the data permanently.

The solution: Always export first, verify the file, then clear. This two-step sequence is the correct procedure on any machine where log retention matters.

# Step 1 — export the log to a dated .evtx archive file
# wevtutil is used here because it is faster and more reliable for full exports
$date     = Get-Date -Format 'yyyy-MM-dd'
$backupPath = "C:\bat\Application-$date.evtx"
wevtutil epl Application $backupPath

# Step 2 — verify the export file exists and has a non-zero size before clearing
if ((Test-Path $backupPath) -and ((Get-Item $backupPath).Length -gt 0)) {
    # Step 3 — clear the log — requires elevated PowerShell
    Clear-EventLog -LogName Application
    Write-Host "Log cleared. Backup saved to $backupPath"
} else {
    Write-Host "Export failed or file is empty. Log was NOT cleared." -ForegroundColor Red
}
Warning: Clear-EventLog permanently deletes all events from the log channel. The verification step in the script above is not optional — always confirm the export file exists and has content before running the clear. There is no undo.
Note: To clear multiple logs at once, pass an array of log names: Clear-EventLog -LogName Application, System. Clearing the Security log additionally requires the “Manage auditing and security log” privilege — on hardened servers, even a local administrator may not have this right by default.
PowerShell script exporting and clearing Windows Event Log with confirmation message

Hidden gems

Get-WinEvent returns objects — pipe them anywhere

Unlike wevtutil which returns text, Get-WinEvent returns event objects with named properties. This means you can pipe results directly into Group-Object to count events by ID, Sort-Object to reorder them, or Where-Object for additional filtering that the hashtable does not support — such as filtering on the Message field content:

# Count how many times each Event ID appeared in the System log today
Get-WinEvent -FilterHashtable @{
    LogName   = 'System'
    StartTime = (Get-Date).Date
} | Group-Object Id | Sort-Object Count -Descending | Select-Object Count, Name
# Find all error events whose message contains a specific string
Get-WinEvent -FilterHashtable @{ LogName = 'Application'; Level = 2 } -MaxEvents 500 |
    Where-Object { $_.Message -like '*connection timeout*' } |
    Select-Object TimeCreated, Id, Message

List all available log channels

Windows has hundreds of Event Log channels beyond System, Application, and Security. Get-WinEvent -ListLog * shows all of them with their current record count and size. Filter by name to find logs for specific components:

# Find all log channels related to Group Policy
Get-WinEvent -ListLog * | Where-Object { $_.LogName -like '*GroupPolicy*' }

# Show all logs that currently have events in them, sorted by record count
Get-WinEvent -ListLog * |
    Where-Object { $_.RecordCount -gt 0 } |
    Sort-Object RecordCount -Descending |
    Select-Object LogName, RecordCount, FileSize | Format-Table -AutoSize

Suppress the error when no events match the filter

When Get-WinEvent finds no events matching the filter, it throws a terminating error instead of returning an empty result — which breaks scripts that expect a clean empty output. Use -ErrorAction SilentlyContinue to handle this gracefully:

# Return empty result instead of an error when no events match
$events = Get-WinEvent -FilterHashtable @{
    LogName   = 'System'
    Level     = 1
    StartTime = (Get-Date).AddHours(-1)
} -ErrorAction SilentlyContinue

if ($events) {
    $events | Select-Object TimeCreated, Id, Message
} else {
    Write-Host "No critical events found in the last hour."
}

Where this matters

Post-incident analysis — after an outage or unexpected reboot, querying the System and Application logs for errors in the hour before the incident is usually the first step in root cause analysis.

Log rotation on servers without a SIEM — smaller environments that do not forward logs to a central collector need a manual or scheduled process to archive and clear logs before they overflow. The export-and-clear script in Example 5 is that process.

Security event monitoring — querying for failed logon events (4625) and account lockouts (4740) on domain controllers or RDP-exposed servers is a basic indicator of brute-force activity that does not require a full SIEM to detect.

Scheduled maintenance reporting — running Get-WinEvent as part of a weekly maintenance script and exporting results to CSV gives a lightweight audit trail without additional tooling.

Kiosk and shared workstation cleanup — clearing logs on machines that accumulate events rapidly keeps disk usage predictable and makes the logs easier to review when something actually goes wrong.


Tips and limitations

  • FilterHashtable is faster than Where-Object. Always apply as many filters as possible inside the hashtable — LogName, Level, Id, StartTime, EndTime — before piping to Where-Object. The hashtable filters happen at the source before events are loaded into memory. Where-Object filters after all matching events are already loaded, which is significantly slower on large logs.
  • Get-WinEvent -ComputerName uses RPC, not WinRM. Unlike most PowerShell remoting which uses WinRM (port 5985/5986), Get-WinEvent -ComputerName uses RPC (port 135 + dynamic ports). If the remote machine is configured for WinRM but not RPC, use Invoke-Command to run the query remotely instead.
  • Clear-EventLog only works on classic logs. For operational logs like Microsoft-Windows-GroupPolicy/Operational, use wevtutil cl "LogName" instead — Clear-EventLog does not support non-classic channels.
  • Exported .evtx files are not text files. They are binary and must be opened in Event Viewer or queried with Get-WinEvent -Path. Do not try to read them with Get-Content — the output will be unreadable binary data.

Official documentation

Related tools

  • Windows Event Log Analyzer — paste raw Event Log output and get an AI-powered summary of what went wrong and what to check next

Related guides