Sergey Nivens - Fotolia
Learn to set up and use PowerShell SSH remoting
Remoting over SSH in PowerShell Core has some advantages over the traditional Windows PowerShell remoting method, but it will require a fair amount of manual configuration work.
When Microsoft said PowerShell would become an open source project that would run on Windows, Linux and macOS in August 2016, there was an interesting wrinkle related to PowerShell remoting.
Microsoft said this PowerShell Core would support remoting over Secure Shell (SSH) as well as Web Services-Management (WS-MAN). You could always use the PowerShell SSH binaries, but the announcement indicated SSH support would be an integral part of PowerShell. This opened up the ability to perform remote administration of Windows and Linux systems easily using the same technologies.
A short history of PowerShell remoting
Microsoft introduced remoting in PowerShell version 2.0 in Windows 7 and Windows Server 2008 R2, which dramatically changed the landscape for Windows administrators. They could create remote desktop sessions to servers, but PowerShell remoting made it possible to manage large numbers of servers simultaneously.
Remoting in Windows PowerShell is based on WS-MAN, an open standard from the Distributed Management Task Force. But because WS-MAN-based remoting is Windows orientated, you needed to use another technology, usually SSH, to administer Linux systems.
Introducing SSH on PowerShell Core
SSH is a protocol for managing systems over a possibly unsecured network. SSH works in a client-server mode and is the de facto standard for remote administration in Linux environments.
PowerShell Core uses OpenSSH, a fork from SSH 1.2.12 which was released under an open source license. OpenSSH is probably the most popular SSH implementation.
The code required to use WS-MAN remoting is installed as part of the Windows operating system. You need to install OpenSSH manually.
Installing OpenSSH
We have grown accustomed to installing software on Windows using the wizards, but the installation of OpenSSH requires more background information and more work from the administrator. Without some manual intervention, many issues can arise.
The installation process for OpenSSH on Windows has improved over time, but it's still not as easy as it should be. Working with the configuration file leaves a lot to be desired.
There are two options when installing PowerShell SSH:
- On Windows 10 1809, Windows Server 1809, Windows Server 2019 and later, OpenSSH is available as an optional feature.
- On earlier versions of Windows, you can download and install OpenSSH from GitHub.
Be sure your system has the latest patches before installing OpenSSH.
Installing the OpenSSH optional feature
You can install the OpenSSH optional feature using PowerShell. First, check your system with the following command:
Get-WindowsCapability -Online | where Name -like '*SSH*'
Figure 1 shows the OpenSSH client software is preinstalled.
You'll need to use Windows PowerShell for the installation unless you download the WindowsCompatibility module for PowerShell Core. Then you can import the Deployment Image Servicing and Management module from Windows PowerShell and run the commands in PowerShell Core.
Install the server feature:
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
Path :
Online : True
RestartNeeded : False
The SSH files install in the C:\Windows\System32\OpenSSH folder.
Download OpenSSH from GitHub
Start by downloading the latest version from GitHub. The latest version of the installation instructions are at this link.
After the download completes, extract the zip file into the C:\Program Files\OpenSSH folder. Change location to C:\Program Files\OpenSSH to install the SSH services:
.\install-sshd.ps1
[SC] SetServiceObjectSecurity SUCCESS
[SC] ChangeServiceConfig2 SUCCESS
[SC] ChangeServiceConfig2 SUCCESS
Configuring OpenSSH
After OpenSSH installs, perform some additional configuration steps.
Ensure that the OpenSSH folder is included on the system path environment variable:
- C:\Windows\System32\OpenSSH\ if installed as the Windows optional feature
- C:\Program Files\OpenSSH\ if installed via the OpenSSH download
Set the two services to start automatically:
Set-Service sshd -StartupType Automatic
Set-Service ssh-agent -StartupType Automatic
If you installed OpenSSH with the optional feature, then Windows creates a new firewall rule to allow inbound access of SSH over port 22. If you installed OpenSSH from the download, then create the firewall rule with this command:
New-NetFirewallRule -Name sshd -DisplayName 'OpenSSH Server (sshd)' `
-Enabled True -Direction Inbound -Protocol TCP `
-Action Allow -LocalPort 22
Start the sshd service to generate the SSH keys:
Start-Service sshd
The SSH keys and configuration file reside in C:\ProgramData\ssh, which is a hidden folder. The default shell used by SSH is the Windows command shell. This needs to change to PowerShell:
New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell `
-Value "C:\Program Files\PowerShell\6\pwsh.exe" -PropertyType String -Force
Now, when you connect to the system over SSH, PowerShell Core will start and will be the default shell. You can also make the default shell Windows PowerShell if desired.
There's a bug in OpenSSH on Windows. It doesn't work with paths with a space, such as the path to the PowerShell Core executable! The workaround is to create a symbolic link that creates a path that OpenSSH can use:
New-Item -ItemType SymbolicLink -Path C:\pwsh -Target 'C:\Program Files\PowerShell\6'
In the sshd_config file, un-comment the following lines:
PubkeyAuthentication yes
PasswordAuthentication yes
Add this line before other subsystem lines:
Subsystem powershell C:\pwsh\pwsh.exe -sshs -NoLogo -NoProfile
This tells OpenSSH to run PowerShell Core.
Comment out the line:
AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys
After saving the changes to the sshd_config file, restart the services:
Restart-Service sshd
Start-Service ssh-agent
You need to restart the sshd service after any change to the config file.
Using PowerShell SSH remoting
Using remoting over SSH is very similar to remoting over WS-MAN. You can access the remote system directly with Invoke-Command:
Invoke-Command -HostName W19DC01 -ScriptBlock {Get-Process}
richard@MANTICORE@w19dc01's password:
You'll get a prompt for the password, which won't be displayed as you type it.
If it's the first time you've connected to the remote system over SSH, then you'll see a message similar to this:
The authenticity of host 'servername (10.00.00.001)' can't be established.
ECDSA key fingerprint is SHA256:(<a large string>).
Are you sure you want to continue connecting (yes/no)?
Type yes and press Enter.
You can create a remoting session:
$sshs = New-PSSession -HostName W19FS01
richard@MANTICORE@w19fs01's password:
And then use it:
Invoke-Command -Session $sshs -ScriptBlock {$env:COMPUTERNAME}
W19FS01
You can enter an OpenSSH remoting session using Enter-PSSession in the same way as a WS-MAN session. You can enter an existing session or use the HostName parameter on Enter-PSSession to create the interactive session.
You can't disconnect an SSH based session; that's a WS-MAN technique.
You can use WS-MAN and SSH sessions to manage multiple computers as shown in Figure 2.
The session information shows the different transport mechanism -- WS-MAN and SSH, respectively -- and the endpoint in use by each session.
If you look closely at Figure 2, you'll notice there was no prompt for the password on the SSH session because the system was set up with SSH key-based authentication.
Using SSH key-based authentication
Open an elevated PowerShell session. Change the location to the .ssh folder in your user area:
Set-Location -Path ~\.ssh
Generate the key pair:
ssh-keygen -t ed25519
Add the key file into the SSH-agent on the local machine:
ssh-add id_ed25519
Once you've added the private key into SSH-agent, back up the private key to a safe location and delete the key from the local machine.
Copy the id_ed25519.pub file into the .ssh folder for the matching user account on the remote server. You can create such an account if required:
$pwd = Read-Host -Prompt 'Password' -AsSecureString
Password: ********
New-LocalUser -Name Richard -Password $pwd -PasswordNeverExpires
Add-LocalGroupMember -Group Administrators -Member Richard
On the remote machine, copy the contents of the key file into the authorized_keys file:
scp id_ed25519.pub authorized_keys
The authorized_keys file needs its permissions changed:
- Open File Explorer, right click authorized_keys and navigate to Properties – Security – Advanced
- Click Disable Inheritance.
- Select Convert inherited permissions into explicit permissions on this object.
- Remove all permissions except for SYSTEM and your user account. Both should have Full control.
You'll see references to using the OpenSSHUtils module to set the permissions, but there's a bug in the version from the PowerShell Gallery that makes the authorized_keys file unusable.
Restart the sshd service on the remote machine.
You can now connect to the remote machine without using a password as shown in Figure 2.
If you're connecting to a non-domain machine from a machine in the domain, then you need to use the UserName parameter after enabling key-pair authentication:
$ss = New-PSSession -HostName W19ND01 -UserName Richard
You need the username on the remote machine to match your domain username. You won't be prompted for a password.
WS-MAN or SSH remoting?
Should you use WS-MAN or SSH based remoting? WS-MAN remoting is available on all Windows systems and is enabled by default on Windows Server 2012 and later server versions. WS-MAN remoting has some issues, notably the double hop issue. WS-MAN also needs extra work to remote to non-domain systems.
SSH remoting is only available in PowerShell Core; Windows PowerShell is restricted to WS-MAN remoting. It takes a significant amount of work to install and configure SSH remoting. The documentation isn't as good as it needs to be. The advantages of SSH remoting are that you can easily access non-domain machines and non-Windows systems where SSH is the standard for remote access.