70 lines
2.9 KiB
PowerShell
70 lines
2.9 KiB
PowerShell
function Get-NextFreePort {
|
|
param([int]$Start = $Script:Port)
|
|
for ($p = [Math]::Max(1024,$Start); $p -lt 65535; $p++) {
|
|
$l = [System.Net.Sockets.TcpListener]::new([Net.IPAddress]::Loopback, $p)
|
|
try { $l.Start(); $l.Stop(); return $p } catch {}
|
|
}
|
|
throw "No free TCP port available."
|
|
}
|
|
|
|
function Start-Server {
|
|
$Global:Listener = [System.Net.HttpListener]::new()
|
|
$primaryPrefix = "http://localhost:$Script:Port/"
|
|
$wildcardPrefix = "http://+:$Script:Port/"
|
|
|
|
try {
|
|
$Global:Listener.Prefixes.Add($primaryPrefix)
|
|
$Global:Listener.Start()
|
|
Write-LogHybrid "Listening on $primaryPrefix" Info Server -LogToEvent
|
|
}
|
|
catch [System.Net.HttpListenerException] {
|
|
if ($_.Exception.ErrorCode -eq 5) {
|
|
Write-LogHybrid "Access denied on $primaryPrefix. Attempting URL ACL…" Warning Server -LogToEvent
|
|
try {
|
|
$user = "$env:USERDOMAIN\$env:USERNAME"
|
|
if (-not $user.Trim()) { $user = $env:USERNAME }
|
|
Start-Process -FilePath "netsh" -ArgumentList "http add urlacl url=$wildcardPrefix user=`"$user`" listen=yes" -Verb RunAs -WindowStyle Hidden -Wait
|
|
$Global:Listener = [System.Net.HttpListener]::new()
|
|
$Global:Listener.Prefixes.Add($wildcardPrefix)
|
|
$Global:Listener.Start()
|
|
Write-LogHybrid "Listening on $wildcardPrefix (URL ACL added for $user)" Success Server -LogToEvent
|
|
} catch {
|
|
Write-LogHybrid "URL ACL registration failed: $($_.Exception.Message)" Error Server -LogToEvent
|
|
return
|
|
}
|
|
}
|
|
elseif ($_.Exception.NativeErrorCode -in 32,183) {
|
|
$old = $Script:Port
|
|
$Script:Port = Get-NextFreePort -Start ($Script:Port + 1)
|
|
$Global:Listener = [System.Net.HttpListener]::new()
|
|
$primaryPrefix = "http://localhost:$Script:Port/"
|
|
$Global:Listener.Prefixes.Add($primaryPrefix)
|
|
$Global:Listener.Start()
|
|
Write-LogHybrid "Port $old busy. Listening on $primaryPrefix" Warning Server -LogToEvent
|
|
}
|
|
else {
|
|
Write-LogHybrid "HttpListener start failed: $($_.Exception.Message)" Error Server -LogToEvent
|
|
return
|
|
}
|
|
}
|
|
|
|
try {
|
|
while ($Global:Listener.IsListening) {
|
|
$ctx = $Global:Listener.GetContext()
|
|
try { Dispatch-Request $ctx }
|
|
catch {
|
|
$msg = $_.Exception.Message
|
|
$pos = if ($_.InvocationInfo) { $_.InvocationInfo.PositionMessage } else { "" }
|
|
$stk = if ($_.ScriptStackTrace) { $_.ScriptStackTrace } else { "" }
|
|
|
|
Write-LogHybrid "Dispatch error: $msg`n$pos`n$stk" Error Server -LogToEvent
|
|
}
|
|
|
|
}
|
|
}
|
|
finally {
|
|
$Global:Listener.Close()
|
|
Write-LogHybrid "Listener closed." Info Server -LogToEvent
|
|
}
|
|
}
|