# StatusQuo_Updates/scripts/update.ps1 # Zentraler Updater - wird von update.bat per Invoke-Expression geladen. # Erwartet im aufrufenden Scope: # $proj - Projektname (z.B. 'VI3DGL', 'FLD-Schichtplanung', 'DRIVE', 'Portal_Union') # $root - Installationspfad (Verzeichnis mit server.ps1, VERSION usw.) # $stopBat - (optional) Dateiname des Stop-Skripts, z.B. 'DRIVE_Stop.bat'. # Leerstring '' = kein Stop-Schritt. Nicht gesetzt = Fallback auf 'stop.bat'. # $startBat - (optional) Dateiname des Start-Skripts, z.B. 'DRIVE_Start.bat'. # Nicht gesetzt = Fallback auf 'dgl.bat'. $ErrorActionPreference = 'Stop' $DistBase = "https://updates.rhino.nrw/rhino/StatusQuo_Updates/raw/branch/main/$proj" # Stop/Start-Namen VOR jeder Ueberschreibung aus dem aufrufenden Scope lesen $_stopName = if ($null -ne $stopBat) { $stopBat } else { 'stop.bat' } $_startName = if ($null -ne $startBat) { $startBat } else { 'dgl.bat' } # Lokale Version lesen $localVer = '0.0.0' $verFile = Join-Path $root 'VERSION' if (Test-Path -LiteralPath $verFile) { $localVer = (Get-Content $verFile -Raw).Trim() } # Remote-Version abfragen Write-Host "Prüfe Update für $proj ..." try { $remoteVer = (Invoke-WebRequest -Uri "$DistBase/VERSION" -UseBasicParsing -TimeoutSec 15).Content.Trim() } catch { Write-Host "FEHLER: Update-Server nicht erreichbar. Netzverbindung prüfen." -ForegroundColor Red return } Write-Host "Lokal: v$localVer" Write-Host "Remote: v$remoteVer" if ($localVer -eq $remoteVer) { Write-Host "Bereits auf aktuellem Stand. Kein Update nötig." -ForegroundColor Green return } $yn = Read-Host "Update von v$localVer auf v$remoteVer installieren? [j/N]" if ($yn -notin 'j','J','y','Y') { Write-Host "Abgebrochen."; return } # Temp-Ordner $tmp = Join-Path $root 'TempUpdate' Remove-Item $tmp -Recurse -Force -ErrorAction SilentlyContinue New-Item -ItemType Directory -Path $tmp | Out-Null # Bundles laden Write-Host "Lade Manifest ..." $manifest = (Invoke-WebRequest -Uri "$DistBase/MANIFEST.txt" -UseBasicParsing -TimeoutSec 30).Content $bundles = ($manifest -split "`n" | Where-Object { $_ -match '^sync-bundle-' } | ForEach-Object { ($_ -split ' ')[0] } | Sort-Object -Unique) foreach ($b in $bundles) { Write-Host " $b ..." Invoke-WebRequest -Uri "$DistBase/$b" -OutFile (Join-Path $tmp $b) -UseBasicParsing -TimeoutSec 120 } Write-Host " sync-entpacken.bat ..." Invoke-WebRequest -Uri "$DistBase/sync-entpacken.bat" -OutFile (Join-Path $tmp 'sync-entpacken.bat') -UseBasicParsing -TimeoutSec 30 # --- CHECKSUMMEN VERIFIZIEREN (optional — wird übersprungen wenn keine CHECKSUMS.txt vorhanden) --- Write-Host "Verifiziere Checksummen ..." try { $chkContent = (Invoke-WebRequest -Uri "$DistBase/CHECKSUMS.txt" -UseBasicParsing -TimeoutSec 15).Content $allOk = $true foreach ($line in ($chkContent -split "`n")) { $line = $line.Trim() if ($line -eq '' -or $line.StartsWith('#')) { continue } # Format: SHA256HASH filename $parts = $line -split '\s+', 2 if ($parts.Count -lt 2) { continue } $expected = $parts[0].ToLower() $filename = $parts[1].Trim() $localPath = Join-Path $tmp $filename if (-not (Test-Path -LiteralPath $localPath)) { continue } $actual = (Get-FileHash -LiteralPath $localPath -Algorithm SHA256).Hash.ToLower() if ($actual -ne $expected) { Write-Host "FEHLER: Checksumme stimmt nicht für $filename!" -ForegroundColor Red Write-Host " Erwartet: $expected" -ForegroundColor Red Write-Host " Erhalten: $actual" -ForegroundColor Red $allOk = $false } } if (-not $allOk) { Remove-Item $tmp -Recurse -Force -ErrorAction SilentlyContinue Write-Host "Update abgebrochen — keine Dateien verändert. Bitte Support kontaktieren." -ForegroundColor Red return } Write-Host " Alle Checksummen OK." -ForegroundColor Green } catch { # CHECKSUMS.txt nicht vorhanden — Prüfung überspringen (abwärtskompatibel) Write-Host " (Keine CHECKSUMS.txt — Prüfung übersprungen)" -ForegroundColor DarkGray } # --- END CHECKSUMMEN --- # Server stoppen Write-Host "Stoppe Server ..." if ($_stopName -ne '') { $_stopPath = Join-Path $root $_stopName if (Test-Path -LiteralPath $_stopPath) { & cmd /c "`"$_stopPath`"" 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 } # --- BACKUP (vor jeder Dateiänderung) --- $ts = Get-Date -Format 'yyyyMMdd-HHmmss' $bkDir = Join-Path $root ".backup\$ts" New-Item -ItemType Directory -Path $bkDir -Force | Out-Null # 1. Nutzerdaten sichern (kritisch!) $_dataPath = Join-Path $root 'data' if (Test-Path -LiteralPath $_dataPath) { Copy-Item -Path $_dataPath -Destination (Join-Path $bkDir 'data') -Recurse -Force $dataCount = (Get-ChildItem -LiteralPath $_dataPath -Recurse -File -ErrorAction SilentlyContinue).Count Write-Host " Nutzerdaten gesichert ($dataCount Dateien)" -ForegroundColor Cyan } else { Write-Host " (Kein data/-Ordner gefunden — übersprungen)" -ForegroundColor DarkGray } # 2. Code-Dateien sichern foreach ($ext in '*.ps1','*.html','*.js','*.css','*.bat','VERSION') { Get-ChildItem -LiteralPath $root -File -Filter $ext -ErrorAction SilentlyContinue | Copy-Item -Destination $bkDir -Force } Write-Host "Backup erstellt: $bkDir" -ForegroundColor Cyan # 3. Alte Backups bereinigen (max. 5 behalten) $_backupBase = Join-Path $root '.backup' $_allBackups = Get-ChildItem -LiteralPath $_backupBase -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -match '^\d{8}-\d{6}$' } | Sort-Object Name -Descending if ($_allBackups.Count -gt 5) { $_allBackups | Select-Object -Skip 5 | ForEach-Object { Remove-Item -Path $_.FullName -Recurse -Force -ErrorAction SilentlyContinue } Write-Host " (Nur 5 neueste Backups behalten)" -ForegroundColor DarkGray } # --- END BACKUP --- # Entpacken (sync-entpacken.bat aus TempUpdate → schreibt in Root eine Ebene hoeher) Write-Host "Entpacke Update-Dateien ..." & cmd /c "`"$(Join-Path $tmp 'sync-entpacken.bat')`"" # VERSION lokal aktualisieren [System.IO.File]::WriteAllText($verFile, ($remoteVer + "`r`n"), [System.Text.Encoding]::UTF8) Write-Host "Version auf v$remoteVer aktualisiert." -ForegroundColor Green # Aufräumen Remove-Item $tmp -Recurse -Force -ErrorAction SilentlyContinue # Server neu starten $_startPath = Join-Path $root $_startName if (Test-Path -LiteralPath $_startPath) { Start-Process -FilePath 'cmd.exe' -ArgumentList "/c `"$_startPath`"" -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 "=== Update abgeschlossen ===" -ForegroundColor Green Write-Host " Backup liegt unter: $bkDir" -ForegroundColor DarkGray Write-Host " Bei Problemen: rollback.bat doppelklicken!" -ForegroundColor DarkGray