- Poll: How reliable are ChatGPT and Bing Chat? - Tue, May 23 2023
- Pip install Boto3 - Thu, Mar 24 2022
- Install Boto3 (AWS SDK for Python) in Visual Studio Code (VS Code) on Windows - Wed, Feb 23 2022
Why SSH transport for PowerShell remoting?
You can use PowerShell remoting cmdlets such as Enter-PSsession and Invoke-Command on a PowerShell 6 console via SSH. However, as you can see in the screenshot below, PowerShell remoting works nicely in the popular SSH client PuTTY. Of course, you can work with any SSH client. SSH is certainly the most common remote management protocol, and clients are available for all operating systems.
The main advantage of PowerShell remoting via SSH is that it easier to manage in environments without Active Directory. If you work with WinRM in this case, you have to configure trusted hosts and set up PowerShell remoting for HTTPS because the default protocol HTTP is not secure outside an Active Directory domain. SSH's host identification and public key authentication are secure, and you don't have to mess with SSL/TLS certificates as with HTTPS.
Enabling SSH for PowerShell on the host
Below I show you how can install and enable PowerShell remoting for SSH transport. As you will notice, the process differs significantly from enabling remoting for WinRM. One big difference is that you no longer need the Enable-PSremoting cmdlet.
Note that you need PowerShell Core 6 to follow this guide because only the latest release of Microsoft's scripting language comes with the required SSH support.
- Download the PowerShell 6 Core MSI and install it on your Windows machine. This is a simple next-next installation. Note that I am working with PowerShell 6.0 here because 6.1 is still in preview at the time of this writing.
- Download OpenSSH for Windows. I worked with the 64-bit version for this guide.
- Extract the OpenSSH-Win64.zip file and copy OpenSSH-Win64 to C:\Program Files\ (the 32-bit edition is fine too).
- Rename OpenSSH-Win64 to OpenSSH.
- Execute the command below to install OpenSSH:
powershell.exe -ExecutionPolicy Bypass -File "C:\Program Files\OpenSSH\install-sshd.ps1"
- Next, we'll add the OpenSSH location to the PATH environment variable to ensure the operating system finds the OpenSSH executables. At a PowerShell console you can run the commands below:
$env:Path="$env:Path;C:\Program Files\OpenSSH\" Set-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH -Value $env:Path
- We can now start the SSH service (sshd) with this PowerShell command:
Start-Service sshd
- I recommend automatically starting the OpenSSH services sshd:
Set-Service sshd -StartupType Automatic
- Launch Notepad as admin (right-click and select Run as administrator) and open sshd_config in C:\ProgramData\SSH\ (change the file type to *.*, otherwise you'll only see .txt files). Note that the ProgramData folder is hidden, and you will therefore only see the file if you enabled Hidden items in the File Explorer View.
- Comment out this line in sshd_config "Subsystem sftp sftp-server.exe" and add this one instead:
Subsystem powershell c:/program files/powershell/6.0.2/pwsh.exe -sshs -NoLogo -NoProfile
Note that the path may vary if you work with another PowerShell Core version.
- To allow remote connections in the Windows Firewall, you have to open the SSH port (22). On a Windows PowerShell console you can do it with this command:
New-NetFirewallRule -DisplayName 'SSH Inbound' -Profile @('Domain', 'Private', 'Public') -Direction Inbound -Action Allow -Protocol TCP ‑LocalPort 22
Notice that this command doesn't work on PowerShell Core 6.0.
This opens the SSH port for all three network profiles (Domain, Private, Public). Depending on your environment, you might want to open port 22 only for one of the profiles
- You now have to reboot the computer to ensure that the environment variable PATH is available systemwide
Testing PowerShell remoting with SSH
That's it. You just enabled PowerShell remoting for SSH. You can now test your connection on a PowerShell 6 console. Note that you have to install OpenSSH on the local and on the remote machine for this work. However, the sshd service only needs to run on the remote machine.
Enter-PSsession -HostName <computer name>
The HostName parameter ensures that PowerShell will use SSH as the transport protocol. PowerShell uses the user name used to log on to your local machine.
If you are working with an Active Directory account, you have to pass the user name with the UserName parameter using this syntax: <user name>:<domain name>.
Enter-PSsession -HostName <computer name> -UserName <user name>:<domain name>
If you sign on the first time on the remote host, you have to acknowledge the key fingerprint by typing "yes." OpenSSH will store the fingerprint in the known_hosts file in the .ssh folder of your user profile. You then have to enter your password, and you are in.
- Of course, you can also work with Invoke-Command:
Invoke-Command -HostName <computer name> -UserName <user name>:<domain name> -ScriptBlock {get-process}
Enter-PSSession and Invoke-Command also offer the SSHTransport switch. If you omit the HostName parameter, you can use SSHTransport to tell PowerShell remoting to connect via SSH.
Enter-PSsession <computer name> -UserName <user name>:<domain name> ‑SSHTransport
The New-PSsession cmdlet supports SSH as well:
$session = New-PSSession -HostName <computer name> -UserName <user name> Invoke-Command -Session $session -ScriptBlock {get-process}
With the Get-PSSession cmdlet you can verify you are connected via SSH:
Using the SSH client
OpenSSH comes with a simple SSH client. At a command prompt, you can connect to your SSH host this way:
ssh <user name>@<computer name>
Or if you want to sign in with an Active Directory account:
ssh <user name>:<domain name>@<computer name>
This will launch cmd.exe instead of PowerShell. To switch to PowerShell, simply run pwsh.
As mentioned above, this works with any SSH client such as PuTTY on Windows or vSSH on a Mac.
You will have noticed that I always had to enter my password after I connected to the remote machine. This is not what we are used to with PowerShell remoting. In an Active Directory domain environment, you are usually already authenticated, and you therefore don't need to enter a password. This currently doesn't work with PowerShell remoting over SSH.
Subscribe to 4sysops newsletter!
However, you can use public key authentication to avoid entering passwords. This is particularly useful when automating remotely with Invoke-Command. I will show you in my next post how you can configure public key authentication.
Awesome!!!… Really Helpful. Deeply Appreciate your post.
Nice write-up Michael! I’ll be saving that so I don’t need to figure out all the steps. Appreciate the work to document the process.
Good job 🙂
Thanks!
Hi
Thanks for the great article! I’d like to run the Invoke-Command non-interactively for a script, but how can I provide the password non-interactively?
I’ve tried this, but the command structure doesn’t seem to support it:
$pw = convertto-securestring -AsPlainText -Force -String <somepassword>
2. set the credential pair
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist “Administrator”,$pw
3. Get a session
“`
PS windows-dns/scripts> $session = New-PSSession -HostName windns -Credential $cred
New-PSSession : Parameter set cannot be resolved using the specified named parameters. One or more parameters issued cannot be used together or an insufficient number of parameters were provided.
“`
Is there a way to obtain SSHTransport session without interactively providing the password?
@Traiano
You are using parameters which belong to different parameter sets.
When you use Get-Help or Get-Command -Syntax, there is a section named Syntax and where you can find all parameter belonging to the same parameter set. One line represent one parameter set.
With the SSHTransport parameter, you cannot use the Credential parameter. Only the UserName parameter can be used, and you will be asked for a password.
In the context of a script, another way to login is by using the KeyFilePath parameter and a key file. But the SSH service on the remote server must be configured to accept key files without providing a username and a password. That’s a common configuration (provide either key file or username/password) because administrators are lazy. The risk is that someone can steal you key file…
Finally, you can also start your process or scheduled task with credential which has already the permission to authenticate on the remote server. Then you don’t have to provide the username and password because it is implicit.
Hi, awsome and clean install, but I cannot seem to get any elevation privileges, which is kind of the point here so as to do admin tasks silently… Do you get elevated priviliges? Is there a way to do that?
Thank you!
Gregory Tsintaris
Hmm, I somehow assumed you have the same privileges as with WinRM. I currently don’t have a test installation. Which command did you run that didn’t work and what was the error message?
I have connected with a local admin account and with a domain admin account with the same results for the below commands:
“Get-WUInstall –MicrosoftUpdate –AcceptAll -Install” and it produced:
Get-WUInstall : Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
At line:1 char:1
+ Get-WUInstall -AcceptAll -Install
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-WindowsUpdate], UnauthorizedAccessException
+ FullyQualifiedErrorId : System.UnauthorizedAccessException,PSWindowsUpdate.GetWindowsUpdate
This command is installed by “Install-Module PSWindowsUpdate” and when run from an elevated powershell prompt it installs windows updates. I used this command as a test as it only works from an elevated PS.
Thank you!
Just to rule out that it isn’t another issue, can you stop services with stop-service? You can also check which account the sshd service uses to logon.
The sshd service uses local system account by default, the command stop-service works for spooler for example.
Is there a way to verify if we have true elevated prompt?
I tried another windows update vbs script which also requires elevated cmd and which runs fine using psexec and get an access denied error also…
I think you can’t stop a service without elevation. You can also try copying a file to “/program files/”. That also wouldn’t work without elevation.
I found out why: https://serverfault.com/questions/473991/run-remote-powershell-as-administrator
The only way to run windows update or any similar action you can’t do it unless you use JEA feature… Back to reading! Thank you!