2026-07-10 09:18:49 +02:00
2025-10-15 14:56:07 +02:00
2026-03-16 14:33:28 +01:00
2026-03-16 14:33:28 +01:00
2026-07-10 09:02:32 +02:00

LIAM

Naming Conventions fuer NTFS-Gruppen

NTFS-Namenskonventionen bestehen aus NamingTemplate, DescriptionTemplate und Wildcard. Die Templates werden beim Erzeugen oder Sicherstellen von AD-Gruppen materialisiert. Der Wildcard ist eine regulaere Expression und wird beim Auslesen der ACLs verwendet, um vorhandene Gruppen wieder einer Rolle zuzuordnen.

Die wichtigsten Eingaben fuer die Ersetzung sind:

Quelle Beispiel
RootPath \\SRVWSM001.imagoverum.com\file_shares\share2
Aktuelle DataArea \\SRVWSM001.imagoverum.com\file_shares\share2\test33
CustomTags Filesystem_GroupGlobalTag=UG, Filesystem_GroupDomainLocalTag=FS, Filesystem_GroupOwnerTag=_OW
Rolle / Scope z. B. Owner und DomainLocal

Standard-Platzhalter

Platzhalter Wirkung Beispielwert bei Root \\server\file_shares\share2 und DataArea ...\share2\test33
{{NAME}} Name des aktuellen Ordners oder Shares. test33
{{RELATIVEPATH}} Relativer Pfad der DataArea unterhalb des RootPath, mit Sanitizing und konfiguriertem Segmenttrenner. test33
{{RELATIVEPATH(0)}} Letztes relatives Pfadsegment. test33
{{RELATIVEPATH(1)}} Die letzten zwei relativen Pfadsegmente. Bei weniger Segmenten werden alle vorhandenen verwendet. z. B. team1_test33
{{ROOT_SERVER}} Server-/Namespace-Teil des UNC-RootPath. server
{{ROOT_NAME}} Letztes Segment des RootPath. share2
{{ROOT_PATH}} Alle RootPath-Segmente ohne Server, mit Segmenttrenner verbunden. file_shares_share2
{{ROOT_PATH(1)}} Letztes RootPath-Segment. share2
{{ROOT_PATH(2)}} Letzte zwei RootPath-Segmente. file_shares_share2
{{ROOT_SEGMENT(0)}} RootPath-Segment per 0-basierter Position, ohne Server. file_shares
{{ROOT_SEGMENT(1)}} Zweites RootPath-Segment. share2

{{RELATIVEPATH(n)}} zaehlt von hinten: 0 ist das letzte Segment, 1 sind die letzten zwei Segmente, 2 die letzten drei Segmente usw. {{ROOT_PATH(n)}} verwendet dagegen die letzten n Segmente des RootPath.

Wenn die aktuelle DataArea dem RootPath selbst entspricht, ist {{RELATIVEPATH}} leer. {{NAME}} ist dann der Name des RootPath, also z. B. share2 oder LEI.01.test.

Rollen- und Scope-Platzhalter

Diese Platzhalter werden aus Rolle, Scope und CustomTags aufgebaut:

Platzhalter Wirkung Typische Werte
{{PREFIX}} Gruppenprefix aus Filesystem_GroupPrefixTag, fallback auf ADGroupPrefix. ACL, FS
{{SCOPETAG}} Scope-Tag. Bei Global aus Filesystem_GroupGlobalTag, bei DomainLocal aus Filesystem_GroupDomainLocalTag. UG, FS, G, DL
{{GROUPTYPEPOSTFIX}} Rollen-Postfix. Owner/Write/Read/Traverse verwenden die jeweiligen Filesystem_Group*Tag Werte. _OW, _RW, _R, _T
{{_LOOP}} Optionaler Eindeutigkeitszaehler. Beim ersten Versuch leer, danach _1, _2, usw. leer, _1, _2
{{LOOP}} Variante ohne Trennzeichen. Beim ersten Versuch leer, danach 1, 2, usw. leer, 1, 2

Der Loop-Platzhalter ist flexibel: Alles innerhalb der geschweiften Klammern, das LOOP enthaelt, wird als Loop-Tag behandelt. {{-LOOP}} wird beim ersten Versuch leer und danach z. B. -1.

CustomTags

Alle Eintraege aus CustomTags koennen ebenfalls direkt verwendet werden. Die Schreibweise muss exakt zum Key passen.

Beispiele:

{{ADGroupPrefix}}_{{RELATIVEPATH}}{{GROUPTYPEPOSTFIX}}
{{Filesystem_GroupGlobalTag}}_{{ROOT_NAME}}_{{NAME}}{{GROUPTYPEPOSTFIX}}
{{Filesystem_GroupDomainLocalTag}}_{{ROOT_PATH(1)}}_{{RELATIVEPATH}}{{GROUPTYPEPOSTFIX}}

Beispiele fuer NamingTemplate

Share-basierte Gruppen nur mit Share-Name:

{{SCOPETAG}}_{{NAME}}{{_LOOP}}{{GROUPTYPEPOSTFIX}}

Bei RootPath=\\intra.brkr.corp\File_Shares\LEI.01.test, Scope DomainLocal, Filesystem_GroupDomainLocalTag=FS und Rolle Owner entsteht:

FS_LEI.01.TEST_OW

Gruppen fuer Unterordner relativ zum Root:

{{SCOPETAG}}_{{RELATIVEPATH}}{{_LOOP}}{{GROUPTYPEPOSTFIX}}

Bei RootPath=\\SRVWSM001.imagoverum.com\file_shares\share2 und DataArea ...\share2\test33 entsteht fuer Owner:

FS_TEST33_OW

Root-Share und Unterordner kombinieren:

{{SCOPETAG}}_{{ROOT_NAME}}.{{RELATIVEPATH}}{{_LOOP}}{{GROUPTYPEPOSTFIX}}

Bei Root share2 und Ordner test33 entsteht:

FS_SHARE2.TEST33_OW

Nur die letzten zwei relativen Pfadsegmente verwenden:

{{SCOPETAG}}_{{RELATIVEPATH(1)}}{{_LOOP}}{{GROUPTYPEPOSTFIX}}

Bei ...\share2\team1\test33 entsteht:

FS_TEAM1_TEST33_OW

Namespace-/Share-Bestandteile aus dem RootPath verwenden:

{{SCOPETAG}}_{{ROOT_SEGMENT(0)}}_{{ROOT_SEGMENT(1)}}_{{NAME}}{{GROUPTYPEPOSTFIX}}

Bei Root \\SRVWSM001.imagoverum.com\file_shares\share2 und Name test33 entsteht:

FS_FILE_SHARES_SHARE2_TEST33_OW

Beispiele fuer AGP und AGDLP

Bei AGP liegen die Global-Gruppen direkt auf der ACL. Eine typische Konvention ist:

NamingTemplate: {{SCOPETAG}}_{{NAME}}{{_LOOP}}{{GROUPTYPEPOSTFIX}}
Scope: Global

Bei AGDLP liegen die DomainLocal-Gruppen auf der ACL, die Global-Gruppen werden darin verschachtelt. Typisch ist:

Global NamingTemplate:      {{SCOPETAG}}_{{NAME}}{{_LOOP}}{{GROUPTYPEPOSTFIX}}
DomainLocal NamingTemplate: {{SCOPETAG}}_{{NAME}}{{_LOOP}}{{GROUPTYPEPOSTFIX}}

Mit Filesystem_GroupGlobalTag=UG und Filesystem_GroupDomainLocalTag=FS entstehen z. B.:

UG_LEI.01.TEST_OW
FS_LEI.01.TEST_OW

In diesem Fall gehoert bei AGDLP die FS_... DomainLocal-Gruppe auf die NTFS-ACL; UG_... wird Mitglied der FS_... Gruppe.

Wildcard-Regeln

Wildcard ist eine regulaere Expression. Sie muss nach Platzhalterersetzung zum erzeugten oder vorhandenen sAMAccountName passen.

Passendes Beispiel:

^{{SCOPETAG}}_[a-zA-ZoeaeueOeAeUess0-9_\-\.]*{{GROUPTYPEPOSTFIX}}$

Mit SCOPETAG=FS und GROUPTYPEPOSTFIX=_OW matcht das:

FS_LEI.01.TEST_OW

Nicht passend ist ein fuehrendes Leerzeichen:

^ {{SCOPETAG}}_[a-zA-ZoeaeueOeAeUess0-9_\-\.]*{{GROUPTYPEPOSTFIX}}$

Dieser Regex erwartet nach ^ ein Leerzeichen und matcht deshalb nicht auf FS_LEI.01.TEST_OW.

Wenn eine Traverse-Naming-Convention keine Gruppe erzeugen soll, kann das NamingTemplate leer bleiben. Fuer Owner/Write/Read sollte der Wildcard nicht leer sein. Ein leerer Regex ist keine sinnvolle Matching-Regel, weil er technisch sehr breit matchen kann.

Sanitizing, Laenge und Grossschreibung

Pfadbasierte Platzhalter wie {{NAME}}, {{RELATIVEPATH}}, {{ROOT_PATH}} und {{ROOT_SEGMENT(n)}} werden fuer AD-Gruppennamen bereinigt. Standardmaessig werden Steuerzeichen und die fuer AD-Gruppennamen bzw. sAMAccountName problematischen Zeichen /, \, [, ], :, ;, |, =, ,, +, *, ?, < und > mit _ ersetzt. Das Ersatzzeichen kann ueber NtfsGroupNameSanitizeReplacement geaendert oder entfernt werden. Zeichen wie Leerzeichen, Bindestrich, Punkt, Unterstrich, Klammern, @ und Quotes bleiben erhalten.

Generierte AD-Gruppennamen werden standardmaessig in Grossbuchstaben geschrieben. Mit PreserveNtfsAdGroupNameCase=1 bleibt die Schreibweise erhalten.

AD-Gruppennamen werden auf die maximale Laenge von 64 Zeichen begrenzt. Wenn ein Template mit {{RELATIVEPATH}} oder {{NAME}} zu lang wird, werden Pfadbestandteile gekuerzt. Fuer Loop-Platzhalter werden bis zu drei Ziffern reserviert.

AdditionalParameters / AdditionalConfiguration

Provider-spezifische Zusatzparameter werden in Matrix42 am DataArea-Collector ueber das Fragment C4IT_GCC_DataArea_Collector_AdditionalAttributes gepflegt. Pro Parameter wird ein Eintrag mit Name und Value angelegt.

Beispiel:

Name Value
EnsureNtfsPermissionGroups 1
NtfsAdDomainControllers dc01.contoso.local,dc02.contoso.local

Im Diagnose-JSON erscheinen diese Werte unter AdditionalConfiguration. Parameternamen werden ohne Beachtung der Gross-/Kleinschreibung gelesen. Boolean-Werte sind in der Regel aktiv, wenn der Wert true, 1 oder yes ist. Leere oder nicht vorhandene Werte deaktivieren den jeweiligen Schalter, sofern unten nichts anderes beschrieben ist.

Allgemein

Parameter Provider Werte Wirkung
WhatIf Workflow / alle Provider, soweit unterstuetzt true, 1, yes Aktiviert den Simulationsmodus fuer Workflow-Pfade, die WhatIf unterstuetzen. Aktionen werden dann vorbereitet und protokolliert, aber nicht dauerhaft ausgefuehrt.

NTFS

