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:
- https://docs.microsoft.com/en-us/windows-server/administration/openssh/openssh_server_configuration
- https://docs.microsoft.com/en-us/powershell/scripting/learn/remoting/ssh-remoting-in-powershell-core?view=powershell-6
- https://techcommunity.microsoft.com/t5/ITOps-Talk-Blog/Installing-and-Configuring-OpenSSH-on-Windows-Server-2019/ba-p/309540
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
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 7.2.1):
Invoke-WebRequest https://github.com/PowerShell/PowerShell/releases/download/v7.2.1/PowerShell-7.2.1-win-x64.msi `
-OutFile $HOME\Downloads\PowerShell-7.2.1-win-x64.msi `
-UseBasicParsing
Then, go ahead and install it:
cd $HOME\Downloads
msiexec.exe /package PowerShell-7.2.1-win-x64.msi /quiet `
ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL=1 `
ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL `
ENABLE_PSREMOTING=1 `
REGISTER_MANIFEST=1
First, install both the SSH Client and Server:
Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
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”
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 : [win.acme.com] 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):
Restart-Computer
The first test will be to connect via ssh, the first time, you should force password authentication:
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no myuser@win.acme.com
Then add you public key (typically ~/.ssh/id_rsa.pub
) to the authorized keys of the Windows server:
ssh myuser@win.acme.com "Add-Content -Path .ssh/authorized_keys -Value '$(cat ~/.ssh/id_rsa.pub)' -NoNewLine"
Subsequent ssh sessions will look like:
ssh myuser@win.acme.com
Negociation will happen with the public key... No more passwords!
If you are familiar with sessions in PowerShell, this will be easy. The main difference is the SSH parameters:
$session = New-PSSession -Hostname there.acme.com -UserName ACME\myuser -SSHTransport
Invoke-Command $session { ls }
Enter-PSSession $session
> dir
> exit
Remove-PsSession $session