Add NTFS ensure level filters
This commit is contained in:
@@ -53,6 +53,20 @@ namespace C4IT.LIAM
|
|||||||
public int Level { get; set; } = -1;
|
public int Level { get; set; } = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private sealed class cNtfsLevelRange
|
||||||
|
{
|
||||||
|
public bool IsConfigured { get; set; }
|
||||||
|
public bool IsValid { get; set; } = true;
|
||||||
|
public int MinLevel { get; set; } = int.MinValue;
|
||||||
|
public int MaxLevel { get; set; } = int.MaxValue;
|
||||||
|
public string ErrorMessage { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public bool Contains(int level)
|
||||||
|
{
|
||||||
|
return !IsConfigured || level >= MinLevel && level <= MaxLevel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private sealed class cNtfsDataAreaDiagnostics
|
private sealed class cNtfsDataAreaDiagnostics
|
||||||
{
|
{
|
||||||
private const int MaxSamples = 10;
|
private const int MaxSamples = 10;
|
||||||
@@ -123,6 +137,10 @@ namespace C4IT.LIAM
|
|||||||
private const string AdditionalConfigurationExcludePathsKey = "NtfsExcludePaths";
|
private const string AdditionalConfigurationExcludePathsKey = "NtfsExcludePaths";
|
||||||
private const string AdditionalConfigurationIncludePathsKey = "NtfsIncludePaths";
|
private const string AdditionalConfigurationIncludePathsKey = "NtfsIncludePaths";
|
||||||
private const string AdditionalConfigurationTraverseBoundaryPathKey = "NtfsTraverseBoundaryPath";
|
private const string AdditionalConfigurationTraverseBoundaryPathKey = "NtfsTraverseBoundaryPath";
|
||||||
|
private const string AdditionalConfigurationPermissionGroupsMinLevelKey = "NtfsPermissionGroupsMinLevel";
|
||||||
|
private const string AdditionalConfigurationPermissionGroupsMaxLevelKey = "NtfsPermissionGroupsMaxLevel";
|
||||||
|
private const string AdditionalConfigurationTraverseGroupsMinLevelKey = "NtfsTraverseGroupsMinLevel";
|
||||||
|
private const string AdditionalConfigurationTraverseGroupsMaxLevelKey = "NtfsTraverseGroupsMaxLevel";
|
||||||
private const string AdditionalConfigurationGroupNameSanitizeReplacementKey = "NtfsGroupNameSanitizeReplacement";
|
private const string AdditionalConfigurationGroupNameSanitizeReplacementKey = "NtfsGroupNameSanitizeReplacement";
|
||||||
private const string AdditionalConfigurationPreserveAdGroupNameCaseKey = "PreserveNtfsAdGroupNameCase";
|
private const string AdditionalConfigurationPreserveAdGroupNameCaseKey = "PreserveNtfsAdGroupNameCase";
|
||||||
private const string AdditionalConfigurationAdDomainControllersKey = "NtfsAdDomainControllers";
|
private const string AdditionalConfigurationAdDomainControllersKey = "NtfsAdDomainControllers";
|
||||||
@@ -1155,6 +1173,16 @@ namespace C4IT.LIAM
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string levelSkipReason;
|
||||||
|
if (!IsPermissionLevelManagedPath(classification, out levelSkipReason))
|
||||||
|
{
|
||||||
|
return Task.FromResult(new ResultToken(System.Reflection.MethodBase.GetCurrentMethod().ToString())
|
||||||
|
{
|
||||||
|
resultErrorId = 30008,
|
||||||
|
resultMessage = levelSkipReason
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
var parentPath = Directory.GetParent(folderPath)?.FullName;
|
var parentPath = Directory.GetParent(folderPath)?.FullName;
|
||||||
var engine = CreateFilesystemEngine(
|
var engine = CreateFilesystemEngine(
|
||||||
folderPath,
|
folderPath,
|
||||||
@@ -1208,7 +1236,19 @@ namespace C4IT.LIAM
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsTraversePermissionManagedPath(folderPath))
|
var traverseLevelRange = GetTraverseLevelRange();
|
||||||
|
if (!traverseLevelRange.IsValid)
|
||||||
|
{
|
||||||
|
var message = $"NTFS traverse ensure skipped for '{folderPath}' because {traverseLevelRange.ErrorMessage}";
|
||||||
|
LogEntry(message, LogLevels.Warning);
|
||||||
|
return Task.FromResult(new ResultToken(System.Reflection.MethodBase.GetCurrentMethod().ToString())
|
||||||
|
{
|
||||||
|
resultErrorId = 30008,
|
||||||
|
resultMessage = message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsTraversePermissionCandidatePath(folderPath))
|
||||||
{
|
{
|
||||||
return Task.FromResult(new ResultToken(System.Reflection.MethodBase.GetCurrentMethod().ToString())
|
return Task.FromResult(new ResultToken(System.Reflection.MethodBase.GetCurrentMethod().ToString())
|
||||||
{
|
{
|
||||||
@@ -1355,6 +1395,16 @@ namespace C4IT.LIAM
|
|||||||
}
|
}
|
||||||
|
|
||||||
private bool IsPermissionManagedPath(string path, params eNtfsPathKind[] supportedKinds)
|
private bool IsPermissionManagedPath(string path, params eNtfsPathKind[] supportedKinds)
|
||||||
|
{
|
||||||
|
if (!IsPermissionManagedPathCandidate(path, supportedKinds))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var classification = ClassifyPath(path);
|
||||||
|
string levelSkipReason;
|
||||||
|
return IsPermissionLevelManagedPath(classification, out levelSkipReason);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsPermissionManagedPathCandidate(string path, params eNtfsPathKind[] supportedKinds)
|
||||||
{
|
{
|
||||||
var classification = ClassifyPath(path);
|
var classification = ClassifyPath(path);
|
||||||
if (!IsSupportedPermissionManagedPathKind(classification, supportedKinds))
|
if (!IsSupportedPermissionManagedPathKind(classification, supportedKinds))
|
||||||
@@ -1365,13 +1415,25 @@ namespace C4IT.LIAM
|
|||||||
if (IsPathBlacklisted(classification, out matchingConfigurationKey, out matchingRule))
|
if (IsPathBlacklisted(classification, out matchingConfigurationKey, out matchingRule))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return IsPathWhitelisted(classification, false, out matchingConfigurationKey, out matchingRule);
|
if (!IsPathWhitelisted(classification, false, out matchingConfigurationKey, out matchingRule))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsTraversePermissionManagedPath(string path)
|
private bool IsTraversePermissionManagedPath(string path)
|
||||||
|
{
|
||||||
|
if (!IsTraversePermissionCandidatePath(path))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
string levelSkipReason;
|
||||||
|
return IsTraverseLevelManagedPath(ClassifyPath(path), out levelSkipReason);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsTraversePermissionCandidatePath(string path)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(GetAdditionalConfigurationValue(AdditionalConfigurationTraverseBoundaryPathKey)))
|
if (string.IsNullOrWhiteSpace(GetAdditionalConfigurationValue(AdditionalConfigurationTraverseBoundaryPathKey)))
|
||||||
return IsPermissionManagedFolderPath(path);
|
return IsPermissionManagedPathCandidate(path, eNtfsPathKind.Folder);
|
||||||
|
|
||||||
var classification = ClassifyPath(path);
|
var classification = ClassifyPath(path);
|
||||||
if (classification == null || classification.Kind == eNtfsPathKind.ServerRoot || classification.Kind == eNtfsPathKind.Unknown)
|
if (classification == null || classification.Kind == eNtfsPathKind.ServerRoot || classification.Kind == eNtfsPathKind.Unknown)
|
||||||
@@ -1385,6 +1447,112 @@ namespace C4IT.LIAM
|
|||||||
return Directory.Exists(path);
|
return Directory.Exists(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool IsPermissionLevelManagedPath(cNtfsPathClassification classification, out string skipReason)
|
||||||
|
{
|
||||||
|
return IsLevelManagedPath(
|
||||||
|
classification,
|
||||||
|
GetPermissionLevelRange(),
|
||||||
|
"permission group ensure",
|
||||||
|
out skipReason);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsTraverseLevelManagedPath(cNtfsPathClassification classification, out string skipReason)
|
||||||
|
{
|
||||||
|
return IsLevelManagedPath(
|
||||||
|
classification,
|
||||||
|
GetTraverseLevelRange(),
|
||||||
|
"traverse group ensure",
|
||||||
|
out skipReason);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsLevelManagedPath(cNtfsPathClassification classification, cNtfsLevelRange range, string operationName, out string skipReason)
|
||||||
|
{
|
||||||
|
skipReason = string.Empty;
|
||||||
|
if (classification == null)
|
||||||
|
{
|
||||||
|
skipReason = $"NTFS {operationName} skipped because the path could not be classified.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (range == null || !range.IsConfigured)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!range.IsValid)
|
||||||
|
{
|
||||||
|
skipReason = $"NTFS {operationName} skipped for '{classification.NormalizedPath}' because {range.ErrorMessage}";
|
||||||
|
LogEntry(skipReason, LogLevels.Warning);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (range.Contains(classification.Level))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
skipReason = $"NTFS {operationName} skipped for '{classification.NormalizedPath}' because level {classification.Level} is outside configured range {range.MinLevel}..{range.MaxLevel}.";
|
||||||
|
LogEntry(skipReason, LogLevels.Debug);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private cNtfsLevelRange GetPermissionLevelRange()
|
||||||
|
{
|
||||||
|
return GetConfiguredLevelRange(
|
||||||
|
AdditionalConfigurationPermissionGroupsMinLevelKey,
|
||||||
|
AdditionalConfigurationPermissionGroupsMaxLevelKey,
|
||||||
|
"permission group level range");
|
||||||
|
}
|
||||||
|
|
||||||
|
private cNtfsLevelRange GetTraverseLevelRange()
|
||||||
|
{
|
||||||
|
return GetConfiguredLevelRange(
|
||||||
|
AdditionalConfigurationTraverseGroupsMinLevelKey,
|
||||||
|
AdditionalConfigurationTraverseGroupsMaxLevelKey,
|
||||||
|
"traverse group level range");
|
||||||
|
}
|
||||||
|
|
||||||
|
private cNtfsLevelRange GetConfiguredLevelRange(string minKey, string maxKey, string label)
|
||||||
|
{
|
||||||
|
var range = new cNtfsLevelRange();
|
||||||
|
var minValue = GetAdditionalConfigurationValue(minKey);
|
||||||
|
var maxValue = GetAdditionalConfigurationValue(maxKey);
|
||||||
|
var hasMin = !string.IsNullOrWhiteSpace(minValue);
|
||||||
|
var hasMax = !string.IsNullOrWhiteSpace(maxValue);
|
||||||
|
range.IsConfigured = hasMin || hasMax;
|
||||||
|
if (!range.IsConfigured)
|
||||||
|
return range;
|
||||||
|
|
||||||
|
int parsedValue;
|
||||||
|
if (hasMin)
|
||||||
|
{
|
||||||
|
if (!int.TryParse(minValue, out parsedValue))
|
||||||
|
{
|
||||||
|
range.IsValid = false;
|
||||||
|
range.ErrorMessage = $"AdditionalConfiguration '{minKey}' for {label} is not a valid integer: '{minValue}'.";
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
|
||||||
|
range.MinLevel = parsedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasMax)
|
||||||
|
{
|
||||||
|
if (!int.TryParse(maxValue, out parsedValue))
|
||||||
|
{
|
||||||
|
range.IsValid = false;
|
||||||
|
range.ErrorMessage = $"AdditionalConfiguration '{maxKey}' for {label} is not a valid integer: '{maxValue}'.";
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
|
||||||
|
range.MaxLevel = parsedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (range.MinLevel > range.MaxLevel)
|
||||||
|
{
|
||||||
|
range.IsValid = false;
|
||||||
|
range.ErrorMessage = $"AdditionalConfiguration {label} is invalid because min level {range.MinLevel} is greater than max level {range.MaxLevel}.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
|
||||||
private static bool IsSupportedPermissionManagedPathKind(cNtfsPathClassification classification, params eNtfsPathKind[] supportedKinds)
|
private static bool IsSupportedPermissionManagedPathKind(cNtfsPathClassification classification, params eNtfsPathKind[] supportedKinds)
|
||||||
{
|
{
|
||||||
if (classification == null || supportedKinds == null || supportedKinds.Length == 0)
|
if (classification == null || supportedKinds == null || supportedKinds.Length == 0)
|
||||||
|
|||||||
27
README.md
27
README.md
@@ -210,6 +210,8 @@ Im Diagnose-JSON erscheinen diese Werte unter `AdditionalConfiguration`. Paramet
|
|||||||
| `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. |
|
| `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 `*`. |
|
| `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. |
|
| `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 beide Parameter leer sind, bleibt das bisherige Verhalten unveraendert. |
|
||||||
| `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. |
|
| `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. |
|
| `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. |
|
| `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. |
|
||||||
@@ -224,6 +226,10 @@ EnsureNtfsTraverseGroups=1
|
|||||||
NtfsIncludePaths=Finance\*;HR\Reports
|
NtfsIncludePaths=Finance\*;HR\Reports
|
||||||
NtfsExcludePaths=*\_archive\*
|
NtfsExcludePaths=*\_archive\*
|
||||||
NtfsTraverseBoundaryPath=\\fileserver\file_shares
|
NtfsTraverseBoundaryPath=\\fileserver\file_shares
|
||||||
|
NtfsPermissionGroupsMinLevel=1
|
||||||
|
NtfsPermissionGroupsMaxLevel=2
|
||||||
|
NtfsTraverseGroupsMinLevel=-1
|
||||||
|
NtfsTraverseGroupsMaxLevel=2
|
||||||
NtfsGroupNameSanitizeReplacement=.
|
NtfsGroupNameSanitizeReplacement=.
|
||||||
PreserveNtfsAdGroupNameCase=1
|
PreserveNtfsAdGroupNameCase=1
|
||||||
NtfsAdDomainControllers=dc01.contoso.local,dc02.contoso.local
|
NtfsAdDomainControllers=dc01.contoso.local,dc02.contoso.local
|
||||||
@@ -261,6 +267,27 @@ EnsureNtfsTraverseGroups=1
|
|||||||
|
|
||||||
In diesem Beispiel koennen Traverse-Gruppen fuer `...\Projekte` selbst und fuer die Ordner darunter sichergestellt werden. Der Boundary-Pfad selbst ist gueltig; er muss nicht zusaetzlich als `NtfsIncludePaths`-Match enthalten sein, solange es nur um Traverse geht.
|
In diesem Beispiel koennen Traverse-Gruppen fuer `...\Projekte` selbst und fuer die Ordner darunter sichergestellt werden. Der Boundary-Pfad selbst ist gueltig; er muss nicht zusaetzlich als `NtfsIncludePaths`-Match enthalten sein, solange es nur um Traverse geht.
|
||||||
|
|
||||||
|
#### Levelbereiche fuer automatisches Ensure
|
||||||
|
|
||||||
|
Die optionalen Levelbereiche schraenken ein, auf welchen Ebenen Gruppen und ACLs automatisch sichergestellt werden. Wenn keiner der Level-Parameter gesetzt ist, bleibt das bisherige Verhalten unveraendert.
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
```text
|
||||||
|
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.
|
||||||
|
|
||||||
|
Wenn nur ein Min- oder Max-Wert gesetzt ist, ist die andere Seite offen. Ungueltige Werte oder ein Min-Wert groesser als der Max-Wert fuehren dazu, dass die betroffene Ensure-Phase mit einer Warning uebersprungen wird.
|
||||||
|
|
||||||
#### WhatIf / Preview
|
#### 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.
|
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.
|
||||||
|
|||||||
Reference in New Issue
Block a user