Parameter Werte Wirkung
EnsureNtfsPermissionGroups true, 1, yes Stellt beim Auslesen von NTFS-Ordnern automatisch fehlende AD-Berechtigungsgruppen und NTFS-ACLs sicher.
EnsureNtfsPermissionGroupsForShares true, 1, yes Erweitert das automatische Ensure auf Share-DataAreas. Ohne diesen Parameter wird das automatische Ensure nur fuer Ordner ausgefuehrt.
EnsureNtfsTraverseGroups true, 1, yes Aktiviert die automatische Traverse-Gruppenverarbeitung als eigene Phase. Traverse-Gruppen und Traverse-ACLs werden sichergestellt; vorhandene LIAM-Owner/Write/Read-Globalgruppen werden in die naechste Traverse-Gruppe aufgenommen.
AllowManualNtfsPermissionEnsureForShares true, 1, yes Erlaubt die manuelle Ensure-Aktivitaet auch fuer Share-DataAreas.
NtfsIncludePaths Pfadliste, getrennt mit ;, | oder Zeilenumbruechen Beschraenkt die NTFS-Verarbeitung auf passende Pfade. Unterstuetzt relative Pfade unterhalb des RootPath, absolute UNC-Pfade und einfache Wildcards mit *. Wenn der Parameter leer ist, sind alle Pfade eingeschlossen.
NtfsExcludePaths Pfadliste, getrennt mit ;, | oder Zeilenumbruechen Schliesst passende Pfade von der NTFS-Verarbeitung aus. Excludes gewinnen gegen Includes. Unterstuetzt relative Pfade, absolute UNC-Pfade und einfache Wildcards mit *.
NtfsTraverseBoundaryPath Relativer oder absoluter Pfad Setzt eine Traverse-Grenze fuer die Traverse-Gruppenverarbeitung. Damit koennen Traverse-Gruppen ueber den eigentlichen Einsprung hinaus bis zu einer definierten Ebene sichergestellt werden. Der Boundary-Pfad selbst darf ebenfalls als Traverse-Ziel verarbeitet werden.
NtfsPermissionGroupsMinLevel / NtfsPermissionGroupsMaxLevel Ganzzahl, z. B. 0, 1, 2 Optionaler Levelbereich fuer Owner/Write/Read-Ensure. Ebene 0 ist der RootPath; Unterordner sind 1, 2, 3, ... Wenn beide Parameter leer sind, bleibt das bisherige Verhalten unveraendert.
NtfsTraverseGroupsMinLevel / NtfsTraverseGroupsMaxLevel Ganzzahl, z. B. -1, 0, 2 Optionaler Levelbereich fuer Traverse-Ensure. Ebene 0 ist der RootPath; Parent-Pfade oberhalb des RootPath sind -1, -2, ... Wenn NtfsTraverseGroupsMaxLevel nicht gesetzt ist, wird fuer Traverse implizit MaxDepth - 1 verwendet.
NtfsGroupNameSanitizeReplacement Zeichenfolge, z. B. _, ., leer, none, remove, <empty> Legt fest, womit ungueltige Zeichen in dynamischen gruppennamenrelevanten Pfadbestandteilen ersetzt werden. Standard ist _. Mit leerem Wert oder none/remove/<empty> werden ungueltige Zeichen entfernt und Pfadsegmente ohne Trennzeichen verbunden.
PreserveNtfsAdGroupNameCase true, 1, yes Unterbindet das automatische Uppercase fuer generierte NTFS-AD-Gruppennamen. Ohne diesen Parameter werden generierte Gruppennamen wie bisher in Grossbuchstaben erzeugt.
ForceStrictAdGroupNames true, 1, yes Erzwingt strikte AD-Gruppennamen. Wildcard-/ACL-basierte Wiederverwendung abweichender bestehender Gruppen wird damit eingeschraenkt; es werden nur exakt passende konfigurierte oder generierte Namen verwendet.
NtfsAdDomainControllers Kommagetrennte DC-Liste, z. B. dc01.contoso.local,dc02.contoso.local Pinnt NTFS-AD-Operationen auf einen Domain Controller. Der erste erreichbare DC wird verwendet. Wenn kein Eintrag erreichbar ist oder der Parameter fehlt, wird der PDC Emulator verwendet; danach faellt der Code auf die normale Domain-Locator-Logik zurueck. Der ausgewaehlte DC wird im Debug-Log protokolliert.

Beispiele:

EnsureNtfsPermissionGroups=1
EnsureNtfsPermissionGroupsForShares=1
EnsureNtfsTraverseGroups=1
NtfsIncludePaths=Finance\*;HR\Reports
NtfsExcludePaths=*\_archive\*
NtfsTraverseBoundaryPath=\\fileserver\file_shares
NtfsPermissionGroupsMinLevel=1
NtfsPermissionGroupsMaxLevel=2
NtfsTraverseGroupsMinLevel=-1
NtfsTraverseGroupsMaxLevel=2
NtfsGroupNameSanitizeReplacement=.
PreserveNtfsAdGroupNameCase=1
NtfsAdDomainControllers=dc01.contoso.local,dc02.contoso.local

Automatisches NTFS-Ensure

Beim Auslesen der NTFS-DataAreas kann LIAM Gruppen und ACLs automatisch sicherstellen. Die automatische Verarbeitung ist bewusst fehlertolerant: Wenn ein einzelner DataArea-Pfad wegen Whitelist, Blacklist, fehlendem Verzeichnis oder Providerfehler nicht verarbeitet werden kann, wird dieser Pfad im Log als Warning uebersprungen und die naechste DataArea weiter verarbeitet.

Die Schalter koennen kombiniert werden:

