Installing and Configuring OpenSSH in PowerShell

Discover how to install and manage OpenSSH on Windows. Windows version 1809 ships with a stable version of OpenSSH.

Jérémie KassianoffCybernetics team 6 min read
Installing and Configuring OpenSSH in PowerShell

Real-world use case

You need to administer a Windows server over SSH rather than RDP: here's how to install and manage OpenSSH via PowerShell.

Installing and configuring OpenSSH in PowerShell

The secure SSH communication protocol has become a must-have on BSD and GNU/Linux systems, with a history going back to the mid-90s. Microsoft managed, in 2017, to integrate native support for the SSH protocol (beta) into Windows. In 2018, to great relief, the OpenSSH version has been stable since Windows build 1809.

With the growing externalization of information systems, Microsoft is promoting open technologies in their proprietary products. It's now possible to connect to a Windows machine using the SSH communication protocol. In the following article, we'll use the OpenSSH client in Windows 10 and the OpenSSH server in Windows Server 2019 with a key pair, and we'll also discover PowerShell aliases.

Installing the OpenSSH client/server

All the steps will be done in PowerShell as an administrator. On a Windows 10 machine or a Windows 2019 server, it's possible to check the state of the OpenSSH feature:

powershell
Get-WindowsCapability -Online | ? Name -like "OpenSSH*"

Name  : OpenSSH.Client~~~~0.0.1.0
State : NotPresent
Name  : OpenSSH.Server~~~~0.0.1.0
State : NotPresent

Currently, the feature is available in a notPresent state to install the OpenSSH client or server:

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

Once the Windows feature installation is done, here's the result:

bash
Path          :
Online        : True
RestartNeeded : False

No restart is needed, we'll now run a test of the SSH client in PowerShell:

bash
ssh
usage: ssh [-46AaCfGgKkMNnqsTtVvXxYy] [-B bind_interface]
           [-b bind_address] [-c cipher_spec] [-D [bind_address:]port]
           [-E log_file] [-e escape_char] [-F configfile] [-I pkcs11]
           [-i identity_file] [-J [user@]host[:port]] [-L address]
           [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]
           [-Q query_option] [-R address] [-S ctl_path] [-W host:port]
           [-w local_tun[:remote_tun]] destination [command]

The client works, we find the source files at the following location: C:WindowsSystem32OpenSSH

bash
ls C:WindowsSystem32OpenSSH

Directory : C:WindowsSystem32OpenSSH

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       05/09/2018     16:07         322560 scp.exe
-a----       05/09/2018     16:07         390144 sftp.exe
-a----       05/09/2018     16:07         491520 ssh-add.exe
-a----       05/09/2018     16:07         384512 ssh-agent.exe
-a----       05/09/2018     16:07         637952 ssh-keygen.exe
-a----       05/09/2018     16:07         530432 ssh-keyscan.exe
-a----       05/09/2018     16:07         882688 ssh.exe

The OpenSSH server uses a dedicated service, the SSH services' status shows:

bash
Get-service ssh*

Status   Name               DisplayName
------   ----               -----------
Stopped  ssh-agent          OpenSSH Authentication Agent
Stopped  sshd               OpenSSH SSH Server

To start the SSHD and SSH-agent services:

bash
net start sshd
The OpenSSH SSH Server service is starting..
The OpenSSH SSH Server service was started successfully.

net start ssh-agent
The OpenSSH Authentication Agent service is starting.
The OpenSSH Authentication Agent service was started successfully.

Let's check that the services have started properly:

bash
Get-service ssh*

Status   Name               DisplayName
------   ----               -----------
Running  ssh-agent          OpenSSH Authentication Agent
Running  sshd               OpenSSH SSH Server

Let's add automatic startup to our SSH service:

powershell
Set-Service sshd -StartupType Automatic

Also to the public key control service, so we can use ssh-add.exe later:

bash
Set-Service ssh-agent -StartupType Automatic

The OpenSSH client and server are installed on the Windows machine. We can run a connection test:

bash
ssh user@ip

Configuring SSH aliases in PowerShell

If you have a large number of SSH connections, it can be essential to use aliases in PowerShell.
To do this, we need to configure a profile for our PowerShell command prompt and allow PS1 script execution:

bash
new-item $PROFILE.CurrentUserAllHosts -ItemType file -Force

To access the script from the user:

