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 } }