Skip to content

Instantly share code, notes, and snippets.

@Tim-S
Last active July 10, 2024 13:23
Show Gist options
  • Save Tim-S/f1c667367f015ef5b7396ed111c2df7f to your computer and use it in GitHub Desktop.
Save Tim-S/f1c667367f015ef5b7396ed111c2df7f to your computer and use it in GitHub Desktop.
Simple PowerShell Websocket server
<!DOCTYPE html>
<meta charset="utf-8" />
<title>WebSocket Test</title>
<script language="javascript" type="text/javascript">
var wsUri = "ws://localhost:5001/";
var output;
function init() {
output = document.getElementById("output");
testWebSocket();
}
function testWebSocket() {
websocket = new WebSocket(wsUri);
websocket.onopen = function (evt) { onOpen(evt) };
websocket.onclose = function (evt) { onClose(evt) };
websocket.onmessage = function (evt) { onMessage(evt) };
websocket.onerror = function (evt) { onError(evt) };
}
function onOpen(evt) {
writeToScreen("CONNECTED");
doSend("Client says Hello!");
}
function onClose(evt) {
writeToScreen("DISCONNECTED");
}
function onMessage(evt) {
writeToScreen('<span style="color: blue;">Received: ' + evt.data + '</span>');
}
function onError(evt) {
writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);
}
function doSend(message) {
writeToScreen("SENT: " + message);
websocket.send(message);
}
function writeToScreen(message) {
var pre = document.createElement("p");
pre.style.wordWrap = "break-word";
pre.innerHTML = message;
output.appendChild(pre);
}
window.addEventListener("load", init, false);
</script>
<body>
<h2>WebSocket Test</h2>
<div id="output"></div>
</body>
write-host "Web Listener: Start"
# maybe need to allow script execution via
# Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine
try {
$listener = New-Object System.Net.HttpListener
# $listener.Prefixes.Add('http://+:81/') # listen on ony interface (matching netsh or running on admin console required)
$listener.Prefixes.Add('http://localhost:5001/')
$listener.Start()
}
catch {
write-error "Unable to open listener. Check Admin permission or NETSH Binding"
exit 1
}
# Helper for awaiting async tasks on powershell
# see https://blog.ironmansoftware.com/powershell-async-method/#:~:text=PowerShell%20does%20not%20provide%20an,when%20calling%20async%20methods%20in%20.
function Wait-Task {
param(
[Parameter(Mandatory, ValueFromPipeline)]
[System.Threading.Tasks.Task[]]$Task
)
Begin {
$Tasks = @()
}
Process {
$Tasks += $Task
}
End {
While (-not [System.Threading.Tasks.Task]::WaitAll($Tasks, 200)) {}
$Tasks.ForEach( { $_.GetAwaiter().GetResult() })
}
}
Set-Alias -Name await -Value Wait-Task -Force
# Create a simple Websocke server proving a Message including teh current time
Write-host "Web Listener listening"
[console]::TreatControlCAsInput = $true
while (!([console]::KeyAvailable)) {
Write-host "Press any key to Stop (requires client to be connected, yet)"
$context = await $listener.GetContextAsync()
if ($context.Request.IsWebSocketRequest)
{
write-host ("Received Websocket-Request on " + $listener.Prefixes )
$webSocketContext = await $context.AcceptWebSocketAsync(([NullString]::Value)) # # https://docs.microsoft.com/de-de/dotnet/api/system.net.httplistenercontext.acceptwebsocketasync?view=netframework-4.5
$webSocket = $webSocketContext.WebSocket;
$ct = New-Object Threading.CancellationToken($false)
while ($webSocket.State -eq [System.Net.WebSockets.WebSocketState]::Open -and !([console]::KeyAvailable))
{
$date = (get-date -Format yyyy-MM-dd-HH:mm:ss)
$workitem = "Hello World "+$date;
[ArraySegment[byte]]$msg = [Text.Encoding]::UTF8.GetBytes($workitem)
$_ = await $webSocket.SendAsync(
$msg,
[System.Net.WebSockets.WebSocketMessageType]::Text, # Binary
$true,
$ct
);
$_ = await([System.Threading.Tasks.Task]::Delay(1000)); # wait one second # ignore result (ie. write to dummy-variable $_)
}
}
$response = $context.Response
$response.OutputStream.close()
$listener.Stop()
}
Write-host "Web Listener Stopping"
$listener.Stop()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment