Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Deploy OpenSSH on Windows 2019 Full and Core

Deploy OpenSSH on Windows Server 2019


We want to install OpenSSH on a Windows Server 2019, so we can remote access it with ssh myuser@win2019.

We want also to turn on PowerShell Remoting over SSH, so we can create PSSession objects from PowerShell Core on Linux/MacOs/Windows.


This work is a compilation of the pages found on Microsoft's official documentation and community:

Login Shell on Windows Server 2019 core

Let me repeat the title... Do this ONLY on Windows Core Edition. This will allow you to login with a PowerShell sessio directly.

If you are on the console, you must be in a cmd.exe, so start a powershell and type these instructions:

Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" `
   -Name Shell `
   -Value powershell.exe

Install PowerShell Core

Even if you don't configure PowerShell Remoting over SSH, PowerShell Core is a Good Thing (tm) to have on your machines.

First download the install from PowerShell's official github (as of this writing we are on 6.2.3 with 7.0.0 lurking around the corner):

Invoke-WebRequest `
    -OutFile $HOME\Downloads\PowerShell-6.2.3-win-x64.msi `

Then, go ahead and install it:

cd $HOME\Downloads
msiexec.exe /package PowerShell-6.2.3-win-x64.msi /quiet `

Deploy and Configure OpenSSH

First, install both the SSH Client and Server:

Add-WindowsCapability -Online -Name OpenSSH.Client~~~~
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~

To be able to use SSH keys to authenticate, install the following module:

Install-Module -Force OpenSSHUtils -Scope AllUsers

Then, start the SSH Agent and the SSH Server services:

Set-Service -Name ssh-agent -StartupType Automatic
Start-Service ssh-agent
Set-Service -Name sshd -StartupType Automatic
Start-Service sshd

You can check the Firewall rule like this:

Get-NetFirewallPortFilter | Where { $_.LocalPort -eq 22  }
Get-NetFirewallRule -Name OpenSSH-Server-In-TCP

Configure Powershell to be the default shell when remoting in via SSH:

New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -PropertyType String -Force

Configure you SSH environment on the Windows server so you can add your SSH public key to authenticate:

mkdir .ssh
touch .ssh\authorized_keys
Repair-AuthorizedKeyPermission C:\users\gcadmin\.ssh\authorized_keys
Icacls authorized_keys /remove NT SERVICE\sshd

Configure PowerShell Remoting over SSH

The final touch is to allow PSSession over SSH. Open the SSHD Config file at C:\ProgramData\SSH\sshd_config, and modify the line that allow public keys to authenticate:

PubkeyAuthentication yes

Then add a new ssh subsystem after sftp:

Subsystem       powershell      C:/progra~1/PowerShell/6/pwsh.exe -sshs -NoLogo -NoProfile

Note: Make sure to use the MS-DOS 8.3 path notation with / to point to the PowerShell executable. Otherwise the SSHD server will fail incoming sessions with some obscure error like:

New-PSSession : [] The SSH client session has ended with error message: The SSH transport process has abruptly terminated causing this remote session to break.

Final step! Reboot the server (Restarting the sshd service does not seem sufficient in my experience):




The first test will be to connect via ssh, the first time, you should force password authentication:

ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no

Then add you public key (typically ~/.ssh/ to the authorized keys of the Windows server:

ssh "Add-Content -Path .ssh/authorized_keys -Value '$(cat ~/.ssh/' -NoNewLine"

Subsequent ssh sessions will look like:


Negociation will happen with the public key... No more passwords!

PowerShell Core sessions

If you are familiar with sessions in PowerShell, this will be easy. The main difference is the SSH parameters:

$session = New-PSSession -Hostname -UserName ACME\myuser -SSHTransport

Invoke-Command $session { ls }
Enter-PSSession $session
> dir
> exit
Remove-PsSession $session
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment