Dateien nach "/" hochladen

This commit is contained in:
2026-08-13 23:35:34 +02:00
parent e3dad5a9f3
commit c0c333b053
+367 -61
View File
@@ -35,6 +35,23 @@ $HealthFileName = "Test-SMTPGraphRelay.ps1"
$RenewFileName = "Renew-SMTPGraphRelayCertificate.ps1"
$ConfigFileName = "config.json"
# Zentrales Gitea-Repository / Updatequelle
$RepoBaseUrl = "https://me-gitea.maieredv.cloud/MAIEREDV/SMTPGraphRelay"
$RemoteVersionUrl = "$RepoBaseUrl/raw/branch/main/version.json"
$RemoteArchiveUrl = "$RepoBaseUrl/archive/main.zip"
$RemoteRelayUrl = "$RepoBaseUrl/raw/branch/main/SMTPGraphRelay.ps1"
# Dateien, die ein Update verändern darf.
# config.json, Queue, Logs und sonstige lokale Daten sind absichtlich NICHT enthalten.
$ManagedReleaseFiles = @(
"SMTPGraphRelay.ps1",
"Test-SMTPGraphRelay.ps1",
"Renew-SMTPGraphRelayCertificate.ps1",
"Setup-SMTPGraphRelay.ps1",
"version.json",
"README.md"
)
function Write-Title {
param([string]$Text)
Write-Host ""
@@ -513,6 +530,166 @@ function Test-NoGlobalMailSend {
}
}
function Enable-Tls12 {
try {
[Net.ServicePointManager]::SecurityProtocol = `
[Net.ServicePointManager]::SecurityProtocol -bor `
[Net.SecurityProtocolType]::Tls12
} catch {}
}
function Get-RemoteVersion {
Enable-Tls12
$tempFile = Join-Path $env:TEMP ("SMTPGraphRelay-version-{0}.json" -f [guid]::NewGuid().ToString("N"))
try {
Invoke-WebRequest `
-Uri $RemoteVersionUrl `
-OutFile $tempFile `
-UseBasicParsing `
-TimeoutSec 20 `
-ErrorAction Stop
$remote = Get-Content -LiteralPath $tempFile -Raw -Encoding UTF8 | ConvertFrom-Json
if (-not $remote.Version) {
throw "Remote version.json enthält keine Version."
}
return $remote
}
finally {
Remove-Item -LiteralPath $tempFile -Force -ErrorAction SilentlyContinue
}
}
function Compare-RelayVersions {
param(
[Parameter(Mandatory)][string]$Installed,
[Parameter(Mandatory)][string]$Remote
)
try {
$installedVersion = [version]$Installed
$remoteVersion = [version]$Remote
if ($remoteVersion -gt $installedVersion) { return 1 }
if ($remoteVersion -lt $installedVersion) { return -1 }
return 0
}
catch {
throw "Versionsvergleich fehlgeschlagen: installiert='$Installed', remote='$Remote'."
}
}
function Find-ExtractedReleaseRoot {
param(
[Parameter(Mandatory)][string]$ExtractPath
)
# Gitea kann beim Archiv einen zusätzlichen Root-Ordner erzeugen.
# Daher suchen wir nach der Kombination aus Relay + version.json statt
# einen konkreten Archivordnernamen vorauszusetzen.
$relayFiles = Get-ChildItem `
-LiteralPath $ExtractPath `
-Recurse `
-File `
-Filter $RelayFileName `
-ErrorAction SilentlyContinue
foreach ($relay in $relayFiles) {
$candidate = $relay.Directory.FullName
if (Test-Path -LiteralPath (Join-Path $candidate "version.json")) {
return $candidate
}
}
throw "Im heruntergeladenen Archiv wurde kein gültiges SMTPGraphRelay-Release gefunden."
}
function Backup-ManagedFiles {
param(
[Parameter(Mandatory)][string]$TargetPath
)
$backupRoot = Join-Path $TargetPath "backup"
$backupPath = Join-Path $backupRoot (Get-Date -Format "yyyyMMdd-HHmmss")
New-Item -ItemType Directory -Path $backupPath -Force | Out-Null
foreach ($name in $ManagedReleaseFiles) {
$source = Join-Path $TargetPath $name
if (Test-Path -LiteralPath $source) {
Copy-Item -LiteralPath $source -Destination (Join-Path $backupPath $name) -Force
}
}
return $backupPath
}
function Restore-ManagedFiles {
param(
[Parameter(Mandatory)][string]$BackupPath,
[Parameter(Mandatory)][string]$TargetPath
)
foreach ($name in $ManagedReleaseFiles) {
$backupFile = Join-Path $BackupPath $name
$targetFile = Join-Path $TargetPath $name
if (Test-Path -LiteralPath $backupFile) {
Copy-Item -LiteralPath $backupFile -Destination $targetFile -Force
}
}
}
function Install-ExtractedRelease {
param(
[Parameter(Mandatory)][string]$ReleaseRoot,
[Parameter(Mandatory)][string]$TargetPath
)
$required = @(
"SMTPGraphRelay.ps1",
"version.json"
)
foreach ($name in $required) {
if (-not (Test-Path -LiteralPath (Join-Path $ReleaseRoot $name))) {
throw "Updatepaket ist unvollständig: '$name' fehlt."
}
}
foreach ($name in $ManagedReleaseFiles) {
$source = Join-Path $ReleaseRoot $name
if (Test-Path -LiteralPath $source) {
Copy-Item -LiteralPath $source -Destination (Join-Path $TargetPath $name) -Force
Write-Ok "Aktualisiert: $name"
}
}
}
function Invoke-PostUpdateHealthCheck {
param(
[Parameter(Mandatory)][string]$TargetPath
)
$health = Join-Path $TargetPath $HealthFileName
if (-not (Test-Path -LiteralPath $health)) {
Write-Warn "Health Check ist nicht installiert; automatische Nachprüfung entfällt."
return 0
}
Write-Info "Starte Health Check nach dem Update..."
& $health -ConfigPath (Join-Path $TargetPath $ConfigFileName)
return $LASTEXITCODE
}
function Install-New {
Write-Title "SMTPGraphRelay - Neuinstallation"
@@ -670,6 +847,32 @@ function Install-New {
elseif (Test-Path -LiteralPath (Join-Path $InstallPath $RelayFileName)) {
Write-Warn "Installierte Version unbekannt (keine version.json)."
}
try {
$remoteVersionInfo = Get-RemoteVersion
if ($remoteVersionInfo -and $remoteVersionInfo.Version) {
Write-Host "Remote (main): $($remoteVersionInfo.Version)"
if ($installedVersion -and $installedVersion.Version) {
$cmp = Compare-RelayVersions `
-Installed ([string]$installedVersion.Version) `
-Remote ([string]$remoteVersionInfo.Version)
if ($cmp -gt 0) {
Write-Warn "Update verfügbar."
}
elseif ($cmp -eq 0) {
Write-Ok "Version ist aktuell."
}
else {
Write-Warn "Lokale Version ist neuer als Repository-main."
}
}
}
}
catch {
Write-Warn "Remote-Version konnte nicht geprüft werden."
}
Write-Host "Client ID: $($app.AppId)"
Write-Host "Tenant ID: $tenantId"
Write-Host "Sender: $senderMailbox"
@@ -725,7 +928,7 @@ function Repair-Installation {
}
function Update-Relay {
Write-Title "SMTPGraphRelay - Update"
Write-Title "SMTPGraphRelay - Online Update"
$config = Get-RelayConfig -TargetPath $InstallPath
if (-not $config) {
@@ -734,76 +937,182 @@ function Update-Relay {
return
}
$packageVersion = Get-PackageVersion
$installedVersion = Get-InstalledVersion -TargetPath $InstallPath
$installedVersionInfo = Get-InstalledVersion -TargetPath $InstallPath
$installedVersion = $null
if ($packageVersion -and $packageVersion.Version) {
Write-Info "Paketversion: $($packageVersion.Version)"
if ($installedVersionInfo -and $installedVersionInfo.Version) {
$installedVersion = [string]$installedVersionInfo.Version
Write-Info "Installierte Version: $installedVersion"
}
if ($installedVersion -and $installedVersion.Version) {
Write-Info "Installierte Version: $($installedVersion.Version)"
try {
$pkgVer = [version]$packageVersion.Version
$instVer = [version]$installedVersion.Version
if ($pkgVer -lt $instVer) {
Write-Warn "Das Paket ist älter als die installierte Version."
if (-not (Confirm-Yes "Downgrade trotzdem durchführen?")) {
return
}
}
elseif ($pkgVer -eq $instVer) {
Write-Warn "Paket- und installierte Version sind identisch."
if (-not (Confirm-Yes "Version trotzdem erneut einspielen?")) {
return
}
}
} catch {
Write-Warn "Versionsvergleich konnte nicht durchgeführt werden."
else {
Write-Warn "Keine installierte version.json gefunden."
$installedVersion = Read-Host "Installierte Version manuell eingeben (z.B. 1.5.0)"
if ([string]::IsNullOrWhiteSpace($installedVersion)) {
Write-Fail "Ohne lokale Versionsinformation kann kein sicheres Online-Update durchgeführt werden."
return
}
}
$sourceRelay = Get-SourceFile -Name $RelayFileName
if (-not $sourceRelay) {
Write-Fail "Kein neues '$RelayFileName' neben dem Installer gefunden."
Write-Info "Prüfe Gitea auf neue Version..."
Write-Info "Repository: $RepoBaseUrl"
try {
$remoteInfo = Get-RemoteVersion
}
catch {
Write-Fail "Remote-Version konnte nicht geladen werden: $($_.Exception.Message)"
return
}
Stop-RelayTask
$remoteVersion = [string]$remoteInfo.Version
Write-Ok "Remote-Version: $remoteVersion"
$installedRelay = Join-Path $InstallPath $RelayFileName
if (Test-Path -LiteralPath $installedRelay) {
$backup = Join-Path $InstallPath ("SMTPGraphRelay-backup-{0}.ps1" -f (Get-Date -Format "yyyyMMdd-HHmmss"))
Copy-Item -LiteralPath $installedRelay -Destination $backup -Force
Write-Ok "Backup erstellt: $backup"
try {
$comparison = Compare-RelayVersions -Installed $installedVersion -Remote $remoteVersion
}
catch {
Write-Fail $_.Exception.Message
return
}
Copy-ProgramFiles -TargetPath $InstallPath -RequireRelay
Ensure-Directories -TargetPath $InstallPath
Ensure-FirewallRule -Port ([int]$config.Smtp.Port)
Ensure-ScheduledTask -TargetPath $InstallPath
Start-RelayTask
if ($comparison -eq 0) {
Write-Ok "SMTPGraphRelay ist bereits aktuell ($installedVersion)."
return
}
$health = Join-Path $InstallPath $HealthFileName
if (Test-Path -LiteralPath $health) {
Write-Info "Starte Health Check..."
& $health -ConfigPath (Join-Path $InstallPath $ConfigFileName)
$healthExit = $LASTEXITCODE
if ($healthExit -eq 0) {
Write-Ok "Update-Health-Check erfolgreich."
if ($comparison -lt 0) {
Write-Warn "Die installierte Version ($installedVersion) ist neuer als main ($remoteVersion)."
if (-not (Confirm-Yes "Downgrade auf $remoteVersion durchführen?")) {
return
}
elseif ($healthExit -eq 1) {
Write-Warn "Update abgeschlossen, Health Check enthält Warnungen."
}
else {
Write-Host ""
Write-Host "Update verfügbar:" -ForegroundColor Green
Write-Host " Installiert: $installedVersion"
Write-Host " Neu: $remoteVersion" -ForegroundColor Yellow
Write-Host ""
if (-not (Confirm-Yes "Update auf $remoteVersion installieren?")) {
return
}
}
Enable-Tls12
$updateRoot = Join-Path $env:TEMP ("SMTPGraphRelay-update-{0}" -f [guid]::NewGuid().ToString("N"))
$archivePath = Join-Path $updateRoot "main.zip"
$extractPath = Join-Path $updateRoot "extract"
New-Item -ItemType Directory -Path $updateRoot -Force | Out-Null
New-Item -ItemType Directory -Path $extractPath -Force | Out-Null
$backupPath = $null
$taskWasRunning = $false
try {
Write-Info "Lade Repository-Archiv..."
Invoke-WebRequest `
-Uri $RemoteArchiveUrl `
-OutFile $archivePath `
-UseBasicParsing `
-TimeoutSec 120 `
-ErrorAction Stop
if (-not (Test-Path -LiteralPath $archivePath)) {
throw "Download des Updatearchivs fehlgeschlagen."
}
Write-Ok "Archiv heruntergeladen."
Expand-Archive `
-LiteralPath $archivePath `
-DestinationPath $extractPath `
-Force
$releaseRoot = Find-ExtractedReleaseRoot -ExtractPath $extractPath
Write-Ok "Release im Archiv gefunden: $releaseRoot"
$downloadedVersionInfo = Get-Content `
-LiteralPath (Join-Path $releaseRoot "version.json") `
-Raw `
-Encoding UTF8 | ConvertFrom-Json
if (-not $downloadedVersionInfo.Version) {
throw "version.json im Archiv enthält keine Version."
}
if ([string]$downloadedVersionInfo.Version -ne $remoteVersion) {
throw "Versionskonflikt: version.json-URL meldet $remoteVersion, Archiv enthält $($downloadedVersionInfo.Version)."
}
$task = Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
if ($task -and $task.State -eq "Running") {
$taskWasRunning = $true
}
Write-Info "Erstelle Backup der verwalteten Programmdateien..."
$backupPath = Backup-ManagedFiles -TargetPath $InstallPath
Write-Ok "Backup: $backupPath"
Stop-RelayTask
Write-Info "Installiere Release $remoteVersion..."
Install-ExtractedRelease `
-ReleaseRoot $releaseRoot `
-TargetPath $InstallPath
Ensure-Directories -TargetPath $InstallPath
Ensure-FirewallRule -Port ([int]$config.Smtp.Port)
Ensure-ScheduledTask -TargetPath $InstallPath
Start-RelayTask
$healthExit = Invoke-PostUpdateHealthCheck -TargetPath $InstallPath
if ($healthExit -ge 2) {
throw "Health Check nach Update meldet FEHLER (ExitCode $healthExit)."
}
if ($healthExit -eq 1) {
Write-Warn "Update erfolgreich, Health Check enthält Warnungen."
}
else {
Write-Fail "Update eingespielt, Health Check meldet Fehler. Backup liegt im Installationsordner."
Write-Ok "Health Check nach Update erfolgreich."
}
Write-Title "Online Update abgeschlossen"
Write-Host "Vorher: $installedVersion"
Write-Host "Jetzt: $remoteVersion" -ForegroundColor Green
Write-Host "Backup: $backupPath"
}
catch {
Write-Host ""
Write-Fail "Update fehlgeschlagen: $($_.Exception.Message)"
if ($backupPath -and (Test-Path -LiteralPath $backupPath)) {
Write-Warn "Automatischer Rollback wird durchgeführt..."
try {
Stop-RelayTask
Restore-ManagedFiles `
-BackupPath $backupPath `
-TargetPath $InstallPath
Ensure-ScheduledTask -TargetPath $InstallPath
Start-RelayTask
Write-Ok "Rollback abgeschlossen."
}
catch {
Write-Fail "Rollback fehlgeschlagen: $($_.Exception.Message)"
Write-Warn "Backup liegt unter: $backupPath"
}
}
}
Write-Title "Update abgeschlossen"
finally {
Remove-Item -LiteralPath $updateRoot -Recurse -Force -ErrorAction SilentlyContinue
}
}
function Verify-CloudRbac {
@@ -1032,20 +1341,17 @@ function Show-Menu {
Write-Title "SMTPGraphRelay - Installer / Repair / Update"
Write-Host "Installationspfad: $InstallPath" -ForegroundColor DarkGray
$packageVersion = Get-PackageVersion
$installedVersion = Get-InstalledVersion -TargetPath $InstallPath
if ($packageVersion -and $packageVersion.Version) {
Write-Host "Paketversion: $($packageVersion.Version)" -ForegroundColor DarkGray
if ($installedVersion -and $installedVersion.Version) {
Write-Host "Installiert: $($installedVersion.Version)" -ForegroundColor DarkGray
}
if ($installedVersion -and $installedVersion.Version) {
Write-Host "Installiert: $($installedVersion.Version)" -ForegroundColor DarkGray
}
Write-Host "Updatequelle: Gitea / main" -ForegroundColor DarkGray
Write-Host ""
Write-Host " [1] Neuinstallation"
Write-Host " [2] Installation reparieren"
Write-Host " [3] Relay aktualisieren"
Write-Host " [3] Nach Online-Updates suchen"
Write-Host " [4] Entra / Exchange RBAC prüfen"
Write-Host " [5] Zertifikat erneuern"
Write-Host " [6] Health Check ausführen"