Dateivergleich inkl. FIFO Backup per Powershell

Dateivergleich inkl. FIFO Backup per Powershell

Vorsicht lang, und viel Code!

Kurzinformationen: Ein Kollege bat mich um Hilfe als er ein Script schreiben sollte das scheinbar die Komplexibilität zuvor vorhandener Projekte überstieg. Zudem das es im laufende Programmierprozess 3 mal geändert wurde. In diesem Rahmen entschied ich mich für ein Powershellscript das ich in eigener Manier um eine Backupfunktion erweiterte. Wie und wieso – mehr dazu im Langtext. Das Script lief bis heute Fehlerfrei und ohne Abbruch.

Der Kollege der auf mich zukam war schon einige Zeit am überlegen wie man die geforderten Datensätze auf Vollständigkeit kontrollieren konnte. Hierbei ging es allerdings nicht um den Inhalt der Dateien sondern um die Zusammengehörigkeit von 2 Dateien (später 3 Dateien) mit verschiedenen Endungen. Dabei musste zudem aussortiert werden welche dieses Kriterium nicht erfüllen, verschoben werden wenn erfüllt und am Ende eine Zusammenfassung erstellt werden und per Mail versendet werden wenn das mal nicht der Fall ist. Grund dafür war ein Prozess der abbrach und eine weitere Verarbeitung somit beendete was teilweise zu Verzögerungen in den darauf folgenden Jobketten zum Nachteil hatte.

Folgendes aktuell & gewünschte Szenario habe ich damals erstellt:

Rot = Alter Verlauf
Grün = Vergleich mit 2 Dateiendungen
Gelb = Vergleich mit 3 Dateiendungen

Die Überschneidungen der Gelben Prozesse und der Grünen habe ich bei den grünen belassen. Grundlegend handelt es sich immer um einen 2 Dateivergleich. Bei dem Wunsch auch drei zu vergleichen kann man dies mit einer zusätzlichen temporären Übergabe-Variable abhandeln. In dieser wird gespeichert ob die vorrangige Vorhanden ist oder nicht. Bei mehr als drei Dateien wird es nicht viel komplizierter im Aufbau. Das Programm ist theoretisch wie eine Dateibasierte Wahrheitstabelle aufgebaut die man aus der Ausbildung in der Elektrotechnik kennt.

Hierbei könnte ich jetzt Dinge anbringen wie „logische Äquivalenz“ und „Boolesche Algebra“ aber dann qualmt es bei einigen in den Köpfen weil das Wissen bereits verstaut und zugestaubt wurde.

Diese Vorgehensweise lässt sich zwar beliebig ausweiten allerdings würde ich ab 3 Dateien bereits ein anderes Verfahren anwenden und nicht mehr mit auf Variablen basierenden logischen Vergleichen Arbeiten. Das wäre so wie ein Bad mit der Zahnbürste zu putzen. Unnötig kompliziert und aufwendig.

So jetzt mal zum eigentlichen Code:

So Standards wie Ordnerstrukturen beschwören und Pfade in Variablen bannen brauche ich nicht drauf einzugehen. Aber da mein Code sowieso direkt als Clear-Code erkennbar ist lässt er sich recht einfach lesen.

Auf jeden Fall sind hier oben Hardcoded die Source und Destination Pfade. Theoretisch kann man diese noch per z.B. XML auslesen lassen, aber ich will hier nichts verkomplizieren. Das mache ich mal in einem anderen Beitrag. Der würde dann HIER (KLICK MICH) verlinkt.
Danach produziere ich noch sog. Returncodes als Rückgabe für das ausführende Programm zum Errorcodehandling.

PowerShell
  
# Setze Return Code auf 0 bevor das Script startet
$Returncode = 0
$ServiceError = ""
 
 
#$OriginalpfadTESTPHASE = [System.IO.Path]::GetDirectoryName($myInvocation.MyCommand.Definition)
 
# Hier NUR Originalpfade eintragen
$FIX_SOURCE = "SOURCEPFAD"
$FIX_DESTINATION = "DESTINATIONPFAD"
$FIX_WORKSPACE = "WORKSPACEPFAD"
 

 
##################################################
# AB HIER SIND KEINE ÄNDERUNGEN MEHR ERORDERLICH #   <= Hinweis für Layer 8 :P
##################################################
 
 
 
#Formatieren des Datumstempels
$DateiDatumserweiterung = Get-Date -Format yyyy_MM_dd_HH_mm_ss
 
 
#Bestimmen der Ordnerpfade Backup und Temporärer Arbeitsordner
$BCKpfad = "$FIX_WORKSPACE/BCK_$DateiDatumserweiterung"
$Temppfad = "$BCKpfad/temp"
$Aussortierte_Paare = "$Temppfad/Versand"
$Aussortierte_Single = "$Temppfad/Fehler"
 
 
 
#Erstellen der benötigten Ordner
#Erst Backup da dort drin der Tempordner erstellt wird
#Danach der Temp Ordner da dort drin die Kategorieordner erstellt werden
mkdir "$BCKpfad"
mkdir "$Temppfad"
mkdir "$Temppfad/Versand"
mkdir "$Temppfad/Fehler"
 
 
#######################################################################
## Prüfen ob Pfade erreichbar sind ansonsten Returncode 1 als Fehler ##
#######################################################################

If (Test-Path $BCKpfad)
{
    Write-Host -BackGroundColor Green "Der Pfad $($BCKpfad) existiert."
    $returncode = 0
    Write-Host "Returncode: $returncode"
}
else
{
    Write-Host -BackgroundColor Red "Der Pfad $($BCKpfad) existiert bisher nicht oder ist nicht erreichbar."
    # Hier wird der Error Codes übergeben
    if ($Returncode -eq '1')
        {$ServiceError}
    exit(1)
}
 
If (Test-Path $FIX_SOURCE)
{
    Write-Host -BackGroundColor Green "Der Pfad $($FIX_SOURCE) existiert."
    $returncode = 0
    Write-Host "Returncode: $returncode"
}
else
{
    Write-Host -BackgroundColor Red "Der Pfad $($FIX_SOURCE) existiert bisher nicht oder ist nicht erreichbar."
    # Hier wird der Error Codes übergeben
    if ($Returncode -eq '1')
        {$ServiceError}
    exit(1)
}
 
If (Test-Path $FIX_DESTINATION)
{
    Write-Host -BackGroundColor Green "Der Pfad $($FIX_DESTINATION) existiert."
    $returncode = 0
    Write-Host "Returncode: $returncode"
}
else
{
    Write-Host -BackgroundColor Red "Der Pfad $($FIX_DESTINATION) existiert bisher nicht oder ist nicht erreichbar."
   
    # Hier wird der Error Codes übergeben
    if ($Returncode -eq '1')
        {$ServiceError}
    exit(1)
}
 
If (Test-Path $FIX_WORKSPACE)
{
    Write-Host -BackGroundColor Green "Der Pfad $($FIX_WORKSPACE) existiert."
    $returncode = 0
    Write-Host "Returncode: $returncode"
}
else
{
    Write-Host -BackgroundColor Red "Der Pfad $($FIX_WORKSPACE) existiert bisher nicht oder ist nicht erreichbar."
    # Hier wird der Error Codes übergeben
    if ($Returncode -eq '1')
        {$ServiceError}
    exit(1)
}

Ich habe jetzt im Workspace folgende Ordnerstruktur:

../Workspace
—-/BCK_yyyy_MM_dd_HH_mm_ss
——–/temp
———–/Versand
———–/Fehler

In den Backup Ordner verschiebe ich jetzt alle Dateien mit den gewünschten Endungen und kopiere Sie danach direkt in den Temporären Ordner in dem die Dateien dann verarbeitet werden. Somit habe ich in der Struktur immer alle Dateien als Backup hinterlegt. Nehmen wir an bei einem Fehler möchte man das Script erneut starten, dann kopiere ich mir die Daten einfach wieder aus dem Backup. Sozusagen als RAW-File, Jungfräulich und unverändert.

Inkrementieren von Datumsangaben

Wenn man eine Datumsangabe im Format YYYYMMDD oder sogar noch mit HHMMSS schreibt und damit Dateien oder ander andere Dinge beziffert werden diese automatisch inkremementiert. Das heißt jeder Name ist einmalig und kann sich nicht wiederholen. Zudem sind Dateien und Ordner damit automatisch nach Alter sortierbar.

PowerShell
####################################
## Jetzt wird das Backup erstellt ##
####################################

#Verschieben von allen WWW/XXX/YYY/ZZZ Dateien zum Backupen und zum verhindern das nachher einiges gedoppelt bearbeitet wird. Verschoben wird in einen Ordner mit Datumsformat YYYY/MM/DD (vorteil ist hier das bei der Anordnung ein Datum automatisch inkrementiert wird)
Move-Item "$FIX_SOURCE/*.WWW" "$BCKpfad"
Move-Item "$FIX_SOURCE/*.XXX" "$BCKpfad"
Move-Item "$FIX_SOURCE/*.YYY" "$BCKpfad"
Move-Item "$FIX_SOURCE/*.ZZZ" "$BCKpfad"
write-host "Backup wird erstellt"
Start-Sleep -s 20
 
##########################################################################################
## Dateien werden in Tempverzeichnis kopiert um Fehler an Dateistrukturen zu verhindern ## 
##########################################################################################

#Kopieren der Dateien aus dem Backupverzeichnis in das TEMP-Verzeichnis
Copy-Item "$BCKpfad\*.*" "$Temppfad"
write-host "Temp wird erstellt"
Start-Sleep -s 20

Der eigentliche Vergleich der Dateien ist relativ simpel. Vorab sei zu sagen das es bei dem Projekt die Vorraussetzung gegeben war das es von den Dateien WWW, XXX und YYY ausnahmslos immer eine geben sollte. Passen dazu sollte es immer eine Datei mit der Endung ZZZ geben. Aussortiert werden dann eben die Dateien die bei denen keine gleichnamige Datei mit Endung ZZZ gefunden wird.

Hierzu nehme ich mir jeden Eintrag des Arrays von WWW und prüfe ob es den Basename der Datei auch in dem Format Basename.ZZZ gibt. Das ist meine IF-Anweisung. Wenn diese TRUE ist werden daraufhin beide Dateien in den Ordner Versand verschoben. Ist dies nicht der Fall wird die Datei Basename.WWW in den Ordner Fehler veschoben.

Ist das Array dann zuende was automatisch mit der foreach Schleife passiert erzeuge ich das Array mit den Dateiendungen XXX und prüfe auf die gleiche Weise.

Das ganze passiert dann nochmal mit den Dateien die, die Endung YYY haben.

Wenn ich jetzt also die Vorraussetzung beachte das es immer eine Datei vom Typ WWW, XXX oder YYY geben soll und ich diese entweder als Paar in den Ordner Versand verschoben habe oder eben als Einzelgänger in den Ordner Fehler. Dürfte es keine Datei mit der Endung ZZZ in dem Ordner geben. Hierzu habe ich dann die Gegeprobe (mein Mathelehrer währe stolz auf mich) gemacht und kontrolliere ob es hiervon noch eine im Ordner gibt. Sollte es wäre hier ein Fehler und man müsste nochmal Manuell nachpflegen bzw. kontrollieren.

Den Compiler austricksen (Cleancode umständlich)

Ich persönlich hasse es wie die Pest wenn sich das Hauptscript nicht oben befindet und wie es sich gehört alle deklarierten Funktionen darunter. Kein Problem – wenn da nicht das Ding mit alles-wissen-wollenden Compier wäre. „Funktion habe ich nicht gesehen, kenn ich nicht!“

Mehr dazu HIER => KLICK MICH
Meine Cleancode Regeln HIER => KLICK MICH

Warum dieser Tipp hier? Spätestens im nächsten Codeblock werden Fragezeichen aufkommen die dort beantwortet werden.

PowerShell
function Hauptscript{
########################################################################################################################################### 
##In diesem Hauptscript wird für jede Dateiendung ein Array erstellt und pro Eintrag die Funktion für die entsprechende Datei aufgerufen ##
###########################################################################################################################################


############################################
## Erster Durchlauf für alle WWW Dateien  ##
############################################
 
# Auswerten aller WWW Dateien des Ordners
$Array_von_WWW_Dateien = Get-ChildItem "$Temppfad\*.*" -Filter "*.WWW"
# Aufruf der Funktion für jede WWW Datei des Arrays
foreach ($Aktuelle_WWW_Datei in $Array_von_WWW_Dateien) {Prüfungsschleife-WWW}
 
############################################
## Zweiter Durchlauf für alle XXX Dateien ##
############################################
 
# Auswerten aller XXX Dateien des Ordners
$Array_von_XXX_Dateien = Get-ChildItem "$Temppfad\*.*" -Filter "*.XXX"
# Aufruf der Funktion für jede XXX Datei des Arrays
foreach ($Aktuelle_XXX_Datei in $Array_von_XXX_Dateien) {Prüfungsschleife-XXX}

 
############################################
## Dritter Durchlauf für alle YYY Dateien ##
############################################
 
# Auswerten aller YYY Dateien des Ordners
$Array_von_YYY_Dateien = Get-ChildItem "$Temppfad\*.*" -Filter "*.YYY"
# Aufruf der Funktion für jede YYY Datei des Arrays
foreach ($Aktuelle_YYY_Datei in $Array_von_YYY_Dateien) {Prüfungsschleife-YYY}

 
############################################
## Vierter Durchlauf für alle ZZZ Dateien ##
############################################
 
# Auswerten aller ZZZ Dateien des Ordners
$Array_von_ZZZ_Dateien = Get-ChildItem "$Temppfad\*.*" -Filter "*.ZZZ"
# Aufruf der Funktion für jede ZZZ Datei des Arrays
foreach ($Aktuelle_ZZZ_Datei in $Array_von_ZZZ_Dateien) {Prüfungsschleife-ZZZ}
 
 
###########################
## Aufruf der Auswertung ##
###########################
 
Auswertung_starten
 
 
}
 
 
 
 
 
############################
## Aufrufen der Functions ##
############################
 
###############################################################################################################################################
## Die Prüfungsschleifen arbeiten alle nach dem gleichen Prinzip. Nimm den Namen der Datei und Prüfe ob eine gleichnamige ZZZ vorhanden ist. ##
## Wenn nicht verschiebe die Datei in den Ordner Single damit Sie weiter verarbeitet werden kann wenn alle Dateien durch sind.               ##
## Alle Dateien die also nach Ablauf des Scripts im Single Ordner sind, sind fehlerhaft.                                                     ##
###############################################################################################################################################


function Prüfungsschleife-WWW{
    #Splitten des Pfades und entfernen von Pfad und Dateierweiterung
    $SingelDateiName = (Get-Item "$Aktuelle_WWW_Datei").Basename
    Write-Host "Aktuelle WWW-Datei $SingelDateiName"
    #Setzen von Variablen zur weiteren verarbeitung
    $Datei_als_WWW = "$Temppfad/$SingelDateiName.WWW"
    $Datei_als_ZZZ = "$Temppfad/$SingelDateiName.ZZZ"
   
            #IF Verzweigung zur Prüfung ob eine auf dem Namenspräfix passende ZZZ Datei vorhanden ist.
            #Wenn die gleichnamige ZZZ Datei vorhanden ist verschiebe beide Dateien in den Versandordner.
            #Wenn keine gleichnamige ZZZ Datei vorhanden ist verschiebe die WWW Datei in den Singleordner.
 
            If ( Test-Path "$Datei_als_ZZZ")
            {
                # IF ZWEIG => ZZZ Datei ist vorhanden
                Write-Host "Versandbereites Datenpaar gefunden $Datei_als_WWW wird verschoben"
                Write-Host "Versandbereites Datenpaar gefunden $Datei_als_ZZZ wird verschoben"
                Move-Item "$Datei_als_WWW" "$Aussortierte_Paare"
                Move-Item "$Datei_als_ZZZ" "$Aussortierte_Paare"
            }
 
            else
            {
                # IF ZWEIG => ZZZ Datei ist NICHT vorhanden
                Write-Host "Keine passende Datei als ZZZ gefunden! $Aktuelle_WWW_Datei wird verschoben"
                Move-Item "$Datei_als_WWW" "$Aussortierte_Single"
 
            }
    }
 
function Prüfungsschleife-XXX{
    #Splitten des Pfades und entfernen von Pfad und Dateierweiterung
    $SingelDateiName = (Get-Item "$Aktuelle_XXX_Datei").Basename
    Write-Host "Aktuelle XXX-Datei $SingelDateiName"
    #Setzen von Variablen zur weiteren verarbeitung
    $Datei_als_XXX = "$Temppfad/$SingelDateiName.XXX"
    $Datei_als_ZZZ = "$Temppfad/$SingelDateiName.ZZZ"
   
            #IF Verzweigung zur Prüfung ob eine auf dem Namenspräfix passende ZZZ Datei vorhanden ist.
            #Wenn die gleichnamige ZZZ Datei vorhanden ist verschiebe beide Dateien in den Versandordner.
            #Wenn keine gleichnamige ZZZ Datei vorhanden ist verschiebe die XXX Datei in den Singleordner.
 
            If ( Test-Path "$Datei_als_ZZZ")
            {
                # IF ZWEIG => ZZZ Datei ist vorhanden
                Write-Host "Versandbereites Datenpaar gefunden $Datei_als_XXX wird verschoben"
                Write-Host "Versandbereites Datenpaar gefunden $Datei_als_ZZZ wird verschoben"
                Move-Item "$Datei_als_XXX" "$Aussortierte_Paare"
                Move-Item "$Datei_als_ZZZ" "$Aussortierte_Paare"
            }
 
            else
            {
                # IF ZWEIG => ZZZ Datei ist NICHT vorhanden
                Write-Host "Keine passende Datei als ZZZ gefunden! $Aktuelle_XXX_Datei wird verschoben"
                Move-Item "$Datei_als_XXX" "$Aussortierte_Single"
            }
    }

function Prüfungsschleife-YYY{
    #Splitten des Pfades und entfernen von Pfad und Dateierweiterung
    $SingelDateiName = (Get-Item "$Aktuelle_YYY_Datei").Basename
    Write-Host "Aktuelle YYY-Datei $SingelDateiName"
    #Setzen von Variablen zur weiteren verarbeitung
    $Datei_als_YYY = "$Temppfad/$SingelDateiName.YYY"
    $Datei_als_ZZZ = "$Temppfad/$SingelDateiName.ZZZ"
   
            #IF Verzweigung zur Prüfung ob eine auf dem Namenspräfix passende ZZZ Datei vorhanden ist.
            #Wenn die gleichnamige ZZZ Datei vorhanden ist verschiebe beide Dateien in den Versandordner.
            #Wenn keine gleichnamige ZZZ Datei vorhanden ist verschiebe die YYY Datei in den Singleordner.
 
            If ( Test-Path "$Datei_als_ZZZ")
            {
                # IF ZWEIG => ZZZ Datei ist vorhanden
                Write-Host "Versandbereites Datenpaar gefunden $Datei_als_YYY wird verschoben"
                Write-Host "Versandbereites Datenpaar gefunden $Datei_als_ZZZ wird verschoben"
                Move-Item "$Datei_als_YYY" "$Aussortierte_Paare"
                Move-Item "$Datei_als_ZZZ" "$Aussortierte_Paare"
            }
 
            else
            {
                # IF ZWEIG => ZZZ Datei ist NICHT vorhanden
                Write-Host "Keine passende Datei als ZZZ gefunden! $Aktuelle_YYY_Datei wird verschoben"
                Move-Item "$Datei_als_YYY" "$Aussortierte_Single"
 
            }
    }
    
function Prüfungsschleife-ZZZ{
#Splitten des Pfades und entfernen von Pfad und Dateierweiterung
    $SingelDateiName = (Get-Item "$Aktuelle_ZZZ_Datei").Basename
    Write-Host "Aktuelle ZZZ-Datei $SingelDateiName"
    #Setzen von Variablen zur weiteren verarbeitung
    $Datei_als_WWW = "$Temppfad/$SingelDateiName.WWW"
    $Datei_als_XXX = "$Temppfad/$SingelDateiName.XXX"
    $Datei_als_YYY = "$Temppfad/$SingelDateiName.YYY"
    $Datei_als_ZZZ = "$Temppfad/$SingelDateiName.ZZZ"
 
            #IF  Verzweigung zur Prüfung ob eine auf dem Namenspräfix passende andere Datei vorhanden ist.
            #Wenn die gleichnamige andere Datei vorhanden ist verschiebe beide Dateien in den Versandordner. (Wird niemals vorkommen da ja bereits alle Paare in vorherigen Durchläufen gefunden worden sind.)
            #Wenn keine gleichnamige andere Datei vorhanden ist verschiebe die ZZZ Datei in den Singleordner. (Eigentlicher Sinn des letzten Durchlaufs)
 
            If ( Test-Path "$Datei_als_WWW")
            {
                # IF ZWEIG => WWW Datei ist vorhanden
   
                #################################
                #  Dann wäre das Script kaputt  #
                #################################
            }
            If ( Test-Path "$Datei_als_XXX")
            {
                # IF ZWEIG => XXX Datei ist vorhanden
   
                #################################
                #  Dann wäre das Script kaputt  #
                #################################
            }
            If ( Test-Path "$Datei_als_YYY")
            {
                # IF ZWEIG => YYY Datei ist vorhanden
   
                #################################
                #  Dann wäre das Script kaputt  #
                #################################
            }
 
            else
            {
                # IF ZWEIG => ZZZ Datei ist NICHT vorhanden
                Write-Host "Keine passende Datei zur ZZZ gefunden! $Aktuelle_ZZZ_Datei wird verschoben"
                Move-Item "$Datei_als_ZZZ" "$Aussortierte_Single"

 
            }
}

Jetzt haben wir also eine Ordnerstruktur in der – wenn alles gut lief – Keine Datei mehr im Temp Ordner liegt, ebenso wie keine Datei in den Singles. Um das zu prüfen mache ich eine einfache Get-Childitem „Abfrage“ und kann das damit erkennen. Ist damit noch eine Datei im Temp Ordner wäre ein Fehler im Script gewesen und ich kann an das ausführende Jobprogramm einen Returncode geben der dies passend meldet.

Als letzten Schritt rufe ich nun die Auswertung auf. Diese ist als abschließender Prozess zu betrachten immerhin mache ich dort nicht nur die Auswertung ob sich wo, wieviele Dateien befinden sondern es werden die verarbeiteten Dateien nun endlich in die Ordner auf dem APINode verschoben. Der Prozess ist bewusst so gewählt worden damit die Verarbeitung nacheinander ablaufen kann und die Daten vollständig weiteregegeben werden. Zudem ist so eine klare Grenze zwischen den Systemen gezogen. Sollte mein Script mal etwas machen das es nicht soll störe ich somit andere Produktivumgebungen nicht.

