Find What Wakes a Windows PC With Get-WinEvent
A PC that turns itself on at night leaves a record in the System log every time it does. Windows writes one event when the PC goes to sleep and another when it wakes up. The wake event names the device or timer that woke it.
This article builds Get-SleepWakeHistory, a function that reads those two events with Get-WinEvent, pairs each sleep with its corresponding wake, and returns one row per sleep with how long the PC slept, why it went to sleep, and what woke it. It then lists the two things Windows allows to wake a PC on its own, scheduled tasks with “Wake the computer to run this task” turned on and devices that are armed to wake it.
Everything here was run with Windows PowerShell 5.1 and PowerShell 7.6 on Windows 11 builds 26200 and 26300.
The two events
Windows records a sleep and a wake as two separate events in the System log.
- Event 42 from
Microsoft-Windows-Kernel-Poweris written as the PC enters sleep. ItsReasonfield says what started the sleep. - Event 1 from
Microsoft-Windows-Power-Troubleshooteris written after the PC resumes. It carries the time the PC went to sleep, the time it woke, and the wake source as text.
You can see both in Event Viewer, but the wake source is only in the message text there. The fields are easier to read from the event XML, where each value has a name.
You don’t need a sleep in the log to find the event names. The provider’s manifest lists every field of every event version, and can be read with Get-WinEvent -ListProvider.
| |
| |
SleepTime and WakeTime are UTC timestamps. WakeSourceText holds the same text Event Viewer shows after “Wake Source”. WakeTimerOwner arrived in version 1 of the event and names the process or task that set the timer when a timer caused the wake.
Run the manifest command with Microsoft-Windows-Kernel-Power and 42 to see that Reason was added to event 42 in version 2. A version 0 event 42 carries only TargetState and EffectiveState, so the function treats a missing Reason as unknown.
The function
| |
The function only uses cmdlets and syntax that work in both Windows PowerShell 5.1 and PowerShell 7, since 5.1 is still the shell on most of the PCs that raise these tickets.
Running it
| |
On a laptop this returned two sleeps for the last 7 days.
| |
In both rows event 42 was written 1 to 5 seconds after the SleepTime in event 1. Across 20 sleeps on that laptop the gap was never more than 13 seconds, which is why the function looks 2 minutes back and 1 minute forward. When two event 42s fall in that window, as they can after a very short sleep, it takes the one closest to the SleepTime.
A wake you caused shows the power button, the lid, or the device you touched as the source. The rows to look at are the ones that happened when nobody was at the PC. For those, the wake source is usually a timer, which points at a scheduled task, or a device such as a network adapter or a mouse.
A timer wake names the task. On the laptop, with the test task from the next section set to run four minutes after it went to sleep, the function returned this.
| |
WakeTimer names the process that set the timer, which for every scheduled task is the Task Scheduler’s own svchost.exe. The task name is in WakeSource.
A device wake often names the port the device sits behind instead of the device. On a desktop woken from the keyboard, the function returned this.
| |
The same wake, with the device’s instance path, can be read with powercfg /lastwake. Look the path up in Device Manager under “Details”, “Device instance path”.
| |
When WakeSource says Unknown, run powercfg /lastwake right after the next unexpected wake. Its output comes directly from the power manager and sometimes names a device the event left blank.
Which tasks and devices can wake the PC
A wake from a timer comes from a scheduled task that has “Wake the computer to run this task” checked. That checkbox is Settings.WakeToRun on the task object.
| |
| |
The list includes disabled tasks, which can’t set a wake timer. Add State -ne 'Disabled' to the filter to see only the tasks that can wake the PC today. On this PC that leaves none, which matches powercfg /waketimers below.
Each timer that is set right now, with the task behind it, can be listed with powercfg /waketimers from an elevated prompt. With no wake tasks enabled, the output is one line.
| |
To see what a real timer looks like, I registered a test task with “Wake the computer to run this task” turned on and a trigger four minutes out.
| |
| |
The task name is in the Reason line.
A wake from a device comes from hardware that is armed to wake the PC. Every device with that permission can be listed with powercfg /devicequery wake_armed.
| |
| |
Three network adapters on this PC are armed, so each of them can wake it from sleep.
Stopping the wake
Match the WakeSource from the function to one of the two lists above, then turn off that one permission.
For a scheduled task, turn off WakeToRun and save the task.
| |
| |
For a device, remove its permission by the name powercfg printed.
| |
| |
The permission can be restored with powercfg /deviceenablewake and the same device name.
Run Get-SleepWakeHistory again after a night or two. The wakes from that task or device should be gone from the list.
Gotchas
Modern Standby PCs log most sleeps as other events
Many newer laptops don’t use S3 sleep. They use Modern Standby. On those laptops “Standby (S0 Low Power Idle)” is listed under the available sleep states in powercfg /a. The laptop above is one of them. In 30 days it logged 412 Kernel-Power 506 events (“The system is entering Modern Standby”) and 410 event 507s (“The system is exiting Modern Standby”), and only 20 pairs of events 42 and 1. Those 20 were hibernations and sleeps that an application started. Every one of the 20 event 1s showed “Wake Source: Unknown”.
On a Modern Standby PC, the Reason line in event 507 says why it left standby.
| |
| |
Some reasons print only as a number. An HTML report of the Modern Standby sessions, with the time and the top power users for each one, can be generated with powercfg /sleepstudy.
No events is an error, not an empty result
Get-WinEvent throws “No events were found that match the specified selection criteria” when the filter matches nothing. The function catches that one error by its FullyQualifiedErrorId and returns nothing, so a PC that never slept in the window doesn’t look like a failure. Any other error, such as access denied on a remote computer, still throws.
Run the function with -Verbose to see the XPath query Get-WinEvent builds from the two hashtables, which helps when a filter returns less than you expect.
A laptop on battery may ignore the timer, or wake and skip the task
The power plan’s “Allow wake timers” setting has separate values for plugged in and on battery. On the Modern Standby laptop used for this article, it was “Important Wake Timers Only” plugged in and “Disable” on battery.
| |
| |
Index 0 is Disable, 1 is Enable, and 2 is Important Wake Timers Only. With the battery value at 0, a task’s timer can’t wake the laptop on battery, so for the test I set it to 1.
Once it woke, the task still didn’t run. Get-ScheduledTaskInfo reported a LastTaskResult of 267011 (the task has not yet run), because New-ScheduledTaskSettingsSet leaves DisallowStartIfOnBatteries set to True. So a laptop can wake on battery for a task that then doesn’t run, which looks like a wake for no reason. Check WakeToRun and the two battery settings on the task you found.
| |
Hibernation counts from the moment the PC hibernated
When a PC hibernates after a stretch in standby, event 42 carries reason 6 (“Hibernate from Sleep - Fixed Timeout”) or reason 13 (“Hibernate from Sleep - Standby Battery Budget Exceeded”). The SleepTime in the corresponding event 1 is the time it went into hibernation, not the time it first went to sleep. On a Modern Standby laptop, the hours it spent in standby before the hibernation are only in events 506 and 507, so Asleep covers the hibernation alone.
References
- Get-WinEvent
- Powercfg command-line options
- Get-ScheduledTask
- Get-SystemAuditPowerCycle in the SecurityFever module, the source of the event 42 reason codes 0 and 7
Related Articles
Find Free Azure CIDR Blocks with PowerShell
Suppose the network team assigns 10.172.0.0/16 to an Azure landing zone. You need to divide it into correctly aligned virtual …
Read moreHow to Toggle Logon Restrictions for AD Accounts
Written by Tino JR This script will allow an administrator to enable or disable logon restrictions for an Active Directory …
Read morePowerShell Escape Room
PowerShell Escape Room by Michiel Hamers by Michiel Hamers https://about.me/michielhamers/ Why on earth you want to create an …
Read more