Skip to content

Instantly share code, notes, and snippets.

@dedenker
Created November 9, 2017 20:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dedenker/52757bf8ac13548853a383f57499e2d1 to your computer and use it in GitHub Desktop.
Save dedenker/52757bf8ac13548853a383f57499e2d1 to your computer and use it in GitHub Desktop.
This Powershell script is to listen on a port and react as ping function would do. Across domain allowed in headers!
Function Start-Pong {
<#
.Synopsis
Creates a new HTTP Listener with PING reply function
.Description
This module is heavily based on a module that is a HTTP listener (see blog).
I just adjusted a little so the HASH convertion is missing and authentication can be ignored.
The function I only required is to "pong" a ping, given to a adres + port + namespace.
This function requires running from an elevated administrator prompt to open a port.
Use Ctrl-C to stop the listener. You'll need to send another web request to allow the listener to stop since
it will be blocked waiting for a request.
Pre-Fork Author: https://social.technet.microsoft.com/profile/powershell%20team/
Based on: https://gallery.technet.microsoft.com/Simple-REST-api-for-b04489f1
Mentioned blog: https://blogs.msdn.microsoft.com/powershell/2014/09/29/simple-http-api-for-executing-powershell-scripts/
.Parameter Port
Port to listen, default is 8888
.Parameter URL
URL to listen, default is /
.Parameter Auth
Optional!
Authentication Schemes to use, default is IntegratedWindowsAuthentication
.Example
Start-Pong -port 8080 -url ping
Will listen on port 8080 to recieve "ping" and will reply "pong"
This is to measure a PING value.
Start-Pong -port 8080 -url ping -Auth
Will do the same, but plus authentication
#>
Param (
[Parameter()]
[Int] $Port = 8888,
[Parameter()]
[String] $Url = "",
[Parameter()]
[Boolean] $Auth = $False
)
Process {
$json = @"
{
"ping": "pong"
}
"@
$ErrorActionPreference = "Stop"
if ($Auth) {$Auth = [System.Net.AuthenticationSchemes]$Auth = [System.Net.AuthenticationSchemes]::IntegratedWindowsAuthentication}
$CurrentPrincipal = New-Object Security.Principal.WindowsPrincipal( [Security.Principal.WindowsIdentity]::GetCurrent())
if ( -not ($currentPrincipal.IsInRole( [Security.Principal.WindowsBuiltInRole]::Administrator ))) {
Write-Error "This script must be executed from an elevated PowerShell session" -ErrorAction Stop
}
if ($Url.Length -gt 0 -and -not $Url.EndsWith('/')) {
$Url += "/"
}
$listener = New-Object System.Net.HttpListener
$prefix = "http://*:$Port/$Url"
$listener.Prefixes.Add($prefix)
if ($Auth) {$listener.AuthenticationSchemes = $Auth }
try {
$listener.Start()
while ($true) {
$statusCode = 200
Write-Warning "Note that thread is blocked waiting for a request. After using Ctrl-C to stop listening, you need to send a valid HTTP request to stop the listener cleanly."
Write-Warning "Sending 'exit' command will cause listener to stop immediately"
Write-Verbose "Listening on $port..."
$context = $listener.GetContext()
$request = $context.Request
if (!$request.IsAuthenticated) {
if ($Url -eq "ping/") {
Write-Warning "zijn er"
$commandOutput = $json #"PONG"
$Format = "TEXT"
} else {
Write-Warning "Rejected request as user was not authenticated"
$statusCode = 403
$commandOutput = "Unauthorized"
}
} else {
$identity = $context.User.Identity
Write-Verbose "Received request $(get-date) from $($identity.Name):"
$request | fl * | Out-String | Write-Verbose
# only allow requests that are the same identity as the one who started the listener
if ($identity.Name -ne $CurrentPrincipal.Identity.Name) {
Write-Warning "Rejected request as user doesn't match current security principal of listener"
$statusCode = 403
$commandOutput = "Unauthorized"
} else {
if (-not $request.QueryString.HasKeys()) {
$commandOutput = "SYNTAX: command=<string> format=[JSON|TEXT|XML|NONE|CLIXML]"
$Format = "TEXT"
} else {
$command = $request.QueryString.Item("command")
if ($command -eq "exit") {
Write-Verbose "Received command to exit listener"
return
}
$Format = $request.QueryString.Item("format")
if ($Format -eq $Null) {
$Format = "JSON"
}
Write-Verbose "Command = $command"
Write-Verbose "Format = $Format"
try {
$script = $ExecutionContext.InvokeCommand.NewScriptBlock($command)
$commandOutput = & $script
} catch {
$commandOutput = $_ | ConvertTo-HashTable
$statusCode = 500
}
}
$commandOutput = switch ($Format) {
TEXT { $commandOutput | Out-String ; break }
JSON { $commandOutput | ConvertTo-JSON; break }
XML { $commandOutput | ConvertTo-XML -As String; break }
CLIXML { [System.Management.Automation.PSSerializer]::Serialize($commandOutput) ; break }
default { "Invalid output format selected, valid choices are TEXT, JSON, XML, and CLIXML"; $statusCode = 501; break }
}
}
}
Write-Verbose "Response:"
if (!$commandOutput) {
$commandOutput = [string]::Empty
}
Write-Verbose $commandOutput
$response = $context.Response
$response.Headers.Add("Access-Control-Allow-Origin","*")
$response.StatusCode = $statusCode
$buffer = [System.Text.Encoding]::UTF8.GetBytes($commandOutput)
$response.ContentLength64 = $buffer.Length
$output = $response.OutputStream
$output.Write($buffer,0,$buffer.Length)
$output.Close()
}
} finally {
$listener.Stop()
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment