Skip to main content

How to Get the Last Shutdown Time in Batch Script

Detecting when a computer was last shut down is critical for forensic auditing, troubleshooting power issues, or verifying that a server maintenance window was followed. Unlike boot time (which is stored as a property in the OS class), the shutdown time must be extracted from the Windows Event Log. Windows records specific events when the system shuts down, both for graceful shutdowns and unexpected crashes, providing a permanent historical record of power cycles.

This guide will explain how to find the last shutdown timestamp and analyze shutdown history using PowerShell from a Batch script.

Shutdown Event IDs Reference

Before querying, it's important to understand which events Windows records during shutdown:

Event IDSourceMeaningContains
1074User32Shutdown/restart initiated by a user or processWho initiated it, which process, reason
6006EventLogEvent Log service stopped (clean shutdown signal)Timestamp only
6008EventLogUnexpected shutdown (crash, power loss, BSOD)Date/time of the unexpected stop
41Kernel-PowerSystem rebooted without clean shutdownBug check code, power state

Event ID 1074 is the most informative, it tells you not just when the shutdown happened, but who triggered it, which process was responsible, and why.

Method 1: Last Shutdown Summary

This method finds the most recent shutdown event of any type and displays a comprehensive summary including the type, time, and initiator.

@echo off
setlocal

:: 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] Finding the last shutdown event...
echo --------------------------------------------------

powershell -NoProfile -Command ^
"$shutdownIds = 1074, 6006, 6008, 41;" ^
"$events = Get-WinEvent -FilterHashtable @{" ^
" LogName='System';" ^
" Id=$shutdownIds" ^
"} -MaxEvents 50 -ErrorAction SilentlyContinue;" ^
"if (-not $events) {" ^
" Write-Host 'No shutdown events found in the System log.';" ^
" exit 0" ^
"};" ^
"$last = $events | Sort-Object TimeCreated -Descending | Select-Object -First 1;" ^
"Write-Host '';" ^
"Write-Host \" Event ID: $($last.Id)\";" ^
"Write-Host \" Time: $($last.TimeCreated.ToString('yyyy-MM-dd HH:mm:ss'))\";" ^
"$desc = switch ($last.Id) {" ^
" 1074 {" ^
" $xml = [xml]$last.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';" ^
" Write-Host \" Action: $(if ($action) { $action } else { 'shutdown' })\";" ^
" Write-Host \" Initiated By: $(if ($user) { $user } else { 'SYSTEM' })\";" ^
" Write-Host \" Process: $process\";" ^
" Write-Host \" Reason: $(if ($reason) { $reason } else { 'No reason given' })\";" ^
" 'Planned shutdown/restart'" ^
" }" ^
" 6006 { 'Clean shutdown (Event Log service stopped)' }" ^
" 6008 {" ^
" Write-Host ' [WARNING] This was an UNEXPECTED shutdown (crash or power loss).' -ForegroundColor Red;" ^
" 'Unexpected/dirty shutdown'" ^
" }" ^
" 41 {" ^
" Write-Host ' [WARNING] Kernel-level crash - system rebooted without clean shutdown.' -ForegroundColor Red;" ^
" 'Kernel power failure'" ^
" }" ^
"};" ^
"Write-Host \" Type: $desc\";" ^
"Write-Host ''"

echo --------------------------------------------------

endlocal
exit /b 0

Sample output (planned restart):

Event ID: 1074
Time: 2024-05-10 03:00:15
Action: restart
Initiated By: NT AUTHORITY\SYSTEM
Process: C:\Windows\servicing\TrustedInstaller.exe
Reason: Operating System: Security fix (Planned)
Type: Planned shutdown/restart

Sample output (unexpected crash):

Event ID: 6008
Time: 2024-05-09 14:22:08
[WARNING] This was an UNEXPECTED shutdown (crash or power loss).
Type: Unexpected/dirty shutdown

Why this queries multiple event IDs:

A system might shut down cleanly (producing 1074 and 6006), crash (producing 6008 and 41), or experience a power loss (producing only 6008 or 41 after the next boot). Querying a single event ID would miss certain shutdown types. By querying all four IDs and taking the most recent, you always find the last shutdown regardless of type.

Method 2: Shutdown History Report

For auditing power cycles over time, verifying maintenance schedules, detecting patterns of instability, or tracking how often a server is restarted.

@echo off
setlocal

set "DaysBack=30"
set "MaxResults=20"

net session >nul 2>&1
if errorlevel 1 (
echo [ERROR] Administrator privileges required. >&2
endlocal
exit /b 1
)

echo [INFO] Shutdown history for the last %DaysBack% days:
echo --------------------------------------------------

powershell -NoProfile -Command ^
"$events = Get-WinEvent -FilterHashtable @{" ^
" LogName='System';" ^
" Id=1074, 6006, 6008, 41;" ^
" StartTime=(Get-Date).AddDays(-%DaysBack%)" ^
"} -ErrorAction SilentlyContinue;" ^
"if (-not $events) {" ^
" Write-Host 'No shutdown events found in the last %DaysBack% days.';" ^
" exit 0" ^
"};" ^
"$results = $events | Sort-Object TimeCreated -Descending |" ^
" Select-Object -First %MaxResults% |" ^
" ForEach-Object {" ^
" $evt = $_;" ^
" $type = switch ($evt.Id) {" ^
" 1074 {" ^
" $xml = [xml]$evt.ToXml();" ^
" $data = $xml.Event.EventData.Data;" ^
" $action = ($data | Where-Object Name -eq 'param5').'#text';" ^
" $user = ($data | Where-Object Name -eq 'param6').'#text';" ^
" $actionStr = if ($action) { $action } else { 'shutdown' };" ^
" $userStr = if ($user) { $user } else { 'SYSTEM' };" ^
" ($actionStr + ' (' + $userStr + ')')" ^
" }" ^
" 6006 { 'Clean shutdown' }" ^
" 6008 { '*** UNEXPECTED ***' }" ^
" 41 { '*** KERNEL CRASH ***' }" ^
" };" ^
" [PSCustomObject]@{" ^
" Time = $evt.TimeCreated.ToString('yyyy-MM-dd HH:mm:ss');" ^
" EventID = $evt.Id;" ^
" Type = $type" ^
" }" ^
" };" ^
"Write-Host ('Found ' + $results.Count + ' shutdown event(s):');" ^
"$results | Format-Table -AutoSize -Wrap;" ^
"$crashes = ($results | Where-Object { $_.EventID -in 6008, 41 }).Count;" ^
"if ($crashes -gt 0) {" ^
" Write-Host (' [WARNING] ' + $crashes + ' unexpected shutdown(s) detected in this period.') -ForegroundColor Yellow" ^
"}"

echo --------------------------------------------------

endlocal
exit /b 0

Sample output:

Found 8 shutdown event(s):

Time EventID Type
---- ------- ----
2024-05-10 03:00:15 1074 restart (NT AUTHORITY\SYSTEM)
2024-05-10 03:00:10 6006 Clean shutdown
2024-05-09 14:22:08 6008 *** UNEXPECTED ***
2024-05-05 02:00:12 1074 restart (NT AUTHORITY\SYSTEM)
2024-05-05 02:00:08 6006 Clean shutdown
2024-04-28 22:30:05 1074 shutdown (CORP\admin)
2024-04-28 22:30:02 6006 Clean shutdown
2024-04-15 08:45:33 6008 *** UNEXPECTED ***

[WARNING] 2 unexpected shutdown(s) detected in this period.

How to interpret the pattern:

  • 1074 + 6006 pairs: Normal, planned shutdown/restart cycles. The 1074 shows who did it and why, the 6006 confirms clean completion.
  • 6008 or 41 without preceding 1074: The system crashed, lost power, or experienced a BSOD. Investigate hardware, drivers, or overheating.
  • Frequent unexpected shutdowns: A pattern of 6008/41 events suggests a hardware problem (failing PSU, overheating, bad RAM) or a driver/software issue causing BSODs.

Method 3: CSV Export for Fleet Auditing

For environments with multiple servers, export the last shutdown details from each machine to a shared CSV for fleet-wide visibility.

@echo off
setlocal

set "CSVFile=\\Server\Audit\shutdown_report.csv"

:: Write header if file is new
if not exist "%CSVFile%" (
echo "Timestamp","Computer","EventID","Type","InitiatedBy","Reason" > "%CSVFile%" 2>nul
)

for /f "tokens=1-5 delims=|" %%a in (
'powershell -NoProfile -Command ^
"$events = Get-WinEvent -FilterHashtable @{" ^
" LogName='System';" ^
" Id=1074, 6006, 6008" ^
"} -MaxEvents 10 -ErrorAction SilentlyContinue;" ^
"if (-not $events) { Write-Output 'NOT_FOUND|||||'; exit 0 };" ^
"$last = $events | Sort-Object TimeCreated -Descending | Select-Object -First 1;" ^
"$ts = $last.TimeCreated.ToString('yyyy-MM-dd HH:mm:ss');" ^
"$type = switch ($last.Id) { 1074 { 'Planned' } 6006 { 'Clean' } 6008 { 'Unexpected' } };" ^
"$user = 'N/A';" ^
"$reason = 'N/A';" ^
"if ($last.Id -eq 1074) {" ^
" $xml = [xml]$last.ToXml();" ^
" $data = $xml.Event.EventData.Data;" ^
" $user = ($data | Where-Object Name -eq 'param6').'#text';" ^
" $reason = ($data | Where-Object Name -eq 'param3').'#text';" ^
" if (-not $user) { $user = 'SYSTEM' };" ^
" if (-not $reason) { $reason = 'No reason' }" ^
"};" ^
"Write-Output ($ts + '|' + $last.Id.ToString() + '|' + $type + '|' + $user + '|' + $reason)"'
) do (
if not "%%a"=="NOT_FOUND" (
echo "%COMPUTERNAME%","%%a","%%b","%%c","%%d","%%e" >> "%CSVFile%" 2>nul
)
)

