Last active
February 18, 2024 23:01
-
-
Save nmoadev/d15e0ec5c508088e00a66850a5b3f170 to your computer and use it in GitHub Desktop.
Zero-dependency Powershell WebServer in a one file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# A zero-dependency tiny, copy-pasteable powershell web server for quick hacks | |
# Credit to https://woshub.com/simple-http-webserver-powershell/ for inspiration | |
# NOTE: If you download this script direclty, you will need to unblock it before running | |
# Unblock-File .\serve.ps1 | |
param ( | |
$webRoot = (Get-Location), # The folder from which to serve all files RECURSIVELY | |
$listenHostname = "localhost", # Hostname to listen on. Change at your own risk. | |
$listenPort = "9090" # The port to listen on. | |
) | |
# Needed for Content-Type header | |
Add-Type -AssemblyName "System.Web" | |
function Serve () { | |
param ( | |
$webRoot = (Get-Location), | |
$listenHostname = "localhost", | |
$listenPort = "9090" | |
) | |
$listener = New-Object System.Net.HttpListener | |
$listener.Prefixes.Add("http://${listenHostname}:${listenPort}/") | |
$listener.Start() | |
try { | |
while (1 -eq 1) { | |
try { | |
$contextTask = $listener.GetContextAsync() | |
while (-not $contextTask.AsyncWaitHandle.WaitOne(1000)) {} | |
$context = $contextTask.GetAwaiter().GetResult() | |
ServeFile $webRoot $context | |
} catch { | |
$context.Response.StatusCode = 500 | |
Log "$_`n$($_.ScriptStackTrace)" | |
} finally { | |
$context.Response.Close() | |
Log "$($context.Request.HttpMethod) $($context.Request.RawUrl) => $($context.Response.StatusCode)" | |
} | |
} | |
} catch { | |
Log "$_`n$($_.ScriptStackTrace)" | |
} finally { | |
$listener.Close() | |
} | |
} | |
function ServeFile() { | |
param ( | |
[string] $webRoot, | |
[System.Net.HttpListenerContext] $context | |
) | |
$contentPath = WebPathToFilePath $webRoot $context.Request.RawUrl | |
if (Test-Path $contentPath -PathType Leaf) { | |
$fileStream = New-Object System.IO.FileStream -ArgumentList $contentPath,3 | |
try { | |
$fileStream.CopyTo($context.Response.OutputStream) | |
$context.Response.StatusCode = 200 | |
$context.Response.ContentType = [System.Web.MimeMapping]::GetMimeMapping($contentPath) | |
} finally { | |
$fileStream.Close(); | |
} | |
} else { | |
$context.Response.StatusCode = 404 | |
} | |
} | |
function Log() { | |
param ( | |
[string] $msg | |
) | |
$time = Get-Date -Format "yyyy-MM-dd HH:mm:ss.fffzzz" | |
Write-Host "${time} | ${msg}" | |
} | |
function WebPathToFilePath() { | |
param ( | |
[string] $webRoot, | |
[string] $webPath | |
) | |
$webPath = $webPath.Replace("/", "\") | |
return (Join-Path $webRoot $webPath) | |
} | |
Serve $webRoot $listenHostname $listenPort |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment