Skip to content

Instantly share code, notes, and snippets.

@andrii-riabchun
Created September 25, 2016 12:52
Show Gist options
  • Select an option

  • Save andrii-riabchun/07f854939ce776f6e54ba6b64f43cc92 to your computer and use it in GitHub Desktop.

Select an option

Save andrii-riabchun/07f854939ce776f6e54ba6b64f43cc92 to your computer and use it in GitHub Desktop.
Powershell static http server
#Requires -RunAsAdministrator
# Simple static http server.
Param(
[int]$port = 8080,
[string]$root = (Get-Location)
)
function Serve {
$listener = [System.Net.HttpListener]::new()
$listener.Prefixes.Add("http://+:$port/")
Write-Host "Root: $root"
try {
$listener.Start()
Write-Host "server started on :$port"
while ($listener.IsListening) {
$context = $null
$ctxTask = $listener.GetContextAsync()
do {
if ($ctxTask.Wait(100)) {
$context = $ctxTask.Result
}
}
while (-not $context)
Handle $context
}
}
catch [System.Exception] {
Write-Host $_
}
finally {
$listener.Stop()
}
}
function Handle([System.Net.HttpListenerContext] $context) {
try {
Write-Host $context.Request.RawUrl
$path = $context.Request.RawUrl.TrimStart("/")
if ([String]::IsNullOrWhiteSpace($path)) {
$path = "index.html"
}
$path = [System.IO.Path]::Combine($root, $path)
if ([System.IO.File]::Exists($path)) {
$fstream = [System.IO.FileStream]::new($path, [System.IO.FileMode]::Open)
$fstream.CopyTo($context.Response.OutputStream)
} else {
$context.Response.StatusCode = 404
}
}
catch [System.Exception] {
$context.Response.StatusCode = 500
Write-Error $_
}
finally {
$context.Response.Close()
}
}
Serve
@niutech
Copy link

niutech commented Nov 7, 2025

Good gist! However, I've made some modifications:

  1. Remove #Requires -RunAsAdministrator and instead type:
$listener.Prefixes.Add("http://127.0.0.1:$port/")
$listener.Prefixes.Add("http://localhost:$port/")
  1. Add Content-Length and Content-Type response headers:
$context.Response.ContentLength64 = (Get-Item $path).Length
$context.Response.ContentType = [System.Web.MimeMapping]::GetMimeMapping($path);
$context.Response.SendChunked = $false
  1. Use async I/O:
$bufferSize = 65536
$fstream = [System.IO.FileStream]::new($path, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::Read, $bufferSize, [System.IO.FileOptions]::Asynchronous)
try {
  $buffer = [byte[]]::new($bufferSize)
  while (($bytes = $fstream.ReadAsync($buffer, 0, $bufferSize).Result) -gt 0) {
    $context.Response.OutputStream.WriteAsync($buffer, 0, $bytes).Wait()
  }
}
finally {
  $fstream.Close()
}

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