# StatusQuo_Updates/scripts/rollback.ps1 # Kanonisches Rollback-Skript (Referenz). rollback.bat enthaelt diese Logik # EINGEBETTET und laeuft vollstaendig OFFLINE. Beachtet .backupignore. # Erwartet im Scope: $root, $stopBat, $startBat $ErrorActionPreference = 'Stop' # Erwartet im Scope: $root, $stopBat, $startBat $_stopName = if ($null -ne $stopBat) { $stopBat } else { 'stop.bat' } $_startName = if ($null -ne $startBat) { $startBat } else { 'dgl.bat' } # Ausschlussliste (identisch zu update.ps1): .backup nie anfassen, plus große # Content-Ordner aus .backupignore — diese bleiben beim Rollback unverändert. $_excl = @('.backup') $_ignoreFile = Join-Path $root '.backupignore' if (Test-Path -LiteralPath $_ignoreFile) { $_extra = @(Get-Content -LiteralPath $_ignoreFile | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne '' -and -not $_.StartsWith('#') }) $_excl = $_excl + $_extra } $_excl = @($_excl) # strikt als Array (verhindert Skalar-Entpackung) $bk = Join-Path $root '.backup' if (-not (Test-Path -LiteralPath $bk)) { Write-Host "Kein Backup-Verzeichnis gefunden. Sicherungen entstehen automatisch beim ersten Update." -ForegroundColor Red return } $snaps = Get-ChildItem -LiteralPath $bk -Filter 'snapshot-*.zip' -ErrorAction SilentlyContinue | Sort-Object Name -Descending if (-not $snaps) { Write-Host "Keine Sicherungen vorhanden. Sicherungen entstehen automatisch beim ersten Update." -ForegroundColor Red return } Write-Host "" Write-Host "Verfügbare Sicherungen (neueste zuerst):" -ForegroundColor Cyan $i = 0 foreach ($s in $snaps) { $size = '{0:N1} MB' -f ($s.Length / 1MB) $tag = if ($i -eq 0) { " <- neueste" } else { "" } Write-Host (" [{0}] {1} ({2}){3}" -f $i, $s.Name, $size, $tag) $i++ } Write-Host "" $c = Read-Host "Nummer der Sicherung wählen (Enter = neueste [0])" if ($c -eq '') { $c = '0' } if ($c -notmatch '^\d+$' -or [int]$c -ge $snaps.Count) { Write-Host "Ungültige Auswahl. Abgebrochen." -ForegroundColor Yellow return } $chosen = $snaps[[int]$c] $zip = $chosen.FullName # Integrität der Sicherung prüfen, BEVOR irgendetwas ersetzt wird Add-Type -AssemblyName System.IO.Compression.FileSystem try { $z = [System.IO.Compression.ZipFile]::OpenRead($zip) $null = $z.Entries.Count $z.Dispose() } catch { Write-Host "FEHLER: Sicherung ist beschädigt — Rollback abgebrochen: $zip" -ForegroundColor Red return } Write-Host "" $yn = Read-Host "Stand '$($chosen.Name)' wiederherstellen? Der aktuelle Stand wird ersetzt! [j/N]" if ($yn -notin 'j','J','y','Y') { Write-Host "Abgebrochen."; return } # Server stoppen Write-Host "Stoppe Server ..." if ($_stopName -ne '') { $sp = Join-Path $root $_stopName if (Test-Path -LiteralPath $sp) { & cmd /c "`"$sp`""; Start-Sleep -Seconds 2 } else { Write-Host " (Stop-Skript '$_stopName' nicht gefunden — übersprungen)" -ForegroundColor DarkYellow } } else { Write-Host " (Kein Stop-Skript konfiguriert — übersprungen)" -ForegroundColor DarkYellow } # Aktuellen Stand beiseite verschieben (Sicherheitsnetz, kein Datenverlust) $aside = Join-Path $bk ("_vor-rollback-" + (Get-Date -Format 'yyyyMMdd-HHmmss')) New-Item -ItemType Directory -Path $aside -Force | Out-Null Get-ChildItem -LiteralPath $root -Force | Where-Object { $_excl -notcontains $_.Name } | ForEach-Object { Move-Item -LiteralPath $_.FullName -Destination (Join-Path $aside $_.Name) -Force } # Sicherung wiederherstellen try { Expand-Archive -LiteralPath $zip -DestinationPath $root -Force Write-Host "Stand wiederhergestellt: $($chosen.Name)" -ForegroundColor Green } catch { Write-Host "FEHLER beim Wiederherstellen — mache Änderung rückgängig ..." -ForegroundColor Red Get-ChildItem -LiteralPath $root -Force | Where-Object { $_excl -notcontains $_.Name } | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue Get-ChildItem -LiteralPath $aside -Force | ForEach-Object { Move-Item -LiteralPath $_.FullName -Destination (Join-Path $root $_.Name) -Force } Write-Host "Vorheriger Zustand wiederhergestellt — kein Datenverlust." -ForegroundColor Yellow return } # Beiseite-Ordner aufräumen: nur die letzten 2 behalten Get-ChildItem -LiteralPath $bk -Directory -Filter '_vor-rollback-*' -ErrorAction SilentlyContinue | Sort-Object Name -Descending | Select-Object -Skip 2 | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue # Server starten $stp = Join-Path $root $_startName if (Test-Path -LiteralPath $stp) { Start-Process -FilePath 'cmd.exe' -ArgumentList "/c `"$stp`"" -WindowStyle Hidden Write-Host "Server gestartet." -ForegroundColor Green } else { Write-Host "Start-Skript '$_startName' nicht gefunden — bitte Server manuell starten." -ForegroundColor Yellow } Write-Host "" Write-Host "=== Rollback abgeschlossen ===" -ForegroundColor Green Write-Host " Wiederhergestellt: $($chosen.Name)" -ForegroundColor Cyan