How to Get the Count of Blue Screen (BSOD) Events in Batch Script
A Blue Screen of Death (BSOD) is the most severe failure a Windows system can experience. While a single crash might be a fluke, a high count of BSOD events indicates failing hardware, corrupt drivers, or chronic system instability. By creating a Batch script that scans the System Event Log for crash-related entries, you can automatically audit a computer's reliability. This crash count is a vital metric for deciding whether a machine needs to be serviced, have drivers rolled back, or be replaced.
This guide will explain how to count, list, and analyze BSOD events using PowerShell from a Batch script.
Understanding BSOD Event IDs
Windows records crash information across multiple event IDs and sources. Using the right combination is essential for accurate counting.
| Event ID | Source | Log | What It Records |
|---|---|---|---|
| 41 | Kernel-Power | System | System rebooted without clean shutdown (kernel crash). Contains BugcheckCode. |
| 1001 | WER-SystemErrorReporting | System | Windows Error Reporting summary of the crash. Contains stop code and parameters. |
| 6008 | EventLog | System | Unexpected shutdown detected at next boot. Records the time of the dirty shutdown. |
Which to query:
- Event ID 41 (Kernel-Power) is the most direct indicator of a BSOD. It is generated by the kernel when the system recovers from a crash and contains the actual BugcheckCode (stop code).
- Event ID 1001 records the Windows Error Report for the crash, including the stop code, parameter values, and the faulting module. However, 1001 events are also generated for application crashes (not just BSODs), so they must be filtered by source.
- Event ID 6008 indicates any unexpected shutdown (including power loss), not just BSODs.
For accurate BSOD counting, query Event ID 41 (Kernel-Power). Event ID 1001 provides additional detail but requires source filtering to avoid counting application crashes.
Method 1: BSOD Count and Summary
This method counts kernel crash events (Event ID 41) within a configurable time window and displays a summary with stop codes.
@echo off
setlocal
set "DaysBack=90"
:: Verify admin privileges
net session >nul 2>&1
if errorlevel 1 (
echo [ERROR] Reading the System log requires administrator privileges. >&2
echo Right-click and select "Run as administrator." >&2
endlocal
exit /b 1
)
echo [INFO] Scanning for BSOD events in the last %DaysBack% days...
echo --------------------------------------------------
powershell -NoProfile -Command ^
"$events = Get-WinEvent -FilterHashtable @{" ^
" LogName='System';" ^
" ProviderName='Microsoft-Windows-Kernel-Power';" ^
" Id=41;" ^
" StartTime=(Get-Date).AddDays(-%DaysBack%)" ^
"} -ErrorAction SilentlyContinue;" ^
"if (-not $events) {" ^
" Write-Host \"No BSOD events found in the last %DaysBack% days.\";" ^
" Write-Host 'System appears stable.';" ^
" exit 0" ^
"};" ^
"Write-Host \"Found $($events.Count) BSOD event(s) in the last %DaysBack% days:`n\";" ^
"$events | ForEach-Object {" ^
" $xml = [xml]$_.ToXml();" ^
" $data = $xml.Event.EventData.Data;" ^
" $bugcheck = ($data | Where-Object Name -eq 'BugcheckCode').'#text';" ^
" $bugcheckHex = if ($bugcheck) { '0x{0:X8}' -f [int]$bugcheck } else { 'Unknown' };" ^
" $param1 = ($data | Where-Object Name -eq 'BugcheckParameter1').'#text';" ^
" [PSCustomObject]@{" ^
" Time = $_.TimeCreated.ToString('yyyy-MM-dd HH:mm:ss');" ^
" StopCode = $bugcheckHex;" ^
" Param1 = if ($param1) { '0x{0}' -f $param1 } else { '-' }" ^
" }" ^
"} | Format-Table -AutoSize;" ^
"Write-Host '';" ^
"$uniqueCodes = $events | ForEach-Object {" ^
" $xml = [xml]$_.ToXml();" ^
" ($xml.Event.EventData.Data | Where-Object Name -eq 'BugcheckCode').'#text'" ^
"} | Sort-Object -Unique;" ^
"Write-Host \"Unique stop codes: $($uniqueCodes.Count)\";" ^
"if ($events.Count -ge 3) {" ^
" Write-Host '';" ^
" Write-Host '[WARNING] Multiple BSODs detected. Investigation recommended.' -ForegroundColor Yellow;" ^
" exit 1" ^
"} else {" ^
" exit 0" ^
"}"
set "PSResult=%errorlevel%"
echo --------------------------------------------------
endlocal
exit /b %PSResult%
Sample output:
Found 4 BSOD event(s) in the last 90 days:
Time StopCode Param1
---- -------- ------
2024-05-08 14:22:15 0x0000000A 0xFFFFF80123456789
2024-05-01 09:15:30 0x000000D1 0xFFFFF80198765432
2024-04-22 03:47:12 0x0000000A 0xFFFFF80123456789
2024-04-15 18:33:45 0x0000001E 0xFFFFF80111111111
Unique stop codes: 3
[WARNING] Multiple BSODs detected. Investigation recommended.
How to interpret stop codes:
| Stop Code | Name | Common Cause |
|---|---|---|
0x0000000A | IRQL_NOT_LESS_OR_EQUAL | Driver accessing invalid memory at wrong IRQL |
0x000000D1 | DRIVER_IRQL_NOT_LESS_OR_EQUAL | Network or storage driver bug |
0x0000001E | KMODE_EXCEPTION_NOT_HANDLED | Driver or hardware exception |
0x00000050 | PAGE_FAULT_IN_NONPAGED_AREA | Faulty RAM or corrupt driver |
0x0000007E | SYSTEM_THREAD_EXCEPTION_NOT_HANDLED | Driver or firmware error |
0x000000EF | CRITICAL_PROCESS_DIED | Critical system process crashed |
Same stop code repeating: Points to a specific driver or hardware component. Look up the stop code and parameter values for targeted troubleshooting.
Different stop codes each time: Suggests a general hardware issue, most commonly failing RAM. Run Windows Memory Diagnostic (mdsched.exe).
Method 2: Detailed Crash Report with Minidump Check
For technician-level investigation, this method combines Event Log data with minidump file availability, the minidump is what analysis tools (like WinDbg or BlueScreenView) need to identify the faulting driver.
@echo off
setlocal
set "DaysBack=30"
set "MinidumpDir=%SystemRoot%\Minidump"
net session >nul 2>&1
if errorlevel 1 (
echo [ERROR] Administrator privileges required. >&2
endlocal
exit /b 1
)
echo [INFO] BSOD diagnostic report for the last %DaysBack% days:
echo --------------------------------------------------
:: Check for crash events
powershell -NoProfile -Command ^
"$crashes = Get-WinEvent -FilterHashtable @{" ^
" LogName='System';" ^
" ProviderName='Microsoft-Windows-Kernel-Power';" ^
" Id=41;" ^
" StartTime=(Get-Date).AddDays(-%DaysBack%)" ^
"} -ErrorAction SilentlyContinue;" ^
"if (-not $crashes) {" ^
" Write-Host 'No BSOD events in the last %DaysBack% days. System is stable.';" ^
" exit 0" ^
"};" ^
"Write-Host \"Crash events found: $($crashes.Count)`n\";" ^
"$crashes | ForEach-Object {" ^
" $xml = [xml]$_.ToXml();" ^
" $data = $xml.Event.EventData.Data;" ^
" $bc = ($data | Where-Object Name -eq 'BugcheckCode').'#text';" ^
" [PSCustomObject]@{" ^
" Date = $_.TimeCreated.ToString('yyyy-MM-dd HH:mm');" ^
" StopCode = if ($bc) { '0x{0:X8}' -f [int]$bc } else { 'N/A' }" ^
" }" ^
"} | Format-Table -AutoSize"
:: Check for minidump files
echo.
echo --- Minidump Files ---
if exist "%MinidumpDir%\*.dmp" (
echo Location: %MinidumpDir%
echo.
for %%f in ("%MinidumpDir%\*.dmp") do (
echo %%~nxf (%%~zf bytes, modified %%~tf^)
)
echo.
echo [INFO] Provide these files to a technician for analysis with WinDbg or BlueScreenView.
) else (
echo No minidump files found in %MinidumpDir%.
echo.
echo [INFO] Minidumps may be disabled. To enable:
echo Control Panel ^> System ^> Advanced ^> Startup and Recovery ^> Settings
echo Set "Write debugging information" to "Small memory dump"
)
echo --------------------------------------------------
endlocal
exit /b 0
Why minidumps are critical:
Event Log entries tell you when a crash occurred and the stop code, but they don't identify which driver caused it. The minidump file (C:\Windows\Minidump\*.dmp) contains the kernel stack trace at the moment of the crash. Loading it in WinDbg or BlueScreenView reveals the specific faulting driver (e.g., nvlddmkm.sys for NVIDIA, tcpip.sys for networking).
If no minidumps exist:
- Minidumps may be disabled in system settings.
- The system drive may have been too full to write the dump.
- On some SSDs, the crash happens too fast for the dump to complete.
Method 3: Fleet-Wide Crash Report
For IT administrators managing multiple machines, collect crash counts from each system into a shared CSV for fleet-wide stability monitoring.
@echo off
setlocal enabledelayedexpansion
set "DaysBack=90"
set "CSVFile=%USERPROFILE%\Desktop\bsod_report.csv"
set "PSScript=%TEMP%\bsod_check.ps1"
set "TempResult=%TEMP%\bsod_result.tmp"
:: Initialize variables
set "CrashCount=0"
set "LastCrash=None"
set "TopCode=N/A"
set "DmpCount=0"
:: Write header if file is new
if not exist "%CSVFile%" (
echo "Timestamp","Computer","CrashCount","MostRecentCrash","TopStopCode","MinidumpCount" > "%CSVFile%"
)
:: Create PowerShell script file (avoids all escaping issues)
(
echo $ErrorActionPreference = 'SilentlyContinue'
echo $days = %DaysBack%
echo $crashes = Get-WinEvent -FilterHashtable @{
echo LogName = 'System'
echo ProviderName = 'Microsoft-Windows-Kernel-Power'
echo Id = 41
echo StartTime = ^(Get-Date^).AddDays^(-$days^)
echo } -ErrorAction SilentlyContinue
echo.
echo $count = if ^($crashes^) { $crashes.Count } else { 0 }
echo $lastCrash = 'None'
echo $topCode = 'N/A'
echo.
echo if ^($crashes^) {
echo $lastCrash = $crashes[0].TimeCreated.ToString^('yyyy-MM-dd HH:mm'^)
echo $codes = $crashes ^| ForEach-Object {
echo $xml = [xml]$_.ToXml^(^)
echo ^($xml.Event.EventData.Data ^| Where-Object { $_.Name -eq 'BugcheckCode' }^).'#text'
echo } ^| Where-Object { $_ }
echo $grouped = $codes ^| Group-Object ^| Sort-Object Count -Descending ^| Select-Object -First 1
echo if ^($grouped^) { $topCode = '0x{0:X8}' -f [int]$grouped.Name }
echo }
echo.
echo $dmpCount = @^(Get-ChildItem "$env:SystemRoot\Minidump\*.dmp" -ErrorAction SilentlyContinue^).Count
echo Write-Output "$count|$lastCrash|$topCode|$dmpCount"
) > "%PSScript%"
:: Run the PowerShell script
powershell -NoProfile -ExecutionPolicy Bypass -File "%PSScript%" > "%TempResult%" 2>&1
:: Parse results
if exist "%TempResult%" (
for /f "usebackq tokens=1-4 delims=|" %%a in ("%TempResult%") do (
set "CrashCount=%%a"
set "LastCrash=%%b"
set "TopCode=%%c"
set "DmpCount=%%d"
)
)
:: Cleanup temp files
del "%PSScript%" 2>nul
del "%TempResult%" 2>nul
:: Generate timestamp
for /f "delims=" %%t in ('powershell -NoProfile -Command "Get-Date -Format \"yyyy-MM-dd HH:mm:ss\""') do set "Timestamp=%%t"
:: Append to CSV
echo "!Timestamp!","!COMPUTERNAME!","!CrashCount!","!LastCrash!","!TopCode!","!DmpCount!" >> "%CSVFile%"
:: Display results
echo.
echo ============================================
echo BSOD Report for !COMPUTERNAME!
echo ============================================
echo Crash Count: !CrashCount!
echo Most Recent: !LastCrash!
echo Top Stop Code: !TopCode!
echo Minidump Files: !DmpCount!
echo Report saved: %CSVFile%
echo ============================================
echo.
if "!CrashCount!"=="0" (
echo [OK] !COMPUTERNAME!: No BSODs in the last %DaysBack% days.
) else (
echo [ALERT] !COMPUTERNAME!: !CrashCount! BSOD^(s^) in %DaysBack% days.
)
endlocal
exit /b 0
What to look for in the fleet report:
- Machines with high crash counts: Prioritize for hardware diagnostics.
- Same stop code across multiple machines: May indicate a bad driver update pushed fleet-wide. Correlate the crash dates with recent driver or Windows Update deployments.
- Machines with crashes but zero minidumps: Minidumps are disabled or the drive was full. Enable minidumps on these machines for future diagnostics.
How to Avoid Common Errors
Wrong Way: Querying Event ID 1001 Without Source Filtering
:: OVERCOUNTS - Event ID 1001 is used for application crashes too, not just BSODs
wevtutil qe System "/q:*[System[(EventID=1001)]]" /f:text
Event ID 1001 from WER-SystemErrorReporting includes both BSOD crash reports AND application crash reports. Without filtering by the specific error type, your count will include every application crash, dramatically inflating the BSOD count.
Correct Way: Use Event ID 41 from Microsoft-Windows-Kernel-Power for accurate BSOD-only counting. This event is generated exclusively for kernel crashes.
Wrong Way: Counting wevtutil Output Lines
:: FRAGILE - counts lines containing "EventID: 1001" in text output
wevtutil qe System "/q:*[System[(EventID=1001)]]" /f:text | find /c "EventID: 1001"
This counts occurrences of the string EventID: 1001 in the text output. If the string appears in a message body or description (not just the event header), the count is inflated. Additionally, different Windows versions may format the text output differently.
Correct Way: Use Get-WinEvent with -FilterHashtable, which returns structured event objects that can be accurately counted with .Count.
Problem: No Results Despite Known Crashes
If the methods return zero results but you know the system has crashed recently:
- Audit policy: Ensure the System log is not restricted.
- Log size: The System log may have overwritten old entries. Check
eventvwr.msc> System log > Properties > Maximum log size. - Fast Startup: A crash during Fast Startup resume may not generate Event ID 41 in all cases.
- Event ID mismatch: Some crashes generate only Event ID 1001, not 41. Try querying both as a fallback.
Problem: Power Loss Counted as BSOD
Event ID 41 (Kernel-Power) can be triggered by power loss (unplugged cable, dead battery) in addition to actual BSODs. The BugcheckCode field helps distinguish them: a value of 0 typically indicates power loss rather than a software crash.
Solution: Filter out events where BugcheckCode is 0 if you want to count only true BSODs:
$crashes | Where-Object {
$xml = [xml]$_.ToXml()
($xml.Event.EventData.Data | Where-Object Name -eq 'BugcheckCode').'#text' -ne '0'
}
Best Practices and Rules
1. Use Event ID 41 (Kernel-Power) for BSOD Counting
Event ID 41 is the most reliable indicator of a kernel crash. Event ID 1001 includes application crashes and must be filtered by source. Event ID 6008 includes power losses. Event ID 41 specifically represents the kernel detecting a dirty shutdown with crash context.
2. Check Minidump Files for Root Cause
Event Log entries tell you when and what (stop code), but minidumps tell you why (which driver crashed). Always check %SystemRoot%\Minidump for .dmp files and provide them to your analysis tool or support team.
3. Look for Patterns in Stop Codes
- Same code repeating: A specific driver or hardware component is failing. Target your investigation.
- Different codes each time: A general hardware problem, most commonly bad RAM. Run
mdsched.exe(Windows Memory Diagnostic). - Crashes at similar times: May correlate with scheduled tasks, backup jobs, or thermal issues (afternoon overheating).
4. Track Across the Fleet
A sudden increase in BSODs across multiple machines often indicates a bad driver or Windows Update. Method 3's fleet report helps identify these patterns by correlating crash dates and stop codes across systems.
5. Export History Before Log Rotation
The System log is circular. On busy servers, crash events can be overwritten within weeks. Export crash data regularly (Method 3) to maintain a permanent reliability record.
Conclusions
Counting BSOD events transforms anecdotal "my computer keeps crashing" reports into hard, actionable data. By querying Event ID 41 for accurate kernel crash counts, extracting stop codes for targeted diagnosis, and checking for minidump files for root-cause analysis, you gain a complete picture of system stability. This professional auditing is a core part of hardware lifecycle management and ensures that unstable systems are identified and repaired before they cause data loss or extended downtime.