-
-
Save 19WAS85/5424431 to your computer and use it in GitHub Desktop.
# This is a super **SIMPLE** example of how to create a very basic powershell webserver | |
# 2019-05-18 UPDATE — Created by me and and evalued by @jakobii and the comunity. | |
# Http Server | |
$http = [System.Net.HttpListener]::new() | |
# Hostname and port to listen on | |
$http.Prefixes.Add("http://localhost:8080/") | |
# Start the Http Server | |
$http.Start() | |
# Log ready message to terminal | |
if ($http.IsListening) { | |
write-host " HTTP Server Ready! " -f 'black' -b 'gre' | |
write-host "now try going to $($http.Prefixes)" -f 'y' | |
write-host "then try going to $($http.Prefixes)other/path" -f 'y' | |
} | |
# INFINTE LOOP | |
# Used to listen for requests | |
while ($http.IsListening) { | |
# Get Request Url | |
# When a request is made in a web browser the GetContext() method will return a request object | |
# Our route examples below will use the request object properties to decide how to respond | |
$context = $http.GetContext() | |
# ROUTE EXAMPLE 1 | |
# http://127.0.0.1/ | |
if ($context.Request.HttpMethod -eq 'GET' -and $context.Request.RawUrl -eq '/') { | |
# We can log the request to the terminal | |
write-host "$($context.Request.UserHostAddress) => $($context.Request.Url)" -f 'mag' | |
# the html/data you want to send to the browser | |
# you could replace this with: [string]$html = Get-Content "C:\some\path\index.html" -Raw | |
[string]$html = "<h1>A Powershell Webserver</h1><p>home page</p>" | |
#resposed to the request | |
$buffer = [System.Text.Encoding]::UTF8.GetBytes($html) # convert htmtl to bytes | |
$context.Response.ContentLength64 = $buffer.Length | |
$context.Response.OutputStream.Write($buffer, 0, $buffer.Length) #stream to broswer | |
$context.Response.OutputStream.Close() # close the response | |
} | |
# ROUTE EXAMPLE 2 | |
# http://127.0.0.1/some/form' | |
if ($context.Request.HttpMethod -eq 'GET' -and $context.Request.RawUrl -eq '/some/form') { | |
# We can log the request to the terminal | |
write-host "$($context.Request.UserHostAddress) => $($context.Request.Url)" -f 'mag' | |
[string]$html = " | |
<h1>A Powershell Webserver</h1> | |
<form action='/some/post' method='post'> | |
<p>A Basic Form</p> | |
<p>fullname</p> | |
<input type='text' name='fullname'> | |
<p>message</p> | |
<textarea rows='4' cols='50' name='message'></textarea> | |
<br> | |
<input type='submit' value='Submit'> | |
</form> | |
" | |
#resposed to the request | |
$buffer = [System.Text.Encoding]::UTF8.GetBytes($html) | |
$context.Response.ContentLength64 = $buffer.Length | |
$context.Response.OutputStream.Write($buffer, 0, $buffer.Length) | |
$context.Response.OutputStream.Close() | |
} | |
# ROUTE EXAMPLE 3 | |
# http://127.0.0.1/some/post' | |
if ($context.Request.HttpMethod -eq 'POST' -and $context.Request.RawUrl -eq '/some/post') { | |
# decode the form post | |
# html form members need 'name' attributes as in the example! | |
$FormContent = [System.IO.StreamReader]::new($context.Request.InputStream).ReadToEnd() | |
# We can log the request to the terminal | |
write-host "$($context.Request.UserHostAddress) => $($context.Request.Url)" -f 'mag' | |
Write-Host $FormContent -f 'Green' | |
# the html/data | |
[string]$html = "<h1>A Powershell Webserver</h1><p>Post Successful!</p>" | |
#resposed to the request | |
$buffer = [System.Text.Encoding]::UTF8.GetBytes($html) | |
$context.Response.ContentLength64 = $buffer.Length | |
$context.Response.OutputStream.Write($buffer, 0, $buffer.Length) | |
$context.Response.OutputStream.Close() | |
} | |
# powershell will continue looping and listen for new requests... | |
} | |
# Note: | |
# To end the loop you have to kill the powershell terminal. ctrl-c wont work :/ |
Powershell Webserver on technet
Working Example
where would be a place to host this tho
Note that this is single-threaded. This server can only serve one client at a time.
Using this example, I managed to create complete server that will serve anything in web/*
directory wherever you run it. The server is insecure against directory crawling attacks.
Check this answer for the code: https://stackoverflow.com/a/63133186/607407
Hi, i wish to use something this in an OAuth Authorization Code flow, where the Identity provider will redirect back to my browser a code.. Any ideas?
Can be improved by de-duplicating code.
#resposed to the request
$buffer = [System.Text.Encoding]::UTF8.GetBytes($html)
$context.Response.ContentLength64 = $buffer.Length
$context.Response.OutputStream.Write($buffer, 0, $buffer.Length)
$context.Response.OutputStream.Close()
To enable the script pipeline to be stopped using CTRL+C we can wrap the while loop in a try/finally and use an async context. E.g.
try {
while ($http.IsListening) {
$contextTask = $http.GetContextAsync()
# Waits in 200ms increments allowing pipeline stops to be processed (i.e. CTRL+C)
# Credit: https://www.reddit.com/r/PowerShell/comments/9n2q03/comment/e7ju5w4/?utm_source=share&utm_medium=web2x&context=3
while (-not $contextTask.AsyncWaitHandle.WaitOne(200)) { }
$context = $contextTask.GetAwaiter().GetResult()
# -- rest of loop
}
}
finally {
# This is always called when ctrl+c is used
$http.Stop()
}
Full Gist: https://gist.github.com/rminderhoud/c603a0a30587ae5c957b211ba386bf37
It's awesome for Windows power users!