In the past whenever I had to manage a Windows Server, I used RDP (Remote Desktop Protocol) to connect to the server and manually click around to change the necessary settings.
While working with Ansible to setup a Windows build agent, I realized that starting with Windows 10, Windows does ship with support for OpenSSH as an optional feature. This means, you can SSH into the server, instead of using RDP, and with the right PowerShell scripts set everything up the way you need it to be. That‘s also the way Ansible works; all it needs is an active SSH connection.
To enable OpenSSH there are few things to keep in mind though, as such I decided to write them down.
Manual Steps
First lets look at the manual steps needed to apply all the changes and then later automate everything with a PowerShell script.
Install OpenSSH
- Search in the start menu for “Add an optional feature” (Windows 11: “Add optional feature”)
- (Windows 11: Then “View” on “Add an optional feature”)
- Usually “OpenSSH Client” is already installed, if not, you may want to install it, so you could also use the server as a jump host
- Click on “Add” and install “OpenSSH Server”
- Open the “Services” application and set “Start up” for the services “OpenSSH Server” and “OpenSSH Agent” to “Automatic”
Setup Key Authentication
While you could stick to password logins, it’s considered best practice to use private/public key authentication. That way not everyone in the domain can login and no passwords can be brute forced.
Note: If your server is in a domain and you want to use a user of that domain, make sure you’re generating the key with your domain user.
Read the Key-based authentication guide for more details on how to generate keys, here is the basic command for it:
ssh-keygen -t ed25519
This generate a private key (id_ed25519
), which you should never give out and a public key (id_ed25519.pub
). The public key needs to be stored on the server, as to inform the SSH service that this is an authorized user/key.
Note: If you plan to automate installations you’ll most likely be using an administrative account, which are managed slightly different. The following steps will assume the use of an administrative account and point out difference for a non-administrative account. See also the last paragraph of the Configure SSHd section.
- Insert the public key on a new line in
C:\ProgramData\ssh\administrators_authorized_keys
- For non-admin accounts the location is:
$env:USERPROFILE\.ssh\authorized_keys
- For non-admin accounts the location is:
- Ensure the permission of the
is set correctly:administrators_authorized_keys
- Disable permission inheritance
- Only two users should have access, that is
SYTEM
&Administrators
- For non-admin accounts this would be
SYSTEM
& your personal account
- For non-admin accounts this would be
- More details here: Setting up OpenSSH for Windows using public key authentication
Configure SSHd
Three configuration changes for the SSH server that you may want to consider:
- Disable password authentication by adding the line
PasswordAuthentication no
to theC:\ProgramData\ssh\sshd_config
- Enable key authentication by adding the line
PubkeyAuthentication
to theC:\ProgramData\ssh\sshd_config
- Enable PowerShell as default OpenSSH shell by setting the string value of the registry key
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\OpenSSH\DefaultShell
toC:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
- See also: DefaultShell
In case you don’t want to manage administrative accounts globally, you can remove the two lines at the end of the C:\ProgramData\ssh\sshd_config
file:
Match Group administrators
AuthrorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys
Don’t forget to restart the sshd
service!
Automated
It’s good to know how to do it manually, but if you have to do it more than once, you’ll of course want a PowerShell script, so here it is!
# Install OpenSSH client & server
Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*'
Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*'
# Configure OpenSSH service
Start-Service sshd
Set-Service -Name sshd -StartupType 'Automatic'
# Enable access for technical user
$authorizedKey = '<insert pub key>'
Add-Content -Force -Path "$env:ProgramData\ssh\administrators_authorized_keys" -Value $authorizedKey
icacls.exe "$env:ProgramData\ssh\administrators_authorized_keys" /inheritance:r /grant "Administrators:F" /grant "SYSTEM:F"
(Get-Content "$env:ProgramData\ssh\sshd_config").Replace('#PubkeyAuthentication yes', 'PubkeyAuthentication yes') | Set-Content "$env:ProgramData\ssh\sshd_config"
(Get-Content "$env:ProgramData\ssh\sshd_config").Replace('#PasswordAuthentication yes', 'PasswordAuthentication no') | Set-Content "$env:ProgramData\ssh\sshd_config"
# Use PowerShell as default OpenSSH shell
New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -PropertyType String -Force
# Apply changes
Restart-Service sshd