igneum/relay/playbooks/boot-check.ps1

30 lines
3.2 KiB
PowerShell

# Was this boot a power loss or a hard reset? (MF-11, 7 October 2026.) Reads the current boot's time, the Kernel-Power 41
# and EventLog 6008 entries since it, the last clean-shutdown marks (1074, 6006) before it, and the video controllers
# (an eGPU just fitted shows here). Read-only; nothing is sent to the installed app. Every finding is a RESULT line.
$ErrorActionPreference = 'Continue'
function Say([string]$m) { Write-Host ((Get-Date -Format 'HH:mm:ss') + ' ' + $m) }
$os = Get-CimInstance Win32_OperatingSystem
$boot = $os.LastBootUpTime
$bootUtc = $boot.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.000Z')
$beforeUtc = $boot.AddHours(-6).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.000Z')
Say ('RESULT boot ' + $boot.ToUniversalTime().ToString('o') + ' UTC (local ' + $boot.ToString('o') + ')')
function Q([string]$xpath, [int]$count) {
try { & wevtutil.exe qe System ('/q:' + $xpath) /f:text ('/c:' + $count) /rd:true 2>&1 | ForEach-Object { "$_" } } catch { @('wevtutil failed: ' + $_.Exception.Message) }
}
$lines = Q ("*[System[(EventID=41 or EventID=6008) and TimeCreated[@SystemTime>='" + $bootUtc + "']]]") 4
$ids = @($lines | Where-Object { $_ -match '^\s*Event ID: (\d+)' } | ForEach-Object { $Matches[1] })
$dates = @($lines | Where-Object { $_ -match '^\s*Date: (\S+)' } | ForEach-Object { $Matches[1] })
if ($ids.Count -gt 0) { Say ('RESULT unexpected-shutdown YES: event ' + ($ids -join ', ') + ' at ' + ($dates -join ', ') + ' (this boot followed a power loss, a hard reset or a hang; no clean shutdown was recorded)') }
else { Say 'RESULT unexpected-shutdown NO: neither 41 nor 6008 since this boot (a clean shutdown or restart preceded it)' }
$clean = Q ("*[System[(EventID=1074 or EventID=6006 or EventID=13) and TimeCreated[@SystemTime>='" + $beforeUtc + "'] and TimeCreated[@SystemTime<='" + $bootUtc + "']]]") 6
$cids = @($clean | Where-Object { $_ -match '^\s*Event ID: (\d+)' } | ForEach-Object { $Matches[1] })
$cdates = @($clean | Where-Object { $_ -match '^\s*Date: (\S+)' } | ForEach-Object { $Matches[1] })
if ($cids.Count -gt 0) { Say ('RESULT clean-shutdown-before-boot: event ' + ($cids -join ', ') + ' at ' + ($cdates -join ', ')) } else { Say 'RESULT clean-shutdown-before-boot: none in the six hours before this boot' }
$who = Q ("*[System[Provider[@Name='User32'] and (EventID=1074) and TimeCreated[@SystemTime>='" + $beforeUtc + "']]]") 2
$who | Where-Object { $_ -match 'Description|process|reason|user' } | Select-Object -First 6 | ForEach-Object { Say (' 1074: ' + $_.Trim()) }
$bug = Q ("*[System[(EventID=1001) and Provider[@Name='Microsoft-Windows-WER-SystemErrorReporting'] and TimeCreated[@SystemTime>='" + $beforeUtc + "']]]") 2
if (@($bug | Where-Object { $_ -match 'Event ID: 1001' }).Count -gt 0) { Say 'RESULT bugcheck 1001 recorded since six hours before this boot' } else { Say 'RESULT bugcheck: none' }
try { Get-CimInstance Win32_VideoController | ForEach-Object { Say ('RESULT video ' + $_.Name + ' driver ' + $_.DriverVersion + ' status ' + $_.Status + ' pnp ' + $_.PNPDeviceID) } } catch { }
try { & nvidia-smi --query-gpu=index,name,pci.bus_id,driver_version --format=csv,noheader 2>&1 | ForEach-Object { Say ('RESULT nvidia ' + "$_") } } catch { }
Say ('RESULT uptime ' + [int]((Get-Date) - $boot).TotalSeconds + ' s')
exit 0