param( [string]$ReportPath = "G:\Gitea_Clone\homelab-infra\docs\audit\dr-workstation-readiness-2026-06-06.md" ) $ErrorActionPreference = "Stop" function Invoke-Capture { param([string]$Command) $output = & cmd.exe /c $Command 2>&1 [pscustomobject]@{ Command = $Command ExitCode = $LASTEXITCODE Output = ($output | ForEach-Object { ([string]$_).Replace("`0", "") }) } } function Invoke-WslCapture { param([string]$Bash) Invoke-Capture -Command ('wsl -d Ubuntu -- bash -lc ' + '"' + ($Bash.Replace('"', '\"')) + '"') } $checks = [ordered]@{} $checks["wsl_status"] = Invoke-Capture -Command "wsl --status" $checks["wsl_list"] = Invoke-Capture -Command "wsl --list --verbose" $checks["ubuntu_os"] = Invoke-WslCapture -Bash "lsb_release -a 2>/dev/null || cat /etc/os-release; uname -r" $checks["tools"] = Invoke-WslCapture -Bash "command -v borg || true; borg --version 2>/dev/null || true; command -v ssh || true; ssh -V 2>&1 || true; command -v git || true; git --version 2>/dev/null || true" $checks["sudo"] = Invoke-WslCapture -Bash "sudo -n true >/dev/null 2>&1 && echo sudo-noprompt-ok || echo sudo-password-needed" $checks["wsl_ssh_files"] = Invoke-WslCapture -Bash "ls -la ~/.ssh 2>/dev/null || true; test -f ~/dr-smoke.sh && ls -la ~/dr-smoke.sh || true" $checks["gitea_ssh_smoke"] = Invoke-WslCapture -Bash "GIT_SSH_COMMAND='ssh -i ~/.ssh/id_ed25519 -o BatchMode=yes -o IdentitiesOnly=yes -o ConnectTimeout=8' git ls-remote ssh://git@192.168.178.58:222/Micha/homelab-infra.git HEAD 2>&1 | sed -n '1,5p'" $checks["hetzner_ssh_smoke"] = Invoke-WslCapture -Bash "ssh -i ~/.ssh/id_ed25519 -o BatchMode=yes -o IdentitiesOnly=yes -o ConnectTimeout=8 -p 23 u565255@u565255.your-storagebox.de 'ls' 2>&1 | sed -n '1,10p'" $borgInstalled = ($checks["tools"].Output -match "borg \d") $giteaOk = ($checks["gitea_ssh_smoke"].Output -match "HEAD") $hetznerOk = -not ($checks["hetzner_ssh_smoke"].Output -match "Permission denied|Connection refused|Could not") $sudoNeedsPassword = ($checks["sudo"].Output -match "sudo-password-needed") $drSmokeExists = ($checks["wsl_ssh_files"].Output -match "dr-smoke.sh") $lines = @() $lines += "# DR-Workstation Readiness - 2026-06-06" $lines += "" $lines += "Automatisch erzeugter lokaler Readiness-Check fuer den Operator-PC. Es wurden keine Secret-Werte, Passphrases oder Private-Key-Inhalte ausgegeben." $lines += "" $lines += "## Zusammenfassung" $lines += "" $lines += "| Check | Ergebnis |" $lines += "|---|---|" $lines += '| WSL2 Ubuntu | vorhanden (`Ubuntu 24.04`, WSL Version 2) |' $lines += "| SSH/Git in WSL | vorhanden |" $lines += "| Gitea-SSH-Smoke mit vorhandenem WSL-Key | " + ($(if ($giteaOk) { "ok" } else { "nicht ok" })) + " |" $lines += "| Borg Client | " + ($(if ($borgInstalled) { "installiert" } else { "fehlt" })) + " |" $lines += "| Hetzner Storage Box mit vorhandenem WSL-Key | " + ($(if ($hetznerOk) { "ok" } else { "nicht ok / separater DR-Key noetig" })) + " |" $lines += '| `~/dr-smoke.sh` | ' + ($(if ($drSmokeExists) { "vorhanden" } else { "fehlt" })) + ' |' $lines += "| WSL sudo ohne Passwortprompt | " + ($(if ($sudoNeedsPassword) { "nein, Operator muss Passwort eingeben" } else { "ja" })) + " |" $lines += "" $lines += "## Bewertung" $lines += "" $lines += "- Der lokale WSL2-/Ubuntu-Unterbau ist vorhanden." $lines += "- Der vorhandene WSL-Key kann das interne Gitea erreichen." $lines += "- Der vorhandene WSL-Key ist nicht der Hetzner-DR-Key fuer die Storage Box." $lines += '- `borgbackup` ist noch nicht installiert.' $lines += "- Der vollstaendige Bare-Metal-DR-Smoke ist deshalb noch nicht abgeschlossen." $lines += "" $lines += "## Naechste Operator-Schritte" $lines += "" $lines += "In Ubuntu ausfuehren:" $lines += "" $lines += '```bash' $lines += "sudo apt update" $lines += "sudo apt install -y borgbackup openssh-client" $lines += "borg --version" $lines += '```' $lines += "" $lines += 'Danach den offline gesicherten Hetzner-DR-Key als Arbeitskopie nach `~/.ssh/dr-hetzner` legen und `chmod 600 ~/.ssh/dr-hetzner` setzen. Anschliessend den Smoke aus `docs/DR_WORKSTATION_SETUP.md` Schritt 3-6 fahren.' $lines += "" $lines += "## Rohchecks" $lines += "" foreach ($name in $checks.Keys) { $check = $checks[$name] $lines += "### $name" $lines += "" $lines += '- ExitCode: `' + $check.ExitCode + '`' $lines += "" $lines += '```text' $lines += ($check.Output | ForEach-Object { $_ -replace ([regex]::Escape($env:USERPROFILE)), '%USERPROFILE%' }) $lines += '```' $lines += "" } New-Item -ItemType Directory -Force -Path (Split-Path -Parent $ReportPath) | Out-Null while ($lines.Count -gt 0 -and $lines[-1] -eq "") { $lines = $lines[0..($lines.Count - 2)] } $lines -join "`r`n" | Set-Content -LiteralPath $ReportPath -Encoding UTF8 Write-Host "Report written: $ReportPath"