Last active
November 4, 2024 16:50
-
-
Save 19WAS85/5424431 to your computer and use it in GitHub Desktop.
A simple web server built with powershell.
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
# 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 :/ |
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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