Konfiguration Verhalten
EnsureNtfsPermissionGroups=1 Erstellt oder reused Owner/Write/Read-Gruppen und setzt die passenden NTFS-ACLs fuer Ordner. Das bestehende Verhalten mit eingebetteter Traverse-Verarbeitung bleibt aktiv, solange EnsureNtfsTraverseGroups nicht gesetzt ist.
EnsureNtfsPermissionGroups=1 und EnsureNtfsPermissionGroupsForShares=1 Wie oben, aber auch fuer Share-DataAreas.
EnsureNtfsTraverseGroups=1 Fuehrt eine separate Traverse-only-Phase fuer Ordner und Share-DataAreas aus. Es werden Traverse-Gruppen und Traverse-ACLs sichergestellt, aber keine Owner/Write/Read-Gruppen erzeugt.
EnsureNtfsPermissionGroups=1 und EnsureNtfsTraverseGroups=1 Fuehrt zuerst Owner/Write/Read-Ensure aus und danach die separate Traverse-only-Phase. Dadurch koennen neu angelegte Owner/Write/Read-Globalgruppen direkt in die Traverse-Gruppen aufgenommen werden. Die eingebettete Traverse-Verarbeitung im Permission-Ensure wird in diesem Modus deaktiviert, damit Traverse nicht doppelt laeuft.

Traverse-only sucht die erwarteten LIAM-Owner/Write/Read-Gruppen anhand der Naming-Conventions und bestehenden ACLs. Gefunden werden nur LIAM-Gruppen, die zur konfigurierten Wildcard passen; beliebige Legacy-ACL-Gruppen werden nicht automatisch als Traverse-Mitglieder uebernommen. Fehlende Owner/Write/Read-Gruppen werden in Traverse-only nicht angelegt, sondern als Warning protokolliert.

Fuer AGP werden die Global-Gruppen auf der ACL und als Traverse-Mitglieder verwendet. Fuer AGDLP liegen weiterhin die DomainLocal-Gruppen auf der NTFS-ACL; die Traverse-Mitgliedschaft verwendet die zugehoerigen Global-Gruppen.

Traverse-Gruppen werden lazy erzeugt: LIAM legt eine Traverse-Gruppe fuer einen Pfad nur dann an, wenn darunter mindestens eine LIAM-Owner/Write/Read-Gruppe oder eine darunterliegende Traverse-Gruppe aufgenommen werden soll. Bestehende Traverse-Gruppen werden weiterverwendet, leere neue Traverse-Gruppen ohne aktuelle Mitglieder werden aber nicht vorsorglich erzeugt.

Traverse-Grenze

NtfsTraverseBoundaryPath begrenzt, bis zu welcher Ebene Traverse-Gruppen und Traverse-ACLs sichergestellt werden. Ohne Boundary orientiert sich die Traverse-Verarbeitung an den normal verwalteten Permission-Pfaden. Mit Boundary darf die Traverse-Verarbeitung auch Pfade oberhalb des Include-Filters erreichen, solange der Pfad existiert und nicht durch NtfsExcludePaths ausgeschlossen ist.

Beispiel:

RootPath=\\intra.brkr.corp\File_Shares\BRE.01.LEW
NtfsIncludePaths=\\intra.brkr.corp\File_Shares\BRE.01.LEW\Projekte\*
NtfsTraverseBoundaryPath=\\intra.brkr.corp\File_Shares\BRE.01.LEW\Projekte
EnsureNtfsTraverseGroups=1

In diesem Beispiel koennen Traverse-Gruppen fuer ...\Projekte selbst und fuer die Ordner darunter sichergestellt werden, sobald darunter Berechtigungsgruppen oder weitere Traverse-Gruppen aufzunehmen sind. Der Boundary-Pfad selbst ist gueltig; er muss nicht zusaetzlich als NtfsIncludePaths-Match enthalten sein, solange es nur um Traverse geht.

Levelbereiche fuer Ensure und Ordneranlage

Die optionalen Levelbereiche schraenken ein, auf welchen Ebenen Gruppen und ACLs automatisch sichergestellt werden. Wenn keine Permission-Level-Parameter gesetzt sind, bleibt Owner/Write/Read unveraendert. Fuer Traverse wird ohne explizites NtfsTraverseGroupsMaxLevel automatisch MaxDepth - 1 als maximale Verarbeitungsebene verwendet.

