utilities/pipelines/sharedScripts/helper/Get-SpecsAlignedResourceName.ps1 (100 lines of code) (raw):

<# .SYNOPSIS Remove a string to its core - i.e. the part the neither indicates plural nor singular. .DESCRIPTION Remove a string to its core - i.e. the part the neither indicates plural nor singular. .PARAMETER StringToReduce Mandatory. The string to reduce. .EXAMPLE Get-ReducedWordString -StringToReduce 'virtualMachines' Returns 'virtualMachine'. .EXAMPLE Get-ReducedWordString -StringToReduce 'factories' Returns 'factor'. #> function Get-ReducedWordString { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string] $StringToReduce ) if ($StringToReduce -match '(.+?)(y|ii|e|ys|ies|es|s)$') { return $Matches[1] } return $StringToReduce } <# .SYNOPSIS Try to find the actual provider namespace and resource type for a given resource identifier. .DESCRIPTION Try to find the actual provider namespace and resource type for a given resource identifier. For example, for 'virtual-machine-images/image-template' it we want to find 'Microsoft.VirtualMachineImages/imageTemplates'. .PARAMETER ResourceIdentifier Mandatory. The resource identifier to search for. .PARAMETER SpecsFilePath Optional. The path to the specs file that contains all available provider namespaces & resource types. Defaults to 'utilities/src/apiSpecsList.json'. .EXAMPLE Get-SpecsAlignedResourceName -ResourceIdentifier 'virtual-machine-images/image-template'. Returns 'Microsoft.VirtualMachineImages/imageTemplates'. #> function Get-SpecsAlignedResourceName { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string] $ResourceIdentifier, [Parameter(Mandatory = $false)] [string] $ApiSpecsFileUri = 'https://azure.github.io/Azure-Verified-Modules/governance/apiSpecsList.json' ) try { $apiSpecs = Invoke-WebRequest -Uri $ApiSpecsFileUri $specs = ConvertFrom-Json $apiSpecs.Content -AsHashtable } catch { Write-Warning "Failed to download API specs file from [$ApiSpecsFileUri]" $specs = @{} } $reducedResourceIdentifier = $ResourceIdentifier -replace '-' $rawProviderNamespace, $rawResourceType = $reducedResourceIdentifier -Split '[\/|\\]', 2 # e.g. 'keyvault' & 'vaults/keys' # Find provider namespace $foundProviderNamespaceMatches = ($specs.Keys | Sort-Object -Culture 'en-US') | Where-Object { $_ -like "Microsoft.$rawProviderNamespace*" } if (-not $foundProviderNamespaceMatches) { $providerNamespace = "Microsoft.$rawProviderNamespace" Write-Warning "Failed to identify provider namespace [$rawProviderNamespace]. Falling back to [$providerNamespace]." } else { $providerNamespace = ($foundProviderNamespaceMatches.Count -eq 1) ? $foundProviderNamespaceMatches : $foundProviderNamespaceMatches[0] } # Find resource type $innerResourceTypes = $specs[$providerNamespace].Keys | Sort-Object -Culture 'en-US' $rawResourceTypeElem = $rawResourceType -split '[\/|\\]' $reducedResourceTypeElements = $rawResourceTypeElem | ForEach-Object { Get-ReducedWordString -StringToReduce $_ } ## We built a regex that matches the resource type, but also the plural and singular form of it along its entire path. For example ^vault(y|ii|e|ys|ies|es|s|)(\/|$)key(y|ii|e|ys|ies|es|s|)(\/|$)$ ### (y|ii|e|ys|ies|es|s|) = Singular or plural form ### (\/|$) = End of string or another resource type level $resourceTypeRegex = '^{0}(y|ii|e|ys|ies|es|s|ses|)(\/|$)$' -f ($reducedResourceTypeElements -join '(y|ii|e|ys|ies|es|s|ses|)(\/|$)') $resourceType = $innerResourceTypes | Where-Object { $_ -match $resourceTypeRegex } # Special case handling: Ambiguous resource types (usually incorrect RP implementations) if ($resourceType.count -gt 1) { switch ($rawResourceType) { 'service/api/policy' { # Setting explicitly as both [apimanagement/service/apis/policies] & [apimanagement/service/apis/policy] exist in the specs and the later seem to have been an initial incorrect publish (only one API version exists) $resourceType = 'service/apis/policies' } Default { throw ('Found ambiguous resource types [{0}] for identifier [{1}]' -f ($resourceType -join ','), $rawResourceType) } } } # Special case handling: If no resource type is found, fall back one level (e.g., for 'authorization\role-definition\management-group' as 'management-group' in this context is no actual resource type) if (-not $resourceType) { $fallbackResourceTypeRegex = '{0}$' -f ($resourceTypeRegex -split $reducedResourceTypeElements[-1])[0] $resourceType = $innerResourceTypes | Where-Object { $_ -match $fallbackResourceTypeRegex } if (-not $resourceType) { # if we still don't find anything (because the resource type straight up does not exist, we fall back to itself as the default) Write-Warning "Resource type [$rawResourceType] cannot be found or does not exist in the API specs / is custom. Falling back to it as default." $resourceType = $rawResourceType } else { Write-Warning ('Failed to find exact match between core matched resource types and [{0}]. Fallback on [{1}].' -f $rawResourceType, (Split-Path $rawResourceType -Parent)) } } # Build result return "$providerNamespace/$resourceType" }