#Keep Awake during script

124 messages · Page 1 of 1 (latest)

mental jay
#

I've been poking at a way to prevent a PC or its display from going to sleep while my script is running, and then when the script is done, and is closed, it will no longer prevent sleep (ie return to normal behavior).

I ran across this blog https://den.dev/blog/caffeinate-windows/ which has a script to call the API used by media players (apparently).

A very simple version is this keepawake one https://gist.github.com/jamesfreeman959/231b068c3d1ed6557675f21c0e346a9c

Has anyone used either of these integrated into their own scripts (and not just to keep the machine awake for 'work purposes')? The first one seems to be pretty independent so im under where (or if) my script can be inserted to work with it. And I dont think it will work if I make it its own script and call it from my main script (as it will just sit there and wait).

The second... just feels weird or clunky to have to dump my entire script within its loop.

Or maybe im reading too much into both of these. Looking for input.

Just like I need coffee to function, Windows needs it to stay awake when I need it to. In this post, I share a simple solution to this problem.

Gist

A very simple PowerShell script to keep a Windows PC awake and make lync think the user is active on the keyboard - keepawake.ps1

sour escarp
mental jay
sour escarp
cobalt vapor
#

yeah SetThreadExecutionState is probably the most resilient method

mental jay
mental jay
cobalt vapor
#

oh nvm i see, that blog talks about using a job

#

should just be able to stop the job

mental jay
# cobalt vapor there a reason you're separating the functionality?

Not.. really? Other than i wasnt sure what part of that script was actually preventing sleep/screensaver and what was meant to simply keep the job window open so it could keep running and wasnt sure which part the looping was vital too. If it is part of the entire process, i didnt want to encase my entire script in its loop just to keep things awake.

Though from what im understanding frim your link, i would still need the Display_required (as well) given i want to keep the display active during the script.

cobalt vapor
#

nah i just misunderstood but i got it after i read the blog

mental jay
cobalt vapor
#

i dont think you need the function or job, i would just try this at the start of your script

$Signature=@'
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern void SetThreadExecutionState(uint esFlags);
'@
$ES_SYSTEM_REQUIRED = [uint32]'0x00000001'
$ES_CONTINUOUS = [uint32]'0x80000000'
$STES = Add-Type -MemberDefinition $Signature -Name System -Namespace Win32 -PassThru
$STES::SetThreadExecutionState($ES_CONTINUOUS -bor $ES_SYSTEM_REQUIRED)
mental jay
#

Thats kinda what i was thinking too but wasn't sure. Does it need to be cleared at the end like the MS-Learn article suggests?

cobalt vapor
#

which part?

i dont think so because it's only setting it for that session. when the process ends it should also stop preventing it from sleep. (like if you force close a media player process, it will also not prevent it from sleep)

mental jay
#

Kinda thought as much. Was just looking over this bit in the sample window.

// Clear EXECUTION_STATE flags to disable away mode and allow the system to idle to sleep normally.
//
SetThreadExecutionState(ES_CONTINUOUS);
mental jay
#

wait.. arent the system idle timer and display idle timer different timers?

mental jay
#

Oh.. ok.. um.. Does this require anything 'extra' installed on a machine to run? Or a specific version of Powershell to work?

cobalt vapor
#

no it uses methods in windows, will work on any version

cobalt vapor
mental jay
#

I do, yeah.

cobalt vapor
#

you can change or add the flag

#

i just thought it was an unattended/background script

mental jay
noble python
mental jay
#

Na, just want the sleep settings to go back to normal when the script is done and closed.

noble python
#

The sleep inhibiting is tied to the thread, so when PowerShell exits, so will the inhibitor.

mental jay
#

Is there a way to get Wind32_PowerPlan to pull the same info as powercfg /requests or is it easier to just call powercfg /requests?

cobalt vapor
#

no that class just represents power plans, nothing to do with power requests

#

i dont think theres an api to call for it either, best to just parse that command i believe

mental jay
#

Yeah, ive been running into that conclusion as. I cobbled up something for the command line, but still trying to work out how to pull the information i want form it for compairson. heh.

cobalt vapor
#

how to parse the output?

mental jay
#

Well, sorta? All im really trying to do is run an internal check to verify that the process holding the requests is powershell.exe. I dont need to display the actual output to the console.

cobalt vapor
#

if ((powercfg /requests) -match '^\[PROCESS\].*powershell\.exe') {

honest basin
# cobalt vapor i dont think you need the function or job, i would just try this at the start of...

this is nice, wasnt aware of this func. i was looking for something to not put my work laptop to sleep while running a long report... changed up a bit to remember the values:

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;

public static class Native
{
    private static EXECUTION_STATE? s_prevState;

    [DllImport("kernel32.dll", SetLastError = true, EntryPoint = "SetThreadExecutionState")]
    private static extern EXECUTION_STATE SetThreadExecutionStateNative(EXECUTION_STATE esFlags);

    public static void SetThreadExecutionState(EXECUTION_STATE esFlags)
    {
        if (esFlags.HasFlag(EXECUTION_STATE.ES_AWAYMODE_REQUIRED)
            && !esFlags.HasFlag(EXECUTION_STATE.ES_CONTINUOUS))
        {
            throw new ArgumentException("ES_AWAYMODE_REQUIRED must be used with ES_CONTINUOUS.");
        }

        EXECUTION_STATE previousState = SetThreadExecutionStateNative(esFlags);
        if (previousState == 0) throw new Win32Exception();
        s_prevState = previousState;
    }

    public static void Restore() => SetThreadExecutionState(s_prevState ?? EXECUTION_STATE.ES_CONTINUOUS);
}

[Flags]
public enum EXECUTION_STATE : uint
{
    ES_AWAYMODE_REQUIRED = 0x00000040,
    ES_CONTINUOUS = 0x80000000,
    ES_DISPLAY_REQUIRED = 0x00000002,
    ES_SYSTEM_REQUIRED = 0x00000001,
}
#

actually doesnt make sense to return, but is worth saving the previous state to restore it later

#

fixed

honest basin
#

it doesnt require WScript.Shell

cobalt vapor
#

nice

#

too bad it doesnt prevent idle

honest basin
#

prevent idle?

honest basin
cobalt vapor
honest basin
#

like im not sure what you mean by it doesnt prevent idle

cobalt vapor
#

oh

#

im wrong anyway, your gist is different

honest basin
#

right i added the shift+f15 to it

#

so i no longer appear as away in teams xD

#

but i didnt like the WScript.Shell usage so I did it using p/invoke instead

cobalt vapor
honest basin
#

xD

cobalt vapor
#

and no one ever knows if im actually there or not

#

but getn my remoteapp disconnected is annoying. caffeine.exe doesnt work when running on the remote for w/e reason. imma try this

honest basin
#

you want to invoke this remotely ?

cobalt vapor
#

on a remote pc im rdp'd to, yeah

#

but not sure its possible, not sure how rdp protocol determines inactivity

honest basin
#

i dont think that's gonna run, not how windows works

#

you can try tho

#

however, if you set a set a scheduled taks that calls this

#

then you trigger that task remotely, then it should work

#

(i think)

cobalt vapor
#

i mean its still interactive, i dont mean winrm or anything

honest basin
#

give it a try let me know how it goes 😄 im interested in knowing

#

the shift+f15 loop is the method called KeepAlive() and ends when you press a key (Console.ReadKey())

cobalt vapor
#

is there any easy way to just build or run jsut the cs?

#

dotnet run wants a project

#

oh no thats just in .net 10

honest basin
#

but its using languages features not compatible with c# 5 (the compiler used in pwsh 5.1)

#

in pwsh 7 you can Add-Type (Get-Content .../keepalive.cs -Raw) -IgnoreWarnings -WA 0

cobalt vapor
#

Add-Type -Path?

honest basin
#

-Path is for an already compiled assembly (a dll)

cobalt vapor
#

weird it didnt error

honest basin
#

rly?

#

😮

cobalt vapor
honest basin
#

OMG

#

i didnt know this!

#

nice!!!

#

i thought -Path was for dll only my bad

cobalt vapor
#

all i've ever done prev was .dll but i just saw the param and tried before i saw your message lol

#

well thats handy to know

honest basin
#

looks like -Path even works in 5.1

#

😮 im happy now

cobalt vapor
#

will see if i time out in the next 20min

cobalt vapor
honest basin
#

i imagined it wouldnt work

#

maybe a sched task

#

you can trigger those remotely

cobalt vapor
#

thatd still be on the remote side though

honest basin
#

you sure?

cobalt vapor
#

cuz its not the pc going idle, its just the RD session

honest basin
#

ahhhhh

#

i see

#

ok i have no idea xD

cobalt vapor
#

can you have CreateKeyEvent target a specific window without making it the active window?

#

or a similar method, since i highly doubt its possible with that one

honest basin
#

SendInput doesnt take a ptr for a window so I dont think so

#

at least not with this winapi

honest basin
#

@cobalt vapor SetThreadExecutionState doesn't work in the RDP session? I would've expected that to work

cobalt vapor
#

i dont think so but i'll test

#

i think because nothing happening over RDP it won't but i have no idea what it does to detect

honest basin
#

what you want is to prevent the rdp window to going idle and locking the session right?

cobalt vapor
#

well, it disconnects rather than lock, but yeah

honest basin
#

so i assume you're running pwsh calling the native apis from the rdp

#

and not locally

cobalt vapor
#

ye lol

honest basin
#

there is also a gpo you can look into

cobalt vapor
#

yeah theres a GPO set to max idle time 30min

#

Key: HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services
Value: MaxIdleTime
(or maybe HKCU)

#

i mean technically i could just exclude my user/machine from the gpo but thats a bit blatant

#

schtask on my the machine that changes the regkeys every 5min to 9999 lol

#

i havent spent a ton of time on it, its just annoying cause im active on my client side computer but thats irrelevant to the rdp session

honest basin
#

next time you try, from my gist use the PreventSleepAndDisplayOff() in the rdp session and don't close the pwsh process that called it

#

if that doesn't work then im out of ideas

cobalt vapor
#

yeah thats what im doing now

#

from a dif machine im doing quser and its showing idle time as 12min so

honest basin
#

😐

cobalt vapor
#

i guess the RDP idle stuff is completely separate from system stuff

#

like directly on the machine, you get locked after 10min of inactivity. which this would definitely prevent