Dateien nach "/" hochladen
This commit is contained in:
@@ -0,0 +1,338 @@
|
|||||||
|
#Requires -Version 5.1
|
||||||
|
#Requires -RunAsAdministrator
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Sichere Zertifikatsrotation für SMTPGraphRelay.
|
||||||
|
|
||||||
|
.DESCRIPTION
|
||||||
|
- Muss mit Windows PowerShell 5.1 ausgeführt werden.
|
||||||
|
- Liest TenantId, ClientId und aktuellen Thumbprint aus config.json.
|
||||||
|
- Erzeugt ein neues nicht exportierbares RSA-Zertifikat in LocalMachine\My.
|
||||||
|
- Meldet einen Entra-Administrator interaktiv an.
|
||||||
|
- Fügt das neue öffentliche Zertifikat zusätzlich zur bestehenden App Registration hinzu.
|
||||||
|
- Testet App-only Authentication mit dem neuen Zertifikat.
|
||||||
|
- Aktualisiert erst danach config.json.
|
||||||
|
- Startet den SMTPGraphRelay Scheduled Task neu.
|
||||||
|
- Entfernt das alte App-Zertifikat / lokale Zertifikat nur auf Wunsch.
|
||||||
|
|
||||||
|
Exchange Application RBAC bleibt unverändert, da ClientId/App Registration gleich bleibt.
|
||||||
|
#>
|
||||||
|
|
||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[string]$ConfigPath = "$PSScriptRoot\config.json",
|
||||||
|
[int]$ValidityYears = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||||
|
|
||||||
|
if ($PSVersionTable.PSEdition -ne "Desktop" -or $PSVersionTable.PSVersion.Major -ne 5) {
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Dieses Skript muss mit Windows PowerShell 5.1 ausgeführt werden." -ForegroundColor Red
|
||||||
|
Write-Host "Bitte starten:" -ForegroundColor Yellow
|
||||||
|
Write-Host " C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
|
||||||
|
Write-Host ""
|
||||||
|
Read-Host "Enter drücken zum Beenden"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not (Test-Path -LiteralPath $ConfigPath)) {
|
||||||
|
throw "config.json nicht gefunden: $ConfigPath"
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ValidityYears -lt 1 -or $ValidityYears -gt 5) {
|
||||||
|
throw "ValidityYears muss zwischen 1 und 5 liegen."
|
||||||
|
}
|
||||||
|
|
||||||
|
$config = Get-Content -LiteralPath $ConfigPath -Raw -Encoding UTF8 | ConvertFrom-Json
|
||||||
|
|
||||||
|
$TenantId = [string]$config.Graph.TenantId
|
||||||
|
$ClientId = [string]$config.Graph.ClientId
|
||||||
|
$OldThumbprint = [string]$config.Graph.CertificateThumbprint
|
||||||
|
|
||||||
|
if ([string]::IsNullOrWhiteSpace($TenantId) -or
|
||||||
|
[string]::IsNullOrWhiteSpace($ClientId) -or
|
||||||
|
[string]::IsNullOrWhiteSpace($OldThumbprint)) {
|
||||||
|
throw "TenantId, ClientId oder CertificateThumbprint fehlen in config.json."
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "==========================================================" -ForegroundColor Cyan
|
||||||
|
Write-Host " SMTPGraphRelay - Zertifikatsrotation" -ForegroundColor Cyan
|
||||||
|
Write-Host "==========================================================" -ForegroundColor Cyan
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Tenant ID: $TenantId"
|
||||||
|
Write-Host "Client ID: $ClientId"
|
||||||
|
Write-Host "Alter Thumbprint:$OldThumbprint"
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
$modules = @(
|
||||||
|
"Microsoft.Graph.Authentication",
|
||||||
|
"Microsoft.Graph.Applications"
|
||||||
|
)
|
||||||
|
|
||||||
|
foreach ($module in $modules) {
|
||||||
|
if (-not (Get-Module -ListAvailable -Name $module)) {
|
||||||
|
Write-Host "-> $module fehlt. Wird für alle Benutzer installiert..." -ForegroundColor Yellow
|
||||||
|
Install-Module $module -Scope AllUsers -Repository PSGallery -Force -AllowClobber
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Import-Module Microsoft.Graph.Authentication -Force -ErrorAction Stop
|
||||||
|
Import-Module Microsoft.Graph.Applications -Force -ErrorAction Stop
|
||||||
|
|
||||||
|
$oldCert = Get-Item -LiteralPath "Cert:\LocalMachine\My\$OldThumbprint" -ErrorAction Stop
|
||||||
|
Write-Host "Altes Zertifikat gültig bis: $($oldCert.NotAfter)" -ForegroundColor DarkGray
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
Write-Host "Schritt 1: Neues Zertifikat erzeugen..." -ForegroundColor Cyan
|
||||||
|
|
||||||
|
$certSubject = "CN=SMTPGraphRelay-$env:COMPUTERNAME"
|
||||||
|
$newCert = New-SelfSignedCertificate `
|
||||||
|
-Subject $certSubject `
|
||||||
|
-CertStoreLocation "Cert:\LocalMachine\My" `
|
||||||
|
-KeyAlgorithm RSA `
|
||||||
|
-KeyLength 2048 `
|
||||||
|
-HashAlgorithm SHA256 `
|
||||||
|
-KeyExportPolicy NonExportable `
|
||||||
|
-KeySpec Signature `
|
||||||
|
-NotAfter (Get-Date).AddYears($ValidityYears)
|
||||||
|
|
||||||
|
Write-Host "-> Neues Zertifikat: $($newCert.Thumbprint)" -ForegroundColor Green
|
||||||
|
Write-Host "-> Gültig bis: $($newCert.NotAfter)" -ForegroundColor Green
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
try {
|
||||||
|
Write-Host "Schritt 2: Entra-Administrator anmelden..." -ForegroundColor Cyan
|
||||||
|
Disconnect-MgGraph -ErrorAction SilentlyContinue | Out-Null
|
||||||
|
Connect-MgGraph `
|
||||||
|
-TenantId $TenantId `
|
||||||
|
-Scopes "Application.ReadWrite.All" `
|
||||||
|
-NoWelcome
|
||||||
|
|
||||||
|
$ctx = Get-MgContext
|
||||||
|
if (-not $ctx -or $ctx.TenantId -ne $TenantId) {
|
||||||
|
throw "Graph-Anmeldung am erwarteten Tenant fehlgeschlagen."
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "-> Angemeldet an Tenant $($ctx.TenantId)." -ForegroundColor Green
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
Write-Host "Schritt 3: Bestehende App Registration laden..." -ForegroundColor Cyan
|
||||||
|
$app = Get-MgApplication -Filter "appId eq '$ClientId'" -Property "id,appId,displayName,keyCredentials" | Select-Object -First 1
|
||||||
|
|
||||||
|
if (-not $app) {
|
||||||
|
throw "App Registration mit ClientId '$ClientId' wurde nicht gefunden."
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "-> App gefunden: $($app.DisplayName)" -ForegroundColor Green
|
||||||
|
|
||||||
|
$alreadyPresent = $false
|
||||||
|
foreach ($key in @($app.KeyCredentials)) {
|
||||||
|
if ($key.CustomKeyIdentifier) {
|
||||||
|
$keyThumb = ([BitConverter]::ToString($key.CustomKeyIdentifier)).Replace("-","")
|
||||||
|
if ($keyThumb -eq $newCert.Thumbprint) {
|
||||||
|
$alreadyPresent = $true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $alreadyPresent) {
|
||||||
|
Write-Host "Schritt 4: Neues Zertifikat zusätzlich zur App hinzufügen..." -ForegroundColor Cyan
|
||||||
|
|
||||||
|
$existingKeys = @()
|
||||||
|
foreach ($key in @($app.KeyCredentials)) {
|
||||||
|
$existingKeys += @{
|
||||||
|
CustomKeyIdentifier = $key.CustomKeyIdentifier
|
||||||
|
DisplayName = $key.DisplayName
|
||||||
|
EndDateTime = $key.EndDateTime
|
||||||
|
KeyId = $key.KeyId
|
||||||
|
StartDateTime = $key.StartDateTime
|
||||||
|
Type = $key.Type
|
||||||
|
Usage = $key.Usage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$newKey = @{
|
||||||
|
Type = "AsymmetricX509Cert"
|
||||||
|
Usage = "Verify"
|
||||||
|
Key = $newCert.GetRawCertData()
|
||||||
|
DisplayName = "SMTPGraphRelay Certificate $($newCert.NotAfter.ToString('yyyy-MM-dd'))"
|
||||||
|
StartDateTime = $newCert.NotBefore.ToUniversalTime()
|
||||||
|
EndDateTime = $newCert.NotAfter.ToUniversalTime()
|
||||||
|
}
|
||||||
|
|
||||||
|
$allKeys = @($existingKeys) + @($newKey)
|
||||||
|
|
||||||
|
Update-MgApplication `
|
||||||
|
-ApplicationId $app.Id `
|
||||||
|
-KeyCredentials $allKeys
|
||||||
|
|
||||||
|
Write-Host "-> Neues Zertifikat wurde zusätzlich registriert." -ForegroundColor Green
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Host "-> Neues Zertifikat ist bereits in der App registriert." -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Schritt 5: App-only Anmeldung mit NEUEM Zertifikat testen..." -ForegroundColor Cyan
|
||||||
|
|
||||||
|
Disconnect-MgGraph -ErrorAction SilentlyContinue | Out-Null
|
||||||
|
|
||||||
|
$authSucceeded = $false
|
||||||
|
$lastAuthError = $null
|
||||||
|
|
||||||
|
# Entra kann kurz brauchen, bis das neue Credential überall verfügbar ist.
|
||||||
|
for ($attempt = 1; $attempt -le 6; $attempt++) {
|
||||||
|
try {
|
||||||
|
Connect-MgGraph `
|
||||||
|
-TenantId $TenantId `
|
||||||
|
-ClientId $ClientId `
|
||||||
|
-Certificate $newCert `
|
||||||
|
-NoWelcome | Out-Null
|
||||||
|
|
||||||
|
$appCtx = Get-MgContext
|
||||||
|
if ($appCtx -and $appCtx.AuthType -eq "AppOnly" -and $appCtx.ClientId -eq $ClientId) {
|
||||||
|
$authSucceeded = $true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
throw "Graph-Kontext ist nicht AppOnly oder hat eine unerwartete ClientId."
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
$lastAuthError = $_.Exception.Message
|
||||||
|
Disconnect-MgGraph -ErrorAction SilentlyContinue | Out-Null
|
||||||
|
|
||||||
|
if ($attempt -lt 6) {
|
||||||
|
Write-Host "-> Noch nicht verfügbar (Versuch $attempt/6), neuer Versuch..." -ForegroundColor Yellow
|
||||||
|
Start-Sleep -Seconds 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $authSucceeded) {
|
||||||
|
throw "Neues Zertifikat konnte nicht zur App-only Anmeldung verwendet werden: $lastAuthError"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "-> App-only Anmeldung mit neuem Zertifikat erfolgreich." -ForegroundColor Green
|
||||||
|
Disconnect-MgGraph -ErrorAction SilentlyContinue | Out-Null
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
Write-Host "Schritt 6: config.json atomar auf neuen Thumbprint umstellen..." -ForegroundColor Cyan
|
||||||
|
|
||||||
|
$backupPath = "$ConfigPath.bak-$(Get-Date -Format 'yyyyMMdd-HHmmss')"
|
||||||
|
Copy-Item -LiteralPath $ConfigPath -Destination $backupPath -Force
|
||||||
|
|
||||||
|
$config.Graph.CertificateThumbprint = $newCert.Thumbprint
|
||||||
|
$tmpConfig = "$ConfigPath.tmp"
|
||||||
|
$config | ConvertTo-Json -Depth 20 | Set-Content -LiteralPath $tmpConfig -Encoding UTF8
|
||||||
|
Move-Item -LiteralPath $tmpConfig -Destination $ConfigPath -Force
|
||||||
|
|
||||||
|
Write-Host "-> config.json aktualisiert." -ForegroundColor Green
|
||||||
|
Write-Host "-> Backup: $backupPath" -ForegroundColor DarkGray
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
Write-Host "Schritt 7: SMTPGraphRelay neu starten..." -ForegroundColor Cyan
|
||||||
|
$task = Get-ScheduledTask -TaskName "SMTPGraphRelay" -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
if ($task) {
|
||||||
|
Stop-ScheduledTask -TaskName "SMTPGraphRelay" -ErrorAction SilentlyContinue
|
||||||
|
Start-Sleep -Seconds 1
|
||||||
|
Start-ScheduledTask -TaskName "SMTPGraphRelay"
|
||||||
|
Start-Sleep -Seconds 2
|
||||||
|
Write-Host "-> Scheduled Task neu gestartet." -ForegroundColor Green
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Host "-> Scheduled Task 'SMTPGraphRelay' nicht gefunden. Bitte Relay manuell neu starten." -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "==========================================================" -ForegroundColor Green
|
||||||
|
Write-Host " ZERTIFIKATSROTATION ERFOLGREICH" -ForegroundColor Green
|
||||||
|
Write-Host "==========================================================" -ForegroundColor Green
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Alter Thumbprint: $OldThumbprint"
|
||||||
|
Write-Host "Neuer Thumbprint: $($newCert.Thumbprint)" -ForegroundColor Yellow
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
Write-Host "Sicherheitsreserve:" -ForegroundColor Cyan
|
||||||
|
Write-Host "Das alte Zertifikat bleibt zunächst parallel registriert."
|
||||||
|
Write-Host "Damit ist ein Rollback über das config.json-Backup möglich."
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
$removeOld = Read-Host "Altes Zertifikat jetzt aus Entra UND LocalMachine entfernen? [j/N]"
|
||||||
|
if ($removeOld -match '^(?i)j|ja|y|yes$') {
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Schritt 8: Altes Zertifikat entfernen..." -ForegroundColor Cyan
|
||||||
|
|
||||||
|
# Für die Änderung wieder Admin-Kontext herstellen.
|
||||||
|
Connect-MgGraph `
|
||||||
|
-TenantId $TenantId `
|
||||||
|
-Scopes "Application.ReadWrite.All" `
|
||||||
|
-NoWelcome
|
||||||
|
|
||||||
|
$appFresh = Get-MgApplication -ApplicationId $app.Id -Property "id,keyCredentials"
|
||||||
|
|
||||||
|
$remainingKeys = @()
|
||||||
|
$oldFound = $false
|
||||||
|
|
||||||
|
foreach ($key in @($appFresh.KeyCredentials)) {
|
||||||
|
$isOld = $false
|
||||||
|
|
||||||
|
if ($key.CustomKeyIdentifier) {
|
||||||
|
$keyThumb = ([BitConverter]::ToString($key.CustomKeyIdentifier)).Replace("-","")
|
||||||
|
if ($keyThumb -eq $OldThumbprint) {
|
||||||
|
$isOld = $true
|
||||||
|
$oldFound = $true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $isOld) {
|
||||||
|
$remainingKeys += @{
|
||||||
|
CustomKeyIdentifier = $key.CustomKeyIdentifier
|
||||||
|
DisplayName = $key.DisplayName
|
||||||
|
EndDateTime = $key.EndDateTime
|
||||||
|
KeyId = $key.KeyId
|
||||||
|
StartDateTime = $key.StartDateTime
|
||||||
|
Type = $key.Type
|
||||||
|
Usage = $key.Usage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($oldFound) {
|
||||||
|
Update-MgApplication `
|
||||||
|
-ApplicationId $app.Id `
|
||||||
|
-KeyCredentials $remainingKeys
|
||||||
|
|
||||||
|
Write-Host "-> Altes Zertifikat aus Entra entfernt." -ForegroundColor Green
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Host "-> Alter Thumbprint war in Entra nicht mehr vorhanden." -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
|
||||||
|
Disconnect-MgGraph -ErrorAction SilentlyContinue | Out-Null
|
||||||
|
|
||||||
|
Remove-Item -LiteralPath "Cert:\LocalMachine\My\$OldThumbprint" -Force -ErrorAction Stop
|
||||||
|
Write-Host "-> Altes lokales Zertifikat entfernt." -ForegroundColor Green
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Host "-> Altes Zertifikat bleibt als Rollback-Reserve bestehen." -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "FEHLER BEI DER ZERTIFIKATSROTATION:" -ForegroundColor Red
|
||||||
|
Write-Host $_.Exception.Message -ForegroundColor Red
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Die bestehende config.json wurde nur nach erfolgreichem Auth-Test geändert." -ForegroundColor Yellow
|
||||||
|
Write-Host "Falls das neue Zertifikat bereits erzeugt/hochgeladen wurde, kann es später manuell bereinigt werden." -ForegroundColor Yellow
|
||||||
|
throw
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
Disconnect-MgGraph -ErrorAction SilentlyContinue | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Read-Host "Enter drücken zum Beenden"
|
||||||
+95
-1
@@ -7,7 +7,7 @@
|
|||||||
Nimmt lokale SMTP-Mails an, speichert sie als .eml in einer Queue und sendet sie
|
Nimmt lokale SMTP-Mails an, speichert sie als .eml in einer Queue und sendet sie
|
||||||
anschließend per Microsoft Graph sendMail mit App-only Zertifikatsauthentifizierung.
|
anschließend per Microsoft Graph sendMail mit App-only Zertifikatsauthentifizierung.
|
||||||
|
|
||||||
V1.3: parallele SMTP-Clients, separater Queue-Worker, robuste Queue, statuscodeabhängiger Graph-Retry
|
V1.4: Zertifikatsüberwachung, parallele SMTP-Clients, separater Queue-Worker, robuste Queue und Graph-Retry
|
||||||
#>
|
#>
|
||||||
|
|
||||||
[CmdletBinding()]
|
[CmdletBinding()]
|
||||||
@@ -803,6 +803,80 @@ function Handle-SmtpClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function Get-RelayCertificateStatus {
|
||||||
|
$thumbprint = [string]$script:Config.Graph.CertificateThumbprint
|
||||||
|
|
||||||
|
if ([string]::IsNullOrWhiteSpace($thumbprint)) {
|
||||||
|
throw "Graph.CertificateThumbprint fehlt in config.json."
|
||||||
|
}
|
||||||
|
|
||||||
|
$certPath = "Cert:\LocalMachine\My\$thumbprint"
|
||||||
|
$cert = Get-Item -LiteralPath $certPath -ErrorAction Stop
|
||||||
|
|
||||||
|
if (-not $cert.HasPrivateKey) {
|
||||||
|
throw "Relay-Zertifikat '$thumbprint' besitzt keinen privaten Schlüssel."
|
||||||
|
}
|
||||||
|
|
||||||
|
$remaining = $cert.NotAfter.ToUniversalTime() - [DateTime]::UtcNow
|
||||||
|
|
||||||
|
return [pscustomobject]@{
|
||||||
|
Certificate = $cert
|
||||||
|
Thumbprint = $cert.Thumbprint
|
||||||
|
Subject = $cert.Subject
|
||||||
|
NotBefore = $cert.NotBefore
|
||||||
|
NotAfter = $cert.NotAfter
|
||||||
|
DaysRemaining = [Math]::Floor($remaining.TotalDays)
|
||||||
|
HoursRemaining = [Math]::Floor($remaining.TotalHours)
|
||||||
|
Expired = ($remaining.TotalSeconds -le 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Test-RelayCertificateExpiry {
|
||||||
|
param(
|
||||||
|
[switch]$ForceLog
|
||||||
|
)
|
||||||
|
|
||||||
|
try {
|
||||||
|
$status = Get-RelayCertificateStatus
|
||||||
|
|
||||||
|
$warningDays = 60
|
||||||
|
$criticalDays = 14
|
||||||
|
|
||||||
|
if ($script:Config.Graph.PSObject.Properties.Name -contains "CertificateWarningDays") {
|
||||||
|
try { $warningDays = [int]$script:Config.Graph.CertificateWarningDays } catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($script:Config.Graph.PSObject.Properties.Name -contains "CertificateCriticalDays") {
|
||||||
|
try { $criticalDays = [int]$script:Config.Graph.CertificateCriticalDays } catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($status.Expired) {
|
||||||
|
Write-Log ("KRITISCH: Graph-Zertifikat {0} ist seit {1} abgelaufen!" -f `
|
||||||
|
$status.Thumbprint, $status.NotAfter.ToString("yyyy-MM-dd HH:mm:ss")) "ERROR"
|
||||||
|
return $status
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($status.DaysRemaining -le $criticalDays) {
|
||||||
|
Write-Log ("KRITISCH: Graph-Zertifikat läuft in {0} Tagen ab ({1}). Bitte Zertifikat erneuern." -f `
|
||||||
|
$status.DaysRemaining, $status.NotAfter.ToString("yyyy-MM-dd HH:mm:ss")) "ERROR"
|
||||||
|
}
|
||||||
|
elseif ($status.DaysRemaining -le $warningDays) {
|
||||||
|
Write-Log ("WARNUNG: Graph-Zertifikat läuft in {0} Tagen ab ({1}). Zertifikatsrotation einplanen." -f `
|
||||||
|
$status.DaysRemaining, $status.NotAfter.ToString("yyyy-MM-dd HH:mm:ss")) "WARN"
|
||||||
|
}
|
||||||
|
elseif ($ForceLog) {
|
||||||
|
Write-Log ("Graph-Zertifikat gültig bis {0} ({1} Tage verbleibend)." -f `
|
||||||
|
$status.NotAfter.ToString("yyyy-MM-dd HH:mm:ss"), $status.DaysRemaining)
|
||||||
|
}
|
||||||
|
|
||||||
|
return $status
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Log ("Zertifikatsprüfung fehlgeschlagen: {0}" -f $_.Exception.Message) "ERROR"
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function Get-FunctionBootstrap {
|
function Get-FunctionBootstrap {
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory)]
|
[Parameter(Mandatory)]
|
||||||
@@ -925,6 +999,21 @@ $script:Config = Get-Content -LiteralPath $ConfigPath -Raw -Encoding UTF8 | Conv
|
|||||||
New-Item -ItemType Directory -Path (Resolve-PathFromConfig $script:Config.Paths.Logs) -Force | Out-Null
|
New-Item -ItemType Directory -Path (Resolve-PathFromConfig $script:Config.Paths.Logs) -Force | Out-Null
|
||||||
Initialize-QueueDirectories
|
Initialize-QueueDirectories
|
||||||
|
|
||||||
|
# Zertifikat beim Start immer prüfen und Status protokollieren.
|
||||||
|
[void](Test-RelayCertificateExpiry -ForceLog)
|
||||||
|
|
||||||
|
# Prüfintervall optional per config, Standard 12 Stunden.
|
||||||
|
$script:CertificateCheckHours = 12
|
||||||
|
if ($script:Config.Graph.PSObject.Properties.Name -contains "CertificateCheckHours") {
|
||||||
|
try {
|
||||||
|
$configuredHours = [int]$script:Config.Graph.CertificateCheckHours
|
||||||
|
if ($configuredHours -ge 1 -and $configuredHours -le 168) {
|
||||||
|
$script:CertificateCheckHours = $configuredHours
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
$script:NextCertificateCheck = (Get-Date).AddHours($script:CertificateCheckHours)
|
||||||
|
|
||||||
# MaxConcurrentClients ist optional, damit bestehende config.json-Dateien unverändert weiterlaufen.
|
# MaxConcurrentClients ist optional, damit bestehende config.json-Dateien unverändert weiterlaufen.
|
||||||
$script:MaxConcurrentClients = 20
|
$script:MaxConcurrentClients = 20
|
||||||
if ($script:Config.Smtp.PSObject.Properties.Name -contains "MaxConcurrentClients") {
|
if ($script:Config.Smtp.PSObject.Properties.Name -contains "MaxConcurrentClients") {
|
||||||
@@ -1040,6 +1129,11 @@ try {
|
|||||||
while ($true) {
|
while ($true) {
|
||||||
Remove-CompletedSmtpWorkers
|
Remove-CompletedSmtpWorkers
|
||||||
|
|
||||||
|
if ((Get-Date) -ge $script:NextCertificateCheck) {
|
||||||
|
[void](Test-RelayCertificateExpiry)
|
||||||
|
$script:NextCertificateCheck = (Get-Date).AddHours($script:CertificateCheckHours)
|
||||||
|
}
|
||||||
|
|
||||||
# Sollte der Queue-Worker unerwartet beendet werden, Relay nicht still
|
# Sollte der Queue-Worker unerwartet beendet werden, Relay nicht still
|
||||||
# ohne Versand weiterlaufen lassen.
|
# ohne Versand weiterlaufen lassen.
|
||||||
if ($script:QueueAsyncResult.IsCompleted) {
|
if ($script:QueueAsyncResult.IsCompleted) {
|
||||||
|
|||||||
Reference in New Issue
Block a user