Private/srgParameters.ps1

<#
    Metadaten aller robocopy-Optionen (Stand Windows 11 24H2 / Server 2025, "robocopy /?").
    Reihenfolge = Reihenfolge in der GUI und im erzeugten Befehl.
 
    Typ Wert im Parameter-Hashtable Ausgabe
    Switch $true /XO
    Int '3' /R:3
    Bytes '1048576' /MAX:1048576 (robocopy kennt hier kein K/M/G)
    Size '10M' /IoRate:10M
    Age '7' oder '20260101' /MAXAGE:7 (< 1900 = Tage, sonst JJJJMMTT)
    Hours '2200-0600' /RH:2200-0600
    Flags 'DAT' /COPY:DAT (erlaubte Buchstaben in Letters)
    Opt $true oder Wert /MT bzw. /MT:16 (ValueKind Int | Size | Enum)
    List @('*.tmp', 'Thumbs.db') /XF *.tmp Thumbs.db
    Path 'C:\Logs\copy.log' /LOG:"C:\Logs\copy.log"
 
    Exclusive: Optionen mit gleichem Schluessel schliessen sich aus - die GUI waehlt die anderen ab,
    Test-sqmRobocopyParameter meldet die Kombination als Fehler.
#>


$script:srgParameters = @(
    # --- Kopieren --------------------------------------------------------------------------------
    @{ Name = 'S'; Group = 'Kopieren'; Type = 'Switch'; Exclusive = 'Subdirs'; Help = 'Kopiert Unterverzeichnisse, aber keine leeren.' }
    @{ Name = 'E'; Group = 'Kopieren'; Type = 'Switch'; Exclusive = 'Subdirs'; Help = 'Kopiert Unterverzeichnisse einschliesslich leerer. Fuer fast alle Ordnerkopien die richtige Wahl.' }
    @{ Name = 'MIR'; Group = 'Kopieren'; Type = 'Switch'; Exclusive = 'Subdirs'; Danger = $true; Help = 'Spiegelt die Verzeichnisstruktur (= /E + /PURGE). LOESCHT im Ziel alles, was es in der Quelle nicht (mehr) gibt.' }
    @{ Name = 'LEV'; Group = 'Kopieren'; Type = 'Int'; Min = 1; Max = 1000; Help = 'Kopiert nur die obersten n Ebenen der Quellstruktur (1 = nur die Quelle selbst).' }
    @{ Name = 'Z'; Group = 'Kopieren'; Type = 'Switch'; Exclusive = 'Restart'; Help = 'Neustartmodus: abgebrochene Dateien werden an der Abbruchstelle fortgesetzt. Gut fuer instabile Netze, etwas langsamer.' }
    @{ Name = 'B'; Group = 'Kopieren'; Type = 'Switch'; Exclusive = 'Restart'; Admin = $true; Help = 'Sicherungsmodus: kopiert mit dem Sicherungsrecht und ignoriert damit Datei-ACLs. Braucht Administrator- bzw. Sicherungs-Operator-Rechte.' }
    @{ Name = 'ZB'; Group = 'Kopieren'; Type = 'Switch'; Exclusive = 'Restart'; Admin = $true; Help = 'Neustartmodus, bei "Zugriff verweigert" automatisch Sicherungsmodus. Braucht fuer den Sicherungsmodus Administratorrechte.' }
    @{ Name = 'J'; Group = 'Kopieren'; Type = 'Switch'; Help = 'Ungepufferte E/A. Empfohlen fuer sehr grosse Dateien (z.B. SQL-Backups, VHDX), fuer viele kleine Dateien langsamer.' }
    @{ Name = 'MT'; Group = 'Kopieren'; Type = 'Opt'; ValueKind = 'Int'; Min = 1; Max = 128; Default = '8'; Help = 'Multithread-Kopie mit n Threads (1-128, ohne Wert 8). Deutlich schneller bei vielen Dateien. Nicht mit /IPG oder /EFSRAW kombinierbar.' }
    @{ Name = 'EFSRAW'; Group = 'Kopieren'; Type = 'Switch'; Help = 'Kopiert EFS-verschluesselte Dateien im RAW-Modus (ohne Entschluesselung).' }
    @{ Name = 'COMPRESS'; Group = 'Kopieren'; Type = 'Switch'; Help = 'Fordert SMB-Netzwerkkomprimierung an (Windows Server 2022 / Windows 11 und neuer). Lohnt sich bei langsamen Leitungen und gut komprimierbaren Daten.' }
    @{ Name = 'NOOFFLOAD'; Group = 'Kopieren'; Type = 'Switch'; Help = 'Kopiert ohne den Windows-Copy-Offload-Mechanismus (ODX).' }
    @{ Name = 'NOCLONE'; Group = 'Kopieren'; Type = 'Switch'; Help = 'Kein Block-Cloning als Optimierung versuchen (ReFS / Dev Drive).' }
    @{ Name = 'SPARSE'; Group = 'Kopieren'; Type = 'Opt'; ValueKind = 'Enum'; Values = @('Y', 'N'); Default = 'Y'; Help = 'Sparse-Status der Dateien beibehalten (Y) oder nicht (N). Ohne Wert = Y.' }
    @{ Name = 'CREATE'; Group = 'Kopieren'; Type = 'Switch'; Help = 'Erstellt nur die Verzeichnisstruktur und leere Dateien (Laenge 0).' }
    @{ Name = 'FAT'; Group = 'Kopieren'; Type = 'Switch'; Help = 'Erstellt Zieldateien nur mit 8.3-FAT-Dateinamen.' }
    @{ Name = '256'; Group = 'Kopieren'; Type = 'Switch'; Help = 'Schaltet die Unterstuetzung sehr langer Pfade (> 256 Zeichen) ab.' }
    @{ Name = 'SJ'; Group = 'Kopieren'; Type = 'Switch'; Help = 'Kopiert Verzeichnis-Junctions als Junction statt deren Ziel.' }
    @{ Name = 'SL'; Group = 'Kopieren'; Type = 'Switch'; Help = 'Kopiert symbolische Links als Link statt deren Ziel.' }

    # --- Dateiinfos & Attribute -------------------------------------------------------------------
    @{ Name = 'COPY'; Group = 'Dateiinfos & Attribute'; Type = 'Flags'; Letters = 'DATSOUX'; Exclusive = 'CopyInfo'; Default = 'DAT'; Help = 'Was je Datei kopiert wird: D=Daten, A=Attribute, T=Zeitstempel, S=NTFS-ACLs, O=Besitzer, U=Ueberwachung, X=alternative Datenstroeme ueberspringen. Standard DAT. S/O/U brauchen Administratorrechte.' }
    @{ Name = 'SEC'; Group = 'Dateiinfos & Attribute'; Type = 'Switch'; Exclusive = 'CopyInfo'; Help = 'Kopiert mit NTFS-Berechtigungen (= /COPY:DATS).' }
    @{ Name = 'COPYALL'; Group = 'Dateiinfos & Attribute'; Type = 'Switch'; Exclusive = 'CopyInfo'; Admin = $true; Help = 'Kopiert alle Dateiinformationen (= /COPY:DATSOU). Braucht fuer Besitzer und Ueberwachung Administratorrechte.' }
    @{ Name = 'NOCOPY'; Group = 'Dateiinfos & Attribute'; Type = 'Switch'; Exclusive = 'CopyInfo'; Help = 'Kopiert keine Dateiinformationen - sinnvoll nur zusammen mit /PURGE (Ziel aufraeumen ohne zu kopieren).' }
    @{ Name = 'DCOPY'; Group = 'Dateiinfos & Attribute'; Type = 'Flags'; Letters = 'DATEX'; Exclusive = 'DirInfo'; Default = 'DA'; Help = 'Was je Verzeichnis kopiert wird: D=Daten, A=Attribute, T=Zeitstempel, E=erweiterte Attribute, X=alternative Datenstroeme ueberspringen. Standard DA. DAT erhaelt auch die Ordner-Zeitstempel.' }
    @{ Name = 'NODCOPY'; Group = 'Dateiinfos & Attribute'; Type = 'Switch'; Exclusive = 'DirInfo'; Help = 'Kopiert keine Verzeichnisinformationen (Standard waere /DCOPY:DA).' }
    @{ Name = 'SECFIX'; Group = 'Dateiinfos & Attribute'; Type = 'Switch'; Help = 'Korrigiert die Berechtigungen aller Dateien, auch der uebersprungenen.' }
    @{ Name = 'TIMFIX'; Group = 'Dateiinfos & Attribute'; Type = 'Switch'; Help = 'Korrigiert die Zeitstempel aller Dateien, auch der uebersprungenen.' }
    @{ Name = 'A+'; Group = 'Dateiinfos & Attribute'; Type = 'Flags'; Letters = 'RASHCNET'; Help = 'Setzt diese Attribute an den kopierten Dateien: R=Schreibgeschuetzt, A=Archiv, S=System, H=Versteckt, C=Komprimiert, N=Nicht indiziert, E=Verschluesselt, T=Temporaer.' }
    @{ Name = 'A-'; Group = 'Dateiinfos & Attribute'; Type = 'Flags'; Letters = 'RASHCNETO'; Help = 'Entfernt diese Attribute an den kopierten Dateien (O = Offline). Typisch: A- R, um den Schreibschutz von CD-Kopien zu entfernen.' }

    # --- Loeschen & Verschieben ----------------------------------------------------------------
    @{ Name = 'PURGE'; Group = 'Loeschen & Verschieben'; Type = 'Switch'; Danger = $true; Help = 'LOESCHT Zieldateien und -verzeichnisse, die es in der Quelle nicht mehr gibt. Mit /E entspricht das /MIR.' }
    @{ Name = 'MOV'; Group = 'Loeschen & Verschieben'; Type = 'Switch'; Exclusive = 'Move'; Danger = $true; Help = 'Verschiebt Dateien: LOESCHT sie nach erfolgreichem Kopieren in der Quelle. Verzeichnisse bleiben stehen.' }
    @{ Name = 'MOVE'; Group = 'Loeschen & Verschieben'; Type = 'Switch'; Exclusive = 'Move'; Danger = $true; Help = 'Verschiebt Dateien UND Verzeichnisse: LOESCHT beides nach dem Kopieren in der Quelle.' }

    # --- Dateiauswahl ---------------------------------------------------------------------------
    @{ Name = 'XF'; Group = 'Dateiauswahl'; Type = 'List'; Picker = 'Files'; Help = 'Schliesst Dateien aus (Namen, Pfade oder Platzhalter wie *.tmp). Mehrere Eintraege mit ; trennen.' }
    @{ Name = 'XD'; Group = 'Dateiauswahl'; Type = 'List'; Picker = 'Folders'; Help = 'Schliesst Verzeichnisse aus (Namen oder vollstaendige Pfade, Platzhalter erlaubt). Mehrere Eintraege mit ; trennen.' }
    @{ Name = 'A'; Group = 'Dateiauswahl'; Type = 'Switch'; Exclusive = 'Archive'; Help = 'Kopiert nur Dateien mit gesetztem Archiv-Attribut.' }
    @{ Name = 'M'; Group = 'Dateiauswahl'; Type = 'Switch'; Exclusive = 'Archive'; Help = 'Kopiert nur Dateien mit Archiv-Attribut und setzt es danach in der Quelle zurueck (inkrementelle Sicherung).' }
    @{ Name = 'IA'; Group = 'Dateiauswahl'; Type = 'Flags'; Letters = 'RASHCNETO'; Help = 'Nur Dateien, bei denen mindestens eines dieser Attribute gesetzt ist.' }
    @{ Name = 'XA'; Group = 'Dateiauswahl'; Type = 'Flags'; Letters = 'RASHCNETO'; Help = 'Schliesst Dateien aus, bei denen eines dieser Attribute gesetzt ist (z.B. SH = System und Versteckt).' }
    @{ Name = 'XC'; Group = 'Dateiauswahl'; Type = 'Switch'; Help = 'Schliesst geaenderte Dateien aus (gleicher Zeitstempel, andere Groesse).' }
    @{ Name = 'XN'; Group = 'Dateiauswahl'; Type = 'Switch'; Help = 'Schliesst neuere Dateien aus: eine Quelldatei, die neuer als die Zieldatei ist, wird NICHT kopiert.' }
    @{ Name = 'XO'; Group = 'Dateiauswahl'; Type = 'Switch'; Help = 'Schliesst aeltere Dateien aus: eine Zieldatei, die neuer ist als die Quelldatei, wird nicht ueberschrieben.' }
    @{ Name = 'XX'; Group = 'Dateiauswahl'; Type = 'Switch'; Help = 'Schliesst zusaetzliche Dateien/Verzeichnisse aus (nur im Ziel vorhanden). Schuetzt sie zusammen mit /MIR oder /PURGE vor dem Loeschen.' }
    @{ Name = 'XL'; Group = 'Dateiauswahl'; Type = 'Switch'; Help = 'Schliesst "einsame" Dateien/Verzeichnisse aus (nur in der Quelle vorhanden) - aktualisiert also nur, was im Ziel schon existiert.' }
    @{ Name = 'IS'; Group = 'Dateiauswahl'; Type = 'Switch'; Help = 'Schliesst identische Dateien ein: kopiert auch Dateien, die im Ziel schon gleich vorhanden sind.' }
    @{ Name = 'IT'; Group = 'Dateiauswahl'; Type = 'Switch'; Help = 'Schliesst "optimierte" Dateien ein (gleiche Daten, abweichende Attribute).' }
    @{ Name = 'IM'; Group = 'Dateiauswahl'; Type = 'Switch'; Help = 'Schliesst Dateien mit abweichender Aenderungszeit (Change Time) ein.' }
    @{ Name = 'MAX'; Group = 'Dateiauswahl'; Type = 'Bytes'; Help = 'Maximale Dateigroesse in Bytes - groessere Dateien werden ausgeschlossen. robocopy akzeptiert hier KEIN K/M/G.' }
    @{ Name = 'MIN'; Group = 'Dateiauswahl'; Type = 'Bytes'; Help = 'Minimale Dateigroesse in Bytes - kleinere Dateien werden ausgeschlossen.' }
    @{ Name = 'MAXAGE'; Group = 'Dateiauswahl'; Type = 'Age'; Help = 'Maximales Dateialter: schliesst Dateien aus, die aelter sind. Zahl < 1900 = Tage, sonst Datum JJJJMMTT.' }
    @{ Name = 'MINAGE'; Group = 'Dateiauswahl'; Type = 'Age'; Help = 'Minimales Dateialter: schliesst Dateien aus, die neuer sind. Zahl < 1900 = Tage, sonst Datum JJJJMMTT.' }
    @{ Name = 'MAXLAD'; Group = 'Dateiauswahl'; Type = 'Age'; Help = 'Maximales Datum des letzten Zugriffs: schliesst Dateien aus, die seit n nicht benutzt wurden.' }
    @{ Name = 'MINLAD'; Group = 'Dateiauswahl'; Type = 'Age'; Help = 'Minimales Datum des letzten Zugriffs: schliesst Dateien aus, die seit n benutzt wurden.' }
    @{ Name = 'FFT'; Group = 'Dateiauswahl'; Type = 'Switch'; Help = 'FAT-Zeitstempel annehmen (2 Sekunden Genauigkeit). Noetig fuer NAS / Linux-Freigaben, sonst wird jedes Mal alles neu kopiert.' }
    @{ Name = 'DST'; Group = 'Dateiauswahl'; Type = 'Switch'; Help = 'Gleicht Zeitunterschiede von genau einer Stunde (Sommerzeit) aus.' }
    @{ Name = 'XJ'; Group = 'Dateiauswahl'; Type = 'Switch'; Help = 'Schliesst Links und Junctions aus (Dateien und Verzeichnisse). Verhindert Endlosschleifen z.B. bei Benutzerprofilen.' }
    @{ Name = 'XJD'; Group = 'Dateiauswahl'; Type = 'Switch'; Help = 'Schliesst symbolische Links und Junctions fuer Verzeichnisse aus.' }
    @{ Name = 'XJF'; Group = 'Dateiauswahl'; Type = 'Switch'; Help = 'Schliesst symbolische Links fuer Dateien aus.' }

    # --- Wiederholung -----------------------------------------------------------------------------
    @{ Name = 'R'; Group = 'Wiederholung'; Type = 'Int'; Min = 0; Max = 1000000; Default = '1000000'; Help = 'Wiederholungen bei Fehlern. Der Standard 1 Million laesst einen Job bei einer gesperrten Datei praktisch ewig haengen - fast immer explizit setzen (z.B. 3).' }
    @{ Name = 'W'; Group = 'Wiederholung'; Type = 'Int'; Min = 0; Max = 86400; Default = '30'; Help = 'Wartezeit in Sekunden zwischen den Wiederholungen. Standard 30.' }
    @{ Name = 'REG'; Group = 'Wiederholung'; Type = 'Switch'; Help = 'Speichert /R und /W als Standard in der Registrierung (HKCU) - wirkt danach auf alle robocopy-Aufrufe dieses Benutzers.' }
    @{ Name = 'TBD'; Group = 'Wiederholung'; Type = 'Switch'; Help = 'Wartet, bis Freigabenamen definiert sind (Wiederholung bei Fehler 67).' }
    @{ Name = 'LFSM'; Group = 'Wiederholung'; Type = 'Opt'; ValueKind = 'Size'; Help = 'Modus "wenig freier Speicherplatz": robocopy pausiert, wenn eine Kopie den freien Platz im Ziel unter die Untergrenze druecken wuerde. Optional Untergrenze n[K|M|G], ohne Wert 10 % des Volumes.' }

    # --- Drosselung & Zeitplan -------------------------------------------------------------------
    @{ Name = 'IPG'; Group = 'Drosselung & Zeitplan'; Type = 'Int'; Min = 1; Max = 60000; Help = 'Pause in Millisekunden zwischen Paketen (64 KB), um Bandbreite auf langsamen Leitungen freizugeben. Nicht mit /MT kombinierbar.' }
    @{ Name = 'IoMaxSize'; Group = 'Drosselung & Zeitplan'; Type = 'Size'; Help = 'Maximale E/A-Groesse je Lese-/Schreibzyklus in n[K|M|G] Bytes.' }
    @{ Name = 'IoRate'; Group = 'Drosselung & Zeitplan'; Type = 'Size'; Help = 'Angestrebte E/A-Rate in n[K|M|G] Bytes pro Sekunde (z.B. 50M) - begrenzt die Last auf Quelle und Ziel.' }
    @{ Name = 'Threshold'; Group = 'Drosselung & Zeitplan'; Type = 'Size'; Help = 'Dateigroesse in n[K|M|G] Bytes, ab der die Drosselung (/IoRate, /IoMaxSize) greift.' }
    @{ Name = 'RH'; Group = 'Drosselung & Zeitplan'; Type = 'Hours'; Help = 'Ausfuehrungszeiten hhmm-hhmm: neue Kopien starten nur in diesem Fenster (z.B. 2200-0600), sonst wartet robocopy.' }
    @{ Name = 'PF'; Group = 'Drosselung & Zeitplan'; Type = 'Switch'; Help = 'Prueft die Ausfuehrungszeiten (/RH) je Datei statt je Durchlauf.' }
    @{ Name = 'MON'; Group = 'Drosselung & Zeitplan'; Type = 'Int'; Min = 1; Max = 1000000; Help = 'Ueberwacht die Quelle und laeuft erneut, sobald mehr als n Aenderungen erkannt werden. robocopy endet dann NICHT von selbst.' }
    @{ Name = 'MOT'; Group = 'Drosselung & Zeitplan'; Type = 'Int'; Min = 1; Max = 100000; Help = 'Ueberwacht die Quelle und laeuft nach m Minuten erneut, wenn sich etwas geaendert hat. robocopy endet dann NICHT von selbst.' }

    # --- Protokoll -------------------------------------------------------------------------------
    @{ Name = 'L'; Group = 'Protokoll'; Type = 'Switch'; Help = 'Nur auflisten: es wird nichts kopiert, geloescht oder mit Zeitstempel versehen. Ideal als Trockenlauf.' }
    @{ Name = 'LOG'; Group = 'Protokoll'; Type = 'Path'; Picker = 'SaveLog'; Exclusive = 'Log'; Help = 'Schreibt die Ausgabe in eine Protokolldatei (ueberschreibt sie). Ohne /TEE erscheint dann nichts mehr in der Konsole.' }
    @{ Name = 'LOG+'; Group = 'Protokoll'; Type = 'Path'; Picker = 'SaveLog'; Exclusive = 'Log'; Help = 'Haengt die Ausgabe an eine vorhandene Protokolldatei an.' }
    @{ Name = 'UNILOG'; Group = 'Protokoll'; Type = 'Path'; Picker = 'SaveLog'; Exclusive = 'Log'; Help = 'Protokolldatei als Unicode (ueberschreibt sie). Noetig, wenn Dateinamen Zeichen ausserhalb der Codepage enthalten.' }
    @{ Name = 'UNILOG+'; Group = 'Protokoll'; Type = 'Path'; Picker = 'SaveLog'; Exclusive = 'Log'; Help = 'Haengt als Unicode an eine vorhandene Protokolldatei an.' }
    @{ Name = 'TEE'; Group = 'Protokoll'; Type = 'Switch'; Help = 'Ausgabe zusaetzlich zur Protokolldatei auch in der Konsole.' }
    @{ Name = 'NP'; Group = 'Protokoll'; Type = 'Switch'; Help = 'Kein Fortschritt in Prozent. Fuer Protokolldateien fast immer sinnvoll, sonst stehen dort tausende Prozentangaben.' }
    @{ Name = 'ETA'; Group = 'Protokoll'; Type = 'Switch'; Help = 'Zeigt die voraussichtliche Ankunftszeit der kopierten Dateien.' }
    @{ Name = 'X'; Group = 'Protokoll'; Type = 'Switch'; Help = 'Meldet alle zusaetzlichen Dateien (nur im Ziel), nicht nur die ausgewaehlten.' }
    @{ Name = 'V'; Group = 'Protokoll'; Type = 'Switch'; Help = 'Ausfuehrliche Ausgabe, auch uebersprungene Dateien.' }
    @{ Name = 'TS'; Group = 'Protokoll'; Type = 'Switch'; Help = 'Gibt die Zeitstempel der Quelldateien aus.' }
    @{ Name = 'FP'; Group = 'Protokoll'; Type = 'Switch'; Help = 'Gibt den vollstaendigen Pfad der Dateien aus.' }
    @{ Name = 'BYTES'; Group = 'Protokoll'; Type = 'Switch'; Help = 'Groessen in Bytes statt k/m/g.' }
    @{ Name = 'NS'; Group = 'Protokoll'; Type = 'Switch'; Help = 'Keine Dateigroessen protokollieren.' }
    @{ Name = 'NC'; Group = 'Protokoll'; Type = 'Switch'; Help = 'Keine Dateiklassen (Neue Datei, Aelter, ...) protokollieren.' }
    @{ Name = 'NFL'; Group = 'Protokoll'; Type = 'Switch'; Help = 'Keine Dateiliste - Dateinamen werden nicht protokolliert.' }
    @{ Name = 'NDL'; Group = 'Protokoll'; Type = 'Switch'; Help = 'Keine Verzeichnisliste - Verzeichnisnamen werden nicht protokolliert.' }
    @{ Name = 'NJH'; Group = 'Protokoll'; Type = 'Switch'; Help = 'Kein Auftragskopf.' }
    @{ Name = 'NJS'; Group = 'Protokoll'; Type = 'Switch'; Help = 'Keine Auftragszusammenfassung (Statistik am Ende).' }
    @{ Name = 'UNICODE'; Group = 'Protokoll'; Type = 'Switch'; Help = 'Gibt den Status als Unicode aus.' }

    # --- Auftragsdatei ---------------------------------------------------------------------------
    @{ Name = 'JOB'; Group = 'Auftragsdatei'; Type = 'Path'; Picker = 'OpenJob'; Help = 'Liest weitere Parameter aus einer robocopy-Auftragsdatei (.RCJ).' }
    @{ Name = 'SAVE'; Group = 'Auftragsdatei'; Type = 'Path'; Picker = 'SaveJob'; Help = 'Speichert die Parameter in eine Auftragsdatei (.RCJ). Hinweis: robocopy speichert dabei z.B. /MT, /IoRate und /LFSM nicht mit.' }
    @{ Name = 'QUIT'; Group = 'Auftragsdatei'; Type = 'Switch'; Help = 'Beendet robocopy nach dem Auswerten der Befehlszeile (nur Parameter anzeigen, z.B. zusammen mit /SAVE).' }
    @{ Name = 'NOSD'; Group = 'Auftragsdatei'; Type = 'Switch'; Help = 'Kein Quellverzeichnis angegeben (kommt aus der Auftragsdatei).' }
    @{ Name = 'NODD'; Group = 'Auftragsdatei'; Type = 'Switch'; Help = 'Kein Zielverzeichnis angegeben (kommt aus der Auftragsdatei).' }
)

