functions/roleManagement/roleManagementPolicies/Export-TmfRoleManagementPolicy.ps1
|
<#
.SYNOPSIS Exports role management policies (PIM) into TMF configuration objects or JSON. .DESCRIPTION Retrieves role management policy assignments and policies (directory scope only) and converts them to TMF shape including rules. Returns objects unless -OutPath is supplied. .PARAMETER SpecificResources Optional list of policy assignment IDs or role definition display names (comma separated accepted) to filter. .PARAMETER Scope AzureResources | AzureAD | AADGroup (default AzureAD). .PARAMETER OutPath Root folder to write export; when omitted objects are returned. .PARAMETER Append Add content to an existing file .PARAMETER ForceBeta Use beta Graph endpoint for retrieval. .PARAMETER Cmdlet Internal pipeline parameter; do not supply manually. .EXAMPLE Export-TmfRoleManagementPolicy -Scope AzureAD -OutPath C:\temp\tmf .EXAMPLE Export-TmfRoleManagementPolicy -Scope AzureResources -SpecificResources Global Reader #> function Export-TmfRoleManagementPolicy { [CmdletBinding()] param( [string[]] $SpecificResources, [ValidateSet('AzureResources', 'AzureAD', 'AADGroup')] [string] $Scope, [Alias('OutPutPath')] [string] $OutPath, [switch] $Append, [switch] $ForceBeta, [System.Management.Automation.PSCmdlet] $Cmdlet = $PSCmdlet ) begin { Test-GraphConnection -Cmdlet $Cmdlet $resourceName = 'roleManagementPolicies' $templateName = 'roleManagementPolicyRuleTemplates' $tenant = (Invoke-MgGraphRequest -Method GET -Uri ("$($script:graphBaseUrl)/organization?`$select=displayname,id")).value $roleManagementPoliciesExport = @() $roleManagementPolicyRuleTemplatesExport = @() function Convert-RoleManagementPolicy { param([object]$policy, [string]$policyScope) $obj = [ordered]@{present = $true } if ($policy.PSObject.Members.Match('id') -and $policy.id) { $roleId = (Invoke-MgGraphRequest -Method "GET" -Uri "$($script:graphBaseUrl)/policies/roleManagementPolicyAssignments?`$filter=scopeId eq '/' and scopeType eq 'Directory' and policyId eq '$($policy.id)'").value.roleDefinitionId $obj.roleReference = Resolve-DirectoryRoleDefinition -InputReference $roleId -DisplayName } $obj.activationApprover = @() if ($policy.PSObject.Members.Match('rules')) { # Derive approval rules irrespective of property naming differences $approverRules = $policy.rules | Where-Object { ($_.PSObject.Members.Match('ruleType') -and $_.ruleType -match 'Approval') -or ($_.PSObject.Members.Match('@odata.type') -and $_.'@odata.type' -match 'unifiedRoleManagementPolicyApprovalRule') } foreach ($rule in $approverRules) { if ($rule.PSObject.Members.Match('setting') -and $rule.setting.PSObject.Members.Match('approvalStages')) { foreach ($stage in $rule.setting.approvalStages) { if ($stage.primaryApprovers) { foreach ($approver in $stage.primaryApprovers) { if ($approver.userId) { $reference = Resolve-User -InputReference $approver.userId -UserPrincipalName } else { $reference = Resolve-Group -InputReference $approver.groupId -DisplayName } $obj.activationApprover += [ordered]@{reference = $reference; type = ($approver.'@odata.type' -replace '#microsoft.graph.', '') } } } } } } } if ($policy.PSObject.Members.Match('scopeId')) { $obj.scopeId = $policy.scopeId } if ($policy.PSObject.Members.Match('scopeType')) { $obj.scopeType = $policy.scopeType } if ($policyScope -eq 'AzureResources') { if ($policy.PSObject.Members.Match('scopeId')) { $scopeParts = $policy.scopeId -split '/' if ($scopeParts.Count -ge 3 -and $scopeParts[1] -eq 'subscriptions') { $obj.subscriptionReference = $scopeParts[2] if ($scopeParts.Count -ge 5 -and $scopeParts[3] -eq 'resourceGroups') { $obj.scopeReference = $scopeParts[4]; $obj.scopeType = 'resourceGroup' } else { $obj.scopeReference = $scopeParts[2]; $obj.scopeType = 'subscription' } } } } else { if (-not ($obj.PSObject.Members.Match('scopeId')) -or $obj.scopeId -eq '/') { $obj.scopeReference = '/'; $obj.scopeType = 'directory' } } if ($policy.PSObject.Members.Match('rules')) { $templateObj = [ordered]@{displayName = "$($obj.roleReference.replace(' ',''))_$($policy.scopeType)" } $templateObj.rules = @() foreach ($rule in $policy.rules) { if ($rule.PSObject.Members.Match('id') -and $rule.id -ne 'Approval_EndUser_Assignment') { $templateObj.rules += $rule } } $obj.ruleTemplate = $templateObj.displayName } if ($templateObj) { return $obj,$templateObj } else { return $obj } } function Get-AllRoleManagementPolicies { param([string]$policyScope, [string[]]$GroupIds) $collected = @() $primaryBase = if ($ForceBeta) { $script:graphBaseUrlbeta } else { $script:graphBaseUrl1 } $attempts = @($primaryBase); if (-not $ForceBeta) { $attempts += $script:graphBaseUrlbeta } # Build required filters based on scope as per Microsoft Docs (List roleManagementPolicies) $filters = @() switch ($policyScope) { 'AzureAD' { $filters += "scopeId eq '/' and scopeType eq 'Directory'" } 'AzureResources' { $filters += "scopeType eq 'AzureResource'" } # placeholder – actual Azure RBAC policies are different API set 'AADGroup' { if ($GroupIds) { foreach ($gid in $GroupIds) { $filters += "scopeId eq '$gid' and scopeType eq 'Group'" } } else { Write-PSFMessage -Level Warning -FunctionName 'Export-TmfRoleManagementPolicy' -Message 'Group scope requested but no group IDs supplied via -SpecificResources; no policies will be returned.' } } default { $filters += "scopeId eq '/' and scopeType eq 'DirectoryRole'" } } foreach ($baseAttempt in $attempts) { foreach ($filter in $filters) { try { $uri = "$baseAttempt/policies/roleManagementPolicies?`$filter=$([uri]::EscapeDataString($filter))&`$expand=rules" $resp = Invoke-MgGraphRequest -Method GET -Uri $uri -ErrorAction Stop if ($resp.value) { $collected += $resp.value } while ($resp.'@odata.nextLink') { $resp = Invoke-MgGraphRequest -Method GET -Uri $resp.'@odata.nextLink' -ErrorAction Stop if ($resp.value) { $collected += $resp.value } } } catch { Write-PSFMessage -Level Warning -FunctionName 'Export-TmfRoleManagementPolicy' -Message ("List policies error (base={0} filter=<{1}>): {2}" -f $baseAttempt, $filter, $_.Exception.Message) } } if ($collected.Count) { if ($baseAttempt -ne $primaryBase) { Write-PSFMessage -Level Verbose -FunctionName 'Export-TmfRoleManagementPolicy' -Message 'Fell back to beta endpoint for roleManagementPolicies.' }; break } } return ($collected | Sort-Object -Property id -Unique) } } process { if ($Scope -and ($Scope -ne "AzureAD")) { $policyScope = 'AzureAD' Write-PSFMessage -Level Warning -FunctionName 'Export-TmfRoleAssignment' -String 'TMF.Export.ScopeNotSupported' -StringValues $Scope,$resourceName,$policyScope } else { $policyScope = 'AzureAD' } if ($SpecificResources) { $identifiers = @() foreach ($entry in $SpecificResources) { $identifiers += $entry -split ',' | ForEach-Object { $_.Trim() } | Where-Object { $_ } } $identifiers = $identifiers | Select-Object -Unique $allRoleManagementPolicies = Get-AllRoleManagementPolicies -policyScope $policyScope foreach ($idOrName in $identifiers) { $match = $allRoleManagementPolicies | Where-Object { $_.id -eq $idOrName -or $_.displayName -eq $idOrName -or $_.roleDefinition.displayName -eq $idOrName } if ($match) { foreach ($m in $match) { $result = Convert-RoleManagementPolicy $m $policyScope if ($result.count -eq 2) { $roleManagementPoliciesExport += $result[0] $roleManagementPolicyRuleTemplatesExport += $result[1] } else { $roleManagementPoliciesExport += $result } } } else { Write-PSFMessage -Level Warning -FunctionName 'Export-TmfRoleManagementPolicy' -String 'TMF.Export.NotFound' -StringValues $idOrName, $resourceName, $tenant.displayName } } } else { $allRoleManagementPolicies = Get-AllRoleManagementPolicies -policyScope $policyScope foreach ($policy in $allRoleManagementPolicies) { $result = Convert-RoleManagementPolicy $policy $policyScope if ($result.count -eq 2) { $roleManagementPoliciesExport += $result[0] $roleManagementPolicyRuleTemplatesExport += $result[1] } else { $roleManagementPoliciesExport += $result } } } } end { if (-not $OutPath) { return $roleManagementPoliciesExport } if ($roleManagementPoliciesExport) { if ($Append) { Write-TmfExportFile -OutPath $OutPath -ParentPath 'roleManagement' -ResourceName $resourceName -Data $roleManagementPoliciesExport -Append } else { Write-TmfExportFile -OutPath $OutPath -ParentPath 'roleManagement' -ResourceName $resourceName -Data $roleManagementPoliciesExport } } if ($roleManagementPolicyRuleTemplatesExport) { if ($Append) { Write-TmfExportFile -OutPath $OutPath -ParentPath 'roleManagement' -ResourceName $templateName -Data $roleManagementPolicyRuleTemplatesExport -Append } else { Write-TmfExportFile -OutPath $OutPath -ParentPath 'roleManagement' -ResourceName $templateName -Data $roleManagementPolicyRuleTemplatesExport } } } } |