Public/Test-CallerRBACAssignment.ps1
|
function Test-CallerRBACAssignment { <# .SYNOPSIS Tests whether a caller already holds the required role(s) at a scope. .DESCRIPTION Checks the caller's effective Azure role assignments at (or above) the supplied scope against a required role set. Returns one result object per required role with a State boolean indicating whether the caller has it. Role assignment lookups use Get-AzRoleAssignment. The Az.Resources module must be available and a context established (Connect-AzAccount) for live checks. When -RoleAssignment is supplied the caller's assignments are taken from that array instead, which makes the function fully testable without a live connection. .PARAMETER CallerId The caller identity to evaluate: a UPN, object id, or sign-in name. .PARAMETER RequiredRole One or more role names the caller is expected to hold. .PARAMETER Scope The Azure scope to evaluate the assignments at. .PARAMETER RoleAssignment Optional pre-fetched role assignment objects (each with RoleDefinitionName and Scope). When supplied, no live Az call is made. .EXAMPLE Test-CallerRBACAssignment -CallerId 'patrick.gallucci@microsoft.com' ` -RequiredRole 'Reader' -Scope '/subscriptions/00000000-0000-0000-0000-000000000000' .OUTPUTS PSCustomObject per role: CallerId, Role, Scope, State. #> [CmdletBinding()] [OutputType([pscustomobject])] param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$CallerId, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string[]]$RequiredRole, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$Scope, [Parameter()] [object[]]$RoleAssignment ) $scope = $Scope.TrimEnd('/') if (-not $PSBoundParameters.ContainsKey('RoleAssignment')) { if (-not (Get-Command -Name 'Get-AzRoleAssignment' -ErrorAction SilentlyContinue)) { throw "Get-AzRoleAssignment is not available. Install/Import Az.Resources or pass -RoleAssignment for offline evaluation." } try { $RoleAssignment = @(Get-AzRoleAssignment -SignInName $CallerId -ErrorAction Stop) } catch { Write-Warning "Falling back to object-id lookup: $($_.Exception.Message)" $RoleAssignment = @(Get-AzRoleAssignment -ObjectId $CallerId -ErrorAction Stop) } } foreach ($role in $RequiredRole) { # The caller holds the role if assigned it at this scope or any ancestor. $match = $RoleAssignment | Where-Object { $_.RoleDefinitionName -eq $role -and $scope.StartsWith(($_.Scope.TrimEnd('/')), [System.StringComparison]::OrdinalIgnoreCase) } | Select-Object -First 1 [pscustomobject]@{ PSTypeName = 'PSAutoRBAC.AssignmentState' CallerId = $CallerId Role = $role Scope = $scope State = [bool]$match } } } |