Add NTFS root path naming placeholders

This commit is contained in:
Meik
2026-05-08 21:34:38 +02:00
parent 123aa5bf2d
commit b9edd16cab
4 changed files with 156 additions and 20 deletions

View File

@@ -586,6 +586,7 @@ namespace C4IT_IAM_SET
? sanitizedSegments[sanitizedSegments.Length - 1]
: Helper.SanitizePathSegment(Path.GetFileName(parent.FullName.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)));
var traverseTags = GetTraverseReplacementTags(parent.FullName);
var rootContext = Helper.GetRootPathTemplateContext(baseFolder);
var boundedTraverseContext = Helper.GetBoundedAdGroupTemplateContext(
traverseGroupTemplate.NamingTemplate,
true,
@@ -594,7 +595,9 @@ namespace C4IT_IAM_SET
folderName,
traverseTags,
Helper.MaxAdGroupNameLength,
$"Traverse fuer '{parent.FullName}'");
$"Traverse fuer '{parent.FullName}'",
"AD-Gruppenname",
rootContext);
var boundedTraverseDescriptionContext = Helper.GetBoundedAdGroupTemplateContext(
traverseGroupTemplate.DescriptionTemplate,
true,
@@ -604,20 +607,21 @@ namespace C4IT_IAM_SET
traverseTags,
Helper.MaxAdGroupDescriptionLength,
$"Traverse fuer '{parent.FullName}'",
"AD-Gruppenbeschreibung");
"AD-Gruppenbeschreibung",
rootContext);
var adjustedTraverseSegments = boundedTraverseContext.SanitizedSegments ?? Array.Empty<string>();
var adjustedTraverseRelativePath = adjustedTraverseSegments.Length > 0 ? string.Join("_", adjustedTraverseSegments) : string.Empty;
var adjustedTraverseFolderName = boundedTraverseContext.FolderName;
var adjustedTraverseDescriptionSegments = boundedTraverseDescriptionContext.SanitizedSegments ?? Array.Empty<string>();
var adjustedTraverseDescriptionRelativePath = adjustedTraverseDescriptionSegments.Length > 0 ? string.Join("_", adjustedTraverseDescriptionSegments) : string.Empty;
var adjustedTraverseDescriptionFolderName = boundedTraverseDescriptionContext.FolderName;
var traverseNameTemplate = Helper.ApplyTemplatePlaceholders(traverseGroupTemplate.NamingTemplate, true, adjustedTraverseRelativePath, adjustedTraverseSegments, adjustedTraverseFolderName).ReplaceTags(traverseTags);
var traverseDescriptionTemplate = Helper.ApplyTemplatePlaceholders(traverseGroupTemplate.DescriptionTemplate, true, adjustedTraverseDescriptionRelativePath, adjustedTraverseDescriptionSegments, adjustedTraverseDescriptionFolderName).ReplaceTags(traverseTags);
var traverseNameTemplate = Helper.ApplyTemplatePlaceholders(traverseGroupTemplate.NamingTemplate, true, adjustedTraverseRelativePath, adjustedTraverseSegments, adjustedTraverseFolderName, rootContext).ReplaceTags(traverseTags);
var traverseDescriptionTemplate = Helper.ApplyTemplatePlaceholders(traverseGroupTemplate.DescriptionTemplate, true, adjustedTraverseDescriptionRelativePath, adjustedTraverseDescriptionSegments, adjustedTraverseDescriptionFolderName, rootContext).ReplaceTags(traverseTags);
string traverseRegex = null;
try
{
traverseRegex = Helper.ApplyTemplatePlaceholders(traverseGroupTemplate.WildcardTemplate, true, adjustedTraverseRelativePath, adjustedTraverseSegments, adjustedTraverseFolderName).ReplaceTags(traverseTags);
traverseRegex = Helper.ApplyTemplatePlaceholders(traverseGroupTemplate.WildcardTemplate, true, adjustedTraverseRelativePath, adjustedTraverseSegments, adjustedTraverseFolderName, rootContext).ReplaceTags(traverseTags);
DefaultLogger.LogEntry(LogLevels.Debug, $"traverseRegex: {traverseRegex}");
}
catch (Exception ex)

View File

@@ -28,6 +28,14 @@ namespace C4IT_IAM_Engine
public string Strategy { get; set; } = string.Empty;
}
public sealed class RootPathTemplateContext
{
public string Server { get; set; } = string.Empty;
public string[] Segments { get; set; } = Array.Empty<string>();
public string Name { get; set; } = string.Empty;
public string Path { get; set; } = string.Empty;
}
public static string ReplaceLoopTag(this string str, int loop)
{
return Regex.Replace(str, @"(?<loopTag>{{(?<prefix>[^}]*)(?<loop>LOOP)(?<postfix>[^{]*)}})", loop <= 0 ? "" : "${prefix}" + loop + "${postfix}");
@@ -40,11 +48,17 @@ namespace C4IT_IAM_Engine
current.Replace("{{" + value.Key + "}}", value.Value));
}
public static string ApplyTemplatePlaceholders(string templateValue, bool allowRelativePath, string defaultRelativePath, string[] sanitizedSegments, string folderName)
{
return ApplyTemplatePlaceholders(templateValue, allowRelativePath, defaultRelativePath, sanitizedSegments, folderName, null);
}
public static string ApplyTemplatePlaceholders(string templateValue, bool allowRelativePath, string defaultRelativePath, string[] sanitizedSegments, string folderName, RootPathTemplateContext rootContext)
{
if (templateValue == null)
return string.Empty;
var result = Regex.Replace(templateValue, @"{{\s*NAME\s*}}", folderName ?? string.Empty, RegexOptions.IgnoreCase);
result = ApplyRootPathPlaceholders(result, rootContext);
if (allowRelativePath)
{
@@ -67,6 +81,27 @@ namespace C4IT_IAM_Engine
return result;
}
public static RootPathTemplateContext GetRootPathTemplateContext(string rootPath)
{
var segments = SplitPathSegments(rootPath);
if (segments.Length == 0)
return new RootPathTemplateContext();
var isUncPath = (rootPath ?? string.Empty).Trim().Replace('/', '\\').StartsWith(@"\\", StringComparison.Ordinal);
var server = isUncPath ? SanitizePathSegment(segments[0]) : string.Empty;
var pathSegments = isUncPath ? segments.Skip(1).ToArray() : segments;
var sanitizedPathSegments = pathSegments.Select(SanitizePathSegment).ToArray();
return new RootPathTemplateContext
{
Server = server,
Segments = sanitizedPathSegments,
Name = sanitizedPathSegments.Length == 0 ? string.Empty : sanitizedPathSegments[sanitizedPathSegments.Length - 1],
Path = sanitizedPathSegments.Length == 0 ? string.Empty : string.Join("_", sanitizedPathSegments)
};
}
public static BoundedTemplateContext GetBoundedAdGroupTemplateContext(
string templateValue,
bool allowRelativePath,
@@ -76,13 +111,14 @@ namespace C4IT_IAM_Engine
IDictionary<string, string> replacementTags,
int maxLength,
string logContext,
string valueLabel = "AD-Gruppenname")
string valueLabel = "AD-Gruppenname",
RootPathTemplateContext rootContext = null)
{
var effectiveSegments = (sanitizedSegments ?? Array.Empty<string>()).Where(i => i != null).ToArray();
var effectiveFolderName = folderName ?? string.Empty;
var currentRelativePath = GetCurrentRelativePath(effectiveSegments, defaultRelativePath);
var originalValue = MaterializeTemplateValue(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags);
var measuredValue = MaterializeTemplateValueForLength(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags);
var originalValue = MaterializeTemplateValue(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags, rootContext);
var measuredValue = MaterializeTemplateValueForLength(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags, rootContext);
var usesRelativePath = allowRelativePath && Regex.IsMatch(templateValue ?? string.Empty, @"{{\s*RELATIVEPATH", RegexOptions.IgnoreCase);
var usesName = Regex.IsMatch(templateValue ?? string.Empty, @"{{\s*NAME\s*}}", RegexOptions.IgnoreCase);
var strategy = string.Empty;
@@ -109,8 +145,8 @@ namespace C4IT_IAM_Engine
break;
currentRelativePath = GetCurrentRelativePath(effectiveSegments, defaultRelativePath);
originalValue = MaterializeTemplateValue(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags);
measuredValue = MaterializeTemplateValueForLength(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags);
originalValue = MaterializeTemplateValue(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags, rootContext);
measuredValue = MaterializeTemplateValueForLength(templateValue, allowRelativePath, currentRelativePath, effectiveSegments, effectiveFolderName, replacementTags, rootContext);
}
var initialValue = MaterializeTemplateValue(
@@ -119,7 +155,8 @@ namespace C4IT_IAM_Engine
GetCurrentRelativePath(sanitizedSegments, defaultRelativePath),
sanitizedSegments,
folderName,
replacementTags);
replacementTags,
rootContext);
var result = new BoundedTemplateContext
{
SanitizedSegments = effectiveSegments,
@@ -181,9 +218,10 @@ namespace C4IT_IAM_Engine
string defaultRelativePath,
string[] sanitizedSegments,
string folderName,
IDictionary<string, string> replacementTags)
IDictionary<string, string> replacementTags,
RootPathTemplateContext rootContext)
{
return ApplyTemplatePlaceholders(templateValue, allowRelativePath, defaultRelativePath, sanitizedSegments, folderName)
return ApplyTemplatePlaceholders(templateValue, allowRelativePath, defaultRelativePath, sanitizedSegments, folderName, rootContext)
.ReplaceTags(replacementTags)
.ToUpper();
}
@@ -194,10 +232,43 @@ namespace C4IT_IAM_Engine
string defaultRelativePath,
string[] sanitizedSegments,
string folderName,
IDictionary<string, string> replacementTags)
IDictionary<string, string> replacementTags,
RootPathTemplateContext rootContext)
{
return NormalizeLoopPlaceholderLength(
MaterializeTemplateValue(templateValue, allowRelativePath, defaultRelativePath, sanitizedSegments, folderName, replacementTags));
MaterializeTemplateValue(templateValue, allowRelativePath, defaultRelativePath, sanitizedSegments, folderName, replacementTags, rootContext));
}
private static string ApplyRootPathPlaceholders(string templateValue, RootPathTemplateContext rootContext)
{
if (templateValue == null)
return string.Empty;
var context = rootContext ?? new RootPathTemplateContext();
var result = Regex.Replace(templateValue, @"{{\s*ROOT_SERVER\s*}}", context.Server ?? string.Empty, RegexOptions.IgnoreCase);
result = Regex.Replace(result, @"{{\s*ROOT_NAME\s*}}", context.Name ?? string.Empty, RegexOptions.IgnoreCase);
result = Regex.Replace(result, @"{{\s*ROOT_PATH(?:\s*\(\s*(\d+)\s*\))?\s*}}", match =>
{
var segments = context.Segments ?? Array.Empty<string>();
if (!match.Groups[1].Success)
return context.Path ?? string.Empty;
if (!int.TryParse(match.Groups[1].Value, out var segmentCount) || segmentCount <= 0)
return string.Empty;
var take = Math.Min(segmentCount, segments.Length);
return take == 0 ? string.Empty : string.Join("_", segments.Skip(segments.Length - take));
}, RegexOptions.IgnoreCase);
result = Regex.Replace(result, @"{{\s*ROOT_SEGMENT\s*\(\s*(\d+)\s*\)\s*}}", match =>
{
var segments = context.Segments ?? Array.Empty<string>();
if (!int.TryParse(match.Groups[1].Value, out var segmentIndex) || segmentIndex < 0 || segmentIndex >= segments.Length)
return string.Empty;
return segments[segmentIndex] ?? string.Empty;
}, RegexOptions.IgnoreCase);
return result;
}
private static string NormalizeLoopPlaceholderLength(string templateValue)
@@ -217,6 +288,14 @@ namespace C4IT_IAM_Engine
return NormalizeLoopPlaceholderLength(templateValue).Length;
}
private static string[] SplitPathSegments(string path)
{
return (path ?? string.Empty)
.Trim()
.Replace('/', '\\')
.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
}
private static string GetCurrentRelativePath(string[] sanitizedSegments, string fallbackRelativePath)
{
if (sanitizedSegments != null && sanitizedSegments.Length > 0)

View File

@@ -150,6 +150,7 @@ namespace C4IT_IAM_Engine
var folderName = sanitizedSegments.Length > 0
? sanitizedSegments[sanitizedSegments.Length - 1]
: Helper.SanitizePathSegment(Path.GetFileName(newFolderPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)));
var rootContext = Helper.GetRootPathTemplateContext(baseFolder);
foreach (var template in resolvedTemplates)
{
@@ -206,7 +207,9 @@ namespace C4IT_IAM_Engine
folderName,
replacementTags,
Helper.MaxAdGroupNameLength,
$"{template.Type}/{template.Scope} fuer '{newFolderPath}'");
$"{template.Type}/{template.Scope} fuer '{newFolderPath}'",
"AD-Gruppenname",
rootContext);
var boundedDescriptionContext = Helper.GetBoundedAdGroupTemplateContext(
template.DescriptionTemplate,
@@ -217,7 +220,8 @@ namespace C4IT_IAM_Engine
replacementTags,
Helper.MaxAdGroupDescriptionLength,
$"{template.Type}/{template.Scope} fuer '{newFolderPath}'",
"AD-Gruppenbeschreibung");
"AD-Gruppenbeschreibung",
rootContext);
var adjustedNameSegments = boundedNameContext.SanitizedSegments ?? Array.Empty<string>();
var adjustedNameRelativePath = adjustedNameSegments.Length > 0 ? string.Join("_", adjustedNameSegments) : string.Empty;
@@ -226,16 +230,16 @@ namespace C4IT_IAM_Engine
var adjustedDescriptionRelativePath = adjustedDescriptionSegments.Length > 0 ? string.Join("_", adjustedDescriptionSegments) : string.Empty;
var adjustedDescriptionFolderName = boundedDescriptionContext.FolderName;
template.NamingTemplate = Helper.ApplyTemplatePlaceholders(template.NamingTemplate, template.Type != SecurityGroupType.Traverse, adjustedNameRelativePath, adjustedNameSegments, adjustedNameFolderName)
template.NamingTemplate = Helper.ApplyTemplatePlaceholders(template.NamingTemplate, template.Type != SecurityGroupType.Traverse, adjustedNameRelativePath, adjustedNameSegments, adjustedNameFolderName, rootContext)
.ReplaceTags(customTags).ReplaceTags(tags)
.ToUpper();
template.DescriptionTemplate = Helper.ApplyTemplatePlaceholders(template.DescriptionTemplate, template.Type != SecurityGroupType.Traverse, adjustedDescriptionRelativePath, adjustedDescriptionSegments, adjustedDescriptionFolderName)
template.DescriptionTemplate = Helper.ApplyTemplatePlaceholders(template.DescriptionTemplate, template.Type != SecurityGroupType.Traverse, adjustedDescriptionRelativePath, adjustedDescriptionSegments, adjustedDescriptionFolderName, rootContext)
.ReplaceTags(customTags).ReplaceTags(tags)
.ToUpper();
template.WildcardTemplate = Helper.ApplyTemplatePlaceholders(template.WildcardTemplate, template.Type != SecurityGroupType.Traverse, adjustedNameRelativePath, adjustedNameSegments, adjustedNameFolderName)
template.WildcardTemplate = Helper.ApplyTemplatePlaceholders(template.WildcardTemplate, template.Type != SecurityGroupType.Traverse, adjustedNameRelativePath, adjustedNameSegments, adjustedNameFolderName, rootContext)
.ReplaceTags(customTags).ReplaceTags(tags)
.ToUpper();