function Get-srgParameterDefinition {
    foreach ($p in $script:srgParameters) { [pscustomobject]$p }
}

function Get-srgParameterLookup {
    # Name -> Definition, unabhaengig von Gross-/Kleinschreibung
    if (-not $script:srgLookup) {
        $script:srgLookup = @{}
        foreach ($d in Get-srgParameterDefinition) { $script:srgLookup[$d.Name] = $d }
    }
    $script:srgLookup
}

# robocopy-Exitcode ist eine Bitmaske. Bewusst eine Liste von Hashtables: ein [ordered]-Dictionary mit
# int-Schluesseln wuerde bei $d[1] nach POSITION indizieren, verschachtelte Arrays rollt PowerShell aus.
$script:srgExitBits = @(
    @{ Bit = 1; Text = 'Dateien kopiert' }
    @{ Bit = 2; Text = 'zusaetzliche Dateien/Verzeichnisse im Ziel' }
    @{ Bit = 4; Text = 'abweichende Dateien/Verzeichnisse (Mismatch)' }
    @{ Bit = 8; Text = 'einige Dateien/Verzeichnisse konnten NICHT kopiert werden' }
    @{ Bit = 16; Text = 'schwerer Fehler - robocopy hat nichts kopiert (Parameter, Zugriff, Pfad)' }
)