Skip to content

Instantly share code, notes, and snippets.

@gitfvb
Created September 29, 2023 12:26
Show Gist options
  • Save gitfvb/02b47478c3fac49c323d3fdeec201996 to your computer and use it in GitHub Desktop.
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
$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