Turn off Win10 display(s) via OpenSSH

There are a lot of solutions to turn off display locally on a Windows10 machine. They all are some form of the following SendMessage line. There's also little executables like nircmd that do this. However there seems to be some limitation when running any of those via OpenSSH. Since my OpenSSH is configured to use the exact same credentials as my local user i can't really figure out why nothing happens. The ps script versions return a simple 1, and solutions like nircmd just return nothing at all. Not even an error. Any insight what might happen here and how to make it work?

Sample script:

powershell (Add-Type '[DllImport(\"user32.dll\")]^public static extern int SendMessage(int hWnd, int hMsg, int wParam, int lParam);' -Name a -Pas)::SendMessage(-1,0x0112,0xF170,2)

Source

edit: maybe i should add that other nircmd options like mute audio work without any problems.


This is because the interactive Windows session is not the current session, so it's not running in a context where the physical display is actively connected. Sound and other features are, but the display is tied to a session. You can either login interactively, or use something like psexec to execute the powershell process in the context of the user. If you're okay with using psexec then you can use this:

 FOR /F "usebackq tokens=4" %s IN (`tasklist /nh /fo table /fi "imagename eq explorer.exe"`) DO psexec -accepteula -nobanner -d -i %s -w "%windir%" powershell (Add-Type '[DllImport(\"user32.dll\")]^public static extern int SendMessage(int hWnd, int hMsg, int wParam, int lParam);' -Name a -Pas)::SendMessage(-1,0x0112,0xF170,2)

You will need psexec for this, though.

If there are more than one interactive sessions, it will be executed more than once.

If running from batch you'll need to replace both %s with %%s.

This is the part that collects the interactive session:

FOR /F "usebackq tokens=4" %s IN (`tasklist /nh /fo table /fi "imagename eq explorer.exe"`) DO echo %s

The following can be copied into a batch file and run from a terminal emulator.

FOR /F "usebackq tokens=4" %%s IN (`tasklist /nh /fo table /fi "imagename eq explorer.exe"`) DO (
    psexec -accepteula -nobanner -d -i %%s -w "%windir%" powershell -NoProfile -NoLogo -Command "(Add-Type '[DllImport(\"user32.dll\")]public static extern int SendMessage(int hWnd, int hMsg, int wParam, int lParam);' -Name a -Pas)::SendMessage(-1,0x0112,0xF170,2)"
)

The only difference is that each %s was changes to %%s.

Be aware that running it interactively on the computer that you're trying to disable the displays on WILL LIKELY FAIL. This is because your interactive session is still active.

To wake your screens you can use the following (tested and works on several of my devices):

:: gather session handle
FOR /F "usebackq tokens=4" %%s IN (`tasklist /nh /fo table /fi "imagename eq explorer.exe"`) DO SET hsession=%%s

:: wake display
psexec -accepteula -nobanner -d -i %hsession% -w "%windir%" powershell -NoProfile -NoLogo -Command "(Add-Type '[DllImport(\"user32.dll\")]public static extern int SendMessage(int hWnd, int hMsg, int wParam, int lParam);' -Name a -Pas)::SendMessage(-1,0x0112,0xF170,-1)"
CALL :wait 2

:: reactivate session
psexec -accepteula -nobanner -d -i %hsession% -w "%windir%" powershell -NoProfile -NoLogo -Command "$x=Add-Type '[DllImport(\"kernel32.dll\")]public static extern void SetThreadExecutionState(uint esFlags);' -name System -namespace Win32 -passThru;$x::SetThreadExecutionState([uint32]\"0x03\");Sleep 5;$x::SetThreadExecutionState([uint32]\"0x40\");"
CALL :wait 2
GOTO:EOF

:wait
SET dowait=%~1
IF "%dowait%"=="" SET dowait=10
ping -n %dowait% 127.0.0.1 >NUL
GOTO:EOF