Wake on Lan another PC via WSL on Windows 10/2019

Exported on 08-Oct-2021 10:53:39

Using Attune to install and configure WSL on Win10/Win2019, then running Wake on Lan python script via the newly installed WSL

This blueprint is used to boot another host in the LAN, through Wake on Lan. Before running the WOL python script, we need to install WSL on a Windows host, and setup the WSL to allow SSH connection. Then we can use Attune to SSH connect to the WSL(same as a Linux physical machine, or virtual machine), and run the python script there.

Tested on Windows 10/2019(WSL will be installed on this host), the WOL target's OS doesn't matter, it only depends on the NIC's BIOS supporting WOL feature, and of course, the target machine's power cord needs to be plugged in.

Explanation of Terms

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.

Wake-on-LAN (WOL) is an Ethernet or Token Ring computer networking standard that allows a computer to be turned on or awakened by a network message.
Which means that a host(Target) is in power off, sleep, or hibernated state. If there is another device(usually another PC, raspberry pi, or even a router which supports running script/app) that is running 7x24, we can use that device to broadcast the Wake on Magic Packet to the LAN, the Target boots up when it sees the Wake on Magic Packet. This feature is useful to control devices remotely.
See this article on setting up WOL in BIOS and Windows.

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 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.
  3. On the Inputs tab, create a Linux node for the WSL(same IP/hostname with the Windows Target).
  4. On the Inputs tab, create a Linux credential for the WSL(this info is used to create the Linux user when installing WSL, and also when running Python script).

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 Node Linux / Unix Server wslNode Same IP with the WSL's host Windows node
WSL User Linux OS Credential wslUser Independent with the Crendential for the host Windows, different username/password pair is acceptable and encouraged for security.
WSL User With Sudo Linux OS Credential wslUserWithSudo Same with `WSL User`, but with `Sudo To` set to `root`.
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.password} None
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
$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 Path {wslInstallerDownloadPath} C:\wsl_image_download\wsl_install.appx
WSL Installer Download URL {wslInstallerDownloadUrl} https://wsldownload.azureedge.net/Ubuntu_2004.2020.424.0_x64.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

3 - Run Wake On Lan Script

After preparing the WSL environment, now comes the real work we want to do -- WOL another PC.
Wake-on-LAN (WOL) is an Ethernet or Token Ring computer networking standard that allows a computer to be turned on or awakened by a network message.
Which means that a host(Target) is in power off, sleep, or hibernated state. If there is another device(usually another PC, raspberry pi, or even a router which supports running script/app) that is running 7x24, we can use that device to broadcast the Wake on Magic Packet to the LAN, the Target boots up when it sees the Wake on Magic Packet. This feature is useful to control devices remotely.
See this article on setting up WOL in BIOS and Windows.

3.1 - Add Python executable alternative

Attune's Python step depends on a python executable resides on the host, but Ubuntu 20.04 comes with only a python3, so we need to create a python link for it.
Use update-alternatives --install to create a normal python executable link to the actual python3.
This step needs a credential with Sudo to Root set.

The connection details have changed from the last step.

Login as user on node

Connect via SSH
ssh user@hostname
This is a Bash Script make sure you run it with bash -l from a terminal session
if which python; then
    : # python is found, nothing needs to be done
else
    update-alternatives --install /usr/bin/python python /usr/bin/python3 1
fi

3.2 - Wake on Lan via WSL Python

Runs the WOL Python script inside WSL.

Please edit the values commented with TODO to reflect the real situation.

This step has the following parameters

Name Script Reference Default Value
WSL Node {wslNode.ip} None
The connection details have changed from the last step.

Login as user on node

Connect via SSH
ssh user@hostname
This is a Python Code make sure you run it with python from a terminal session
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Wake on Lan

import socket
import struct


def WOL(macaddress):
        if len(macaddress) == 12:
                pass
        elif len(macaddress) == 12 + 5:
                sep = macaddress[2]
                macaddress = macaddress.replace(sep, '')
        else:
                raise ValueError('Incorrect MAC address format')

        data = ''.join(['FFFFFFFFFFFF', macaddress * 16])
        send_data = b''

        for i in range(0, len(data), 2):
                byte_dat = struct.pack('B', int(data[i: i + 2], 16))
                send_data = send_data + byte_dat

        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        sock.bind(('{wslNode.ip}', 20000))
        # TODO: change to the broadcast IP of your LAN
        sock.sendto(send_data, ('192.168.31.255', 9))
        sock.close()


if __name__ == '__main__':
        # TODO: change to the MAC of the Target NIC
        WOL('00:e0:b4:1d:01:f4')