bash
ise $PROFILE.CurrentUserAllHosts

A warning message appears, since by default group policy applies to script execution. In order to be able to read our script: profile.ps1, we need to change the value to unrestricted.

powershell
Set-ExecutionPolicy -Scope CurrentUser

We now need to add:

bash
RemoteSigned

We need to run the command again to access the script from the user:

bash
ise $PROFILE.CurrentUserAllHosts

A new folder is now present in My Documents, along with a profile.ps1 script. Let's edit it with a text editor or the PowerShell ISE editor in order to add an SSH alias:

bash
function sshserver1 { ssh "user@ip"}

It's also possible to use port forwarding like this (e.g.: vnc):

bash
function sshvncserver1 {ssh -L "localhost:5900:localhost:5900" "user@ip"}

Generating an SSH key pair in PowerShell

Key pair authentication is a recommended method, by default, the folder containing it is in your user's personal location: ~.ssh. If it doesn't exist, we need to generate an SSH key pair (e.g.: ecdsa):

bash
ssh-keygen -t ecdsa -b 521
Generating public/private ecdsa key pair.
Enter file in which to save the key (C:Usersmyuser/.ssh/id_ecdsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in C:Usersmyuser/.ssh/id_ecdsa.
Your public key has been saved in C:Usersmyuser/.ssh/id_ecdsa.pub.
The key fingerprint is:
SHA256:tryXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX mydomainmyuser@nondns
The key's randomart image is:
+---[ECDSA 521]---+
|                 |
|                 |
|.        .       |
|X.  . ... .      |
|.X. .XXXXx       |
|x .#.X-X.*.      |
|. ..X)+&XX       |
| . X .-.X.       |
|  . .  ...       |
+----[SHA256]-----+

Now we need to add the private key to our SSH server:

bash
ssh-add.exe .id_ecdsa 
Enter passphrase for .id_ecdsa: 
Identity added: 
.id_ecdsa (.id_ecdsa)

To transfer an SSH public key from our client to our server (listening on port e.g.: 2222):

bash
scp -P 2222 C:Usersmyuser.sshid_ecdsa.pub mydomainuser@ip:C:Usersmyuser.ssh/authorized_keys

Once the copy is done, you can connect with your SSH key to the Windows server.

Configuring the OpenSSH server in PowerShell

The configuration options for a Windows SSH server are limited, as the wiki explains: not supported.
In PowerShell, let's run the following command to edit the OpenSSH server's configuration file:

bash
 notepad.exe "C:ProgramDatasshsshd_config"

Here's my sshd_config configuration file:

bash
Port 2222
ListenAddress 192.168.0.2
PubkeyAuthentication yes
AuthorizedKeysFile    .ssh/authorized_keys
PasswordAuthentication no
Subsystem    sftp    sftp-server.exe
DenyUsers mydomain.local*
Match Group administrators
       AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys

It might be necessary to add a firewall rule to allow SSH access:

powershell
New-NetFirewallRule -Name sshd -DisplayName 'OpenSSH Server (sshd)' -Service sshd -Enabled True -Direction Inbound -Protocol TCP -Action Allow -Profile Domain

Name                  : sshd
DisplayName           : OpenSSH Server (sshd)
Description           :
DisplayGroup          :
Group                 :
Enabled               : True
Profile               : Domain
Platform              : {}
Direction             : Inbound
Action                : Allow
EdgeTraversalPolicy   : Block
LooseSourceMapping    : False
LocalOnlyMapping      : False
Owner                 :
PrimaryStatus         : OK
Status                : The rule was parsed from the store. (65536)
EnforcementStatus     : NotApplicable
PolicyStoreSource     : PersistentStore
PolicyStoreSourceType : Local

Installing and configuring OpenSSH in PowerShell is now complete.

Conclusion

Jérémie Kassianoff

Cybernetics team

View profile

Read next

Achieving a 0% Exposure Score with Microsoft Defender Vulnerability Management
Microsoft

Achieving a 0% Exposure Score with Microsoft Defender Vulnerability Management

Read the article
Take Back Control of Your Microsoft Directories with an Infrastructure as Code Approach
Microsoft

Take Back Control of Your Microsoft Directories with an Infrastructure as Code Approach

Read the article
Installing and Configuring Azure Active Directory Connect
Microsoft

Installing and Configuring Azure Active Directory Connect

Read the article