Install Windows Subsystem for Linux (WSL) with Ubuntu 20.04 on Windows 10

Exported on 11-Oct-2021 12:03:56

Using Attune to install and configure WSL on Win10/Win2019

The Windows Subsystem for Linux(WSL) lets developers run a GNU/Linux environment -- including most command-line tools, utilities, and applications -- directly on Windows, unmodified, without the overhead of a traditional virtual machine or dualboot setup.
In this case, we'll install Ubuntu 20.04.
After running this blueprint, we can treat the newly installed WSL as a normal Linux, and run Execute Linux Script steps against it. See this blueprint's 3rd group step Run Wake On Lan Script for an example.

Tested on Windows 10/2019

Known issues
  1. There is a 'ubuntu2004.exe' command 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 you wish to install WSL.
  2. On the Inputs tab, create a Windows credential to connect to the node you wish to install WSL.
  3. On the Inputs tab, create a Linux credential for the WSL(this info is used to create the Linux user when installing WSL).

Parameters

Name Type Script Reference Default Value Comment
WSL Installer Download Path Text wslInstallerDownloadPath C:\wsl_image_download\wsl_install.appx The installation image will be downloaded here.
WSL Installer Download URL Text wslInstallerDownloadUrl https://wsldownload.azureedge.net/Ubuntu_2004.2020.424.0_x64.appx The installation image download link.
WSL User Linux OS Credential wslUser Independent with the Crendential for the host Windows, different username/password pair is acceptable and encouraged for security.
Windows Node Windows Server windowsNode
Windows User Windows OS Credential windowsUser

1 - Install WSL(Ubuntu 20.04)

For simplicity, we use WSL version 1.0, which is sufficient for running this Python script.

There is a 'ubuntu2004.exe install' step, 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

1.1 - Enable WSL feature on Windows

Same with select Windows Subsystem for Linux in Turn Windows features on or off dialog, which can be accessed through Control Panel -> Uninstall or change a program, it's on the left pane.

Using the norestart(postpone restarting Windows, because we have other steps to do before restarting) argument results in exit code to 3010 other than the normal 0.

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 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
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart

1.2 - 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 attended 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.

TODO: Remember the original state of this parameter, we should restore it after setting up WSL.

This step has the following parameters

Name Script Reference Default Value
Windows User {windowsUser.user} None
Windows User {windowsUser.password} None

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

1.3 - winreboot

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

1.4 - WinRM Wait for Reboot

