Skip to content

Instantly share code, notes, and snippets.

@composite
Forked from daehahn/wsl2-network.ps1
Last active February 9, 2023 01:01
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save composite/003e27c68b70325a049caff2b32c2ea8 to your computer and use it in GitHub Desktop.
Save composite/003e27c68b70325a049caff2b32c2ea8 to your computer and use it in GitHub Desktop.
WSL 2 TCP NETWORK FORWARDING, IMPROVED FOR TASK SCHEDULER! ALSO WORKS ON WINDOWS SERVER 2022!
# WSL2 network port forwarding script v1
# for enable script, 'Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope CurrentUser' in Powershell,
# for delete exist rules and ports use 'delete' as parameter, for show ports use 'list' as parameter.
# written by Daehyuk Ahn, Aug-1-2020
# edited by Ukjin Yang, Jun-7-2022 (Windows Server 2022 also works!)
# Improved features: more detailed logs for Task Scheduler, saved IP check, etc.
If ($Args[0] -eq "list") {
netsh interface portproxy show v4tov4;
exit;
}
# If elevation needed, start new process
If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator))
{
# Relaunch as an elevated process:
Start-Process powershell.exe "-File",('"{0}"' -f $MyInvocation.MyCommand.Path),"$Args runas" -Verb RunAs
exit
}
# You should modify '$Ports' for your applications
$Ports = (22,80,443,8080)
# log file and saving IP file
$today = [System.DateTime]::Today.ToString("yyyyMMdd")
$logdir = "$PSScriptRoot\logs"
$logfile = "$logdir\wsl2ip_$today.log"
$lastfile = "$logdir\wsl2ip.txt"
# mkdir log folder if not exists
if (-not (Test-Path $logdir -PathType Container)) {
New-Item -Path "$logdir" -ItemType "directory" | Out-Null
}
# Log helper function
function Log-Append {
[CmdletBinding()]
param(
[Parameter()]
[string] $Text
)
$now = [System.DateTime]::Now.ToString("yyyy-MM-dd HH:mm:ss.fff")
Tee-Object -FilePath "$logfile" -Append -InputObject "WSL2IP: [$now] $Text"
}
# Get WSL Interface IP, and get only first IP. (I don't know why multiple IPs registered)
wsl hostname -I | Set-Variable -Name "WslIp"
$WslIp = $WslIp.split(" ")[0]
$found = $WslIp -match '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}';
if (-not $found) {
Log-Append "WSL2 cannot be found. Terminate script."
exit;
}
# Get saved IP for prevent unexpected running.
$OldIp = ""
if (Test-Path $lastfile -PathType Leaf) {
$OldIp = Get-Content "$lastfile"
}
$OldIp = $OldIp.Trim()
if ($WslIp -eq $OldIp) {
Log-Append "WSL2 IP ($WslIp) already bound in port proxy. Terminate script."
exit;
}
# If you got new WSL IP, Go ahead!
Log-Append "Applying WSL IP to port proxy."
# Remove and Create NetFireWallRule
Log-Append "Replacing Firewall rules..."
Remove-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' | Tee-Object -FilePath "$logfile" -Append;
if ($Args[0] -ne "delete") {
New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Outbound -LocalPort $Ports -Action Allow -Protocol TCP | Tee-Object -FilePath "$logfile" -Append;
New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Inbound -LocalPort $Ports -Action Allow -Protocol TCP | Tee-Object -FilePath "$logfile" -Append;
New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Outbound -LocalPort $Ports -Action Allow -Protocol UDP | Tee-Object -FilePath "$logfile" -Append;
New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Inbound -LocalPort $Ports -Action Allow -Protocol UDP | Tee-Object -FilePath "$logfile" -Append;
}
# Add each port into portproxy
Log-Append "Replacing port forwarding any to WSL2 Port..."
$Addr = "0.0.0.0"
Foreach ($Port in $Ports) {
iex "netsh interface portproxy delete v4tov4 listenaddress=$Addr listenport=$Port | Out-Null";
if ($Args[0] -ne "delete") {
iex "netsh interface portproxy add v4tov4 listenaddress=$Addr listenport=$Port connectaddress=$WslIp connectport=$Port | Out-Null";
}
}
# Display all portproxy information
Log-Append "Retrieving port forwarding table..."
netsh interface portproxy show v4tov4 | Tee-Object -FilePath "$logfile" -Append;
# Give user to chance to see above list when relaunched start
If ($Args[0] -eq "runas" -Or $Args[1] -eq "runas") {
Write-Host -NoNewLine 'Press any key to close! ';
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');
}
# Save successful WSL IP to file.
Log-Append "Saving successful IP $WslIp to $lastfile ..."
$WslIp | Out-File -FilePath "$lastfile"
# Preserve WSL service scripts here.
Log-Append "Executing WSL Startup scripts..."
iex "wsl sudo service ssh start" | Tee-Object -FilePath "$logfile" -Append
iex "wsl sudo service cron start" | Tee-Object -FilePath "$logfile" -Append
Log-Append "Done."
Add-Content "$logfile" ""
@composite
Copy link
Author

If you want start service without prompt password, you should run sudo visudo and append a line like this:

# change username to your linux default user name who can run sudo.
username ALL=(ALL:ALL) NOPASSWD: ALL

If you worried about all executables security, you can just replace last ALL to /sbin/service, /usr/sbin/service and sudo without password process as you want.

# change username to your linux default user name who can run sudo.
username ALL=(ALL:ALL) NOPASSWD: /sbin/service, /usr/sbin/service

@composite
Copy link
Author

composite commented Jun 9, 2022

If you want full instructions for Windows server 2022, check out my blog post.
Windows 10 also will help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment