Event Viewer is fine for occasional manual checks. It breaks down the moment you need to search across multiple machines, filter by time range, correlate events by ID, or automate any part of the process. Get-WinEvent is the PowerShell cmdlet that covers all of that — it queries any event log on any machine, supports structured filtering that runs server-side, and returns objects you can sort, group, and export without parsing text.
This guide covers practical filtering patterns for real troubleshooting scenarios: failed logins, service crashes, application errors, and targeted queries across multiple machines. It also covers where Get-WinEvent fits alongside the Windows Event Log Analyzer tool for faster triage of unfamiliar log entries.
Quick answer
Get the last 50 errors from the System log:
Get-WinEvent -LogName System -MaxEvents 50 | Where-Object { $_.LevelDisplayName -eq "Error" }
Get all failed login attempts (Event ID 4625) from the Security log:
Get-WinEvent -LogName Security -FilterXPath "*[System[EventID=4625]]" -MaxEvents 100
Get-WinEvent vs Get-EventLog
Windows PowerShell has two cmdlets for reading event logs. Use Get-WinEvent. The older Get-EventLog only accesses classic Windows logs (Application, System, Security) and cannot query modern ETW-based logs like Microsoft-Windows-DNS-Client/Operational or any provider-specific log. Get-WinEvent covers all of them.
Get-EventLog is deprecated. It still works on current Windows versions but has no equivalent in PowerShell 7+ on non-Windows platforms and will eventually be removed. Build new scripts with Get-WinEvent from the start.
Filtering methods
Get-WinEvent supports three filtering approaches. Understanding which to use matters for performance — especially when querying large logs or remote machines.
| Method | Parameter | Runs server-side | Best for |
|---|---|---|---|
| XPath filter | -FilterXPath | Yes | Event ID, time range, single conditions |
| Hashtable filter | -FilterHashtable | Yes | Multiple conditions, readable syntax |
| Where-Object | (pipeline) | No | Post-fetch filtering on returned objects |
Server-side filtering means the query runs on the machine where the log lives — only matching events are transferred. Where-Object fetches everything first and filters locally, which is slow on large logs and generates unnecessary network traffic on remote queries.
-FilterHashtable as your default. It is more readable than XPath and still runs server-side. Reserve -FilterXPath for conditions that hashtable filtering does not support — like filtering on specific event data fields inside the XML body.
Common Event IDs reference
These are the Event IDs that come up most often in day-to-day admin work:
| Event ID | Log | Meaning |
|---|---|---|
| 4624 | Security | Successful logon |
| 4625 | Security | Failed logon attempt |
| 4634 | Security | Account logoff |
| 4648 | Security | Logon attempt with explicit credentials |
| 4720 | Security | User account created |
| 4740 | Security | User account locked out |
| 4776 | Security | Domain controller credential validation |
| 7034 | System | Service terminated unexpectedly |
| 7036 | System | Service entered running or stopped state |
| 1074 | System | System was shut down or restarted |
| 41 | System | System rebooted without clean shutdown (crash/power loss) |
| 1000 | Application | Application crash |
| 1001 | Application | Windows Error Reporting — follow-up to crash |
Practical filtering examples
Filter by Event ID and time range
The most common query pattern: find all occurrences of a specific Event ID within a time window. Use -FilterHashtable with StartTime and EndTime for clean, readable syntax:
# Find all failed logins in the last 24 hours
# StartTime filters server-side — only matching events are returned
Get-WinEvent -FilterHashtable @{
LogName = 'Security'
Id = 4625
StartTime = (Get-Date).AddDays(-1)
} | Select-Object TimeCreated, Message | Format-List
# Find service crashes in the last 7 days
Get-WinEvent -FilterHashtable @{
LogName = 'System'
Id = 7034
StartTime = (Get-Date).AddDays(-7)
} | Select-Object TimeCreated, Message
Filter by severity level
Event levels map to numeric values in the filter: 1 = Critical, 2 = Error, 3 = Warning, 4 = Information, 5 = Verbose. Use the Level key in the hashtable:
# Get all Critical and Error events from the System log in the last hour
Get-WinEvent -FilterHashtable @{
LogName = 'System'
Level = 1, 2 # 1 = Critical, 2 = Error
StartTime = (Get-Date).AddHours(-1)
} | Select-Object TimeCreated, LevelDisplayName, Message
Search event message text
When you know a keyword but not the Event ID, use Where-Object to filter on the message text. This runs client-side, so combine it with a server-side time filter to keep the result set manageable:
# Find Application log events mentioning a specific service name
# StartTime runs server-side, Where-Object runs client-side on the returned set
Get-WinEvent -FilterHashtable @{
LogName = 'Application'
StartTime = (Get-Date).AddDays(-3)
} | Where-Object { $_.Message -like "*Spooler*" } |
Select-Object TimeCreated, Id, LevelDisplayName, Message
Query a remote machine
Add -ComputerName to run the same query against any machine on the network. Credentials, firewall rules, and WinRM availability permitting:
# Query failed logins on a remote domain controller
# Requires WinRM to be enabled and appropriate permissions on the remote machine
Get-WinEvent -ComputerName SRV-DC-01 -FilterHashtable @{
LogName = 'Security'
Id = 4625
StartTime = (Get-Date).AddHours(-4)
} | Select-Object TimeCreated, Message
Enable-PSRemoting) and the querying account to have read permissions on the Security log — which typically means membership in the Event Log Readers group or local administrator rights on the target.
Query across multiple machines
Loop through a list of servers to aggregate results from multiple machines into a single output:
# Check for service crashes on a list of servers over the last 24 hours
$servers = 'SRV-APP-01', 'SRV-APP-02', 'SRV-WEB-01'
foreach ($server in $servers) {
Write-Host "--- $server ---"
Get-WinEvent -ComputerName $server -FilterHashtable @{
LogName = 'System'
Id = 7034
StartTime = (Get-Date).AddDays(-1)
} -ErrorAction SilentlyContinue |
Select-Object TimeCreated, Message |
Format-List
}
-ErrorAction SilentlyContinue prevents the loop from stopping if one machine is unreachable. Remove it during development so you can see connection errors clearly.
Query provider-specific logs
Beyond Application/System/Security, Windows has hundreds of provider-specific logs under Applications and Services Logs. These are not accessible with Get-EventLog — only with Get-WinEvent:
# List all available logs — useful for finding the exact log name
Get-WinEvent -ListLog * | Where-Object { $_.RecordCount -gt 0 } |
Select-Object LogName, RecordCount | Sort-Object LogName
# Query the DNS Client operational log — not available via Get-EventLog
Get-WinEvent -LogName 'Microsoft-Windows-DNS-Client/Operational' -MaxEvents 50 |
Select-Object TimeCreated, Id, Message
Get-WinEvent -ListLog 'Microsoft-Windows-DNS-Client/Operational' | Select-Object IsEnabled. Enable with wevtutil sl "LogName" /e:true.
Exporting results
Event objects contain more fields than what Format-List shows. Export to CSV for further analysis or to share with others:
# Export failed logins to CSV — useful for sharing or analysis in Excel
Get-WinEvent -FilterHashtable @{
LogName = 'Security'
Id = 4625
StartTime = (Get-Date).AddDays(-7)
} | Select-Object TimeCreated, Id, LevelDisplayName, Message |
Export-Csv -Path C:\bat\failed-logins.csv -NoTypeInformation
For structured reporting, format results as a table and write to a text file:
# Write a summary of recent System errors to a text report
Get-WinEvent -FilterHashtable @{
LogName = 'System'
Level = 1, 2
StartTime = (Get-Date).AddDays(-1)
} | Select-Object TimeCreated, Id, LevelDisplayName, Message |
Format-Table -AutoSize |
Out-File -FilePath C:\bat\system-errors-report.txt
Using Event Log Analyzer for unfamiliar events
When a query returns events with cryptic descriptions or XML payloads you have not seen before, the fastest path to understanding is the Windows Event Log Analyzer tool. Paste the raw event XML — which you can get with $event.ToXml() — and it explains what the event means and what to check next.
# Get raw XML for a specific event — paste into Event Log Analyzer for AI analysis
$events = Get-WinEvent -FilterHashtable @{
LogName = 'System'
Id = 41
StartTime = (Get-Date).AddDays(-30)
} -MaxEvents 1
# Output the full XML body of the first result
$events[0].ToXml()
Tips and limitations
- Security log requires elevation. Querying the Security log locally requires the session to be running as administrator. Without elevation,
Get-WinEvent -LogName Securityreturns an access denied error. On domain controllers, the account also needsManage auditing and security logrights. - Always use server-side filtering on large logs. The Security log on an active domain controller can contain millions of records. Using only
Where-Objectwithout a-FilterHashtableStartTime will attempt to load the entire log into memory — expect it to be very slow or fail entirely. - -MaxEvents limits results from the newest end.
-MaxEvents 100returns the 100 most recent matching events. There is no built-in equivalent for oldest-first without sorting after the fact. - Message text is localized. The
Messageproperty is generated at query time using the local machine’s language pack. The same event queried from an English and a German Windows machine can produce different message text. The Event ID and XML data are always consistent regardless of locale. - Some logs require enabling before they capture anything. Operational logs under
Applications and Services Logsare often disabled by default. Query them withGet-WinEvent -ListLogto checkIsEnabledbefore wondering why they are empty.
Official documentation
- Get-WinEvent — Microsoft Learn — full parameter reference including XPath filtering and hashtable syntax
Related tools
- Windows Event Log Analyzer — paste raw event XML for AI-powered explanation and next-step suggestions
Related guides
- DCDIAG — Active Directory troubleshooting — AD health checks that often surface issues visible in Security event logs
- NLTEST command — domain trust and replication diagnostics that pair with Security log analysis
- Fix trust relationship between workstation and domain — a common scenario where Security event log analysis is part of the diagnosis
- PowerShell Commands Cheat Sheet — quick reference for PowerShell commands used in event log workflows