Run powershell script remotely via ssh and get the exit code

Hossein Yousefi
ITNEXT
Published in
2 min readFeb 26, 2024

--

Such a surprise: if you run a cmd (.bat) script remotely, you will get the exit code, but in the case of your script being written in PowerShell (.ps1), you won’t get it.

Let’s make it clear

  • what’s our goal? to run a script or command remotely on a windows machine.
  • what’s the easiest way? install openssh-server on windows machine.
  • what’s the problem? if I run a powershell script remotely, it can’t get the exit code, better to say it always return 0 even when the script fails.
  • what’s the solution? There is No official solution for it.

What’s happening?

I usually run commands and scripts remotely on windows machine because I don’t want to get headache with WinRM or similar tools. how?

Firstly, you need to install openssh-server on windows machine.
One of the easiest way is:

Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
Start-Service sshd

if (!(Get-NetFirewallRule -Name "OpenSSH-Server-In-TCP" -ErrorAction SilentlyContinue | Select-Object Name, Enabled)) {
Write-Output "Firewall Rule 'OpenSSH-Server-In-TCP' does not exist, creating it..."
New-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22
} else {
Write-Output "Firewall rule 'OpenSSH-Server-In-TCP' has been created and exists."
}

if you want to know more about it, follow this documentation.

Secondly, check if everything is OK, you are good to go. (from another VM)

ssh USER@YOUR_VM_IP_ADDR

Thirdly, It’s time to send your command through ssh.

ssh USER@YOUR_VM_IP_ADDR 'ANY COMMAND YOU WANT'
# bare in mind that the commands will be executed in cmd.

# run a simple command and get the exit code.
ssh user-1@10.10.10.10 'dir'
echo $?

# run a cmd script and get the exit code. (Script exists on user's home directory)
ssh user-1@10.10.10.10 'test.bat'
echo $?

# run a powershell script and get the exit code.
ssh user-1@10.10.10.10 'powershell -File test.ps1'
echo $?

So far everything is clear and fine. However, if a powershell script returns error, you won’t get that with echo $?, why?!
Since we are using “-File”, it’s designed to always return 0 or true.
What should we do in this case?

It is possible to run encoded commands with powershell like:

$command = 'dir "c:\program files"'
$bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
$encodedCommand = [Convert]::ToBase64String($bytes)

powershell.exe -encodedCommand $encodedCommand

This is a useful feature, how should we adopt it to use script instead of command??

MY SOLUTION

ssh user-1@10.10.10 "powershell -c \
> \"\$scriptContent = Get-Content -Path 'test.ps1' -Raw ; \
> \$encodedScript = [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes(\$scriptContent)) ; \
> powershell -EncodedCommand \"\$encodedScript\""

echo $?

In this way, you will get the right exit code.

If you already have an easier solution, please share it here. TNX

--

--

As a Platform Engineer who likes sharing knowledge, I believe we shouldn’t experience something that other people have experienced it before.