Add automatic NTFS traverse ensure

This commit is contained in:
Meik
2026-06-18 21:32:13 +02:00
parent 6abe0a690b
commit 2217a393be
3 changed files with 353 additions and 137 deletions

View File

@@ -1178,6 +1178,77 @@ namespace C4IT.LIAM
return Task.FromResult(resultToken); return Task.FromResult(resultToken);
} }
public Task<ResultToken> EnsureTraverseGroupsAsync(
string folderPath,
IDictionary<string, string> customTags = null,
bool whatIf = false)
{
var classification = ClassifyPath(folderPath);
if (!IsSupportedPermissionManagedPathKind(
classification,
eNtfsPathKind.Folder,
eNtfsPathKind.ClassicShare,
eNtfsPathKind.DfsLink))
{
return Task.FromResult(new ResultToken(System.Reflection.MethodBase.GetCurrentMethod().ToString())
{
resultErrorId = 30008,
resultMessage = $"NTFS traverse ensure is only supported for folder and share paths. DFS namespaces and server roots are skipped: {folderPath}"
});
}
string matchingConfigurationKey;
string matchingRule;
if (IsPathBlacklisted(classification, out matchingConfigurationKey, out matchingRule))
{
return Task.FromResult(new ResultToken(System.Reflection.MethodBase.GetCurrentMethod().ToString())
{
resultErrorId = 30008,
resultMessage = $"NTFS traverse ensure skipped for '{folderPath}' due to AdditionalConfiguration rule '{matchingConfigurationKey}={matchingRule}'."
});
}
if (!IsTraversePermissionManagedPath(folderPath))
{
return Task.FromResult(new ResultToken(System.Reflection.MethodBase.GetCurrentMethod().ToString())
{
resultErrorId = 30008,
resultMessage = $"NTFS traverse ensure skipped for '{folderPath}' because the path is not managed by the traverse configuration."
});
}
var parentPath = GetEngineParentPath(classification, folderPath);
var engine = CreateFilesystemEngine(
folderPath,
parentPath,
customTags,
null,
null,
null);
engine.WhatIf = whatIf;
return Task.FromResult(engine.ensureTraversePermissionsOnly());
}
private static string GetEngineParentPath(cNtfsPathClassification classification, string folderPath)
{
if (classification != null && !string.IsNullOrWhiteSpace(classification.ParentPath))
return classification.ParentPath;
if (classification != null && !string.IsNullOrWhiteSpace(classification.ParentBoundaryPath))
return classification.ParentBoundaryPath;
try
{
var parentPath = Directory.GetParent(folderPath)?.FullName;
return string.IsNullOrWhiteSpace(parentPath) ? folderPath : parentPath;
}
catch
{
return folderPath;
}
}
private DataArea_FileSystem CreateFilesystemEngine( private DataArea_FileSystem CreateFilesystemEngine(
string folderPath, string folderPath,
string parentFolderPath, string parentFolderPath,

View File

@@ -324,11 +324,11 @@ namespace C4IT_IAM_SET
if (string.IsNullOrWhiteSpace(boundaryPath)) if (string.IsNullOrWhiteSpace(boundaryPath))
return resultToken; return resultToken;
var targetParent = new DirectoryInfo(newFolderPath).Parent; var targetPath = NormalizeDirectoryPath(newFolderPath);
if (targetParent == null) if (string.IsNullOrWhiteSpace(targetPath))
{ {
resultToken.resultErrorId = 30009; resultToken.resultErrorId = 30009;
resultToken.resultMessage = $"Traverse boundary '{traverseBoundaryPath}' cannot be validated because '{newFolderPath}' has no parent directory."; resultToken.resultMessage = $"Traverse boundary '{traverseBoundaryPath}' cannot be validated because the target path is empty.";
return resultToken; return resultToken;
} }
@@ -339,10 +339,10 @@ namespace C4IT_IAM_SET
return resultToken; return resultToken;
} }
if (!IsSameOrAncestorPath(boundaryPath, targetParent.FullName)) if (!IsSameOrAncestorPath(boundaryPath, targetPath))
{ {
resultToken.resultErrorId = 30009; resultToken.resultErrorId = 30009;
resultToken.resultMessage = $"Traverse boundary '{traverseBoundaryPath}' is not a parent path of '{newFolderPath}'."; resultToken.resultMessage = $"Traverse boundary '{traverseBoundaryPath}' is not the target path or a parent path of '{newFolderPath}'.";
} }
return resultToken; return resultToken;
@@ -388,13 +388,6 @@ namespace C4IT_IAM_SET
if (ensureTraverseGroups) if (ensureTraverseGroups)
{ {
if (WhatIf)
{
resultToken.warnings.Add("Traverse group preview is not supported in WhatIf mode for automatic DataArea ensure.");
resultToken.resultMessage = "Gruppen- und ACL-Vorschau erfolgreich erstellt";
return resultToken;
}
var traverseResult = SetTraversePermissions(); var traverseResult = SetTraversePermissions();
if (traverseResult != null) if (traverseResult != null)
{ {
@@ -430,7 +423,105 @@ namespace C4IT_IAM_SET
} }
} }
private ResultToken SetTraversePermissions() public ResultToken ensureTraversePermissionsOnly()
{
LogMethodBegin(MethodBase.GetCurrentMethod());
try
{
var resultToken = checkRequiredVariablesForEnsure();
if (resultToken.resultErrorId != 0)
return resultToken;
if (Connection != null)
Connection.Dispose();
using (Connection = new cNetworkConnection(baseFolder, username, new NetworkCredential("", password).Password))
{
if (!Directory.Exists(newFolderPath))
{
resultToken.resultErrorId = 30203;
resultToken.resultMessage = "Verzeichnis existiert nicht";
return resultToken;
}
var parentDirectory = Directory.GetParent(newFolderPath);
if (string.IsNullOrWhiteSpace(newFolderParent))
newFolderParent = parentDirectory?.FullName;
InitializeFolderContext();
var traverseBoundaryResult = ValidateTraverseBoundaryForCurrentFolder();
if (traverseBoundaryResult.resultErrorId != 0)
return traverseBoundaryResult;
EnsureExistingPermissionGroupsForTraverse(resultToken);
resultToken = MergeResultTokens(resultToken, SetTraversePermissions(true));
if (resultToken.resultErrorId == 0)
{
resultToken.resultMessage = WhatIf
? "Traverse-Gruppen- und ACL-Vorschau erfolgreich erstellt"
: "Traverse-Gruppen und ACLs erfolgreich sichergestellt";
}
return resultToken;
}
}
catch (Exception E)
{
cLogManager.DefaultLogger.LogException(E);
throw;
}
finally
{
LogMethodEnd(MethodBase.GetCurrentMethod());
}
}
private void EnsureExistingPermissionGroupsForTraverse(ResultToken resultToken)
{
newSecurityGroups.IAM_SecurityGroups.Clear();
newSecurityGroups.GenerateNewSecurityGroups(baseFolder,
newDataArea.IAM_Folders[0].technicalName,
groupPrefix,
groupOUPath,
groupPermissionStrategy,
groupTraverseTag,
groupReadTag,
groupWriteTag,
groupOwnerTag,
groupDLTag,
groupGTag,
groupCustomTags,
templates,
ReadACLPermission,
WriteACLPermission,
OwnerACLPermission,
0,
0,
groupNameSanitizeReplacement,
preserveAdGroupNameCase);
var existingGroups = new List<IAM_SecurityGroup>();
foreach (var securityGroup in newSecurityGroups.IAM_SecurityGroups)
{
var existingGroup = newSecurityGroups.PreviewADGroup(groupOUPath, securityGroup, newDataArea.IAM_Folders[0].technicalName);
if (existingGroup == null || string.IsNullOrWhiteSpace(securityGroup.UID))
{
if (securityGroup.Scope == GroupScope.Global)
resultToken.warnings.Add($"Traverse-only: LIAM-Berechtigungsgruppe '{securityGroup.Name}' fehlt und wird nicht angelegt.");
continue;
}
resultToken.reusedGroups.Add(securityGroup.Name);
existingGroups.Add(securityGroup);
}
newSecurityGroups.IAM_SecurityGroups.Clear();
newSecurityGroups.IAM_SecurityGroups.AddRange(existingGroups);
}
private ResultToken SetTraversePermissions(bool includeCurrentFolder = false)
{ {
LogMethodBegin(MethodBase.GetCurrentMethod()); LogMethodBegin(MethodBase.GetCurrentMethod());
@@ -467,13 +558,13 @@ namespace C4IT_IAM_SET
DirectoryInfo newDir = new DirectoryInfo(newDataArea.IAM_Folders[0].technicalName); DirectoryInfo newDir = new DirectoryInfo(newDataArea.IAM_Folders[0].technicalName);
DefaultLogger.LogEntry(LogLevels.Debug, $"Neues Verzeichnis: {newDir.FullName}"); DefaultLogger.LogEntry(LogLevels.Debug, $"Neues Verzeichnis: {newDir.FullName}");
DirectoryInfo parent = newDir.Parent; DirectoryInfo parent = includeCurrentFolder ? newDir : newDir.Parent;
if (parent == null) if (parent == null)
{ {
DefaultLogger.LogEntry(LogLevels.Error, "Parent-Verzeichnis ist null."); DefaultLogger.LogEntry(LogLevels.Error, "Traverse-Startverzeichnis ist null.");
return resultToken; return resultToken;
} }
DefaultLogger.LogEntry(LogLevels.Debug, $"Parent-Verzeichnis: {parent.FullName}"); DefaultLogger.LogEntry(LogLevels.Debug, $"Traverse-Startverzeichnis: {parent.FullName}");
var lvl = DataArea.GetRelativePath(parent.FullName, baseFolder).Count(n => n == Path.DirectorySeparatorChar); var lvl = DataArea.GetRelativePath(parent.FullName, baseFolder).Count(n => n == Path.DirectorySeparatorChar);
DefaultLogger.LogEntry(LogLevels.Debug, $"Ebene (lvl): {lvl}"); DefaultLogger.LogEntry(LogLevels.Debug, $"Ebene (lvl): {lvl}");
@@ -519,6 +610,7 @@ namespace C4IT_IAM_SET
} }
GroupPrincipal traverseGroup = null; GroupPrincipal traverseGroup = null;
string traverseGroupName = null;
// Überprüfen, ob createTraverseGroupLvl initialisiert ist // Überprüfen, ob createTraverseGroupLvl initialisiert ist
DefaultLogger.LogEntry(LogLevels.Debug, $"createTraverseGroupLvl: {createTraverseGroupLvl}"); DefaultLogger.LogEntry(LogLevels.Debug, $"createTraverseGroupLvl: {createTraverseGroupLvl}");
@@ -583,6 +675,7 @@ namespace C4IT_IAM_SET
} }
GroupPrincipal parentTraverseGroup = null; GroupPrincipal parentTraverseGroup = null;
string parentTraverseGroupName = null;
var parentTraverseAclExists = false; var parentTraverseAclExists = false;
string relativePathRaw = DataArea.GetRelativePath(parent.FullName, baseFolder).Trim(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); string relativePathRaw = DataArea.GetRelativePath(parent.FullName, baseFolder).Trim(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
relativePathRaw = relativePathRaw.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); relativePathRaw = relativePathRaw.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
@@ -684,11 +777,15 @@ namespace C4IT_IAM_SET
break; break;
} }
if (parentTraverseGroup != null)
parentTraverseGroupName = parentTraverseGroup.Name;
if (parentTraverseGroup == null && hasTraverseWildcard && !forceStrictAdGroupNames) if (parentTraverseGroup == null && hasTraverseWildcard && !forceStrictAdGroupNames)
{ {
parentTraverseGroup = FindTraverseGroupByWildcard(domainContext, traverseRegex); parentTraverseGroup = FindTraverseGroupByWildcard(domainContext, traverseRegex);
if (parentTraverseGroup != null) if (parentTraverseGroup != null)
{ {
parentTraverseGroupName = parentTraverseGroup.Name;
resultToken.reusedGroups.Add(parentTraverseGroup.Name); resultToken.reusedGroups.Add(parentTraverseGroup.Name);
resultToken.ensuredTraverseGroups.Add(parentTraverseGroup.Name); resultToken.ensuredTraverseGroups.Add(parentTraverseGroup.Name);
DefaultLogger.LogEntry(LogLevels.Debug, $"Vorhandene Traverse-Gruppe per Wildcard wiederverwendet: {parentTraverseGroup.Name}"); DefaultLogger.LogEntry(LogLevels.Debug, $"Vorhandene Traverse-Gruppe per Wildcard wiederverwendet: {parentTraverseGroup.Name}");
@@ -704,6 +801,7 @@ namespace C4IT_IAM_SET
if (parentTraverseGroup == null) if (parentTraverseGroup == null)
continue; continue;
parentTraverseGroupName = parentTraverseGroup.Name;
resultToken.reusedGroups.Add(candidateName); resultToken.reusedGroups.Add(candidateName);
resultToken.ensuredTraverseGroups.Add(candidateName); resultToken.ensuredTraverseGroups.Add(candidateName);
DefaultLogger.LogEntry(LogLevels.Debug, $"Vorhandene Traverse-Gruppe wiederverwendet: {candidateName}"); DefaultLogger.LogEntry(LogLevels.Debug, $"Vorhandene Traverse-Gruppe wiederverwendet: {candidateName}");
@@ -751,60 +849,56 @@ namespace C4IT_IAM_SET
continue; continue;
} }
if (parent.Parent != null) DefaultLogger.LogEntry(LogLevels.Debug, "Erstelle AD-Gruppe.");
if (WhatIf)
{ {
DefaultLogger.LogEntry(LogLevels.Debug, "Parent.Parent ist nicht null. Erstelle AD-Gruppe."); parentTraverseGroupName = newTraverseGroup.Name;
if (WhatIf) resultToken.createdGroups.Add(newTraverseGroup.Name);
{ resultToken.ensuredTraverseGroups.Add(newTraverseGroup.Name);
resultToken.createdGroups.Add(newTraverseGroup.Name); resultToken.warnings.Add($"Traverse-Gruppe würde angelegt werden: {newTraverseGroup.Name}");
resultToken.ensuredTraverseGroups.Add(newTraverseGroup.Name); resultToken.addedAclEntries.Add(newTraverseGroup.Name);
resultToken.warnings.Add($"Traverse-Gruppe würde angelegt werden: {newTraverseGroup.Name}"); parentTraverseAclExists = true;
resultToken.addedAclEntries.Add(newTraverseGroup.Name);
parentTraverseAclExists = true;
}
else
{
try
{
newSecurityGroups.CreateADGroup(groupOUPath, newTraverseGroup, null);
DefaultLogger.LogEntry(LogLevels.Debug, $"AD-Gruppe erstellt: {newTraverseGroup.Name}");
resultToken.createdGroups.Add(newTraverseGroup.Name);
resultToken.ensuredTraverseGroups.Add(newTraverseGroup.Name);
}
catch (Exception ex)
{
DefaultLogger.LogEntry(LogLevels.Error, $"Fehler beim Erstellen der AD-Gruppe: {ex.Message}");
continue;
}
parentTraverseGroup = GroupPrincipal.FindByIdentity(domainContext, newTraverseGroup.Name);
if (parentTraverseGroup == null)
{
DefaultLogger.LogEntry(LogLevels.Error, $"parentTraverseGroup konnte nach Erstellung der Gruppe nicht gefunden werden: {newTraverseGroup.Name}");
continue;
}
try
{
var accesscontrol = parent.GetAccessControl();
accesscontrol.AddAccessRule(new FileSystemAccessRule(parentTraverseGroup.Sid,
FileSystemRights.Read, InheritanceFlags.None, PropagationFlags.None,
AccessControlType.Allow));
DefaultLogger.LogEntry(LogLevels.Debug, $"Setze Traverse-ACL auf: {parent.FullName} für {parentTraverseGroup.DistinguishedName}");
parent.SetAccessControl(accesscontrol);
resultToken.addedAclEntries.Add(parentTraverseGroup.Name);
parentTraverseAclExists = true;
}
catch (Exception ex)
{
DefaultLogger.LogEntry(LogLevels.Error, $"Fehler beim Setzen der ACL: {ex.Message}");
continue;
}
}
} }
else else
{ {
DefaultLogger.LogEntry(LogLevels.Debug, "Parent.Parent ist null. Traverse-ACL kann nicht gesetzt werden."); try
{
newSecurityGroups.CreateADGroup(groupOUPath, newTraverseGroup, null);
DefaultLogger.LogEntry(LogLevels.Debug, $"AD-Gruppe erstellt: {newTraverseGroup.Name}");
resultToken.createdGroups.Add(newTraverseGroup.Name);
resultToken.ensuredTraverseGroups.Add(newTraverseGroup.Name);
}
catch (Exception ex)
{
DefaultLogger.LogEntry(LogLevels.Error, $"Fehler beim Erstellen der AD-Gruppe: {ex.Message}");
continue;
}
parentTraverseGroup = GroupPrincipal.FindByIdentity(domainContext, newTraverseGroup.Name);
if (parentTraverseGroup == null)
{
DefaultLogger.LogEntry(LogLevels.Error, $"parentTraverseGroup konnte nach Erstellung der Gruppe nicht gefunden werden: {newTraverseGroup.Name}");
continue;
}
parentTraverseGroupName = parentTraverseGroup.Name;
try
{
var accesscontrol = parent.GetAccessControl();
accesscontrol.AddAccessRule(new FileSystemAccessRule(parentTraverseGroup.Sid,
FileSystemRights.Read, InheritanceFlags.None, PropagationFlags.None,
AccessControlType.Allow));
DefaultLogger.LogEntry(LogLevels.Debug, $"Setze Traverse-ACL auf: {parent.FullName} für {parentTraverseGroup.DistinguishedName}");
parent.SetAccessControl(accesscontrol);
resultToken.addedAclEntries.Add(parentTraverseGroup.Name);
parentTraverseAclExists = true;
}
catch (Exception ex)
{
DefaultLogger.LogEntry(LogLevels.Error, $"Fehler beim Setzen der ACL: {ex.Message}");
continue;
}
} }
} }
} }
@@ -843,8 +937,9 @@ namespace C4IT_IAM_SET
} }
} }
if (parentTraverseGroup != null) if (parentTraverseGroup != null || !string.IsNullOrWhiteSpace(parentTraverseGroupName))
{ {
var displayTraverseGroupName = parentTraverseGroup?.Name ?? parentTraverseGroupName;
if (!processedNearestTraverseParent) if (!processedNearestTraverseParent)
{ {
DefaultLogger.LogEntry(LogLevels.Debug, "Verarbeite SecurityGroups bei oberster Ebene."); DefaultLogger.LogEntry(LogLevels.Debug, "Verarbeite SecurityGroups bei oberster Ebene.");
@@ -860,7 +955,7 @@ namespace C4IT_IAM_SET
if (WhatIf) if (WhatIf)
{ {
resultToken.warnings.Add($"Traverse-Gruppe '{parentTraverseGroup.Name}' würde Mitglied '{currentSecGroup.Name}' erhalten."); resultToken.warnings.Add($"Traverse-Gruppe '{displayTraverseGroupName}' würde Mitglied '{currentSecGroup.Name}' erhalten.");
continue; continue;
} }
@@ -868,25 +963,23 @@ namespace C4IT_IAM_SET
continue; continue;
} }
traverseGroup = parentTraverseGroup; traverseGroup = parentTraverseGroup;
traverseGroupName = displayTraverseGroupName;
processedNearestTraverseParent = true; processedNearestTraverseParent = true;
} }
else else
{ {
if (traverseGroup != null && parentTraverseGroup != null) if (!string.IsNullOrWhiteSpace(traverseGroupName))
{ {
try try
{ {
if (!parentTraverseGroup.Members.Contains(traverseGroup)) if (WhatIf)
{ {
if (WhatIf) resultToken.warnings.Add($"Traverse-Gruppe '{displayTraverseGroupName}' würde verschachtelte Gruppe '{traverseGroupName}' erhalten.");
{ }
resultToken.warnings.Add($"Traverse-Gruppe '{parentTraverseGroup.Name}' würde verschachtelte Gruppe '{traverseGroup.Name}' erhalten."); else if (traverseGroup != null && parentTraverseGroup != null && !parentTraverseGroup.Members.Contains(traverseGroup))
} {
else if (!TryEnsureNestedTraverseGroupMembershipWithRetry(parentTraverseGroup, traverseGroup))
{ continue;
if (!TryEnsureNestedTraverseGroupMembershipWithRetry(parentTraverseGroup, traverseGroup))
continue;
}
} }
} }
catch (Exception ex) catch (Exception ex)
@@ -898,7 +991,7 @@ namespace C4IT_IAM_SET
} }
try try
{ {
if (!WhatIf) if (!WhatIf && parentTraverseGroup != null)
{ {
parentTraverseGroup.Save(); parentTraverseGroup.Save();
DefaultLogger.LogEntry(LogLevels.Debug, $"parentTraverseGroup gespeichert: {parentTraverseGroup.Name}"); DefaultLogger.LogEntry(LogLevels.Debug, $"parentTraverseGroup gespeichert: {parentTraverseGroup.Name}");
@@ -914,8 +1007,8 @@ namespace C4IT_IAM_SET
DefaultLogger.LogEntry(LogLevels.Debug, "parentTraverseGroup ist null."); DefaultLogger.LogEntry(LogLevels.Debug, "parentTraverseGroup ist null.");
} }
if (parentTraverseGroup != null && !resultToken.ensuredTraverseGroups.Contains(parentTraverseGroup.Name)) if (!string.IsNullOrWhiteSpace(parentTraverseGroupName) && !resultToken.ensuredTraverseGroups.Contains(parentTraverseGroupName))
resultToken.ensuredTraverseGroups.Add(parentTraverseGroup.Name); resultToken.ensuredTraverseGroups.Add(parentTraverseGroupName);
if (IsTraverseBoundaryPath(parent.FullName)) if (IsTraverseBoundaryPath(parent.FullName))
break; break;

View File

@@ -421,60 +421,112 @@ namespace LiamWorkflowActivities
var allowFolderEnsure = IsAdditionalConfigurationEnabled(provider, "EnsureNtfsPermissionGroups"); var allowFolderEnsure = IsAdditionalConfigurationEnabled(provider, "EnsureNtfsPermissionGroups");
var allowSharePathEnsure = IsAdditionalConfigurationEnabled(provider, "EnsureNtfsPermissionGroupsForShares"); var allowSharePathEnsure = IsAdditionalConfigurationEnabled(provider, "EnsureNtfsPermissionGroupsForShares");
if (!allowFolderEnsure && !allowSharePathEnsure) var allowTraverseEnsure = IsAdditionalConfigurationEnabled(provider, "EnsureNtfsTraverseGroups");
if (!allowFolderEnsure && !allowSharePathEnsure && !allowTraverseEnsure)
return true; return true;
foreach (var ntfsArea in dataAreas if (allowFolderEnsure || allowSharePathEnsure)
.Where(dataArea =>
allowFolderEnsure && dataArea is cLiamNtfsFolder
|| allowSharePathEnsure && dataArea is cLiamNtfsShare)
.Cast<cLiamNtfsPermissionDataAreaBase>())
{ {
var folderPath = ntfsArea.TechnicalName; foreach (var ntfsArea in dataAreas
if (string.IsNullOrWhiteSpace(folderPath)) .Where(dataArea =>
continue; allowFolderEnsure && dataArea is cLiamNtfsFolder
|| allowSharePathEnsure && dataArea is cLiamNtfsShare)
if (!Directory.Exists(folderPath)) .Cast<cLiamNtfsPermissionDataAreaBase>())
{ {
LogEntry($"Skipping automatic NTFS permission group ensure for '{folderPath}' because the directory does not exist.", LogLevels.Warning); var folderPath = ntfsArea.TechnicalName;
continue; if (string.IsNullOrWhiteSpace(folderPath))
} continue;
var ensureResult = await ntfsProvider.EnsureMissingPermissionGroupsAsync( if (!Directory.Exists(folderPath))
folderPath, {
null, LogEntry($"Skipping automatic NTFS permission group ensure for '{folderPath}' because the directory does not exist.", LogLevels.Warning);
null, continue;
null, }
null,
allowSharePathEnsure, var ensureResult = await ntfsProvider.EnsureMissingPermissionGroupsAsync(
ntfsArea is cLiamNtfsFolder || ntfsArea is cLiamNtfsShare, folderPath,
simulateOnly); null,
if (ensureResult == null) null,
null,
null,
allowSharePathEnsure,
!allowTraverseEnsure && (ntfsArea is cLiamNtfsFolder || ntfsArea is cLiamNtfsShare),
simulateOnly);
if (ensureResult == null)
{
var providerMessage = ntfsProvider.GetLastErrorMessage() ?? "Provider returned no result.";
LogEntry(
$"Automatic NTFS permission group ensure skipped for '{folderPath}' because the provider returned no result. ProviderMessage='{providerMessage}'",
LogLevels.Warning);
continue;
}
if (ensureResult.resultErrorId != 0)
{
LogEntry(
$"Automatic NTFS permission group ensure skipped for '{folderPath}' after resultErrorId={ensureResult.resultErrorId}. ResultMessage='{ensureResult.resultMessage ?? string.Empty}'",
LogLevels.Warning);
continue;
}
if (simulateOnly)
{
LogAutomaticNtfsEnsurePreviewDebug(folderPath, ensureResult, "permission group ensure");
result.AutomaticEnsurePreview.Add(MapAutomaticEnsurePreview(folderPath, ensureResult));
continue;
}
LogAutomaticNtfsEnsureDebug(folderPath, ensureResult, "permission group ensure");
await ntfsArea.ResolvePermissionGroupsAsync(folderPath);
}
}
if (allowTraverseEnsure)
{
foreach (var ntfsArea in dataAreas
.Where(dataArea => dataArea is cLiamNtfsFolder || dataArea is cLiamNtfsShare)
.Cast<cLiamNtfsPermissionDataAreaBase>())
{ {
var providerMessage = ntfsProvider.GetLastErrorMessage() ?? "Provider returned no result."; var folderPath = ntfsArea.TechnicalName;
LogEntry( if (string.IsNullOrWhiteSpace(folderPath))
$"Automatic NTFS permission group ensure skipped for '{folderPath}' because the provider returned no result. ProviderMessage='{providerMessage}'", continue;
LogLevels.Warning);
continue;
}
if (ensureResult.resultErrorId != 0) if (!Directory.Exists(folderPath))
{ {
LogEntry( LogEntry($"Skipping automatic NTFS traverse group ensure for '{folderPath}' because the directory does not exist.", LogLevels.Warning);
$"Automatic NTFS permission group ensure skipped for '{folderPath}' after resultErrorId={ensureResult.resultErrorId}. ResultMessage='{ensureResult.resultMessage ?? string.Empty}'", continue;
LogLevels.Warning); }
continue;
}
if (simulateOnly) var ensureResult = await ntfsProvider.EnsureTraverseGroupsAsync(
{ folderPath,
LogAutomaticNtfsEnsurePreviewDebug(folderPath, ensureResult); null,
result.AutomaticEnsurePreview.Add(MapAutomaticEnsurePreview(folderPath, ensureResult)); simulateOnly);
continue; if (ensureResult == null)
} {
var providerMessage = ntfsProvider.GetLastErrorMessage() ?? "Provider returned no result.";
LogEntry(
$"Automatic NTFS traverse group ensure skipped for '{folderPath}' because the provider returned no result. ProviderMessage='{providerMessage}'",
LogLevels.Warning);
continue;
}
LogAutomaticNtfsEnsureDebug(folderPath, ensureResult); if (ensureResult.resultErrorId != 0)
await ntfsArea.ResolvePermissionGroupsAsync(folderPath); {
LogEntry(
$"Automatic NTFS traverse group ensure skipped for '{folderPath}' after resultErrorId={ensureResult.resultErrorId}. ResultMessage='{ensureResult.resultMessage ?? string.Empty}'",
LogLevels.Warning);
continue;
}
if (simulateOnly)
{
LogAutomaticNtfsEnsurePreviewDebug(folderPath, ensureResult, "traverse group ensure");
result.AutomaticEnsurePreview.Add(MapAutomaticEnsurePreview(folderPath, ensureResult));
continue;
}
LogAutomaticNtfsEnsureDebug(folderPath, ensureResult, "traverse group ensure");
}
} }
return true; return true;
@@ -496,13 +548,13 @@ namespace LiamWorkflowActivities
}; };
} }
private static void LogAutomaticNtfsEnsurePreviewDebug(string folderPath, ResultToken ensureResult) private static void LogAutomaticNtfsEnsurePreviewDebug(string folderPath, ResultToken ensureResult, string operationLabel)
{ {
if (ensureResult == null) if (ensureResult == null)
return; return;
LogEntry( LogEntry(
$"Automatic NTFS permission group ensure preview finished for '{folderPath}'. " + $"Automatic NTFS {operationLabel} preview finished for '{folderPath}'. " +
$"WouldCreateGroups={ensureResult.createdGroups.Count}, " + $"WouldCreateGroups={ensureResult.createdGroups.Count}, " +
$"WouldReuseGroups={ensureResult.reusedGroups.Count}, " + $"WouldReuseGroups={ensureResult.reusedGroups.Count}, " +
$"WouldAddAcls={ensureResult.addedAclEntries.Count}, " + $"WouldAddAcls={ensureResult.addedAclEntries.Count}, " +
@@ -513,13 +565,13 @@ namespace LiamWorkflowActivities
LogLevels.Debug); LogLevels.Debug);
} }
private static void LogAutomaticNtfsEnsureDebug(string folderPath, ResultToken ensureResult) private static void LogAutomaticNtfsEnsureDebug(string folderPath, ResultToken ensureResult, string operationLabel)
{ {
if (ensureResult == null) if (ensureResult == null)
return; return;
LogEntry( LogEntry(
$"Automatic NTFS permission group ensure finished for '{folderPath}'. " + $"Automatic NTFS {operationLabel} finished for '{folderPath}'. " +
$"CreatedGroups={ensureResult.createdGroups.Count}, " + $"CreatedGroups={ensureResult.createdGroups.Count}, " +
$"ReusedGroups={ensureResult.reusedGroups.Count}, " + $"ReusedGroups={ensureResult.reusedGroups.Count}, " +
$"AddedAcls={ensureResult.addedAclEntries.Count}, " + $"AddedAcls={ensureResult.addedAclEntries.Count}, " +
@@ -532,42 +584,42 @@ namespace LiamWorkflowActivities
if (ensureResult.createdGroups.Count > 0) if (ensureResult.createdGroups.Count > 0)
{ {
LogEntry( LogEntry(
$"Automatic NTFS permission group ensure detected missing AD groups for '{folderPath}' and created them: {string.Join(", ", ensureResult.createdGroups)}", $"Automatic NTFS {operationLabel} detected missing AD groups for '{folderPath}' and created them: {string.Join(", ", ensureResult.createdGroups)}",
LogLevels.Debug); LogLevels.Debug);
} }
if (ensureResult.reusedGroups.Count > 0) if (ensureResult.reusedGroups.Count > 0)
{ {
LogEntry( LogEntry(
$"Automatic NTFS permission group ensure reused existing AD groups for '{folderPath}': {string.Join(", ", ensureResult.reusedGroups)}", $"Automatic NTFS {operationLabel} reused existing AD groups for '{folderPath}': {string.Join(", ", ensureResult.reusedGroups)}",
LogLevels.Debug); LogLevels.Debug);
} }
if (ensureResult.addedAclEntries.Count > 0) if (ensureResult.addedAclEntries.Count > 0)
{ {
LogEntry( LogEntry(
$"Automatic NTFS permission group ensure added missing ACL entries for '{folderPath}': {string.Join(", ", ensureResult.addedAclEntries)}", $"Automatic NTFS {operationLabel} added missing ACL entries for '{folderPath}': {string.Join(", ", ensureResult.addedAclEntries)}",
LogLevels.Debug); LogLevels.Debug);
} }
if (ensureResult.skippedAclEntries.Count > 0) if (ensureResult.skippedAclEntries.Count > 0)
{ {
LogEntry( LogEntry(
$"Automatic NTFS permission group ensure kept existing ACL entries for '{folderPath}': {string.Join(", ", ensureResult.skippedAclEntries)}", $"Automatic NTFS {operationLabel} kept existing ACL entries for '{folderPath}': {string.Join(", ", ensureResult.skippedAclEntries)}",
LogLevels.Debug); LogLevels.Debug);
} }
if (ensureResult.ensuredTraverseGroups.Count > 0) if (ensureResult.ensuredTraverseGroups.Count > 0)
{ {
LogEntry( LogEntry(
$"Automatic NTFS permission group ensure touched traverse groups for '{folderPath}': {string.Join(", ", ensureResult.ensuredTraverseGroups)}", $"Automatic NTFS {operationLabel} touched traverse groups for '{folderPath}': {string.Join(", ", ensureResult.ensuredTraverseGroups)}",
LogLevels.Debug); LogLevels.Debug);
} }
if (ensureResult.warnings.Count > 0) if (ensureResult.warnings.Count > 0)
{ {
LogEntry( LogEntry(
$"Automatic NTFS permission group ensure produced warnings for '{folderPath}': {string.Join(" | ", ensureResult.warnings)}", $"Automatic NTFS {operationLabel} produced warnings for '{folderPath}': {string.Join(" | ", ensureResult.warnings)}",
LogLevels.Debug); LogLevels.Debug);
} }
} }