1

We're trying to create a script that tells a list of computers to stay awake.

I've shopped around, and decided to go with one I believe I found here, but I can't get it to work on a remote system. I tried to invoke-command before, then -filepath to the script, and specified the computer name, but it does nothing. What am I doing wrong?

function workflow-Scrollock {
  Clear-Host
  Echo "Keep-alive with Scroll Lock..."
  $WShell = New-Object -com "Wscript.Shell"
  while ($true)
  {
    $WShell.sendkeys("{CAPSLOCK}")
    Start-Sleep -Milliseconds 2000
    $WShell.sendkeys("{CAPSLOCK}")
    Start-Sleep -Seconds 2
  }
}

I want to see the remote computer turn it's capslock on and off until I reboot it or stop the script.

Emil Reña Enriquez
  • 2,929
  • 1
  • 29
  • 32
ksimp88
  • 13
  • 3
  • 3
    I'd recommend changing the energy setting to "do not sleep away" instead of annoying the computer with pointless keyboard actions. ;-) – Olaf Oct 23 '19 at 23:23

1 Answers1

0

As long as your primary goal is keeping the computer awake (and not flashing the Caps Lock key), this answer to a related question should help. Basically you just need to slam all that C# into an Add-Type with a few modifications, eg:

Add-Type -TypeDefinition @"
    using System;
    using System.Net;
    using System.Runtime.InteropServices;

    public class PowerManager {
        POWER_REQUEST_CONTEXT _PowerRequestContext;
        IntPtr _PowerRequest; // HANDLE

        // Availability Request Functions
        [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)]
        internal 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;
        const int POWER_REQUEST_CONTEXT_DETAILED_STRING = 0x2;

        // Availablity Request Structure
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct POWER_REQUEST_CONTEXT
        {
            public UInt32 Version;
            public UInt32 Flags;
            [MarshalAs(UnmanagedType.LPWStr)]
            public string SimpleReasonString;
        }

        public void EnableConstantDisplayAndPower(bool enable, string reason)
        {
            if (enable)
            {
                // Set up the diagnostic string
                _PowerRequestContext.Version = POWER_REQUEST_CONTEXT_VERSION;
                _PowerRequestContext.Flags = POWER_REQUEST_CONTEXT_SIMPLE_STRING;
                _PowerRequestContext.SimpleReasonString = reason; // your reason for changing the power settings

                // Create the request, get a handle
                _PowerRequest = PowerCreateRequest(ref _PowerRequestContext);

                // Set the request
                PowerSetRequest(_PowerRequest, PowerRequestType.PowerRequestSystemRequired);
                PowerSetRequest(_PowerRequest, PowerRequestType.PowerRequestDisplayRequired);
            }
            else
            {
                // Clear the request
                PowerClearRequest(_PowerRequest, PowerRequestType.PowerRequestSystemRequired);
                PowerClearRequest(_PowerRequest, PowerRequestType.PowerRequestDisplayRequired);

                CloseHandle(_PowerRequest);
            }
        }
    }
"@
(New-Object PowerManager).EnableConstantDisplayAndPower($true, "Keeping the computer awake")
Wait-Event

I cleaned it up slightly to remove some unused things and to make it into a class, then added Wait-Event so that it will stay running.

Now you just need to execute it remotely:

Invoke-Command -AsJob -ComputerName remotecomputer -FilePath C:\Path\To\Set-KeepAwake.ps1

You can prove that it's working by checking powercfg /requests:

Invoke-Command -ComputerName remotecomputer -ScriptBlock { powercfg /requests }

Which outputs:

DISPLAY:
None.

SYSTEM:
[PROCESS] \Device\HarddiskVolume1\Windows\System32\wsmprovhost.exe
Keeping the computer awake

AWAYMODE:
None.
fission
  • 1,170
  • 18
  • 35
  • Awesome, I'll try it tomorrow. We can't just change the power settings because the group policy needs to be untouched, and it will override what we set. We're doing this for imaging purposes, and we only need it to last until we end the script or reboot the machines. – ksimp88 Oct 24 '19 at 01:54