Ich lasse mir also relativ einfach alles ausgeben was sich im Fehler-Ordner befindet und pipe die Ausgabe dann in ein Out-File das ich im Backupordner ablege. Den Versand der Email handel ich nicht im Script ab sondern das macht dann das entsprechende Job-Programm das mit einem passenden Returncode regaiert und die Datei in seine Griffel nimmt und in irgendein Postfach katapultiert. Wie ist dann egal. Das ist ein anderes Script.

PowerShell
#####################################################################################
## Alle Dateien im Singleordner werden in eine Datei als Auswertung gepackt        ##
## Dann werden alle Dateien aus Single in den Produktiven Fehler-Ordner verschoben ##
## Dann werden alle Dateien aus Paare in den Produktiven Versand-Ordner verschoben ##
#####################################################################################

Get-ChildItem "$Aussortierte_Single/*.*" -Name |  Out-File -FilePath "$BCKpfad/#Auswertung_Singledateien.txt"
 
#Kopieren von TEMP zu AUSGABE DESTINATION
Copy-Item "$Aussortierte_Single\*.*" "$FIX_DESTINATION/Fehler"
write-host "Fehlerordner wird transferiert"
Start-Sleep -s 20
Copy-Item "$Aussortierte_Paare\*.*" "$FIX_DESTINATION/Versand"
write-host "Fehlerordner wird transferiert"
Start-Sleep -s 20
 
 
###################################
## Prüfe auf leeren Singleordner ##
###################################
 
#Die Job-Software benötigt über den erfolgreichen Durchlauf noch einen Returncode. Ebenso ob es "Fehler" gab. Bei nicht gematchen Dateien wird Return-Code 2 ausgegeben was den Versand
#der Textdatei mit sich bringt. 

if((get-childitem $FIX_WORKSPACE/Fehler).count -eq 0)
{
     
    $returncode = 0
    Write-Host -BackgroundColor Green "Der Ordner Fehler ist leer. Es befinden sich nur Paare in Versand."
    Write-Host -BackgroundColor Green "Das Script ist erfolgreich durchgelaufen." 
 
}
else
{
 
    $ServiceError = ""
    $returncode = 2
 
    Write-Host -BackgroundColor Green "Das Script ist erfolgreich gelaufen. Versandbereite Paare und Singledateien wurden verschoben."
    Write-Host -BackgroundColor Red "Der Ordner Fehler ist nicht leer. Es wird der Return Code 2 ausgegeben."
    Write-Host "Returncode: $returncode"
 
#Im Fehlerfall Ausgabe der Variable §ServiceError. Ist nicht immer Verfügbar aber hilft beim Debuggen wenn das Job-Programm logged (was es sollte)
if ($Returncode -eq '2')
    {$ServiceError}
exit(2)
}

Damit ist das Script dann zuende. Andere Dinge die man beachten muss wären dann noch zu finden in meiner CleanCode Erklärung. Bei mir müsste man dann natürlich am Ende des Scripts die Funktion Hauptscript aufrufen. Danach folgt eigentlich nur noch der EXIT-Befehl.

Ich weiß das es nicht die goldene Art ist etwas zu prüfen und man kann auch mit z.B. Switchen arbeiten was das Script stark verkürzt ebenso ein Errorhandling machen mit einer Try und Catch allerdings war ich zum Zeitpunkt als ich das Script geschrieben habe nicht mit solchen Commands bewandert worraus dann eben dieses Script wuchs. Ebenso könnte man die Variablen zum aufsplitten anders Schreiben In Kurzform oder in Formen wie „$_.Basename“. Allerdings liebe ich es wenn ich ein Script schreibe das auch jemand verstehen kann der kein Wissen in dieser Programmiersprache hat. Daher auch die ganzen Kommentare. Aber dazu mehr in meinem ClearCode Ratgeber 😉