in src/PSRule.Rules.Azure/Common/ResourceHelper.cs [342:423]
internal static string ResourceId(string? scopeTenant, string? scopeManagementGroup, string? scopeSubscriptionId, string? scopeResourceGroup, string[]? resourceType, string[]? resourceName, int depth = int.MaxValue)
{
var resourceTypeLength = resourceType?.Length ?? 0;
var nameLength = resourceName?.Length ?? 0;
if (resourceTypeLength != nameLength)
throw new TemplateFunctionException(nameof(resourceType), FunctionErrorType.MismatchingResourceSegments, PSRuleResources.MismatchingResourceSegments);
// Coalesce depth.
var actualDepth = ResourceIdDepth(scopeTenant, scopeManagementGroup, scopeSubscriptionId, scopeResourceGroup, resourceType, resourceName);
depth = depth < 0 ? actualDepth + depth : depth > actualDepth ? actualDepth : depth;
var parts = scopeTenant == SLASH ? 1 : scopeSubscriptionId != null ? 4 : scopeManagementGroup != null ? 8 : 0;
parts += scopeResourceGroup != null ? 4 : 0;
parts += depth >= resourceTypeLength ? resourceTypeLength * 4 : depth * 4;
// Add additional provider segments.
for (var p = 0; resourceType != null && p < resourceType.Length; p++)
{
if (resourceType[p].Contains(DOT))
parts += 2;
}
var result = new string[parts];
var i = 0;
var j = 0;
var currentDepth = 0;
if (scopeTenant == null && scopeManagementGroup != null && depth >= 1)
{
result[i++] = SLASH;
result[i++] = PROVIDERS;
result[i++] = SLASH;
result[i++] = PROVIDER_MICROSOFT_MANAGEMENT;
result[i++] = SLASH;
result[i++] = MANAGEMENT_GROUPS;
result[i++] = SLASH;
result[i++] = scopeManagementGroup;
currentDepth++;
}
else if (scopeTenant == null && scopeSubscriptionId != null && depth >= 1)
{
result[i++] = SLASH;
result[i++] = SUBSCRIPTIONS;
result[i++] = SLASH;
result[i++] = scopeSubscriptionId;
currentDepth++;
if (scopeResourceGroup != null && depth >= 2)
{
result[i++] = SLASH;
result[i++] = RESOURCE_GROUPS;
result[i++] = SLASH;
result[i++] = scopeResourceGroup;
currentDepth++;
}
}
// Handle resource type and name.
if (depth > currentDepth && resourceType != null && resourceName != null && resourceTypeLength > 0)
{
while (i < result.Length && depth > currentDepth && j < resourceTypeLength)
{
// If a resource provider is included providers segment.
if (resourceType[j].Contains(DOT))
{
result[i++] = SLASH;
result[i++] = PROVIDERS;
}
// Don't increment when providers is already in the type segment.
if (!string.Equals(resourceType[j], PROVIDERS, StringComparison.OrdinalIgnoreCase))
currentDepth++;
result[i++] = SLASH;
result[i++] = resourceType[j];
result[i++] = SLASH;
result[i++] = resourceName[j++];
}
}
return scopeTenant != null && i == 0 ? SLASH : string.Concat(result);
}