Private/Test-AzLocalResourceNames.ps1
|
Function Test-AzLocalResourceNames { <# .SYNOPSIS Validates all resolved Azure resource names against Azure naming rules. .DESCRIPTION Checks each resolved resource name against Azure naming constraints (maximum length, allowed characters, required prefixes) and throws an error if any name is invalid. This prevents deployment failures caused by invalid resource names. Azure resource naming rules enforced: - Storage Accounts: 3-24 chars, lowercase alphanumeric only (no hyphens/underscores) - Key Vaults: 3-24 chars, alphanumeric and hyphens, must start with a letter - Resource Groups: 1-90 chars, alphanumeric, hyphens, underscores, periods, parentheses - Cluster Name: 1-15 chars, alphanumeric and hyphens (NetBIOS computer name) - Node Names: 1-15 chars, alphanumeric and hyphens (NetBIOS computer name) - Custom Location: 1-63 chars, alphanumeric and hyphens - Resource Bridge: 1-63 chars, alphanumeric and hyphens - Deployment Name: 1-64 chars, alphanumeric, hyphens, underscores, periods .PARAMETER Names A hashtable of resource name label to resolved name value. #> [OutputType([void])] [CmdletBinding()] param ( [Parameter(Mandatory = $true, Position = 0)] [hashtable]$Names ) # Define Azure naming rules per resource type # Each rule: MaxLength, Pattern (regex of allowed chars), Description (for error messages) $rules = @{ 'ClusterName' = @{ MaxLength = 15; Pattern = '^[a-zA-Z0-9][a-zA-Z0-9\-]*$'; Description = '1-15 chars, alphanumeric and hyphens, must start with alphanumeric (NetBIOS name)' } 'ResourceGroupName' = @{ MaxLength = 90; Pattern = '^[a-zA-Z0-9\.\-_\(\)]+$'; Description = '1-90 chars, alphanumeric, hyphens, underscores, periods, parentheses' } 'KeyVaultName' = @{ MaxLength = 24; Pattern = '^[a-zA-Z][a-zA-Z0-9\-]+$'; Description = '3-24 chars, alphanumeric and hyphens, must start with a letter'; MinLength = 3 } 'CustomLocation' = @{ MaxLength = 63; Pattern = '^[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9]$|^[a-zA-Z0-9]$'; Description = '1-63 chars, alphanumeric and hyphens, cannot start/end with hyphen' } 'ResourceBridgeName' = @{ MaxLength = 63; Pattern = '^[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9]$|^[a-zA-Z0-9]$'; Description = '1-63 chars, alphanumeric and hyphens, cannot start/end with hyphen' } 'DiagnosticStorageAccountName' = @{ MaxLength = 24; Pattern = '^[a-z0-9]+$'; Description = '3-24 chars, lowercase alphanumeric only (no hyphens or uppercase)'; MinLength = 3 } 'ClusterWitnessStorageAccountName'= @{ MaxLength = 24; Pattern = '^[a-z0-9]+$'; Description = '3-24 chars, lowercase alphanumeric only (no hyphens or uppercase)'; MinLength = 3 } 'NodeName' = @{ MaxLength = 15; Pattern = '^[a-zA-Z0-9][a-zA-Z0-9\-]*$'; Description = '1-15 chars, alphanumeric and hyphens, must start with alphanumeric (NetBIOS name)' } 'DeploymentName' = @{ MaxLength = 64; Pattern = '^[a-zA-Z0-9\.\-_]+$'; Description = '1-64 chars, alphanumeric, hyphens, underscores, periods' } } $errors = @() foreach ($entry in $Names.GetEnumerator()) { $label = $entry.Key $name = $entry.Value if ([string]::IsNullOrWhiteSpace($name)) { $errors += " - $label : Name is empty or null." continue } # Determine which rule to apply based on the label $ruleKey = $null switch -Wildcard ($label) { 'ClusterName' { $ruleKey = 'ClusterName' } 'ResourceGroupName' { $ruleKey = 'ResourceGroupName' } 'KeyVaultName' { $ruleKey = 'KeyVaultName' } 'CustomLocation' { $ruleKey = 'CustomLocation' } 'ResourceBridgeName' { $ruleKey = 'ResourceBridgeName' } 'DiagnosticStorageAccountName' { $ruleKey = 'DiagnosticStorageAccountName' } 'ClusterWitnessStorageAccountName' { $ruleKey = 'ClusterWitnessStorageAccountName' } 'NodeName*' { $ruleKey = 'NodeName' } 'DeploymentName' { $ruleKey = 'DeploymentName' } default { continue } } $rule = $rules[$ruleKey] # Check minimum length $minLen = if ($rule.ContainsKey('MinLength')) { $rule.MinLength } else { 1 } if ($name.Length -lt $minLen) { $errors += " - $label = '$name' ($($name.Length) chars): Too short. $($rule.Description)" } # Check maximum length if ($name.Length -gt $rule.MaxLength) { $errors += " - $label = '$name' ($($name.Length) chars): Exceeds maximum of $($rule.MaxLength) characters. $($rule.Description)" } # Check allowed characters (case-sensitive match to enforce lowercase-only rules like storage accounts) if ($name -cnotmatch $rule.Pattern) { $errors += " - $label = '$name': Contains invalid characters. $($rule.Description)" } } if ($errors.Count -gt 0) { $errorMessage = "Resource name validation failed:`n" + ($errors -join "`n") Write-AzLocalLog $errorMessage -Level Error Write-AzLocalLog "Adjust the naming patterns in .config/naming-standards-config.json or use a shorter/valid UniqueID." -Level Warning throw $errorMessage } Write-Verbose "All resource names passed Azure naming validation." } |