How to Get System Boot Time from the Event Log in Batch Script
Knowing exactly when a computer last started is critical for troubleshooting uptime issues, verifying that a scheduled maintenance reboot actually occurred, or detecting unexpected crashes. While there are several ways to retrieve this information, the most reliable approach combines WMI queries (for the current boot time) with Event Log analysis (for historical boot and shutdown events). By querying Win32_OperatingSystem and scanning for specific event IDs, you can determine both the current uptime and the pattern of reboots over time.
This guide will explain how to extract boot time and uptime information using PowerShell from a Batch script.
Method 1: Current Boot Time and Uptime
This method retrieves the last boot time and calculates how long the system has been running, presented in a human-readable format.
@echo off
setlocal
echo [INFO] Querying system boot time and uptime...
echo.
powershell -NoProfile -Command ^
"try {" ^
" $os = Get-CimInstance Win32_OperatingSystem -ErrorAction Stop;" ^
" $boot = $os.LastBootUpTime;" ^
" $uptime = (Get-Date) - $boot;" ^
" Write-Host \" Boot Time: $($boot.ToString('yyyy-MM-dd HH:mm:ss'))\";" ^
" Write-Host \" Uptime: $($uptime.Days) days, $($uptime.Hours) hours, $($uptime.Minutes) minutes\";" ^
" Write-Host \" OS: $($os.Caption)\";" ^
" Write-Host '';" ^
" if ($uptime.Days -gt 30) {" ^
" Write-Host ' [WARNING] System has not been rebooted in over 30 days.' -ForegroundColor Yellow;" ^
" exit 1" ^
" } elseif ($uptime.Days -gt 14) {" ^
" Write-Host ' [INFO] System has been running for over 2 weeks.';" ^
" exit 0" ^
" } else {" ^
" Write-Host ' [OK] Uptime is within normal range.';" ^
" exit 0" ^
" }" ^
"} catch {" ^
" Write-Error $_.Exception.Message;" ^
" exit 2" ^
"}"
set "PSResult=%errorlevel%"
endlocal
exit /b %PSResult%
Sample output:
Boot Time: 2024-05-08 06:15:23
Uptime: 2 days, 8 hours, 17 minutes
OS: Microsoft Windows 11 Pro
[OK] Uptime is within normal range.
Why Get-CimInstance instead of wmic:
wmic.exeis deprecated since Windows 10 21H1.wmicreturnsLastBootUpTimeas a raw WMI datetime string (20240508061523.500000+060) that requires manual substring parsing in Batch. The\rcharacters inwmicoutput also corrupt the variable, causing the substring operations to extract wrong characters.Get-CimInstancereturnsLastBootUpTimeas a nativeDateTimeobject that PowerShell can format, compare, and calculate with directly.
Fast Startup warning:
Windows 10/11 "Fast Startup" is a partial hibernation. A standard "Shut Down" followed by a power-on does NOT reset LastBootUpTime, the system resumes from hibernation. Only a "Restart" (or disabling Fast Startup) performs a true boot. If your boot time seems older than expected, Fast Startup is likely the cause.
Method 2: Boot and Shutdown History from the Event Log
For verifying that scheduled reboots occurred, detecting unexpected crashes, or auditing reboot patterns, you need the Event Log history, not just the current boot time.
@echo off
setlocal
set "DaysBack=30"
set "MaxResults=20"
echo [INFO] Boot and shutdown history (last %DaysBack% days^):
echo --------------------------------------------------
powershell -NoProfile -Command ^
"$startTime = (Get-Date).AddDays(-%DaysBack%);" ^
"$events = @();" ^
"$bootEvents = Get-WinEvent -FilterHashtable @{" ^
" LogName='System';" ^
" Id=6005,6006,6008,6009,1074;" ^
" StartTime=$startTime" ^
"} -ErrorAction SilentlyContinue;" ^
"if (-not $bootEvents) {" ^
" Write-Host 'No boot/shutdown events found in the last %DaysBack% days.';" ^
" exit 0" ^
"};" ^
"$bootEvents | Sort-Object TimeCreated -Descending |" ^
" Select-Object -First %MaxResults% |" ^
" ForEach-Object {" ^
" $desc = switch ($_.Id) {" ^
" 6005 { 'Event Log Started (System Boot)' }" ^
" 6006 { 'Event Log Stopped (Clean Shutdown)' }" ^
" 6008 { 'UNEXPECTED SHUTDOWN (Crash/Power Loss)' }" ^
" 6009 { 'OS Version at Boot' }" ^
" 1074 { 'Shutdown Initiated by User/Process' }" ^
" };" ^
" [PSCustomObject]@{" ^
" Time = $_.TimeCreated.ToString('yyyy-MM-dd HH:mm:ss');" ^
" EventID = $_.Id;" ^
" Description = $desc" ^
" }" ^
" } | Format-Table -AutoSize -Wrap"
echo --------------------------------------------------
endlocal
exit /b 0
Event ID reference:
| Event ID | Log | Source | Meaning |
|---|---|---|---|
| 6005 | System | EventLog | The Event Log service started, indicates a system boot |
| 6006 | System | EventLog | The Event Log service stopped, indicates a clean shutdown |
| 6008 | System | EventLog | Unexpected shutdown (crash, power loss, BSOD) |
| 6009 | System | EventLog | OS version information logged at boot time |
| 1074 | System | User32 | Shutdown/restart initiated by a user or process (includes who/why) |
| 41 | System | Kernel-Power | System rebooted without clean shutdown (kernel-level crash) |
Sample output:
Time EventID Description
---- ------- -----------
2024-05-08 06:15:23 6005 Event Log Started (System Boot)
2024-05-08 06:15:20 6009 OS Version at Boot
2024-05-08 06:14:55 1074 Shutdown Initiated by User/Process
2024-05-08 06:14:50 6006 Event Log Stopped (Clean Shutdown)
2024-05-01 03:00:12 6005 Event Log Started (System Boot)
2024-05-01 03:00:01 6008 UNEXPECTED SHUTDOWN (Crash/Power Loss)
2024-04-28 22:30:45 6005 Event Log Started (System Boot)
2024-04-28 22:30:05 1074 Shutdown Initiated by User/Process
How to read the history:
- A 6006 (clean shutdown) followed by 6005 (boot) is a normal restart cycle.
- A 6008 (unexpected shutdown) followed by 6005 (boot) indicates the system crashed or lost power, investigate further.
- 1074 shows who initiated the shutdown and why, useful for verifying maintenance reboots.
Method 3: Uptime Report for Fleet Management
When managing multiple machines, you need each computer to report its boot time to a central location for identifying systems that need rebooting (e.g., for patch application).
@echo off
setlocal EnableDelayedExpansion
set "CSVFile=\\Server\Audit\uptime_report.csv"
:: Check network path first
if not exist "\\Server\Audit\" (
echo [ERROR] Network path not available: \\Server\Audit
exit /b 1
)
:: Write header if file is new
if not exist "%CSVFile%" (
echo "Computer","Timestamp","BootTime","UptimeDays","OS" > "%CSVFile%" 2>nul
)
for /f "usebackq tokens=1-4 delims=|" %%a in (`
powershell -NoProfile -Command ^
"$os = Get-CimInstance Win32_OperatingSystem; ^
$boot = $os.LastBootUpTime; ^
$uptime = ((Get-Date) - $boot).Days; ^
$ts = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'; ^
$bootStr = $boot.ToString('yyyy-MM-dd HH:mm:ss'); ^
Write-Output ($ts + '^|' + $bootStr + '^|' + $uptime + '^|' + $os.Caption)"
`) do (
>>"%CSVFile%" echo "%COMPUTERNAME%","%%a","%%b","%%c","%%d"
)
if errorlevel 1 (
echo [WARNING] Could not write to: %CSVFile% >&2
)
endlocal
exit /b 0
Deployment:
Run this script on each machine via Group Policy logon script, scheduled task, or deployment tool. Each machine appends one row to the shared CSV. Sort by the UptimeDays column to find systems that haven't been rebooted, these are likely missing security patches that require a restart.
Method 4: Shutdown Initiator Details
Event ID 1074 contains rich information about who or what triggered a shutdown/restart. This method extracts those details for specific investigation.
@echo off
setlocal
set "MaxResults=5"
echo [INFO] Recent shutdown/restart initiators:
echo --------------------------------------------------
powershell -NoProfile -Command ^
"$events = Get-WinEvent -FilterHashtable @{" ^
" LogName='System';" ^
" Id=1074" ^
"} -MaxEvents %MaxResults% -ErrorAction SilentlyContinue;" ^
"if (-not $events) {" ^
" Write-Host 'No shutdown events found.';" ^
" exit 0" ^
"};" ^
"$events | ForEach-Object {" ^
" $xml = [xml]$_.ToXml();" ^
" $data = $xml.Event.EventData.Data;" ^
" $process = ($data | Where-Object Name -eq 'param1').'#text';" ^
" $user = ($data | Where-Object Name -eq 'param6').'#text';" ^
" $reason = ($data | Where-Object Name -eq 'param3').'#text';" ^
" $action = ($data | Where-Object Name -eq 'param5').'#text';" ^
" [PSCustomObject]@{" ^
" Time = $_.TimeCreated.ToString('yyyy-MM-dd HH:mm:ss');" ^
" Action = if ($action) { $action } else { 'shutdown' };" ^
" InitiatedBy = if ($user) { $user } else { 'SYSTEM' };" ^
" Process = $process;" ^
" Reason = if ($reason) { $reason } else { 'No reason given' }" ^
" }" ^
"} | Format-Table -AutoSize -Wrap"
endlocal
exit /b 0
Sample output:
Time Action InitiatedBy Process Reason
---- ------ ----------- ------- ------
2024-05-08 06:14:55 restart CORP\admin C:\Windows\system32\shutdown.exe Operating System: Service pack (Planned)
2024-05-01 02:59:58 restart NT AUTHORITY\SYSTEM C:\Windows\servicing\TrustedInstaller.exe Operating System: Security fix (Planned)
2024-04-28 22:30:02 restart CORP\admin C:\Windows\system32\shutdown.exe Other (Planned)
Why this is valuable:
- Verifying maintenance: Confirms that the 3 AM reboot was initiated by
TrustedInstaller.exe(Windows Update), not by an unauthorized user. - Identifying unexpected reboots: If the process is not
shutdown.exeorTrustedInstaller.exe, investigate why. - Accountability: Shows exactly which user account triggered each restart.
How to Avoid Common Errors
Wrong Way: Using net statistics workstation
:: MISLEADING: shows when the Workstation service started, not the OS
net stats workstation | findstr "since"
This shows when the Workstation service started. With Fast Startup enabled, the service may persist across shutdowns, giving an incorrect (older) time. Additionally, if the Workstation service is restarted independently, the time resets without a reboot.
Correct Way: Use Get-CimInstance Win32_OperatingSystem for the current boot time, or Event IDs 6005/1074 for the historical record.
Wrong Way: Using wmic for Boot Time
:: BROKEN: wmic output contains \r characters that corrupt substring parsing
for /f "tokens=2 delims==" %%a in ('wmic os get lastbootuptime /value') do set "boot=%%a"
set "year=%boot:~0,4%"
The \r at the end of %%a shifts all substring positions, causing %boot:~8,2% to extract the wrong characters. The result is a garbled date.
Correct Way: Use PowerShell's Get-CimInstance, which returns a native DateTime object that can be formatted directly.
Problem: Fast Startup Makes Boot Time Stale
With Fast Startup enabled (default on Windows 10/11), a "Shut Down" + power-on does not reset LastBootUpTime because Windows resumes from hibernation rather than performing a cold boot.
Solution: Be aware that LastBootUpTime on client workstations may show a date older than the last power cycle. Only a "Restart" or a shutdown with Fast Startup disabled performs a true boot. For accurate reboot verification, check Event ID 6005 (Event Log started) in the System log, which IS recorded on both true boots and Fast Startup resumes.
Problem: Event Log Overwritten
On busy servers, the System log may overwrite boot events within weeks. If you need a 6-month reboot history, the events may already be gone.
Solution: Use Method 3 to export boot times to a CSV at regular intervals, creating a permanent record that survives log rotation.
Best Practices and Rules
1. Check Event ID 6008 After Every Boot
After a boot event (6005), check whether it was preceded by a clean shutdown (6006) or an unexpected shutdown (6008). An unexpected shutdown indicates a crash, BSOD, or power loss that may need investigation.
2. Use Event ID 1074 for Accountability
Event ID 1074 records who initiated a restart and why. This is essential for verifying maintenance windows and investigating unexpected reboots.
3. Account for Fast Startup on Workstations
On client machines, LastBootUpTime may not reflect the most recent power cycle due to Fast Startup. For strict uptime tracking, either disable Fast Startup via Group Policy or supplement WMI queries with Event Log checks.
4. Export Boot History for Fleet Management
Run Method 3 on every machine via logon script or scheduled task. Sort the resulting CSV by UptimeDays to identify machines that haven't been rebooted, these are likely missing pending patches.
5. Set Uptime Thresholds
Systems that haven't rebooted in 30+ days are likely missing critical security updates. Method 1 includes a configurable threshold that flags systems exceeding 30 days of uptime.
Conclusions
Retrieving system boot time and history is a fundamental step in system diagnostics. By combining Get-CimInstance for current uptime, Event Log scanning for historical boot and shutdown records, and Event ID 1074 for shutdown accountability, you gain a complete picture of your systems' lifecycle. This visibility ensures you can verify maintenance windows, detect unexpected crashes, identify systems needing reboots for patches, and maintain clear documentation of your environment's availability.