Event Viewer shows one log at a time and takes a while to load a busy one. Get-WinEvent reads the same logs from PowerShell, filters them on the server before anything is sent back, and gives you objects you can sort, count, and export. Run PowerShell as administrator: the Security log and some others can’t be read without it.
List the logs on a server
PS> Get-WinEvent -ListLog * | Where-Object RecordCount | Sort-Object RecordCount -Descending | Select-Object -First 5 LogName, RecordCount, FileSize# trimmed: the five largest logs, with their event counts and sizes in bytes
The three you’ll read most are System (the kernel, drivers, and services), Application (programs and server roles), and Security (logons and audit events). Many roles write to their own log under Applications and Services Logs, such as Microsoft-Windows-TaskScheduler/Operational.
Find the errors of the last day
PS> Get-WinEvent -FilterHashtable @{LogName='System'; Level=2; StartTime=(Get-Date).AddDays(-1)} ProviderName: Service Control Manager TimeCreated Id LevelDisplayName Message----------- -- ---------------- -------24/10/2026 03:12:40 7034 Error The Print Spooler service terminated unexpectedly. It has done this 1 time(s).# dates print in the server's regional format
A filter hashtable is turned into a query that the Event Log service runs, so only the matching events reach PowerShell. Piping every event into Where-Object gives the same result, but the whole log is read and sent first, which takes minutes on a Security log with millions of entries.
| Key | Matches |
|---|---|
LogName | One log or several: 'System', 'Application' |
Level | The severity, as a number (below) |
Id | One event ID or several: 41, 6008, 1074 |
ProviderName | The source that wrote the event, as Event Viewer shows it: 'Service Control Manager' |
StartTime | Events from this time on: (Get-Date).AddHours(-6) |
EndTime | Events up to this time |
| Level | Means |
|---|---|
| 1 | Critical |
| 2 | Error |
| 3 | Warning |
| 4 | Information |
| 5 | Verbose |
Read one event in full
The table cuts long messages off at the edge of the window. Format-List prints every field, and -MaxEvents limits the output to the newest matches.
PS> Get-WinEvent -FilterHashtable @{LogName='System'; Id=1074} -MaxEvents 1 | Format-List TimeCreated, Id, ProviderName, MessagePS> Get-WinEvent -FilterHashtable @{LogName='System'; Level=1,2} -MaxEvents 20 | Select-Object TimeCreated, Id, ProviderName, Message
Event IDs worth knowing
| Log | ID | Provider | What happened |
|---|---|---|---|
| System | 41 | Microsoft-Windows-Kernel-Power | The server restarted without shutting down cleanly: power loss, a hard reset, or a crash |
| System | 6008 | EventLog | The previous shutdown was unexpected, with its date and time |
| System | 6005, 6006 | EventLog | The Event Log service started (the server booted) and stopped (a clean shutdown) |
| System | 1074 | User32 | A process or a user started a restart or shutdown, with the account and the reason given |
| System | 7031, 7034 | Service Control Manager | A service stopped unexpectedly. 7031 also says what recovery action follows. |
| Security | 4624 | Microsoft-Windows-Security-Auditing | An account logged on |
| Security | 4625 | Microsoft-Windows-Security-Auditing | A logon failed, with the account name and the source address |
| Security | 4740 | Microsoft-Windows-Security-Auditing | An account was locked out. For domain accounts, it’s logged on the domain controllers. |
To find out why a server restarted, ask for the four IDs that explain a restart. Get-WinEvent lists the newest first.
PS> Get-WinEvent -FilterHashtable @{LogName='System'; Id=41,1074,6006,6008; StartTime=(Get-Date).AddDays(-2)} | Format-Table TimeCreated, Id, Message -WrapA 1074 before the restart means somebody or something asked for it, Windows Update included. A 41 or 6008 without a 1074 means it wasn’t planned.
To count the services that stopped unexpectedly in the last seven days, group the events by the service’s name, the first value in each event’s data:
PS> Get-WinEvent -FilterHashtable @{LogName='System'; ProviderName='Service Control Manager'; Id=7031,7034; StartTime=(Get-Date).AddDays(-7)} | Group-Object { $_.Properties[0].Value } | Sort-Object Count -Descending | Select-Object Count, NameQuery another server
PS> Get-WinEvent -ComputerName srv02 -FilterHashtable @{LogName='System'; Level=1,2; StartTime=(Get-Date).AddDays(-1)}PS> Invoke-Command -ComputerName srv02, srv03 -ScriptBlock { Get-WinEvent -FilterHashtable @{LogName='System'; Level=1,2; StartTime=(Get-Date).AddDays(-1)} }
-ComputerName on Get-WinEvent uses the Remote Event Log Management protocol over RPC, so the target’s firewall has to allow the Remote Event Log Management rule group. Invoke-Command runs the query over WinRM instead, on several servers at once, and adds a PSComputerName field to every event so you can tell them apart.
Export the result
PS> Get-WinEvent -FilterHashtable @{LogName='System'; Level=1,2; StartTime=(Get-Date).AddDays(-7)} | Select-Object TimeCreated, Id, ProviderName, Message | Export-Csv -Path C:\Temp\system-errors.csv -NoTypeInformation -Encoding UTF8-NoTypeInformation keeps Windows PowerShell 5.1 from writing a type line above the header (PowerShell 7 leaves it out by default). -Encoding UTF8 keeps umlauts and other non-ASCII characters intact in 5.1, which otherwise writes ASCII.
Last checked on 24 October 2026 against Windows Server 2019, Windows Server 2022, Windows Server 2025, Windows PowerShell 5.1, and PowerShell 7.4. If a step doesn’t match what you see, contact us with the command and what it printed.