Dateien nach "/" hochladen
This commit is contained in:
+308
-195
@@ -151,6 +151,92 @@ function Ensure-Modules {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function New-RepoStagingArea {
|
||||||
|
Enable-Tls12
|
||||||
|
|
||||||
|
$root = Join-Path $env:TEMP ("SMTPGraphRelay-repo-{0}" -f [guid]::NewGuid().ToString("N"))
|
||||||
|
$archive = Join-Path $root "main.zip"
|
||||||
|
$extract = Join-Path $root "extract"
|
||||||
|
|
||||||
|
New-Item -ItemType Directory -Path $extract -Force | Out-Null
|
||||||
|
|
||||||
|
Write-Info "Lade aktuellen Stand aus Gitea..."
|
||||||
|
Write-Info "Quelle: $RemoteArchiveUrl"
|
||||||
|
|
||||||
|
Invoke-WebRequest `
|
||||||
|
-Uri $RemoteArchiveUrl `
|
||||||
|
-OutFile $archive `
|
||||||
|
-UseBasicParsing `
|
||||||
|
-TimeoutSec 120 `
|
||||||
|
-ErrorAction Stop
|
||||||
|
|
||||||
|
if (-not (Test-Path -LiteralPath $archive)) {
|
||||||
|
throw "Gitea-Archiv wurde nicht heruntergeladen."
|
||||||
|
}
|
||||||
|
|
||||||
|
Expand-Archive `
|
||||||
|
-LiteralPath $archive `
|
||||||
|
-DestinationPath $extract `
|
||||||
|
-Force
|
||||||
|
|
||||||
|
$releaseRoot = Find-ExtractedReleaseRoot -ExtractPath $extract
|
||||||
|
|
||||||
|
# Pflichtdateien prüfen.
|
||||||
|
foreach ($required in @("SMTPGraphRelay.ps1", "version.json")) {
|
||||||
|
if (-not (Test-Path -LiteralPath (Join-Path $releaseRoot $required))) {
|
||||||
|
throw "Repository-Archiv ist unvollständig: '$required' fehlt."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$versionInfo = Get-Content `
|
||||||
|
-LiteralPath (Join-Path $releaseRoot "version.json") `
|
||||||
|
-Raw `
|
||||||
|
-Encoding UTF8 | ConvertFrom-Json
|
||||||
|
|
||||||
|
if (-not $versionInfo.Version) {
|
||||||
|
throw "version.json aus dem Repository enthält keine Version."
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Ok "Repository-Version $($versionInfo.Version) geladen."
|
||||||
|
|
||||||
|
return [pscustomobject]@{
|
||||||
|
TempRoot = $root
|
||||||
|
ReleaseRoot = $releaseRoot
|
||||||
|
VersionInfo = $versionInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Remove-RepoStagingArea {
|
||||||
|
param($Staging)
|
||||||
|
|
||||||
|
if ($Staging -and $Staging.TempRoot) {
|
||||||
|
Remove-Item -LiteralPath $Staging.TempRoot -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Install-RepoProgramFiles {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory)][string]$ReleaseRoot,
|
||||||
|
[Parameter(Mandatory)][string]$TargetPath
|
||||||
|
)
|
||||||
|
|
||||||
|
New-Item -ItemType Directory -Path $TargetPath -Force | Out-Null
|
||||||
|
|
||||||
|
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 "Installiert: $name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function Get-SourceFile {
|
function Get-SourceFile {
|
||||||
param([Parameter(Mandatory)][string]$Name)
|
param([Parameter(Mandatory)][string]$Name)
|
||||||
|
|
||||||
@@ -691,200 +777,185 @@ function Invoke-PostUpdateHealthCheck {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Install-New {
|
function Install-New {
|
||||||
Write-Title "SMTPGraphRelay - Neuinstallation"
|
Write-Title "SMTPGraphRelay - Neuinstallation aus Gitea"
|
||||||
|
|
||||||
if (Test-Path -LiteralPath (Join-Path $InstallPath $ConfigFileName)) {
|
if (Test-Path -LiteralPath (Join-Path $InstallPath $ConfigFileName)) {
|
||||||
Write-Warn "Es existiert bereits eine config.json unter:"
|
Write-Warn "Es existiert bereits eine config.json unter:"
|
||||||
Write-Host " $InstallPath"
|
Write-Host " $InstallPath"
|
||||||
Write-Warn "Neuinstallation würde eine neue App/Zertifikat erzeugen."
|
Write-Warn "Neuinstallation würde eine neue App/Zertifikat erzeugen."
|
||||||
|
|
||||||
if (-not (Confirm-Yes "Trotzdem fortfahren?")) {
|
if (-not (Confirm-Yes "Trotzdem fortfahren?")) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure-Modules -IncludeExchange
|
$staging = $null
|
||||||
Copy-ProgramFiles -TargetPath $InstallPath -RequireRelay
|
|
||||||
Ensure-Directories -TargetPath $InstallPath
|
|
||||||
|
|
||||||
$packageVersion = Get-PackageVersion
|
|
||||||
if ($packageVersion -and $packageVersion.Version) {
|
|
||||||
Write-Ok "Installiere Paketversion $($packageVersion.Version)."
|
|
||||||
}
|
|
||||||
|
|
||||||
$appName = Read-Default "Name der Entra App" $AppDefaultName
|
|
||||||
|
|
||||||
$senderMailbox = Read-Host "M365-Absenderpostfach (z.B. info@firma.de)"
|
|
||||||
while ([string]::IsNullOrWhiteSpace($senderMailbox) -or $senderMailbox -notmatch '^[^@\s]+@[^@\s]+\.[^@\s]+$') {
|
|
||||||
$senderMailbox = Read-Host "Bitte eine gültige Mailadresse eingeben"
|
|
||||||
}
|
|
||||||
|
|
||||||
$listenAddress = Read-Default "Lokale Listen-IP" "0.0.0.0"
|
|
||||||
$port = [int](Read-Default "SMTP-Port" "2525")
|
|
||||||
$allowedText = Read-Default "Erlaubte Netze, mit Komma getrennt" "127.0.0.1/32,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"
|
|
||||||
$allowedNetworks = @($allowedText -split ',' | ForEach-Object { $_.Trim() } | Where-Object { $_ })
|
|
||||||
|
|
||||||
Write-Info "Erzeuge Relay-Zertifikat..."
|
|
||||||
$cert = New-RelayCertificate
|
|
||||||
Write-Ok "Zertifikat erstellt: $($cert.Thumbprint)"
|
|
||||||
|
|
||||||
Write-Info "Microsoft Graph Anmeldung erforderlich (Entra-Admin)."
|
|
||||||
Connect-RelayGraphAdmin
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$tenantId = (Get-MgContext).TenantId
|
$staging = New-RepoStagingArea
|
||||||
Write-Ok "Tenant: $tenantId"
|
|
||||||
|
|
||||||
$appParams = @{
|
Ensure-Modules -IncludeExchange
|
||||||
DisplayName = $appName
|
Ensure-Directories -TargetPath $InstallPath
|
||||||
SignInAudience = "AzureADMyOrg"
|
|
||||||
KeyCredentials = @(
|
# Nur Programmdateien aus Git übernehmen.
|
||||||
(Convert-CertToKeyCredential -Certificate $cert)
|
Install-RepoProgramFiles `
|
||||||
)
|
-ReleaseRoot $staging.ReleaseRoot `
|
||||||
|
-TargetPath $InstallPath
|
||||||
|
|
||||||
|
Write-Ok "Programmdateien aus Gitea installiert."
|
||||||
|
|
||||||
|
$appName = Read-Default "Name der Entra App" $AppDefaultName
|
||||||
|
|
||||||
|
$senderMailbox = Read-Host "M365-Absenderpostfach (z.B. info@firma.de)"
|
||||||
|
while ([string]::IsNullOrWhiteSpace($senderMailbox) -or $senderMailbox -notmatch '^[^@\s]+@[^@\s]+\.[^@\s]+$') {
|
||||||
|
$senderMailbox = Read-Host "Bitte eine gültige Mailadresse eingeben"
|
||||||
}
|
}
|
||||||
|
|
||||||
$app = New-MgApplication -BodyParameter $appParams
|
$listenAddress = Read-Default "Lokale Listen-IP" "0.0.0.0"
|
||||||
Write-Ok "App Registration erstellt: $($app.AppId)"
|
$port = [int](Read-Default "SMTP-Port" "2525")
|
||||||
|
$allowedText = Read-Default "Erlaubte Netze, mit Komma getrennt" "127.0.0.1/32,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"
|
||||||
|
$allowedNetworks = @($allowedText -split ',' | ForEach-Object { $_.Trim() } | Where-Object { $_ })
|
||||||
|
|
||||||
$sp = $null
|
Write-Info "Erzeuge Relay-Zertifikat..."
|
||||||
for ($i = 0; $i -lt 10 -and -not $sp; $i++) {
|
$cert = New-RelayCertificate
|
||||||
try {
|
Write-Ok "Zertifikat erstellt: $($cert.Thumbprint)"
|
||||||
$sp = New-MgServicePrincipal -AppId $app.AppId
|
|
||||||
|
Write-Info "Microsoft Graph Anmeldung erforderlich (Entra-Admin)."
|
||||||
|
Connect-RelayGraphAdmin
|
||||||
|
|
||||||
|
try {
|
||||||
|
$tenantId = (Get-MgContext).TenantId
|
||||||
|
Write-Ok "Tenant: $tenantId"
|
||||||
|
|
||||||
|
$appParams = @{
|
||||||
|
DisplayName = $appName
|
||||||
|
SignInAudience = "AzureADMyOrg"
|
||||||
|
KeyCredentials = @(
|
||||||
|
(Convert-CertToKeyCredential -Certificate $cert)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
catch {
|
|
||||||
Start-Sleep -Seconds 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (-not $sp) {
|
$app = New-MgApplication -BodyParameter $appParams
|
||||||
throw "Entra Service Principal konnte nicht erstellt werden."
|
Write-Ok "App Registration erstellt: $($app.AppId)"
|
||||||
}
|
|
||||||
|
|
||||||
Write-Ok "Entra Service Principal erstellt: $($sp.Id)"
|
$sp = $null
|
||||||
|
for ($i = 0; $i -lt 10 -and -not $sp; $i++) {
|
||||||
# Keine globale Graph Mail.Send Permission!
|
try {
|
||||||
Test-NoGlobalMailSend -ServicePrincipalObjectId $sp.Id
|
$sp = New-MgServicePrincipal -AppId $app.AppId
|
||||||
|
|
||||||
Ensure-ExchangeRbac `
|
|
||||||
-TenantId $tenantId `
|
|
||||||
-ClientId $app.AppId `
|
|
||||||
-ServicePrincipalObjectId $sp.Id `
|
|
||||||
-AppName $appName `
|
|
||||||
-SenderMailbox $senderMailbox
|
|
||||||
|
|
||||||
$config = [ordered]@{
|
|
||||||
Smtp = [ordered]@{
|
|
||||||
ListenAddress = $listenAddress
|
|
||||||
Port = $port
|
|
||||||
Hostname = $env:COMPUTERNAME
|
|
||||||
AllowedNetworks = $allowedNetworks
|
|
||||||
MaxMessageSizeMB = 25
|
|
||||||
ClientTimeoutSeconds = 120
|
|
||||||
MaxConcurrentClients = 20
|
|
||||||
}
|
|
||||||
Graph = [ordered]@{
|
|
||||||
TenantId = $tenantId
|
|
||||||
ClientId = $app.AppId
|
|
||||||
CertificateThumbprint = $cert.Thumbprint
|
|
||||||
SenderMailbox = $senderMailbox
|
|
||||||
ForceSender = $true
|
|
||||||
CertificateWarningDays = 60
|
|
||||||
CertificateCriticalDays = 14
|
|
||||||
CertificateCheckHours = 12
|
|
||||||
}
|
|
||||||
Queue = [ordered]@{
|
|
||||||
PollSeconds = 10
|
|
||||||
MaxRetries = 8
|
|
||||||
RetryMinutes = @(1,5,15,30,60,120,240,480)
|
|
||||||
}
|
|
||||||
Paths = [ordered]@{
|
|
||||||
Queue = "queue"
|
|
||||||
Failed = "failed"
|
|
||||||
Logs = "logs"
|
|
||||||
}
|
|
||||||
Logging = [ordered]@{
|
|
||||||
MaxFileSizeMB = 10
|
|
||||||
RetentionDays = 30
|
|
||||||
CleanupHours = 12
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-RelayConfig -Config $config -TargetPath $InstallPath
|
|
||||||
Ensure-FirewallRule -Port $port
|
|
||||||
Ensure-ScheduledTask -TargetPath $InstallPath
|
|
||||||
|
|
||||||
Write-Info "Teste App-only Anmeldung mit Relay-Zertifikat..."
|
|
||||||
Disconnect-MgGraph -ErrorAction SilentlyContinue | Out-Null
|
|
||||||
|
|
||||||
Connect-MgGraph `
|
|
||||||
-TenantId $tenantId `
|
|
||||||
-ClientId $app.AppId `
|
|
||||||
-Certificate $cert `
|
|
||||||
-NoWelcome | Out-Null
|
|
||||||
|
|
||||||
$ctx = Get-MgContext
|
|
||||||
if (-not $ctx -or $ctx.AuthType -ne "AppOnly") {
|
|
||||||
throw "App-only Anmeldung konnte nicht bestätigt werden."
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Ok "App-only Anmeldung funktioniert."
|
|
||||||
Disconnect-MgGraph -ErrorAction SilentlyContinue | Out-Null
|
|
||||||
|
|
||||||
Start-RelayTask
|
|
||||||
|
|
||||||
Write-Title "Neuinstallation abgeschlossen"
|
|
||||||
Write-Host "Installationspfad: $InstallPath"
|
|
||||||
|
|
||||||
$packageVersion = Get-PackageVersion
|
|
||||||
$installedVersion = Get-InstalledVersion -TargetPath $InstallPath
|
|
||||||
|
|
||||||
if ($packageVersion -and $packageVersion.Version) {
|
|
||||||
Write-Host "Paketversion: $($packageVersion.Version)"
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($installedVersion -and $installedVersion.Version) {
|
|
||||||
Write-Host "Installierte Version: $($installedVersion.Version)"
|
|
||||||
}
|
|
||||||
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) {
|
catch {
|
||||||
Write-Ok "Version ist aktuell."
|
Start-Sleep -Seconds 2
|
||||||
}
|
|
||||||
else {
|
|
||||||
Write-Warn "Lokale Version ist neuer als Repository-main."
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (-not $sp) {
|
||||||
|
throw "Entra Service Principal konnte nicht erstellt werden."
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Ok "Entra Service Principal erstellt: $($sp.Id)"
|
||||||
|
Test-NoGlobalMailSend -ServicePrincipalObjectId $sp.Id
|
||||||
|
|
||||||
|
Ensure-ExchangeRbac `
|
||||||
|
-TenantId $tenantId `
|
||||||
|
-ClientId $app.AppId `
|
||||||
|
-ServicePrincipalObjectId $sp.Id `
|
||||||
|
-AppName $appName `
|
||||||
|
-SenderMailbox $senderMailbox
|
||||||
|
|
||||||
|
$config = [ordered]@{
|
||||||
|
Smtp = [ordered]@{
|
||||||
|
ListenAddress = $listenAddress
|
||||||
|
Port = $port
|
||||||
|
Hostname = $env:COMPUTERNAME
|
||||||
|
AllowedNetworks = $allowedNetworks
|
||||||
|
MaxMessageSizeMB = 25
|
||||||
|
ClientTimeoutSeconds = 120
|
||||||
|
MaxConcurrentClients = 20
|
||||||
|
}
|
||||||
|
Graph = [ordered]@{
|
||||||
|
TenantId = $tenantId
|
||||||
|
ClientId = $app.AppId
|
||||||
|
CertificateThumbprint = $cert.Thumbprint
|
||||||
|
SenderMailbox = $senderMailbox
|
||||||
|
ForceSender = $true
|
||||||
|
CertificateWarningDays = 60
|
||||||
|
CertificateCriticalDays = 14
|
||||||
|
CertificateCheckHours = 12
|
||||||
|
}
|
||||||
|
Queue = [ordered]@{
|
||||||
|
PollSeconds = 10
|
||||||
|
MaxRetries = 8
|
||||||
|
RetryMinutes = @(1,5,15,30,60,120,240,480)
|
||||||
|
}
|
||||||
|
Paths = [ordered]@{
|
||||||
|
Queue = "queue"
|
||||||
|
Failed = "failed"
|
||||||
|
Logs = "logs"
|
||||||
|
}
|
||||||
|
Logging = [ordered]@{
|
||||||
|
MaxFileSizeMB = 10
|
||||||
|
RetentionDays = 30
|
||||||
|
CleanupHours = 12
|
||||||
|
}
|
||||||
|
Update = [ordered]@{
|
||||||
|
Repository = $RepoBaseUrl
|
||||||
|
Branch = "main"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-RelayConfig -Config $config -TargetPath $InstallPath
|
||||||
|
Ensure-FirewallRule -Port $port
|
||||||
|
Ensure-ScheduledTask -TargetPath $InstallPath
|
||||||
|
|
||||||
|
Write-Info "Teste App-only Anmeldung mit Relay-Zertifikat..."
|
||||||
|
Disconnect-MgGraph -ErrorAction SilentlyContinue | Out-Null
|
||||||
|
|
||||||
|
Connect-MgGraph `
|
||||||
|
-TenantId $tenantId `
|
||||||
|
-ClientId $app.AppId `
|
||||||
|
-Certificate $cert `
|
||||||
|
-NoWelcome | Out-Null
|
||||||
|
|
||||||
|
$ctx = Get-MgContext
|
||||||
|
if (-not $ctx -or $ctx.AuthType -ne "AppOnly") {
|
||||||
|
throw "App-only Anmeldung konnte nicht bestätigt werden."
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Ok "App-only Anmeldung funktioniert."
|
||||||
|
Disconnect-MgGraph -ErrorAction SilentlyContinue | Out-Null
|
||||||
|
|
||||||
|
Start-RelayTask
|
||||||
|
|
||||||
|
$health = Join-Path $InstallPath $HealthFileName
|
||||||
|
if (Test-Path -LiteralPath $health) {
|
||||||
|
Write-Info "Starte abschließenden Health Check..."
|
||||||
|
& $health -ConfigPath (Join-Path $InstallPath $ConfigFileName)
|
||||||
|
$healthExit = $LASTEXITCODE
|
||||||
|
|
||||||
|
if ($healthExit -ge 2) {
|
||||||
|
Write-Warn "Installation abgeschlossen, Health Check meldet Fehler. Bitte Ausgabe prüfen."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Title "Neuinstallation abgeschlossen"
|
||||||
|
Write-Host "Version: $($staging.VersionInfo.Version)"
|
||||||
|
Write-Host "Installationspfad: $InstallPath"
|
||||||
|
Write-Host "Client ID: $($app.AppId)"
|
||||||
|
Write-Host "Tenant ID: $tenantId"
|
||||||
|
Write-Host "Sender: $senderMailbox"
|
||||||
|
Write-Host "SMTP: $listenAddress`:$port"
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
Disconnect-MgGraph -ErrorAction SilentlyContinue | Out-Null
|
||||||
}
|
}
|
||||||
}
|
|
||||||
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"
|
|
||||||
Write-Host "SMTP: $listenAddress`:$port"
|
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
Disconnect-MgGraph -ErrorAction SilentlyContinue | Out-Null
|
Remove-RepoStagingArea -Staging $staging
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function Repair-Installation {
|
function Repair-Installation {
|
||||||
Write-Title "SMTPGraphRelay - Repair"
|
Write-Title "SMTPGraphRelay - Repair aus Gitea"
|
||||||
|
|
||||||
$config = Get-RelayConfig -TargetPath $InstallPath
|
$config = Get-RelayConfig -TargetPath $InstallPath
|
||||||
if (-not $config) {
|
if (-not $config) {
|
||||||
@@ -893,38 +964,80 @@ function Repair-Installation {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure-Modules
|
$staging = $null
|
||||||
Copy-ProgramFiles -TargetPath $InstallPath
|
$backupPath = $null
|
||||||
Ensure-Directories -TargetPath $InstallPath
|
|
||||||
|
|
||||||
$certPath = "Cert:\LocalMachine\My\$($config.Graph.CertificateThumbprint)"
|
try {
|
||||||
$cert = Get-Item -LiteralPath $certPath -ErrorAction SilentlyContinue
|
$staging = New-RepoStagingArea
|
||||||
|
|
||||||
if (-not $cert) {
|
Ensure-Modules
|
||||||
Write-Fail "Konfiguriertes Zertifikat fehlt: $($config.Graph.CertificateThumbprint)"
|
Ensure-Directories -TargetPath $InstallPath
|
||||||
Write-Warn "Repair erzeugt absichtlich kein neues Credential. Nutze Zertifikat erneuern."
|
|
||||||
|
$certPath = "Cert:\LocalMachine\My\$($config.Graph.CertificateThumbprint)"
|
||||||
|
$cert = Get-Item -LiteralPath $certPath -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
if (-not $cert) {
|
||||||
|
Write-Fail "Konfiguriertes Zertifikat fehlt: $($config.Graph.CertificateThumbprint)"
|
||||||
|
Write-Warn "Repair erzeugt absichtlich kein neues Credential. Nutze Zertifikat erneuern."
|
||||||
|
}
|
||||||
|
elseif (-not $cert.HasPrivateKey) {
|
||||||
|
Write-Fail "Konfiguriertes Zertifikat besitzt keinen privaten Schlüssel."
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Ok "Zertifikat vorhanden und besitzt Private Key."
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Info "Sichere aktuelle Programmdateien..."
|
||||||
|
$backupPath = Backup-ManagedFiles -TargetPath $InstallPath
|
||||||
|
Write-Ok "Backup: $backupPath"
|
||||||
|
|
||||||
|
Stop-RelayTask
|
||||||
|
|
||||||
|
Install-RepoProgramFiles `
|
||||||
|
-ReleaseRoot $staging.ReleaseRoot `
|
||||||
|
-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 Repair meldet FEHLER (ExitCode $healthExit)."
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($healthExit -eq 1) {
|
||||||
|
Write-Warn "Repair abgeschlossen, Health Check enthält Warnungen."
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Ok "Repair Health Check erfolgreich."
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Title "Repair abgeschlossen"
|
||||||
|
Write-Host "Installierte Repo-Version: $($staging.VersionInfo.Version)"
|
||||||
}
|
}
|
||||||
elseif (-not $cert.HasPrivateKey) {
|
catch {
|
||||||
Write-Fail "Konfiguriertes Zertifikat besitzt keinen privaten Schlüssel."
|
Write-Fail "Repair fehlgeschlagen: $($_.Exception.Message)"
|
||||||
|
|
||||||
|
if ($backupPath -and (Test-Path -LiteralPath $backupPath)) {
|
||||||
|
Write-Warn "Stelle vorherige Programmdateien wieder her..."
|
||||||
|
|
||||||
|
try {
|
||||||
|
Stop-RelayTask
|
||||||
|
Restore-ManagedFiles -BackupPath $backupPath -TargetPath $InstallPath
|
||||||
|
Ensure-ScheduledTask -TargetPath $InstallPath
|
||||||
|
Start-RelayTask
|
||||||
|
Write-Ok "Rollback nach Repair abgeschlossen."
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Fail "Repair-Rollback fehlgeschlagen: $($_.Exception.Message)"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
finally {
|
||||||
Write-Ok "Zertifikat vorhanden und besitzt Private Key."
|
Remove-RepoStagingArea -Staging $staging
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure-FirewallRule -Port ([int]$config.Smtp.Port)
|
|
||||||
Ensure-ScheduledTask -TargetPath $InstallPath
|
|
||||||
|
|
||||||
Start-RelayTask
|
|
||||||
|
|
||||||
$health = Join-Path $InstallPath $HealthFileName
|
|
||||||
if (Test-Path -LiteralPath $health) {
|
|
||||||
Write-Info "Starte Health Check..."
|
|
||||||
& $health -ConfigPath (Join-Path $InstallPath $ConfigFileName)
|
|
||||||
$healthExit = $LASTEXITCODE
|
|
||||||
Write-Info "Health Check ExitCode: $healthExit"
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Title "Repair abgeschlossen"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function Update-Relay {
|
function Update-Relay {
|
||||||
@@ -1338,7 +1451,7 @@ function Show-Status {
|
|||||||
|
|
||||||
function Show-Menu {
|
function Show-Menu {
|
||||||
Clear-Host
|
Clear-Host
|
||||||
Write-Title "SMTPGraphRelay - Installer / Repair / Update"
|
Write-Title "SMTPGraphRelay - Bootstrap / Repair / Online Update"
|
||||||
Write-Host "Installationspfad: $InstallPath" -ForegroundColor DarkGray
|
Write-Host "Installationspfad: $InstallPath" -ForegroundColor DarkGray
|
||||||
|
|
||||||
$installedVersion = Get-InstalledVersion -TargetPath $InstallPath
|
$installedVersion = Get-InstalledVersion -TargetPath $InstallPath
|
||||||
@@ -1349,8 +1462,8 @@ function Show-Menu {
|
|||||||
|
|
||||||
Write-Host "Updatequelle: Gitea / main" -ForegroundColor DarkGray
|
Write-Host "Updatequelle: Gitea / main" -ForegroundColor DarkGray
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host " [1] Neuinstallation"
|
Write-Host " [1] Neuinstallation aus Gitea"
|
||||||
Write-Host " [2] Installation reparieren"
|
Write-Host " [2] Installation aus Gitea reparieren"
|
||||||
Write-Host " [3] Nach Online-Updates suchen"
|
Write-Host " [3] Nach Online-Updates suchen"
|
||||||
Write-Host " [4] Entra / Exchange RBAC prüfen"
|
Write-Host " [4] Entra / Exchange RBAC prüfen"
|
||||||
Write-Host " [5] Zertifikat erneuern"
|
Write-Host " [5] Zertifikat erneuern"
|
||||||
|
|||||||
Reference in New Issue
Block a user