Files
HM_project_Viewer_Board/scripts/setup_windows_all_portproxies.ps1

249 lines
8.3 KiB
PowerShell

param(
[string]$ListenAddress = "0.0.0.0",
[string]$WslIp = ""
)
$ErrorActionPreference = "Stop"
$knownPorts = @{
8000 = @{ Name = "hm-biz-process"; RuleName = "HM-BIZ-PROCESS-8000" }
8010 = @{ Name = "my-intranet-app"; RuleName = "MyIntranetApp-8010" }
8020 = @{ Name = "b17301"; RuleName = "B17301-8020" }
}
function Get-WslListeningPorts {
$raw = wsl.exe bash -lc "ss -ltnH 2>/dev/null"
if (-not $raw) {
return @()
}
$portMap = @{}
foreach ($line in ($raw -split "`r?`n")) {
if ([string]::IsNullOrWhiteSpace($line)) {
continue
}
$parts = ($line -split "\s+") | Where-Object { $_ -ne "" }
if ($parts.Count -lt 4) {
continue
}
$localAddress = $parts[3].Trim()
if ([string]::IsNullOrWhiteSpace($localAddress)) {
continue
}
$hostPart = $localAddress
$portPart = ""
$lastColon = $localAddress.LastIndexOf(":")
if ($lastColon -lt 0) {
continue
}
$hostPart = $localAddress.Substring(0, $lastColon)
$portPart = $localAddress.Substring($lastColon + 1)
$parsedPort = 0
if (-not [int]::TryParse($portPart, [ref]$parsedPort)) {
continue
}
$port = [int]$parsedPort
if ($port -le 0) {
continue
}
$normalizedHost = $hostPart.Trim("[", "]")
$isLoopback = (
$normalizedHost -eq "127.0.0.1" -or
$normalizedHost -eq "::1" -or
$normalizedHost -eq "localhost"
)
if (-not $portMap.ContainsKey($port)) {
$portMap[$port] = [ordered]@{
Port = $port
Hosts = New-Object System.Collections.Generic.List[string]
ExternallyReachable = $false
}
}
$entry = $portMap[$port]
if (-not $entry.Hosts.Contains($normalizedHost)) {
$entry.Hosts.Add($normalizedHost)
}
if (-not $isLoopback) {
$entry.ExternallyReachable = $true
}
}
return $portMap.Values | Sort-Object Port
}
function Get-DockerPublishedPorts {
$publishedPorts = New-Object System.Collections.Generic.HashSet[int]
try {
$raw = docker ps --format "{{.Ports}}" 2>$null
if (-not $raw) {
return $publishedPorts
}
foreach ($line in ($raw -split "`r?`n")) {
if ([string]::IsNullOrWhiteSpace($line)) {
continue
}
foreach ($match in [regex]::Matches($line, "(?:0\.0\.0\.0|\[::\]):(?<port>\d+)->")) {
$port = 0
if ([int]::TryParse($match.Groups["port"].Value, [ref]$port)) {
[void]$publishedPorts.Add($port)
}
}
}
} catch {
return $publishedPorts
}
return $publishedPorts
}
if ([string]::IsNullOrWhiteSpace($WslIp)) {
$detected = wsl.exe hostname -I 2>$null
if (-not $detected) {
throw "WSL IP를 자동으로 찾지 못했습니다. -WslIp 옵션으로 직접 지정해 주세요."
}
$WslIp = (($detected -split "\s+") | Where-Object { $_ -match '^\d+\.\d+\.\d+\.\d+$' } | Select-Object -First 1)
if (-not $WslIp) {
throw "WSL IP를 자동으로 파싱하지 못했습니다. -WslIp 옵션으로 직접 지정해 주세요."
}
}
$windowsIps = Get-NetIPAddress -AddressFamily IPv4 |
Where-Object {
$_.IPAddress -notlike '127.*' `
-and $_.IPAddress -notlike '169.254*' `
-and $_.InterfaceAlias -notlike '*WSL*'
} |
Select-Object -ExpandProperty IPAddress
$listenAddresses = @($ListenAddress)
if ($ListenAddress -eq "0.0.0.0") {
$listenAddresses += $windowsIps
}
$listenAddresses = $listenAddresses | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | Select-Object -Unique
Write-Host "Setting Windows portproxy for all active WSL TCP ports..." -ForegroundColor Cyan
Write-Host "WSL IP: $WslIp"
$portEntries = @(Get-WslListeningPorts)
$dockerPublishedPorts = @(Get-DockerPublishedPorts)
if ($dockerPublishedPorts.Count -gt 0) {
Write-Host "Docker-published Windows ports: $((@($dockerPublishedPorts) | Sort-Object) -join ', ')" -ForegroundColor Cyan
}
$knownPortEntries = @()
foreach ($knownPort in ($knownPorts.Keys | Sort-Object)) {
$existingEntry = @($portEntries | Where-Object { [int]$_.Port -eq [int]$knownPort } | Select-Object -First 1)
if ($existingEntry -and $existingEntry.Count -gt 0) {
continue
}
$hosts = New-Object System.Collections.Generic.List[string]
$hosts.Add("not-listening-yet")
$knownPortEntries += [ordered]@{
Port = [int]$knownPort
Hosts = $hosts
ExternallyReachable = $true
Assumed = $true
}
}
$portEntries = @($portEntries + $knownPortEntries | Sort-Object Port)
if (-not $portEntries -or $portEntries.Count -eq 0) {
throw "등록할 WSL TCP 포트를 찾지 못했습니다."
}
Write-Host "Detected ports: $((@($portEntries | ForEach-Object { $_.Port })) -join ', ')"
$reachableEntries = @($portEntries | Where-Object { $_.ExternallyReachable })
$loopbackOnlyEntries = @($portEntries | Where-Object { -not $_.ExternallyReachable })
if (-not $reachableEntries -or $reachableEntries.Count -eq 0) {
throw "현재 WSL에서 내부망에 공개 가능한 포트를 찾지 못했습니다. 앱이 0.0.0.0 또는 WSL IP에 바인딩되어 있는지 확인해 주세요."
}
$configuredPorts = New-Object System.Collections.Generic.List[int]
foreach ($entry in $reachableEntries) {
$port = [int]$entry.Port
$appInfo = $knownPorts[$port]
$displayName = if ($appInfo) { [string]$appInfo.Name } else { "wsl-port-$port" }
$ruleName = if ($appInfo) { [string]$appInfo.RuleName } else { "WSL-PORT-$port" }
$assumed = $false
if ($entry.Contains("Assumed")) {
$assumed = [bool]$entry.Assumed
}
Write-Host ""
Write-Host "$displayName : $port ($($entry.Hosts -join ', '))" -ForegroundColor Cyan
if ($assumed) {
Write-Host " Known service port is not listening yet; portproxy will still be refreshed to the current WSL IP." -ForegroundColor Yellow
}
foreach ($address in $listenAddresses) {
netsh interface portproxy delete v4tov4 listenport=$port listenaddress=$address | Out-Null
if ($dockerPublishedPorts -notcontains $port) {
netsh interface portproxy add v4tov4 listenport=$port listenaddress=$address connectport=$port connectaddress=$WslIp
}
}
if ($dockerPublishedPorts -contains $port) {
Write-Host " Docker already publishes this port on Windows; stale portproxy entries were removed and only firewall is refreshed." -ForegroundColor Yellow
}
$existingRule = Get-NetFirewallRule -DisplayName $ruleName -ErrorAction SilentlyContinue
if ($existingRule) {
Remove-NetFirewallRule -DisplayName $ruleName | Out-Null
}
New-NetFirewallRule `
-DisplayName $ruleName `
-Direction Inbound `
-Action Allow `
-Protocol TCP `
-LocalPort $port | Out-Null
if (-not $configuredPorts.Contains($port)) {
$configuredPorts.Add($port)
}
}
Write-Host ""
Write-Host "Completed." -ForegroundColor Green
Write-Host "Use these URLs from another PC on the intranet:"
if ($windowsIps) {
foreach ($ip in $windowsIps) {
foreach ($port in $configuredPorts) {
$appInfo = $knownPorts[$port]
$label = if ($appInfo) { [string]$appInfo.Name } else { "wsl-port-$port" }
Write-Host ("{0,-15}: http://{1}:{2}" -f $label, $ip, $port)
}
}
} else {
foreach ($port in $configuredPorts) {
$appInfo = $knownPorts[$port]
$label = if ($appInfo) { [string]$appInfo.Name } else { "wsl-port-$port" }
Write-Host ("{0,-15}: http://<Windows-IP>:{1}" -f $label, $port)
}
}
if ($loopbackOnlyEntries.Count -gt 0) {
Write-Host ""
Write-Host "Loopback-only ports (not published to intranet):" -ForegroundColor Yellow
foreach ($entry in $loopbackOnlyEntries) {
Write-Host ("- {0}: {1}" -f $entry.Port, ($entry.Hosts -join ', '))
}
Write-Host "These ports are bound only to 127.0.0.1/::1 inside WSL. Run those apps on 0.0.0.0 (or the WSL IP) to expose them to the intranet." -ForegroundColor Yellow
}
Write-Host ""
Write-Host "Tip: if WSL restarts and its IP changes, run this script again."