Running SSH Server on Windows with PowerShell

If I’m going to be working on windows, especially mainly with powershell, I’d rather do it from a terminal on my local machine over ssh. That way I don’t have to deal with the windows gui getting in my way. To add to this, my experience with windows powershell and powershell 7 within a qemu/kvm virtual machine has been an annoying lag while typing. This seems to have been caused by the display UI and not the shell itself, since I don’t experience the issue over ssh.

Powershell 7 and winget

To get started were going to need powershell 6+, with the current version being 7. We’ll also need winget installed.

PS> winget install -e --id Microsoft.PowerShell

You now should see two powershells. One windows powershell and powershell 7 when searching for apps.

Open powershell 7 as admin and check for any ssh installation:

PS> Get-WindowsCapability -Online | ? Name -like 'OpenSSH*'

# Result:
Name  : OpenSSH.Client~~~~0.0.1.0
State : Installed
Name  : OpenSSH.Server~~~~0.0.1.0
State : NotPresent

Since the server isn’t present I’m going to add it with the following:

PS> Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0

And start the SSH daemon service

PS> Start-Service sshd # start ssh daemon
PS> Set-Service sshfs -StartupType Automatic # start ssh daemon on boot

Next, edit the sshd config and add the SSH subsystem that hosts powershell process:

PS> Subsystem powershell c:/progra~1/powershell/7/pwsh.exe -sshs -nologo

If you’re wondering what the hell this means and where it comes from, there’s more info in the docs , along with this command:

PS> Get-CimInstance Win32_Directory -Filter 'Name="C:\\Program Files"' | Select-Object EightDotThreeFileName

EightDotThreeFileName
---------------------
c:\progra~1

Now we can restart the sshd service

PS> Restart-Service sshd

And we should now be able to connect to our machine over ssh. After login, we’ll be thrown into the classic cmd, so use pwsh to launch powershell.

Troubleshooting a virtual machine

In one case, I was running windows locally in a vm with NAT networking that uses port forwarding for ssh access from localhost. I was not able to connect. We can see that the windows firewall rule for ssh has been created:

PS> Get-NetFirewallRule -Name *ssh*

This is using the private profile rule. So I made another rule for port 22 with the public profile and it works! This can be done in the gui or in the shell:

New-NetFirewallRule -Name sshd -DisplayName 'SSH local tunnel' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22 -Profile Public

Success!