skripte:rsk_erinnerung_und_pruefen_manuell
RSK_Erinnerung_und_prüfen (Manuelle Version)
Nutzen: Dieses Skript automatisiert das komplette monatliche Meldeverfahren für RSK-Daten. Es ist für die manuelle Ausführung durch einen Anwender konzipiert.
Funktion:
Liest eine Stammdaten-Datei, um alle meldepflichtigen Mandanten zu ermitteln.
Führt eine zentrale Melde-Historie in einer Excel-Datei. Eine einmal erfolgte Meldung ('1') wird für den Monat nicht mehr überschrieben.
Verarbeitet eingehende Melde-Dateien, prüft sie auf Korrektheit und verschiebt sie.
Generiert am Ende drei separate Textdateien mit E-Mail-Adressen für Feedback, Erinnerungen und (nach 3 fehlenden Meldungen) Eskalationen.
Protokolliert alle Aktionen in einem Logfile.
--- KONFIGURATION: Pfade und Dateinamen --- $basePath = "PATH" $spoolerPath = Join-Path $basePath "SpoolerRSK" $inputFolder = Join-Path $spoolerPath "EMAIL-ANHANG-ZIEL" $stammdatenPath = Join-Path $basePath "Stammdaten\StammdatenMandanten.xlsx" $meldeDatenPath = Join-Path $basePath "Stammdaten\Meldungen.xlsx" $zielOrdnerArchiv = $spoolerPath $feedbackMailFileBase = Join-Path $spoolerPath "E-Mail-Feedback" $erinnerungsMailFile = Join-Path $spoolerPath "E-Mail-Erinnerung.txt" $eskalationsMailFile = Join-Path $spoolerPath "E-Mail-Eskalation.txt" $logfilePath = Join-Path $spoolerPath "Logfile.txt" $cell_MandantenNummer = "E1" $cell_Datum = "F1" --- FUNKTION: Protokollierung --- $logFileOverwritten = $false function Write-Log($message) { $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" $logEntry = "$timestamp - $message" if (-not $script:logFileOverwritten) { $logEntry | Out-File -FilePath $logfilePath -Encoding UTF8 $script:logFileOverwritten = $true } else { $logEntry | Out-File -FilePath $logfilePath -Append -Encoding UTF8 } Write-Host $logEntry } --- FUNKTION: Dateisperre prüfen --- function Test-FileLock { param ([string]$Path) try { $stream = [System.IO.File]::Open($Path, 'Open', 'Read', 'Write') if ($stream) { $stream.Close() }; return true } catch { Write-Log "FEHLER: Datei '(Split-Path $Path -Leaf)' ist gesperrt und kann nicht verarbeitet werden." return $false } } --- Skriptstart --- Write-Log "========== Skript 'RSK_Erinnerung_und_prüfen' gestartet ==========" $heutigesDatum = Get-Date $zielMonatJahr = $heutigesDatum.ToString("MM.yyyy") $spaltenHeaderMonat = $heutigesDatum.ToString("yyyy-MM") Write-Log "Aktueller Prüfungsmonat: $zielMonatJahr (Spalten-Header: $spaltenHeaderMonat)" $excel = New-Object -ComObject Excel.Application $excel.Visible = $false $excel.DisplayAlerts = $false try { Write-Log "Lese Stammdaten..." if (-not (Test-Path $stammdatenPath)) { throw "Stammdaten-Datei nicht gefunden!" } if (-not (Test-FileLock -Path $stammdatenPath)) { throw "Stammdaten-Datei ist gesperrt." } $stammdatenWorkbook = $excel.Workbooks.Open($stammdatenPath, $true) $stammdatenSheet = $stammdatenWorkbook.Worksheets.Item(1) $stammdatenRange = $stammdatenSheet.UsedRange $alleMandanten = @{} for ($i = 2; $i -le $stammdatenRange.Rows.Count; $i++) { $rskKreis = $stammdatenRange.Cells.Item($i, 4).Text if ($rskKreis) { $mandantNr = $stammdatenRange.Cells.Item($i, 1).Text if ($mandantNr) { $alleMandanten[$mandantNr] = @{ Name = $stammdatenRange.Cells.Item($i, 2).Text; RSKKreis = $rskKreis Mail1 = $stammdatenRange.Cells.Item($i, 23).Text; Mail2 = $stammdatenRange.Cells.Item($i, 24).Text Eskalation = $stammdatenRange.Cells.Item($i, 25).Text } } } } stammdatenWorkbook.Close()Write−Log"($alleMandanten.Count) meldepflichtige Mandanten geladen." Write-Log "Initialisiere Melde-Historie..." if (-not (Test-Path $meldeDatenPath)) { Write-Log "Melde-Datei existiert nicht, wird neu erstellt." $meldeWorkbook = $excel.Workbooks.Add(); $meldeSheet = $meldeWorkbook.Worksheets.Item(1) $meldeSheet.Cells.Item(1, 1).Value2 = "Mandantennummer" } else { if (-not (Test-FileLock -Path $meldeDatenPath)) { throw "Melde-Datei ist gesperrt."} $meldeWorkbook = $excel.Workbooks.Open($meldeDatenPath); $meldeSheet = $meldeWorkbook.Worksheets.Item(1) } $headerRange = $meldeSheet.Rows.Item(1); $spaltenIndex = 0 for ($j = 1; $j -le $meldeSheet.UsedRange.Columns.Count; $j++) { if (($headerRange.Cells.Item(1, $j).Text).Trim() -eq $spaltenHeaderMonat) { $spaltenIndex = $j; break } } if ($spaltenIndex -eq 0) { $spaltenIndex = $meldeSheet.UsedRange.Columns.Count + 1 $meldeSheet.Cells.Item(1, $spaltenIndex).Value2 = $spaltenHeaderMonat Write-Log "Neue Spalte '$spaltenHeaderMonat' in Melde-Historie erstellt." } foreach ($mandantNr in $alleMandanten.Keys) { $findMandant = $meldeSheet.Columns.Item(1).Find($mandantNr) $zeilenIndex = if ($null -ne $findMandant) { $findMandant.Row } else { $meldeSheet.UsedRange.Rows.Count + 1 } if ($null -eq $findMandant) { $meldeSheet.Cells.Item($zeilenIndex, 1).Value2 = $mandantNr } if ($null -eq $meldeSheet.Cells.Item($zeilenIndex, $spaltenIndex).Value2) { $meldeSheet.Cells.Item($zeilenIndex, $spaltenIndex).Value2 = 0 } } $meldeWorkbook.Save(); $meldeWorkbook.Close() Write-Log "Melde-Historie für '$spaltenHeaderMonat' initialisiert." Write-Log "Beginne mit der Verarbeitung von Eingangsdateien..." $inputFiles = Get-ChildItem -Path $inputFolder -Filter "*.xlsx" if ($inputFiles.Count -eq 0) { Write-Log "Keine Dateien zur Verarbeitung gefunden." } else { if (-not (Test-FileLock -Path $meldeDatenPath)) { throw "Melde-Datei ist für Updates gesperrt." } $meldeWorkbook = $excel.Workbooks.Open($meldeDatenPath); $meldeSheet = $meldeWorkbook.Worksheets.Item(1) foreach ($file in $inputFiles) { try { $stream = [System.IO.File]::Open($file.FullName, 'Open', 'Read', 'Write'); $stream.Close() } catch { Write-Log "WARNUNG: Datei '$($file.Name)' ist gesperrt und wird übersprungen."; continue } $inputWorkbook = $excel.Workbooks.Open($file.FullName, $true); $inputSheet = $inputWorkbook.Worksheets.Item(1) $geleseneNummer = $inputSheet.Range($cell_MandantenNummer).Text $gelesenesDatum = $inputSheet.Range($cell_Datum).Text; $inputWorkbook.Close() if (-not $alleMandanten.ContainsKey($geleseneNummer)) { Write-Log "FEHLER: Mandant '$geleseneNummer' aus '$($file.Name)' ist unbekannt."; continue } if ($gelesenesDatum -notlike "*$zielMonatJahr*") { Write-Log "FEHLER: Datum '$gelesenesDatum' in '$($file.Name)' stimmt nicht."; continue } Write-Log "ERFOLG: Datei '$($file.Name)' für Mandant $($alleMandanten[$geleseneNummer].Name) ist gültig." $findMandant = $meldeSheet.Columns.Item(1).Find($geleseneNummer) if ($null -ne $findMandant) { $meldeSheet.Cells.Item($findMandant.Row, $spaltenIndex).Value2 = 1 Write-Log "INFO: Status für '$geleseneNummer' auf '1' (gemeldet) gesetzt." } $neuerDateiname = "$($heutigesDatum.ToString('yyyy-MM'))_RSK_$geleseneNummer.xlsx" $zielPfad = Join-Path $zielOrdnerArchiv $neuerDateiname Move-Item -Path $file.FullName -Destination $zielPfad -Force Write-Log "INFO: Datei '$($file.Name)' nach '$zielPfad' verschoben." } $meldeWorkbook.Save(); $meldeWorkbook.Close() } Write-Log "Generiere E-Mail-Listen basierend auf finaler Melde-Historie..." $feedbackMailsGruppiert = @{}; $erinnerungsMails = [System.Collections.Generic.List[string]]::new(); $eskalationsMails = [System.Collections.Generic.List[string]]::new() if (-not (Test-FileLock -Path $meldeDatenPath)) { throw "Melde-Datei für E-Mail-Listen gesperrt." } $meldeWorkbook = $excel.Workbooks.Open($meldeDatenPath, $true); $meldeSheet = $meldeWorkbook.Worksheets.Item(1) $headerAktuell = $heutigesDatum.ToString("yyyy-MM"); $headerVormonat1 = ($heutigesDatum.AddMonths(-1)).ToString("yyyy-MM"); $headerVormonat2 = ($heutigesDatum.AddMonths(-2)).ToString("yyyy-MM") $colIdxAktuell = 0; $colIdxVormonat1 = 0; $colIdxVormonat2 = 0 $headerRange = $meldeSheet.Rows.Item(1) for ($j = 1; $j -le $meldeSheet.UsedRange.Columns.Count; $j++) { $headerText = ($headerRange.Cells.Item(1, $j).Text).Trim() if ($headerText -eq $headerAktuell) { $colIdxAktuell = $j } if ($headerText -eq $headerVormonat1) { $colIdxVormonat1 = $j } if ($headerText -eq $headerVormonat2) { $colIdxVormonat2 = $j } } foreach ($mandantNr in $alleMandanten.Keys) { $findMandant = $meldeSheet.Columns.Item(1).Find($mandantNr) if ($null -ne $findMandant) { $mandantInfo = $alleMandanten[$mandantNr] $statusAktuell = $meldeSheet.Cells.Item($findMandant.Row, $colIdxAktuell).Value2 if ($statusAktuell -eq 1) { $rskKreis = $mandantInfo.RSKKreis if (-not $feedbackMailsGruppiert.ContainsKey($rskKreis)) { $feedbackMailsGruppiert[$rskKreis] = [System.Collections.Generic.List[string]]::new() } if ($mandantInfo.Mail1) { $feedbackMailsGruppiert[$rskKreis].Add($mandantInfo.Mail1) } if ($mandantInfo.Mail2) { $feedbackMailsGruppiert[$rskKreis].Add($mandantInfo.Mail2) } } else { if ($mandantInfo.Mail1) { $erinnerungsMails.Add($mandantInfo.Mail1) } if ($mandantInfo.Mail2) { $erinnerungsMails.Add($mandantInfo.Mail2) } $eskaliere = $false if ($colIdxAktuell -ne 0 -and $colIdxVormonat1 -ne 0 -and $colIdxVormonat2 -ne 0) { $statusVormonat1 = $meldeSheet.Cells.Item($findMandant.Row, $colIdxVormonat1).Value2 $statusVormonat2 = $meldeSheet.Cells.Item($findMandant.Row, $colIdxVormonat2).Value2 if (($statusAktuell -ne 1) -and ($statusVormonat1 -ne 1) -and ($statusVormonat2 -ne 1)) { $eskaliere = $true } } if ($eskaliere) { Write-Log "INFO: Mandant '$mandantNr' hat 3 Monate in Folge nicht gemeldet. Eskalation wird ausgelöst." if ($mandantInfo.Eskalation) { $eskalationsMails.Add($mandantInfo.Eskalation) } } } } } $meldeWorkbook.Close() foreach ($kreis in $feedbackMailsGruppiert.Keys) { ($feedbackMailsGruppiert[$kreis] | Get-Unique) -join ";" | Out-File "$($feedbackMailFileBase)-$($kreis).txt" -Encoding UTF8BOM } ($erinnerungsMails | Get-Unique) -join ";" | Out-File $erinnerungsMailFile -Encoding UTF8BOM ($eskalationsMails | Get-Unique) -join ";" | Out-File $eskalationsMailFile -Encoding UTF8BOM Write-Log "E-Mail-Listen wurden erfolgreich erstellt." } catch { Write-Log "FATALER FEHLER: Skript wurde abgebrochen. Grund: (_.Exception.Message)" } finally { if ($excel) { $excel.Quit() [System.Runtime.InteropServices.Marshal]::ReleaseComObject($excel) | Out-Null Remove-Variable excel -ErrorAction SilentlyContinue } Write-Log "========== Skript 'RSK_Erinnerung_und_prüfen' beendet ==========" } //Author: Stefan Agethen //Letzte Bearbeitung: 2025//
skripte/rsk_erinnerung_und_pruefen_manuell.txt · Zuletzt geändert: von Stefan Agethen