WIN2019 needs 40 seconds Post Wait Time(although 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 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.

1.5 - Download WSL installer

Download WSL appx installer from the official URL.

This step has the following parameters

Name Script Reference Default Value
WSL Installer Download URL {wslInstallerDownloadUrl} https://wsldownload.azureedge.net/Ubuntu_2004.2020.424.0_x64.appx
WSL Installer Download Path {wslInstallerDownloadPath} C:\wsl_image_download\wsl_install.appx
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
$DIR=Split-Path -Path {wslInstallerDownloadPath}
if (-not (Test-Path $DIR)) {
    New-Item $DIR -ItemType Directory
}

if (-not (Test-Path {wslInstallerDownloadPath})) {
    Invoke-WebRequest -Uri {wslInstallerDownloadUrl} -OutFile {wslInstallerDownloadPath}
}

1.6 - Install WSL install image

Install the appx package.

This step has the following parameters

Name Script Reference Default Value
WSL Installer Download Path {wslInstallerDownloadPath} C:\wsl_image_download\wsl_install.appx

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
Add-AppxPackage -Path {wslInstallerDownloadPath}

1.7 - Remove WSL install image

Remove the appx package.

This step has the following parameters

Name Script Reference Default Value
WSL Installer Download Path {wslInstallerDownloadPath} C:\wsl_image_download\wsl_install.appx

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
if (Test-Path {wslInstallerDownloadPath}) {
    Remove-Item -Recurse {wslInstallerDownloadPath}
}

1.8 - WSL ubuntu install via scheduled task

After installing the appx, it is required to do a ubuntu2004.exe install to make the WSL system usable. We can use wsl -l -v to check the status of the newly installed WSL system.
If running ubuntu2004.exe directly from WinRM, will get "A specified logon session does not exist. It may already have been terminated." error.

Tweak with Windows Task Scheduler, see https://gitlab.com/AttuneOps/attune/-/issues/21

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
# Make the task start running after 15 seconds
$ts = New-TimeSpan -Seconds 15
$Trigger = New-ScheduledTaskTrigger -Once -At ((Get-date) + $ts)

# We use the '--root' argument here to avoid the input prompt
$Action= New-ScheduledTaskAction -Execute "C:\Users\kinzlaw\AppData\Local\Microsoft\WindowsApps\ubuntu2004.exe" -Argument "install --root"
$setting = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries

Register-ScheduledTask -TaskName "WSL Ubuntu install" -Trigger $Trigger -Action $Action -Settings $setting -Force

1.9 - 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 ubuntu2004.exe has finished running.
2 minutes is an estimated value, and tested to work on an I5-8250u 2 core 4GB with SSD Windows virtual machine.

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

1.10 - WSL create normal user

Create a normal user for WSL, using credential in 'WSL User' Parameter.
From the host, we can use wsl to issue command to the WSL system.

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

This step has the following parameters

Name Script Reference Default Value
WSL User {wslUser.password}
WSL User {wslUser.user} None

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
# create user account
wsl -u root useradd -m {wslUser.user}
wsl -u root sh -c "echo {wslUser.user}:{wslUser.password} | chpasswd" # wrapped in sh -c to get the pipe to work
wsl -u root chsh -s /bin/bash {wslUser.user}
wsl -u root usermod -aG adm,cdrom,sudo,dip,plugdev {wslUser.user}

1.11 - WSL allow sudo NOPASSWD

By default, sudo will interactively ask the user to enter his password, which is unfriendly to unattended automation tasks. So we disable it with NOPASSWD.
From the host, we can use bash to issue command to the WSL system.

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
bash -c "echo '%sudo ALL=(ALL) NOPASSWD: ALL' | EDITOR='tee -a' visudo"

1.12 - WSL change default login to normal user via scheduled task

The ubuntu2004.exe install --root we previously executed makes the WSL to use root as default credential, which is unrecommended for Ubuntu. So after creating a normal user, we issue ubuntu2004.exe config --default-user {wslUser.user} here to change the default login. If running ubuntu2004.exe directly from WinRM, will get "A specified logon session does not exist. It may already have been terminated." error.

Tweak with Windows Task Scheduler, see https://gitlab.com/AttuneOps/attune/-/issues/21

See doc for the meaning of {wslUser.user} .

This step has the following parameters

Name Script Reference Default Value
WSL User {wslUser.user} None

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
# Make the task start running after 15 seconds
$ts = New-TimeSpan -Seconds 15
$Trigger = New-ScheduledTaskTrigger -Once -At ((Get-date) + $ts)

$Action= New-ScheduledTaskAction -Execute "C:\Users\kinzlaw\AppData\Local\Microsoft\WindowsApps\ubuntu2004.exe" -Argument "config --default-user {wslUser.user}"
$setting = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
Register-ScheduledTask -TaskName "WSL Ubuntu default user" -Trigger $Trigger -Action $Action -Settings $setting -Force

1.13 - Wait 40 seconds 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 ubuntu2004.exe has finished running.
This task should finish within 1 or 2 seconds, so 40 seconds 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 40

2 - Configure WSL to Allow SSH

The WSL Ubuntu system's sshd service is not properly configured, so we do the configuration in this group step, to allow Attune to connect the Ubuntu via SSH.
Before SSH is configured, we can use bash to issue command to the WSL system from the host.

2.1 - WSL reinstall OpenSSH Server

The openssh-server installed by default with WSL Ubuntu lacks some config files, reinstalling it helps creating the needed files.

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
bash -c "sudo apt remove openssh-server -y"
bash -c "sudo apt install openssh-server -y"

2.2 - Edit the sshd_config

After this step, we effectively have the following settings in /etc/ssh/sshd_config

# Allow login with password
PasswordAuthentication yes
# By default, we will lose the connection in several minutes of idle time
# So we change the following params to keep the connection alive
TCPKeepAlive yes
ClientAliveInterval 120
ClientAliveCountMax 720

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
bash -c "sudo sed -i `'/PasswordAuthentication no/c\PasswordAuthentication yes`' /etc/ssh/sshd_config"
# in case the parameter previously commented
bash -c "sudo sed -i `'/PasswordAuthentication yes/c\PasswordAuthentication yes`' /etc/ssh/sshd_config"

bash -c "sudo sed -i `'/TCPKeepAlive no/c\TCPKeepAlive yes`' /etc/ssh/sshd_config"
# in case the parameter previously commented
bash -c "sudo sed -i `'/TCPKeepAlive yes/c\TCPKeepAlive yes`' /etc/ssh/sshd_config"

bash -c "sudo sed -i `'/ClientAliveInterval [[:digit:]]\+/c\ClientAliveInterval 120`' /etc/ssh/sshd_config"

bash -c "sudo sed -i `'/ClientAliveCountMax [[:digit:]]\+/c\ClientAliveCountMax 720`' /etc/ssh/sshd_config"

2.3 - Restart OpenSSH Server

Restart the service for the new config files to take effect.

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
bash -c "sudo service ssh restart"

2.4 - WSL SSH Windows Firewall setup

Allow the TCP 22 port(SSH) to be connected.
Remember the Ubuntu is an WSL within the Windows, whose network is the same as the host system, so we create the firewall rule in Windows.

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
New-NetFirewallRule -DisplayName 'WSL SSH' `
                  -Name 'WSL SSH' `
                  -Profile Any `
                  -LocalPort 22 `
                  -Protocol TCP

2.5 - Automatically start OpenSSH Server on bootup

WSL isn't started automatically when the host system boot up, so we can't use Ubuntu's systemctl enable sshd to do this.
Here we create a Windows scheduled task in the host system, using bash to issue the sudo service ssh start command, which is a usual command to manually startup a service.

This step has the following parameters

Name Script Reference Default Value
Windows User {windowsUser.user} None

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 this task every time the computer start up
$Trigger= New-ScheduledTaskTrigger -AtStartup

$principal = New-ScheduledTaskPrincipal -LogonType S4U -UserId '{windowsUser.user}'
$Action= New-ScheduledTaskAction -Execute "bash" -Argument "-c `'sudo service ssh start`'"
$setting = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
Register-ScheduledTask -TaskName "SSH service start on bootup" -Trigger $Trigger -Principal $principal -Action $Action -Settings $setting -Force