endlocal
exit /b 0

Deployment:

Run on each server via scheduled task or deployment tool. The CSV builds a fleet-wide shutdown audit trail showing when each server was last shut down, whether it was planned or unexpected, and who initiated it.

How to Avoid Common Errors

Wrong Way: Checking File Timestamps

Examining the "Last Modified" date of system files (like pagefile.sys or ntuser.dat) is unreliable. Background processes modify files during shutdown, hibernate, and even after the user has initiated shutdown, making the timestamps inconsistent.

Correct Way: Always use Event Log IDs (1074, 6006, 6008) for accurate shutdown timestamps.

Wrong Way: Relying on Event ID 6006 Alone

:: INCOMPLETE: misses unexpected shutdowns entirely
wevtutil qe System "/q:*[System[(EventID=6006)]]" /f:text /c:1 /rd:true

Event 6006 is only generated during clean shutdowns. If the system crashed or lost power, there is no 6006 event, only 6008 (after the next boot). Querying only 6006 would show the shutdown before the crash, not the crash itself.

Correct Way: Query multiple event IDs (1074, 6006, 6008, 41) and take the most recent, as shown in all methods.

Problem: Security Log vs. System Log

Shutdown events are recorded in the System log, not the Security log. Querying LogName='Security' for these event IDs will always return zero results.

Problem: Admin Privileges Required

The System log may require administrator privileges to read certain events, and some methods of querying (like wevtutil) always require elevation.

Solution: Check admin rights at startup:

net session >nul 2>&1
if errorlevel 1 (
echo [ERROR] Administrator privileges required. >&2
exit /b 1
)

Problem: Fast Startup Masks Shutdown Events

With Windows 10/11 Fast Startup enabled, a "Shut Down" is actually a partial hibernation. The system may not generate Event ID 1074 or 6006 in the same way as a true shutdown. Only a "Restart" produces the full shutdown event sequence.

Solution: Be aware that on client workstations with Fast Startup, the most recent 6006/1074 event may correspond to the last restart, not the last time the user clicked "Shut Down." For accurate tracking, either disable Fast Startup or supplement with Event ID 42 (sleep/hibernate) from the Kernel-Power provider.

Best Practices and Rules

1. Always Check Multiple Event IDs

Query 1074, 6006, 6008, and 41 together. Using a single ID misses entire categories of shutdowns (planned vs. crash vs. power loss).

2. Distinguish Clean from Unexpected

A clean shutdown produces a 1074 (initiation) and 6006 (completion) pair. An unexpected shutdown produces only a 6008 (detected at next boot). The distinction is critical, frequent unexpected shutdowns indicate hardware or driver problems.

3. Examine Event ID 1074 Details

Event 1074 contains who initiated the shutdown, which process triggered it, and the stated reason. This is essential for accountability, determining whether a 3 AM restart was a scheduled Windows Update or an unauthorized manual restart.

4. Export History for Compliance

Event Logs are circular and overwrite old entries. Export shutdown events to CSV (Method 3) at regular intervals to maintain a permanent audit trail that survives log rotation.

5. Investigate Unexpected Shutdowns Promptly

Any 6008 or 41 event should be investigated. Check for:

  • Event ID 41 with BugcheckCode: Indicates a BSOD. Check C:\Windows\Minidump for crash dump files.
  • Event ID 6008 without 41: Power loss or forced shutdown (holding the power button). Check UPS logs if available.
  • Recurring pattern: Multiple unexpected shutdowns over days suggest a hardware issue (overheating, failing PSU, bad RAM).

Conclusions

Finding the last shutdown time and understanding how the system shut down turns an operational mystery into a documented case. By querying multiple event IDs and extracting the rich detail from Event 1074, you gain a complete picture of your system's power lifecycle. This capability is essential for post-mortem analysis of crashes, verification of maintenance windows, and maintaining compliance documentation in professional environments.