Install OpenSSH Server on Windows via Add-WindowsCapability

Exported on 19-Nov-2021 13:09:37

Using Attune to install and configure OpenSSH Server on Win10/Win11/Win2019

This blueprint is used to install and configure OpenSSH Server on Win10/Win2019. OpenSSH is a connectivity tool for remote login that uses the SSH protocol. It encrypts all traffic between client and server to eliminate eavesdropping, connection hijacking, and other attacks.

OpenSSH is the de-facto standard tool used by administrators of Linux and other non-Windows for cross-platform management of remote systems. It has been added to Windows (as of autumn 2018), and is included in Windows 10 and Windows Server 2019.

See Microsoft Doc on Install OpenSSH using PowerShell and other general info. In this blueprint we follow this installation guide, with the following known issue and its workaround.

Tested on Windows 10/11/2019

Known issues
  1. The Add-WindowsCapability cmdlet that needs to be run during setup, which can't run successfully directly from Attune(which uses the WinRM protocol under the hood), as a workaround, we setup a Windows scheduled task to accomplish the task. Detailed info here
Pre-Blueprint Attune setup
  1. On the Inputs tab, create a Windows node for the Target you wish to install WSL.
  2. On the Inputs tab, create a Windows credential to connect to the Target you wish to install WSL.
TODO
  1. Add install confirmation logic.
  2. Restore Users must enter a user name and password to use this computer setting to it's original value.

Parameters

Name Type Script Reference Default Value Comment
Windows Node Windows Server windowsNode
Windows User Windows OS Credential windowsUser

1 - Clear "Users must enter a user name and password to use this computer"

Clear Users must enter a user name and password to use this computer with registry. It's identical to do the setting in GUI with netplwiz.exe.

A GUI session is needed to run ubuntu2004.exe / Add-WindowsCapability, but in unattended automation, it's assumed we don't have local access to the host, and using RDP to establish a GUI session usually asks the user to do interactions. So clear the Users must enter a user name and password to use this computer setting and do a system restart, will guarantee that the host will boot with a GUI session logged in.

See doc for the meaning of {windowsUser.user} and {windowsUser.password}.

TODO: Remember the original state of this parameter, we should restore it after installing Brave.

This step has the following parameters

Name Script Reference Default Value
Windows User {windowsUser.user} None
Windows User {windowsUser.password} None
The connection details have changed from the last step.

Login as user on node

  1. Connect via RDP
    mstsc /admin /v:Windows Node
  2. Login as user {Windows User}
  3. Then open a command prompt
This is a PowerShell Script make sure you run it with powershell.exe Click start menu, enter "powershell" in the search bar, then select the powersehll program
$RegPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
$DefaultUsername = "{windowsUser.user}"
$DefaultPassword = "{windowsUser.password}"
Set-ItemProperty $RegPath "AutoAdminLogon" -Value "1" -type String 
Set-ItemProperty $RegPath "DefaultUsername" -Value "$DefaultUsername" -type String 
Set-ItemProperty $RegPath "DefaultPassword" -Value "$DefaultPassword" -type String

2 - Reboot Windows

Reboot the computer.

Login as user on node

  1. Connect via RDP
    mstsc /admin /v:Windows Node
  2. Login as user {Windows User}
  3. Then open a command prompt
This is a Windows Batch File make sure you run it with cmd.exe Click start menu, enter "command" in the search bar, then select the command program
shutdown -r -t 0

3 - WinRM Wait for Reboot

Wait for the WinRM port to come alive after system reboot.

It's seen on some system that it needs 40 seconds Post Wait Time(When the system is going to reboot, previous successful ping will fail for the period the OS is down, then after the OS gets up, ping will succeed shortly. Post Wait Time means after the port come back alive again, we wait Post Wait Time more seconds before this step finish), although the port is open, but the WinRM service is not in a ready state. Less than this may result in error with the following steps.

The TCP Port value should be the same with the WinRM Connection Type of the Windows node value(check this on the Inputs tab) that we're connecting to, 5986 is the port of the default connection type.

The connection details have changed from the last step.

on node

Check if tcp port 5986 is listening make sure it goes down for 5 seconds, once its up, wait 40 seconds .

Use Telnet to check if the TCP service is accepting connections.

4 - Add-WindowsCapability via scheduled task

Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 is the major command of installing OpenSSH Server.

If running Add-WindowsCapability directly from WinRM, will get "Access is denied." error. Tweak with Windows Task Scheduler, see the discussion

See doc for the meaning of {windowsUser.user} and {windowsUser.password}.

This step has the following parameters

Name Script Reference Default Value
Windows User {windowsUser.user} None
The connection details have changed from the last step.

Login as user on node

  1. Connect via RDP
    mstsc /admin /v:Windows Node
  2. Login as user {Windows User}
  3. Then open a command prompt
This is a PowerShell Script make sure you run it with powershell.exe Click start menu, enter "powershell" in the search bar, then select the powersehll program
# Run the task 15 seconds after task creation
$ts = New-TimeSpan -Seconds 15
$Trigger = New-ScheduledTaskTrigger -Once -At ((Get-date) + $ts)

# Run only when user is logged on / Run with highest privileges
$principal = New-ScheduledTaskPrincipal -UserId "{windowsUser.user}" -RunLevel Highest
$Action= New-ScheduledTaskAction -Execute "powershell.exe" -Argument "Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0"
$setting = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
Register-ScheduledTask -TaskName "Add-WindowsCapability OpenSSH.Server" -Trigger $Trigger -Principal $principal -Action $Action -Settings $setting -Force

5 - Wait 2 minutes to allow scheduled task completes

This is a simplified solution, the wiser method would be to continuously wait a short time period(say 1 second), check if Add-WindowsCapability has finished running.
This task should finish within 1 minute for a modern computer, so 2 minutes of wait is enough(the task is scheduled to run after 15 seconds).

Login as user on node

  1. Connect via RDP
    mstsc /admin /v:Windows Node
  2. Login as user {Windows User}
  3. Then open a command prompt
This is a PowerShell Script make sure you run it with powershell.exe Click start menu, enter "powershell" in the search bar, then select the powersehll program
start-sleep 120

6 - Start sshd service

Start and configure OpenSSH Server for initial use.

Login as user on node

  1. Connect via RDP
    mstsc /admin /v:Windows Node
  2. Login as user {Windows User}
  3. Then open a command prompt
This is a PowerShell Script make sure you run it with powershell.exe Click start menu, enter "powershell" in the search bar, then select the powersehll program
# Start the sshd service
Start-Service sshd

# make the service automatically start when Windows booting up
Set-Service -Name sshd -StartupType Automatic

7 - Open SSH port in Windows Firewall

Config Windows Firewall to allow 22 port(SSH default port) to be connected by SSH client.

Login as user on node

  1. Connect via RDP
    mstsc /admin /v:Windows Node
  2. Login as user {Windows User}
  3. Then open a command prompt
This is a PowerShell Script make sure you run it with powershell.exe Click start menu, enter "powershell" in the search bar, then select the powersehll program
# Confirm the Firewall rule is configured. It should be created automatically by setup. Run the following to verify
if (!(Get-NetFirewallRule -Name "OpenSSH-Server-In-TCP" -ErrorAction SilentlyContinue | Select-Object Name, Enabled)) {
    Write-Output "Firewall Rule 'OpenSSH-Server-In-TCP' does not exist, creating it..."
    New-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22
} else {
    Write-Output "Firewall rule 'OpenSSH-Server-In-TCP' has been created and exists."
}