'How to stop a windows 10 machine from sleeping/hibernating down when running a powershell process?
I have a powershell process that reads records from a remote server and copies them into a local database. When it runs, it might run for 8-12 hours.
How do I prevent the computer from shutting down (or going into sleep/hibernate mode) during this time? I know I can adjust the 'Power and sleep settings' to set the computer to never sleep, but that's not what I'm looking for - I do want it to go to sleep when the process isn't running.
I know that sleep/hibernate is suspended if a netflix or youtube video is running, I'd like the computer to do the same when a powershell process is running.
The powershell process runs in a command window on the desktop - I'm happy for the screen saver to activate, but what I don't want to happen is for me to wake the machine after 8 hours and discover that the process only ran for 10 minutes before the computer went to sleep!
Solution 1:[1]
With some extra effort, you can achieve the desired behavior with the standard powercfg.exe
utility, by using a custom, always-on power scheme that is created on demand and temporarily activated for the duration of your script run:
Note:
Look for comment
# YOUR CODE GOES HERE
below.For a .NET / Windows API-based alternative, see this answer.
# Define the properties of a custom power scheme, to be created on demand.
$schemeGuid = 'e03c2dc5-fac9-4f5d-9948-0a2fb9009d67' # randomly created with New-Guid
$schemeName = 'Always on'
$schemeDescr = 'Custom power scheme to keep the system awake indefinitely.'
# Helper function that ensures that the most recent powercfg.exe call succeeded.
function assert-ok { if ($LASTEXITCODE -ne 0) { throw } }
# Determine the currently active power scheme, so it can be restored at the end.
$prevGuid = (powercfg -getactivescheme) -replace '^.+([-0-9a-f]{36}).+$', '$1'
assert-ok
# Temporarily activate a custom always-on power scheme; create it on demand.
try {
# Try to change to the custom scheme.
powercfg -setactive $schemeGuid 2>$null
if ($LASTEXITCODE -ne 0) { # Changing failed -> create the scheme on demand.
# Clone the 'High performance' scheme.
$null = powercfg -duplicatescheme SCHEME_MIN $schemeGuid
assert-ok
# Change its name and description.
$null = powercfg -changename $schemeGuid $schemeName $schemeDescr
# Activate it
$null = powercfg -setactive $schemeGuid
assert-ok
# Change all settings to be always on.
# Note:
# * Remove 'monitor-timeout-ac', 'monitor-timeout-dc' if it's OK
# for the *display* to go to sleep.
# * If you make changes here, you'll have to run powercfg -delete $schemeGuid
# or delete the 'Always on' scheme via the GUI for changes to take effect.
# * On an AC-only machine (desktop, server) the *-ac settings aren't needed.
$settings = 'monitor-timeout-ac', 'monitor-timeout-dc', 'disk-timeout-ac', 'disk-timeout-dc', 'standby-timeout-ac', 'standby-timeout-dc', 'hibernate-timeout-ac', 'hibernate-timeout-dc'
foreach ($setting in $settings) {
powercfg -change $setting 0 # 0 == Never
assert-ok
}
}
# YOUR CODE GOES HERE.
# In this sample, wait for the user to press Enter before exiting.
# Before that, the 'Always on' power scheme should remain in
# effect, and the machine shouldn't go to sleep.
pause
} finally { # Executes even when the script is aborted with Ctrl-C.
# Reactivate the previously active power scheme.
powercfg -setactive $prevGuid
}
You could create a wrapper script from the above, to which you pass the path of the script to execute.
If you don't mind modifying the currently active scheme, you can use the approach shown in Kerr's answer, using per-setting powercfg -change <setting> <value-in-minutes>
calls (/x
/ -x
is an alias of /change
/ -change
), using one of the following <setting>
names in each call; passing 0
as <value-in-minutes>
represents never:
monitor-timeout-ac
monitor-timeout-dc
disk-timeout-ac
disk-timeout-dc
standby-timeout-ac
standby-timeout-dc
hibernate-timeout-ac
hibernate-timeout-dc
Note, however, that such changes are persistent, so you may want to restore the original values later, which takes extra effort.
Solution 2:[2]
To offer a .NET / Windows API-based alternative to the powercfg.exe
-based solution:
Note:
The solution uses
Add-Type
to compile C# code on demand, which incurs a performance penalty the first time the code is called in the current session.It is important to call
::StayAwake($false)
in the same session in order to clear the power requests made.Look for comment
# YOUR CODE GOES HERE
below.This solution was adapted from this C# answer by MarkusEgle.
Add-Type -ErrorAction Stop -Name PowerUtil -Namespace Windows -MemberDefinition @'
// Member variables.
static IntPtr _powerRequest;
static bool _mustResetDisplayRequestToo;
// P/Invoke function declarations.
[DllImport("kernel32.dll")]
static extern IntPtr PowerCreateRequest(ref POWER_REQUEST_CONTEXT Context);
[DllImport("kernel32.dll")]
static extern bool PowerSetRequest(IntPtr PowerRequestHandle, PowerRequestType RequestType);
[DllImport("kernel32.dll")]
static extern bool PowerClearRequest(IntPtr PowerRequestHandle, PowerRequestType RequestType);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
static extern int CloseHandle(IntPtr hObject);
// Availablity Request Enumerations and Constants
enum PowerRequestType
{
PowerRequestDisplayRequired = 0,
PowerRequestSystemRequired,
PowerRequestAwayModeRequired,
PowerRequestMaximum
}
const int POWER_REQUEST_CONTEXT_VERSION = 0;
const int POWER_REQUEST_CONTEXT_SIMPLE_STRING = 0x1;
// Availablity Request Structures
// Note: Windows defines the POWER_REQUEST_CONTEXT structure with an
// internal union of SimpleReasonString and Detailed information.
// To avoid runtime interop issues, this version of
// POWER_REQUEST_CONTEXT only supports SimpleReasonString.
// To use the detailed information,
// define the PowerCreateRequest function with the first
// parameter of type POWER_REQUEST_CONTEXT_DETAILED.
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct POWER_REQUEST_CONTEXT
{
public UInt32 Version;
public UInt32 Flags;
[MarshalAs(UnmanagedType.LPWStr)]
public string SimpleReasonString;
}
/// <summary>
/// Prevents the system from going to sleep, by default including the display.
/// </summary>
/// <param name="enable">
/// True to turn on, False to turn off. Passing True must be paired with a later call passing False.
/// If you pass True repeatedly, subsequent invocations take no actions and ignore the parameters.
/// If you pass False, the remaining paramters are ignored.
// If you pass False without having passed True earlier, no action is performed.
//// </param>
/// <param name="includeDisplay">True to also keep the display awake; defaults to True.</param>
/// <param name="reasonString">
/// A string describing why the system is being kept awake; defaults to the current process' command line.
/// This will show in the output from `powercfg -requests` (requires elevation).
/// </param>
public static void StayAwake(bool enable, bool includeDisplay = true, string reasonString = null)
{
if (enable)
{
// Already enabled: quietly do nothing.
if (_powerRequest != IntPtr.Zero) { return; }
// Configure the reason string.
POWER_REQUEST_CONTEXT powerRequestContext;
powerRequestContext.Version = POWER_REQUEST_CONTEXT_VERSION;
powerRequestContext.Flags = POWER_REQUEST_CONTEXT_SIMPLE_STRING;
powerRequestContext.SimpleReasonString = reasonString ?? System.Environment.CommandLine; // The reason for making the power request.
// Create the request (returns a handle).
_powerRequest = PowerCreateRequest(ref powerRequestContext);
// Set the request(s).
PowerSetRequest(_powerRequest, PowerRequestType.PowerRequestSystemRequired);
if (includeDisplay) { PowerSetRequest(_powerRequest, PowerRequestType.PowerRequestDisplayRequired); }
_mustResetDisplayRequestToo = includeDisplay;
}
else
{
// Not previously enabled: quietly do nothing.
if (_powerRequest == IntPtr.Zero) { return; }
// Clear the request
PowerClearRequest(_powerRequest, PowerRequestType.PowerRequestSystemRequired);
if (_mustResetDisplayRequestToo) { PowerClearRequest(_powerRequest, PowerRequestType.PowerRequestDisplayRequired); }
CloseHandle(_powerRequest);
_powerRequest = IntPtr.Zero;
}
}
// Overload that allows passing a reason string while defaulting to keeping the display awake too.
public static void StayAwake(bool enable, string reasonString)
{
StayAwake(enable, false, reasonString);
}
'@
try {
# Create power request(s) that keep the system awake.
# Pass $false as the 2nd argument to allow the display to go to sleep.
# The reason string is visible when you run `powercfg.exe -requests` to show current requests
# (requires elevation).
# Defaults: keep the display awake too, use the current process' command line as the reason string.
[Windows.PowerUtil]::StayAwake($true, $true, "Running long-running script $PSCommandPath.")
# YOUR CODE GOES HERE.
# In this sample, wait for the user to press Enter before exiting.
# Before that, the system should stay awake indefinitely.
pause
} finally { # This ensures that the previous scheme is restored even when the script is aborted with Ctrl-C.
# Clear the power requests.
[Windows.PowerUtil]::StayAwake($false)
}
Solution 3:[3]
Simple one-liner that I use:
Powercfg /x -standby-timeout-ac 0
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | mklement0 |
Solution 3 | KERR |