Ebene 0 ist immer der konfigurierte RootPath. Unterordner unterhalb des RootPath haben positive Level (1, 2, 3, ...). Parent-Pfade oberhalb des RootPath haben negative Level (-1, -2, ...). Negative Level sind vor allem fuer Traverse relevant, wenn NtfsTraverseBoundaryPath oberhalb des RootPath liegt.

Beispiel:

RootPath=\\server\share\Bereich
NtfsTraverseBoundaryPath=\\server\share
NtfsPermissionGroupsMinLevel=1
NtfsPermissionGroupsMaxLevel=2
NtfsTraverseGroupsMinLevel=-1
NtfsTraverseGroupsMaxLevel=2

Damit werden Owner/Write/Read-Gruppen nur fuer \\server\share\Bereich\... auf Ebene 1 und 2 erzeugt. Traverse-Gruppen duerfen zusaetzlich bis zum Share auf Ebene -1 erzeugt werden. NtfsTraverseBoundaryPath bleibt die harte Grenze fuer Traverse; die Min-/Max-Level legen nur fest, welche Ebenen innerhalb dieses Korridors verarbeitet werden.

Die Permission-Level gelten auch fuer die explizite NTFS-Ordneranlage ueber CreateDataArea. Wenn der Zielordner ausserhalb des Permission-Levelbereichs liegt oder die Permission-Levelkonfiguration ungueltig ist, wird die Ordneranlage vor AD-/ACL-Aenderungen abgebrochen. Traverse-Level blockieren die Ordneranlage nicht; sie schraenken nur die Traverse-Gruppen und Traverse-ACLs ein.

Wenn nur ein Min- oder Max-Wert gesetzt ist, ist die andere Seite offen. Ausnahme: Fuer Traverse ist ein fehlender Max-Wert durch MaxDepth - 1 begrenzt. Ungueltige Werte oder ein Min-Wert groesser als der Max-Wert fuehren dazu, dass die betroffene Ensure-Phase mit einer Warning uebersprungen wird; bei CreateDataArea fuehrt eine ungueltige Permission-Levelkonfiguration zum Abbruch vor der Anlage.

WhatIf / Preview

Wenn WhatIf=1 gesetzt ist, fuehrt LIAM die automatische NTFS-Verarbeitung als Preview aus. Fuer Permission-Ensure und Traverse-Ensure werden geplante Gruppen, wiederverwendete Gruppen, geplante ACLs, bestehende ACLs, Traverse-Gruppen und Warnings im Ergebnis und im Debug-Log ausgegeben. Es werden keine AD-Gruppen, Gruppenmitgliedschaften oder ACLs dauerhaft geaendert.

Active Directory

Parameter Werte Wirkung
AdDomainControllers Kommagetrennte DC-Liste, z. B. dc01.contoso.local,dc02.contoso.local Pinnt Active-Directory-Provider-Operationen auf einen Domain Controller. Der erste erreichbare DC wird verwendet. Wenn kein Eintrag erreichbar ist oder der Parameter fehlt, wird der PDC Emulator verwendet; danach faellt der Code auf die normale Domain-Locator-Logik zurueck. Der ausgewaehlte DC wird im Debug-Log protokolliert.
ActiveDirectoryDomainControllers Kommagetrennte DC-Liste Alias/Fallback fuer AdDomainControllers, wenn AdDomainControllers nicht gesetzt ist.

Beispiel:

AdDomainControllers=dc01.contoso.local,dc02.contoso.local

Microsoft Teams

Parameter Werte Wirkung
WithoutPrivateChannels true, 1 Private Channels werden beim Teams-Provider nicht beruecksichtigt.

Hinweise zur Pfad- und Listen-Syntax

NtfsIncludePaths und NtfsExcludePaths verwenden ;, | oder Zeilenumbrueche als Trenner. Kommas sind dort Teil des Werts. Die Domain-Controller-Parameter verwenden dagegen eine kommagetrennte Prioritaetsliste.

Pfadfilter koennen relativ zum konfigurierten NTFS-RootPath oder als absolute UNC-Pfade angegeben werden. Einfache Wildcards mit * sind moeglich.

Description
No description provided
Readme 32 MiB
Languages
C# 95.4%
PowerShell 4.4%
Batchfile 0.2%