Run powershell script remotely via ssh and get the exit code
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