# GOTT Remote Agent - Windows PowerShell Client # Verbindet sich per WebSocket zum GOTT-Server und fuehrt Befehle aus. # # Verwendung: # irm https://gott.example.com/remote.ps1 | iex # oder: # .\remote.ps1 -Url "wss://gott.example.com/api/remote" param( [string]$Url = "{{WS_URL}}" ) $ErrorActionPreference = "Stop" Write-Host "" Write-Host " ============================" -ForegroundColor Cyan Write-Host " GOTT Remote Agent" -ForegroundColor Cyan Write-Host " ============================" -ForegroundColor Cyan Write-Host "" Write-Host " Verbinde zu: $Url" -ForegroundColor Gray Write-Host "" try { $ws = New-Object System.Net.WebSockets.ClientWebSocket $ct = New-Object System.Threading.CancellationToken # Verbindung aufbauen $ws.ConnectAsync([Uri]$Url, $ct).GetAwaiter().GetResult() Write-Host " [OK] Verbunden!" -ForegroundColor Green # Hello-Message senden $hostname = $env:COMPUTERNAME $username = $env:USERNAME $osVersion = [System.Environment]::OSVersion.VersionString $hello = @{ type = "hello" hostname = $hostname username = $username os = $osVersion } | ConvertTo-Json -Compress $helloBytes = [System.Text.Encoding]::UTF8.GetBytes($hello) $segment = New-Object System.ArraySegment[byte] -ArgumentList @(,$helloBytes) $ws.SendAsync($segment, [System.Net.WebSockets.WebSocketMessageType]::Text, $true, $ct).GetAwaiter().GetResult() Write-Host " Host: $username@$hostname ($osVersion)" -ForegroundColor Gray Write-Host "" Write-Host " Warte auf Befehle... (Strg+C zum Beenden)" -ForegroundColor Yellow Write-Host "" # Empfangs-Loop $buffer = New-Object byte[] 65536 $messageBuffer = New-Object System.IO.MemoryStream # Heartbeat-Timer (alle 30 Sekunden) $lastPing = [DateTime]::UtcNow while ($ws.State -eq [System.Net.WebSockets.WebSocketState]::Open) { # Heartbeat senden if (([DateTime]::UtcNow - $lastPing).TotalSeconds -gt 30) { $pingBytes = [System.Text.Encoding]::UTF8.GetBytes('{"type":"ping"}') $pingSegment = New-Object System.ArraySegment[byte] -ArgumentList @(,$pingBytes) try { $ws.SendAsync($pingSegment, [System.Net.WebSockets.WebSocketMessageType]::Text, $true, $ct).GetAwaiter().GetResult() } catch { break } $lastPing = [DateTime]::UtcNow } # Auf Nachricht warten (mit Timeout fuer Heartbeat) $receiveTask = $ws.ReceiveAsync((New-Object System.ArraySegment[byte] -ArgumentList @(,$buffer)), $ct) if (-not $receiveTask.Wait(5000)) { continue } $result = $receiveTask.Result if ($result.MessageType -eq [System.Net.WebSockets.WebSocketMessageType]::Close) { Write-Host " Server hat Verbindung geschlossen." -ForegroundColor Yellow break } $messageBuffer.SetLength(0) $messageBuffer.Write($buffer, 0, $result.Count) # Mehrteilige Nachrichten zusammenbauen while (-not $result.EndOfMessage) { $result = $ws.ReceiveAsync((New-Object System.ArraySegment[byte] -ArgumentList @(,$buffer)), $ct).GetAwaiter().GetResult() $messageBuffer.Write($buffer, 0, $result.Count) } $json = [System.Text.Encoding]::UTF8.GetString($messageBuffer.ToArray()) $msg = $json | ConvertFrom-Json switch ($msg.type) { "execute" { $command = $msg.command $timestamp = Get-Date -Format "HH:mm:ss" Write-Host " [$timestamp] Ausfuehren: " -NoNewline -ForegroundColor Cyan Write-Host $command -ForegroundColor White $exitCode = 0 $stdout = "" $stderr = "" try { # PowerShell-Befehl ausfuehren $output = & powershell.exe -NoProfile -NonInteractive -Command $command 2>&1 $stdout = ($output | Where-Object { $_ -isnot [System.Management.Automation.ErrorRecord] }) -join "`n" $stderrLines = ($output | Where-Object { $_ -is [System.Management.Automation.ErrorRecord] }) | ForEach-Object { $_.ToString() } $stderr = $stderrLines -join "`n" $exitCode = $LASTEXITCODE if ($null -eq $exitCode) { $exitCode = 0 } } catch { $stderr = $_.Exception.Message $exitCode = 1 } # Ergebnis senden $response = @{ type = "result" exitCode = $exitCode output = if ($stdout) { $stdout } else { "" } error = if ($stderr) { $stderr } else { "" } } | ConvertTo-Json -Compress $responseBytes = [System.Text.Encoding]::UTF8.GetBytes($response) $responseSegment = New-Object System.ArraySegment[byte] -ArgumentList @(,$responseBytes) $ws.SendAsync($responseSegment, [System.Net.WebSockets.WebSocketMessageType]::Text, $true, $ct).GetAwaiter().GetResult() # Kurzausgabe if ($stdout) { $preview = if ($stdout.Length -gt 200) { $stdout.Substring(0, 200) + "..." } else { $stdout } Write-Host " -> $preview" -ForegroundColor Gray } if ($stderr) { Write-Host " [stderr] $stderr" -ForegroundColor Red } Write-Host " [Exit: $exitCode]" -ForegroundColor $(if ($exitCode -eq 0) { "Green" } else { "Red" }) Write-Host "" } "pong" { # Heartbeat-Antwort – ignorieren } default { Write-Host " Unbekannte Nachricht: $($msg.type)" -ForegroundColor Yellow } } } } catch [System.Net.WebSockets.WebSocketException] { Write-Host " Verbindung verloren." -ForegroundColor Red } catch { Write-Host " Fehler: $_" -ForegroundColor Red } finally { if ($ws -and $ws.State -eq [System.Net.WebSockets.WebSocketState]::Open) { try { $ws.CloseAsync([System.Net.WebSockets.WebSocketCloseStatus]::NormalClosure, "bye", $ct).GetAwaiter().GetResult() } catch { } } if ($ws) { $ws.Dispose() } Write-Host "" Write-Host " Verbindung beendet." -ForegroundColor Yellow }