Private/RoleManagement/Azure/Get-AzureReducedScopeOptions.ps1
|
function Get-AzureReducedScopeOptions { [CmdletBinding()] param( [Parameter(Mandatory)] [string]$OriginalScope ) $getPropertyValue = { param( [object]$InputObject, [string[]]$PropertyNames ) if (-not $InputObject) { return $null } foreach ($propertyName in $PropertyNames) { if ($InputObject.PSObject.Properties[$propertyName] -and -not [string]::IsNullOrWhiteSpace([string]$InputObject.$propertyName)) { return [string]$InputObject.$propertyName } } return $null } $getNestedPropertyValue = { param( [object]$InputObject, [string[]]$PropertyNames ) $directValue = & $getPropertyValue $InputObject $PropertyNames if ($directValue) { return $directValue } if ($InputObject -and $InputObject.PSObject.Properties['properties'] -and $InputObject.properties) { return & $getPropertyValue $InputObject.properties $PropertyNames } return $null } $normalizeScope = { param([string]$Scope) if ([string]::IsNullOrWhiteSpace($Scope)) { return $null } $normalized = $Scope.Trim() if (-not $normalized.StartsWith('/')) { $normalized = "/$normalized" } while ($normalized.Length -gt 1 -and $normalized.EndsWith('/')) { $normalized = $normalized.Substring(0, $normalized.Length - 1) } return $normalized } $getSubscriptionIdFromScope = { param([string]$Scope) if ($Scope -and $Scope -match '^/subscriptions/([^/]+)') { return $matches[1] } return $null } $getResourceGroupFromScope = { param([string]$Scope) if ($Scope -and $Scope -match '^/subscriptions/[^/]+/resourceGroups/([^/]+)') { return [System.Uri]::UnescapeDataString($matches[1]) } return $null } $getScopeDisplayName = { param( [string]$Scope, [object]$Entry, [string]$ResourceType ) $displayName = & $getNestedPropertyValue $Entry @('displayName', 'resourceDisplayName', 'resourceName', 'name') if (-not [string]::IsNullOrWhiteSpace($displayName)) { return $displayName } if ($Scope -match '^/subscriptions/[^/]+/resourceGroups/([^/]+)/providers/[^/]+/[^/]+/([^/]+)$') { return [System.Uri]::UnescapeDataString($matches[2]) } if ($Scope -match '^/subscriptions/[^/]+/resourceGroups/([^/]+)$') { return [System.Uri]::UnescapeDataString($matches[1]) } if ($Scope -match '^/subscriptions/([^/]+)$') { return $matches[1] } if ($Scope -match '^/providers/Microsoft\.Management/managementGroups/([^/]+)$') { return $matches[1] } if (-not [string]::IsNullOrWhiteSpace($ResourceType)) { return $ResourceType } return $Scope } $original = & $normalizeScope $OriginalScope if ([string]::IsNullOrWhiteSpace($original)) { throw 'OriginalScope is required when listing Azure reduced-scope options.' } $tokenObj = Get-AzAccessToken -ResourceUrl 'https://management.azure.com/' -ErrorAction Stop $token = if ($tokenObj.Token -is [System.Security.SecureString]) { [System.Net.NetworkCredential]::new('', $tokenObj.Token).Password } else { $tokenObj.Token } $headers = @{ Authorization = "Bearer $token" 'Content-Type' = 'application/json' } $items = [System.Collections.ArrayList]::new() $seenScopes = @{} $scopePath = if ($original -eq '/') { '' } else { $original } $uri = "https://management.azure.com$scopePath/providers/Microsoft.Authorization/eligibleChildResources?api-version=2020-10-01-preview" Write-Verbose "Get-AzureReducedScopeOptions: listing eligible child resources for original scope '$original'." while ($uri) { $response = Invoke-RestMethod -Uri $uri -Headers $headers -Method Get -ErrorAction Stop foreach ($entry in @($response.value)) { $scope = $null if ($entry.PSObject.Properties['properties'] -and $entry.properties) { $scope = & $getPropertyValue $entry.properties @('scope', 'resourceId', 'id') } if ([string]::IsNullOrWhiteSpace($scope)) { $scope = & $getPropertyValue $entry @('scope', 'resourceId', 'id') } $scope = & $normalizeScope $scope if ([string]::IsNullOrWhiteSpace($scope) -or $scope.Equals($original, [System.StringComparison]::OrdinalIgnoreCase)) { continue } if ($seenScopes.ContainsKey($scope)) { continue } $seenScopes[$scope] = $true $resourceType = & $getNestedPropertyValue $entry @('resourceType', 'type') $displayName = & $getScopeDisplayName $scope $entry $resourceType if (-not [string]::IsNullOrWhiteSpace($resourceType) -and $displayName -notlike "*($resourceType)") { $displayName = "$displayName ($resourceType)" } $null = $items.Add([PSCustomObject]@{ DisplayName = $displayName Name = $displayName SubscriptionId = & $getSubscriptionIdFromScope $scope ResourceGroup = & $getResourceGroupFromScope $scope ResourceId = $scope Scope = $scope Type = $resourceType }) } $uri = if ($response.PSObject.Properties['nextLink'] -and $response.nextLink) { if ($response.nextLink -match '^https?://') { $response.nextLink } else { "https://management.azure.com$($response.nextLink)" } } else { $null } } Write-Verbose "Get-AzureReducedScopeOptions: returning $($items.Count) eligible child resource option(s)." return @($items | Sort-Object DisplayName) } |