Dateien nach "/" hochladen
This commit is contained in:
+356
-1
@@ -440,15 +440,60 @@ function Ensure-ScheduledTask {
|
||||
|
||||
function Stop-RelayTask {
|
||||
$task = Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
|
||||
if ($task -and $task.State -eq "Running") {
|
||||
|
||||
if (-not $task -or $task.State -ne "Running") {
|
||||
return
|
||||
}
|
||||
|
||||
$graceSeconds = 30
|
||||
|
||||
try {
|
||||
$config = Get-RelayConfig -TargetPath $InstallPath
|
||||
if ($config -and $config.Smtp.PSObject.Properties.Name -contains "GracefulShutdownSeconds") {
|
||||
$configured = [int]$config.Smtp.GracefulShutdownSeconds
|
||||
if ($configured -ge 5 -and $configured -le 300) {
|
||||
$graceSeconds = $configured
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {}
|
||||
|
||||
$signalPath = Join-Path $InstallPath "shutdown.request"
|
||||
|
||||
try {
|
||||
[IO.File]::WriteAllText(
|
||||
$signalPath,
|
||||
([DateTime]::UtcNow.ToString("o")),
|
||||
(New-Object Text.UTF8Encoding($false))
|
||||
)
|
||||
|
||||
Write-Info "Graceful Shutdown angefordert. Warte auf Relay (max. $graceSeconds Sekunden)..."
|
||||
|
||||
$deadline = (Get-Date).AddSeconds($graceSeconds + 5)
|
||||
|
||||
while ((Get-Date) -lt $deadline) {
|
||||
Start-Sleep -Milliseconds 250
|
||||
$current = Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
|
||||
|
||||
if (-not $current -or $current.State -ne "Running") {
|
||||
Write-Ok "Relay sauber beendet."
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
Write-Warn "Graceful-Shutdown-Timeout erreicht. Task wird hart beendet."
|
||||
Stop-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
|
||||
Start-Sleep -Milliseconds 750
|
||||
}
|
||||
finally {
|
||||
Remove-Item -LiteralPath $signalPath -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
|
||||
function Start-RelayTask {
|
||||
$task = Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
|
||||
if ($task) {
|
||||
Remove-Item -LiteralPath (Join-Path $InstallPath "shutdown.request") -Force -ErrorAction SilentlyContinue
|
||||
Start-ScheduledTask -TaskName $TaskName
|
||||
Start-Sleep -Seconds 2
|
||||
Write-Ok "Scheduled Task gestartet."
|
||||
@@ -879,6 +924,7 @@ function Install-New {
|
||||
AuthMaxFailures = 5
|
||||
AllowUnauthenticatedNetworks = @()
|
||||
AuthUsers = @()
|
||||
GracefulShutdownSeconds = 30
|
||||
}
|
||||
Graph = [ordered]@{
|
||||
TenantId = $tenantId
|
||||
@@ -1483,6 +1529,308 @@ function Save-SmtpAuthConfigAndRestart {
|
||||
Start-RelayTask
|
||||
}
|
||||
|
||||
|
||||
function Get-FailedQueuePath {
|
||||
param([Parameter(Mandatory)]$Config)
|
||||
|
||||
$path = [string]$Config.Paths.Failed
|
||||
|
||||
if ([IO.Path]::IsPathRooted($path)) {
|
||||
return $path
|
||||
}
|
||||
|
||||
return (Join-Path $InstallPath $path)
|
||||
}
|
||||
|
||||
function Get-PendingQueuePath {
|
||||
param([Parameter(Mandatory)]$Config)
|
||||
|
||||
$path = [string]$Config.Paths.Queue
|
||||
|
||||
if (-not [IO.Path]::IsPathRooted($path)) {
|
||||
$path = Join-Path $InstallPath $path
|
||||
}
|
||||
|
||||
return (Join-Path $path "pending")
|
||||
}
|
||||
|
||||
function Get-FailedQueueEntries {
|
||||
param([Parameter(Mandatory)]$Config)
|
||||
|
||||
$failedPath = Get-FailedQueuePath -Config $Config
|
||||
|
||||
if (-not (Test-Path -LiteralPath $failedPath)) {
|
||||
return @()
|
||||
}
|
||||
|
||||
$entries = @()
|
||||
|
||||
foreach ($file in Get-ChildItem -LiteralPath $failedPath -Filter "*.eml" -File -ErrorAction SilentlyContinue | Sort-Object LastWriteTime) {
|
||||
$metaPath = "$($file.FullName).json"
|
||||
$meta = $null
|
||||
|
||||
if (Test-Path -LiteralPath $metaPath) {
|
||||
try {
|
||||
$meta = Get-Content -LiteralPath $metaPath -Raw -Encoding UTF8 | ConvertFrom-Json
|
||||
}
|
||||
catch {}
|
||||
}
|
||||
|
||||
$queueId = [IO.Path]::GetFileNameWithoutExtension($file.Name)
|
||||
if ($meta -and $meta.PSObject.Properties.Name -contains "QueueId" -and $meta.QueueId) {
|
||||
$queueId = [string]$meta.QueueId
|
||||
}
|
||||
|
||||
$entries += [pscustomobject]@{
|
||||
QueueId = $queueId
|
||||
FileName = $file.Name
|
||||
Path = $file.FullName
|
||||
MetaPath = $metaPath
|
||||
SizeKB = [Math]::Round($file.Length / 1KB, 1)
|
||||
FailedSince = $file.LastWriteTime
|
||||
RetryCount = if ($meta -and $meta.RetryCount -ne $null) { [int]$meta.RetryCount } else { $null }
|
||||
From = if ($meta) { [string]$meta.EnvelopeFrom } else { "" }
|
||||
Recipients = if ($meta) { (@($meta.EnvelopeRecipients) -join ", ") } else { "" }
|
||||
LastStatusCode = if ($meta) { [string]$meta.LastStatusCode } else { "" }
|
||||
LastError = if ($meta) { [string]$meta.LastError } else { "" }
|
||||
AuthenticatedUser = if ($meta -and $meta.PSObject.Properties.Name -contains "AuthenticatedUser") { [string]$meta.AuthenticatedUser } else { "" }
|
||||
Meta = $meta
|
||||
}
|
||||
}
|
||||
|
||||
return @($entries)
|
||||
}
|
||||
|
||||
function Retry-FailedQueueEntry {
|
||||
param(
|
||||
[Parameter(Mandatory)]$Config,
|
||||
[Parameter(Mandatory)]$Entry
|
||||
)
|
||||
|
||||
$pendingPath = Get-PendingQueuePath -Config $Config
|
||||
New-Item -ItemType Directory -Path $pendingPath -Force | Out-Null
|
||||
|
||||
$targetEml = Join-Path $pendingPath $Entry.FileName
|
||||
$targetMeta = "$targetEml.json"
|
||||
|
||||
if (Test-Path -LiteralPath $targetEml) {
|
||||
throw "Pending enthält bereits '$($Entry.FileName)'."
|
||||
}
|
||||
|
||||
if ($Entry.Meta) {
|
||||
$meta = $Entry.Meta
|
||||
|
||||
if ($meta.PSObject.Properties.Name -contains "RetryCount") {
|
||||
$meta.RetryCount = 0
|
||||
} else {
|
||||
$meta | Add-Member -NotePropertyName RetryCount -NotePropertyValue 0
|
||||
}
|
||||
|
||||
$now = [DateTime]::UtcNow.ToString("o")
|
||||
|
||||
if ($meta.PSObject.Properties.Name -contains "NextAttemptUtc") {
|
||||
$meta.NextAttemptUtc = $now
|
||||
} else {
|
||||
$meta | Add-Member -NotePropertyName NextAttemptUtc -NotePropertyValue $now
|
||||
}
|
||||
|
||||
if ($meta.PSObject.Properties.Name -contains "RequeuedUtc") {
|
||||
$meta.RequeuedUtc = $now
|
||||
} else {
|
||||
$meta | Add-Member -NotePropertyName RequeuedUtc -NotePropertyValue $now
|
||||
}
|
||||
|
||||
$meta | ConvertTo-Json -Depth 10 | Set-Content -LiteralPath $Entry.MetaPath -Encoding UTF8
|
||||
}
|
||||
|
||||
if (Test-Path -LiteralPath $Entry.MetaPath) {
|
||||
Move-Item -LiteralPath $Entry.MetaPath -Destination $targetMeta -Force
|
||||
}
|
||||
|
||||
Move-Item -LiteralPath $Entry.Path -Destination $targetEml -Force
|
||||
}
|
||||
|
||||
function Remove-FailedQueueEntry {
|
||||
param([Parameter(Mandatory)]$Entry)
|
||||
|
||||
Remove-Item -LiteralPath $Entry.Path -Force -ErrorAction Stop
|
||||
Remove-Item -LiteralPath $Entry.MetaPath -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
function Manage-FailedQueue {
|
||||
$config = Get-RelayConfig -TargetPath $InstallPath
|
||||
|
||||
if (-not $config) {
|
||||
Write-Fail "config.json nicht gefunden."
|
||||
return
|
||||
}
|
||||
|
||||
while ($true) {
|
||||
Clear-Host
|
||||
Write-Title "SMTPGraphRelay - Failed Queue"
|
||||
|
||||
$entries = @(Get-FailedQueueEntries -Config $config)
|
||||
|
||||
Write-Host "Failed-Mails: $($entries.Count)"
|
||||
Write-Host ""
|
||||
|
||||
Write-Host " [1] Failed Queue anzeigen"
|
||||
Write-Host " [2] Details einer Mail anzeigen"
|
||||
Write-Host " [3] Eine Mail erneut zustellen"
|
||||
Write-Host " [4] Alle Mails erneut zustellen"
|
||||
Write-Host " [5] Eine Mail endgültig löschen"
|
||||
Write-Host " [6] Alle Failed-Mails endgültig löschen"
|
||||
Write-Host " [0] Zurück"
|
||||
Write-Host ""
|
||||
|
||||
$choice = Read-Host "Auswahl"
|
||||
|
||||
switch ($choice) {
|
||||
"1" {
|
||||
if ($entries.Count -eq 0) {
|
||||
Write-Ok "Failed Queue ist leer."
|
||||
}
|
||||
else {
|
||||
$entries |
|
||||
Select-Object QueueId,FailedSince,RetryCount,From,Recipients,LastStatusCode,SizeKB |
|
||||
Format-Table -AutoSize
|
||||
}
|
||||
|
||||
Read-Host "Enter"
|
||||
}
|
||||
|
||||
"2" {
|
||||
$id = Read-Host "Queue-ID"
|
||||
|
||||
$entry = $entries |
|
||||
Where-Object { $_.QueueId -eq $id -or $_.FileName -eq $id -or $_.FileName -eq "$id.eml" } |
|
||||
Select-Object -First 1
|
||||
|
||||
if (-not $entry) {
|
||||
Write-Fail "Queue-ID '$id' nicht gefunden."
|
||||
}
|
||||
else {
|
||||
Write-Host ""
|
||||
Write-Host "Queue-ID: $($entry.QueueId)"
|
||||
Write-Host "Datei: $($entry.FileName)"
|
||||
Write-Host "Fehlgeschlagen:$($entry.FailedSince)"
|
||||
Write-Host "RetryCount: $($entry.RetryCount)"
|
||||
Write-Host "Von: $($entry.From)"
|
||||
Write-Host "An: $($entry.Recipients)"
|
||||
Write-Host "Auth-User: $($entry.AuthenticatedUser)"
|
||||
Write-Host "Status: $($entry.LastStatusCode)"
|
||||
Write-Host "Größe: $($entry.SizeKB) KB"
|
||||
Write-Host ""
|
||||
Write-Host "Letzter Fehler:" -ForegroundColor Yellow
|
||||
Write-Host $entry.LastError
|
||||
}
|
||||
|
||||
Read-Host "Enter"
|
||||
}
|
||||
|
||||
"3" {
|
||||
$id = Read-Host "Queue-ID"
|
||||
|
||||
$entry = $entries |
|
||||
Where-Object { $_.QueueId -eq $id -or $_.FileName -eq $id -or $_.FileName -eq "$id.eml" } |
|
||||
Select-Object -First 1
|
||||
|
||||
if (-not $entry) {
|
||||
Write-Fail "Queue-ID '$id' nicht gefunden."
|
||||
}
|
||||
else {
|
||||
Retry-FailedQueueEntry -Config $config -Entry $entry
|
||||
Write-Ok "[$($entry.QueueId)] zurück nach pending verschoben."
|
||||
}
|
||||
|
||||
Read-Host "Enter"
|
||||
}
|
||||
|
||||
"4" {
|
||||
if ($entries.Count -eq 0) {
|
||||
Write-Ok "Failed Queue ist leer."
|
||||
}
|
||||
elseif (Confirm-Yes "Alle $($entries.Count) Failed-Mails erneut zustellen?") {
|
||||
$ok = 0
|
||||
$failed = 0
|
||||
|
||||
foreach ($entry in $entries) {
|
||||
try {
|
||||
Retry-FailedQueueEntry -Config $config -Entry $entry
|
||||
$ok++
|
||||
}
|
||||
catch {
|
||||
$failed++
|
||||
Write-Warn "[$($entry.QueueId)] konnte nicht requeued werden: $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
|
||||
Write-Ok "$ok Mail(s) zurück nach pending verschoben."
|
||||
if ($failed -gt 0) {
|
||||
Write-Warn "$failed Mail(s) konnten nicht verschoben werden."
|
||||
}
|
||||
}
|
||||
|
||||
Read-Host "Enter"
|
||||
}
|
||||
|
||||
"5" {
|
||||
$id = Read-Host "Queue-ID"
|
||||
|
||||
$entry = $entries |
|
||||
Where-Object { $_.QueueId -eq $id -or $_.FileName -eq $id -or $_.FileName -eq "$id.eml" } |
|
||||
Select-Object -First 1
|
||||
|
||||
if (-not $entry) {
|
||||
Write-Fail "Queue-ID '$id' nicht gefunden."
|
||||
}
|
||||
elseif (Confirm-Yes "[$($entry.QueueId)] endgültig aus Failed löschen?") {
|
||||
Remove-FailedQueueEntry -Entry $entry
|
||||
Write-Ok "[$($entry.QueueId)] gelöscht."
|
||||
}
|
||||
|
||||
Read-Host "Enter"
|
||||
}
|
||||
|
||||
"6" {
|
||||
if ($entries.Count -eq 0) {
|
||||
Write-Ok "Failed Queue ist leer."
|
||||
}
|
||||
elseif (Confirm-Yes "WIRKLICH alle $($entries.Count) Failed-Mails endgültig löschen?") {
|
||||
if (Confirm-Yes "Endgültiges Löschen nochmals bestätigen?") {
|
||||
$ok = 0
|
||||
|
||||
foreach ($entry in $entries) {
|
||||
try {
|
||||
Remove-FailedQueueEntry -Entry $entry
|
||||
$ok++
|
||||
}
|
||||
catch {
|
||||
Write-Warn "[$($entry.QueueId)] konnte nicht gelöscht werden."
|
||||
}
|
||||
}
|
||||
|
||||
Write-Ok "$ok Failed-Mail(s) endgültig gelöscht."
|
||||
}
|
||||
}
|
||||
|
||||
Read-Host "Enter"
|
||||
}
|
||||
|
||||
"0" {
|
||||
return
|
||||
}
|
||||
|
||||
default {
|
||||
Write-Warn "Ungültige Auswahl."
|
||||
Start-Sleep -Seconds 1
|
||||
}
|
||||
}
|
||||
|
||||
$config = Get-RelayConfig -TargetPath $InstallPath
|
||||
}
|
||||
}
|
||||
|
||||
function Manage-SmtpAuth {
|
||||
$config = Get-RelayConfig -TargetPath $InstallPath
|
||||
|
||||
@@ -1850,6 +2198,11 @@ function Show-Status {
|
||||
$authUsers = if ($config.Smtp.PSObject.Properties.Name -contains "AuthUsers") { @($config.Smtp.AuthUsers).Count } else { 0 }
|
||||
Write-Host " AUTH: $authText ($authUsers Benutzer)"
|
||||
}
|
||||
|
||||
try {
|
||||
$failedCount = @(Get-FailedQueueEntries -Config $config).Count
|
||||
Write-Host " Failed: $failedCount Mail(s)"
|
||||
} catch {}
|
||||
} catch {}
|
||||
}
|
||||
else {
|
||||
@@ -1887,6 +2240,7 @@ function Show-Menu {
|
||||
Write-Host " [7] Deinstallieren"
|
||||
Write-Host " [8] Status anzeigen"
|
||||
Write-Host " [9] SMTP-AUTH verwalten"
|
||||
Write-Host " [10] Failed Queue verwalten"
|
||||
Write-Host " [0] Beenden"
|
||||
Write-Host ""
|
||||
}
|
||||
@@ -1908,6 +2262,7 @@ while ($true) {
|
||||
"7" { Uninstall-Relay }
|
||||
"8" { Show-Status }
|
||||
"9" { Manage-SmtpAuth }
|
||||
"10" { Manage-FailedQueue }
|
||||
"0" { break }
|
||||
default { Write-Warn "Ungültige Auswahl." }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user