Created
September 29, 2023 12:26
-
-
Save gitfvb/02b47478c3fac49c323d3fdeec201996 to your computer and use it in GitHub Desktop.
Small notes on opening a webserver in PowerShell in the background and wait for a query parameter and also showing a progress bar
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
$webserverProcess = [scriptblock]{ | |
param( | |
[uri]$redirect | |
) | |
Add-Type -AssemblyName System.Web | |
$http = [System.Net.HttpListener]::new() | |
# Hostname and port to listen on | |
$http.Prefixes.Add($redirect) | |
# Start the Http Server | |
$http.Start() | |
# Log ready message to terminal | |
if ($http.IsListening) { | |
Write-Information -MessageData " HTTP Server Ready on '$( $http.Prefixes )'" | |
#write-Log " HTTP Server Ready on '$( $http.Prefixes )'" #-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' | |
} else { | |
throw "There was an error starting the HTTP server, pleasy retry or choose another port" | |
} | |
# Let the webserver listen, this loop gets only executed when a request takes place | |
$r = $null | |
$closeHttpListener = $false | |
$code = "" | |
do { | |
# Get Request Url | |
# When a request is made in a web browser the GetContext() method will return a request object | |
$context = $http.GetContext() | |
# Raw url | |
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 = "Waiting for Code." | |
#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 | |
} | |
# If the url contains the code | |
if ( $context.request.RawUrl -like "*code=*" ) { | |
#Write-Verbose "Got a code" -verbose | |
# Looking for code in query | |
$callbackUri = [uri]$context.Request.Url | |
$callbackUriSegments = [System.Web.HttpUtility]::ParseQueryString($callbackUri.Query) | |
$code = $callbackUriSegments["code"] | |
$r = $context | |
$closeHttpListener = $true | |
# 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>Received code: $( $code )</h1>" | |
#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 | |
} | |
<# | |
a few examples | |
$context.Request.HttpMethod gives you the method like GET | |
$context.Request.RawUrl | |
$context.Request.UserHostAddress | |
$context.Request.Url | |
#> | |
# powershell will continue looping and listen for new requests... | |
} until ( $closeHttpListener -eq $true ) #$http.IsListening | |
$code | |
} | |
# Start the webserver in the background | |
$u = "http://localhost:$( Get-Random -Minimum 49152 -Maximum 65535 )/" | |
Write-Information -MessageData "Using $( $u )" -InformationAction Continue | |
$job = Start-Job -Name "ReceiveCodeViaHTTP" -ArgumentList $u -ScriptBlock $webserverProcess #| Wait-Job | |
# Show a progress bar and wait for a result | |
$maxSeconds = 360 # 5 minutes | |
$waitingStart = [datetime]::Now | |
Do { | |
# Show the progress | |
$ts = New-TimeSpan -Start $waitingStart -End ( [datetime]::now ) | |
$secondsRemaining = [math]::Ceiling($maxSeconds - $ts.TotalSeconds) | |
Write-Progress -Activity "Waiting for callback/redirect" -Status "$( $secondsRemaining ) seconds left" -SecondsRemaining $secondsRemaining -PercentComplete ([math]::Round($secondsRemaining/$maxSeconds*100)) | |
# Wait | |
Start-Sleep -Milliseconds 500 | |
} While ( $ts.TotalSeconds -lt $maxSeconds -and $job.State -eq "Running") | |
# Kill the job, if it not completed yet | |
If ( $job.State -ne "Completed" ) { | |
try { | |
$job.StopJob() | |
} catch { | |
} | |
} | |
# Look for a result | |
$code = Receive-Job -Job $job | |
If ( $code.Length -gt 0 ) { | |
Write-Host $code | |
} else { | |
throw "No usable code received" | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment