如何在 运行 一个 powershell 进程时从 sleeping/hibernating 停止 windows 10 台机器?

How to stop a windows 10 machine from sleeping/hibernating down when running a powershell process?

我有一个 powershell 进程,它从远程服务器读取记录并将它们复制到本地数据库中。当它 运行 秒时,它可能会 运行 持续 8-12 小时。

如何防止计算机在此期间关机(或进入 sleep/hibernate 模式)?我知道我可以调整 'Power and sleep settings' 以将计算机设置为永不休眠,但这不是我要找的 - 我 do 希望它在进程时进入休眠状态不是 运行宁。

我知道 sleep/hibernate 在 netflix 或 youtube 视频 运行ning 时暂停,我希望计算机在 powershell 进程 运行ning 时执行相同的操作.

桌面上命令 window 中的 powershell 进程 运行s - 我很高兴屏幕保护程序激活,但我不想发生的是我8 小时后唤醒机器,发现进程仅 运行 10 分钟后计算机进入休眠状态!

通过一些额外的努力,您可以使用 标准 powercfg.exe utility 实现所需的行为,方法是使用 自定义的始终开启的电源方案 按需创建并在脚本运行期间临时激活 运行:

注:

  • 在下面寻找评论# YOUR CODE GOES HERE

  • 对于基于 .NET / Windows API 的替代方案,请参阅 .

# 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}).+$', ''
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
}

您可以从上面创建一个 wrapper 脚本,将要执行的脚本路径传递给该脚本。


如果你不介意修改当前激活的方案,你可以使用Kerr's answer中所示的方法,使用每个设置 powercfg -change <setting> <value-in-minutes> 调用(/x / -x/change / -change 的别名),使用以下 <setting> 名称之一在每次通话中;传递 0 作为 <value-in-minutes> 表示 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

但是请注意,此类更改是持久性的,因此您可能希望稍后恢复原始值,这需要额外的努力.

提供基于 .NET / Windows API 的替代方案 :

注:

  • 该方案使用Add-Type按需编译C#代码,在当前会话中第一次调用代码时会产生性能损失。

  • 重要的是在 同一个 会话中调用 ::StayAwake($false) 以清除发出的电源请求。

  • 在下方寻找评论# YOUR CODE GOES HERE

  • 此解决方案改编自 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)

}

我使用的简单单线:

Powercfg /x -standby-timeout-ac 0