When troubleshooting Windows systems, distinguishing between intentional shutdowns and unexpected power losses is crucial. While standard shutdowns generate Event ID 1074 in the Windows Event Log, abrupt power interruptions leave different forensic traces.
Windows records power-related events under these important IDs:
- Event ID 41: "The system has rebooted without cleanly shutting down first" - Event ID 6008: "The previous system shutdown was unexpected" - Event ID 1001: "Windows Error Reporting events for improper shutdowns"
This PowerShell script checks for recent power-related shutdown events:
# PowerShell script to detect power failure shutdowns $lastBootTime = (Get-CimInstance -ClassName Win32_OperatingSystem).LastBootUpTime $powerEvents = Get-WinEvent -LogName System -MaxEvents 100 | Where-Object { ($_.Id -eq 41 -or $_.Id -eq 6008) -and $_.TimeCreated -ge $lastBootTime } if ($powerEvents) { Write-Host "Detected unclean shutdown(s) possibly from power failure:" $powerEvents | Format-Table TimeCreated, Id, Message -AutoSize } else { Write-Host "No recent power failure events detected" }
For deeper analysis, examine the Kernel-Power source events:
# Check detailed kernel power events Get-WinEvent -FilterHashtable @{ LogName='System' ProviderName='Microsoft-Windows-Kernel-Power' StartTime=(Get-Date).AddDays(-1) } | Format-List TimeCreated, Id, Message
Here's a complete monitoring solution that logs to a file:
# Persistent power failure monitor $logPath = "C:\Monitoring\PowerEvents.log" $today = Get-Date -Format "yyyy-MM-dd" $criticalEvents = Get-WinEvent -FilterHashtable @{ LogName='System' Id=@(41,6008,1001) StartTime=(Get-Date).AddDays(-1) } | Select-Object TimeCreated, Id, Message if ($criticalEvents) { Add-Content -Path $logPath -Value "n[$today] Power-related events detected:" $criticalEvents | ForEach-Object { Add-Content -Path $logPath -Value "$($_.TimeCreated) - ID $($_.Id)" } }
Key patterns indicating power failure:
- Event 41 followed by 6008 typically indicates power loss
- Missing "user initiated" shutdown events before reboot
- Short time difference between shutdown and startup events
Create a scheduled task to run this check periodically and email alerts:
# Email notification script $smtpServer = "smtp.yourdomain.com" $mailParams = @{ From = "monitor@yourdomain.com" To = "admin@yourdomain.com" Subject = "Power Failure Detected on $env:COMPUTERNAME" Body = "Critical power event detected: " + ($criticalEvents | Out-String) SmtpServer = $smtpServer } if ($criticalEvents) { Send-MailMessage @mailParams }
When troubleshooting Windows systems, distinguishing between intentional shutdowns and unexpected power losses is crucial. While standard shutdowns generate clear Event ID 1074 in the System log, power failures leave different forensic traces.
The Windows Event Log contains several critical indicators:
- Event ID 41: "The system has rebooted without cleanly shutting down first" (Kernel-Power source)
- Event ID 6008: "The previous system shutdown was unexpected"
- Event ID 1101: "Audit events have been dropped by the transport"
Here's a comprehensive PowerShell script to analyze shutdown events:
# Get all unexpected shutdown events from last 7 days
$StartTime = (Get-Date).AddDays(-7)
$ShutdownEvents = Get-WinEvent -LogName System | Where-Object {
($_.Id -eq 41 -or $_.Id -eq 6008) -and
$_.TimeCreated -ge $StartTime
}
# Analyze each event
$ShutdownEvents | ForEach-Object {
$Event = [xml]$_.ToXml()
$Time = $_.TimeCreated
$Reason = if ($_.Id -eq 41) {
"Critical power failure detected"
} else {
$Event.Event.EventData.Data | Where-Object Name -eq "ShutdownType" | Select-Object -ExpandProperty "#text"
}
[PSCustomObject]@{
Time = $Time
EventID = $_.Id
Reason = $Reason
Details = $Event.Event.EventData.Data | Out-String
}
}
For more precise filtering, use XPath queries with wevtutil:
wevtutil qe System /q:"*[System[(EventID=41 or EventID=6008)]]" /f:Text /rd:true /c:10
Genuine power failures typically show:
- No preceding shutdown initiation events
- Abrupt termination of running processes
- Possible hardware warnings before the crash (like temperature alerts)
- Missing proper service termination sequences
Create a scheduled task to log shutdown context:
$Trigger = New-ScheduledTaskTrigger -AtStartup
$Action = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument "-File C:\Scripts\LogShutdownContext.ps1"
Register-ScheduledTask -TaskName "Shutdown Monitor" -Trigger $Trigger -Action $Action -RunLevel Highest
The monitoring script (LogShutdownContext.ps1) could capture:
$LastShutdown = Get-WinEvent -FilterHashtable @{
LogName='System'
ID=6008
} -MaxEvents 1 -ErrorAction SilentlyContinue
if ($LastShutdown) {
$Details = @{
Timestamp = Get-Date
WasUnexpected = $true
LastBootTime = (Get-CimInstance Win32_OperatingSystem).LastBootUpTime
} | ConvertTo-Json
$Details | Out-File "C:\Logs\ShutdownAnalysis.json" -Append
}