Last active
December 22, 2025 21:35
-
-
Save sean-mcardle/a915d86f2b9985607e3006ebcd91a0c9 to your computer and use it in GitHub Desktop.
Script for activating PIM roles. Meant to be used within the Azure shell when the PIM portal acts up again. Copy pasta. It utilizes REST APIs for role eligibility and activation to avoid DLL conflicts in the Identity Governance cmdlets (some of us just want to do our jobs instead of fight with your dependencies Microsoft).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| function Out-SelectorMenu { | |
| param ( | |
| [Parameter(ValueFromPipeline=$true)] | |
| $InputObject, | |
| [Parameter(Position=0)] | |
| $Title, | |
| $Selector | |
| ) | |
| begin { | |
| $_items = @() | |
| } | |
| process { | |
| if ($InputObject) { | |
| $_items += $InputObject | |
| } | |
| } | |
| end { | |
| Write-Host $Title | |
| Write-Host ($_items | ForEach-Object {$index=0} {$_; $index++} | Format-Table @{Label="Index";Expression={$index}; Width=5 }, * | Out-String) | |
| $selectionMade = $false | |
| $selection = $null | |
| do{ | |
| $selection = Read-Host -Prompt "Make a selection by index ('c' to cancel)#" | |
| if ($selection -match '[0-9]+' -and [int]$selection -ge 0 -and [int]$selection -lt $_items.Count) { | |
| $selectionMade = $true | |
| break | |
| } elseif ($selection -and $selection.Trim() -like 'c') { | |
| break | |
| } | |
| } while ($true) | |
| if ($selectionMade) { | |
| return $_items[$selection] | Select-Object -ExcludeProperty 'Index' | |
| } | |
| } | |
| } | |
| $fmt_roleName = @{Name='Role';Expression={$_.roleDefinition.displayName}} | |
| $fmt_roleScope = @{ | |
| Name='Scope'; | |
| Expression={ | |
| if($_.scopedResource) { | |
| "$( if($_.scopedResource.type -like "administrativeUnits"){"AU"}else{$_.scopedResource.type}) : $($_.scopedResource.displayName)" | |
| } else { | |
| "Directory : /" | |
| } | |
| } | |
| } | |
| # Get the user id of the cloud shell user | |
| $subjectId = & az ad signed-in-user show --query id | |
| $subjectId = $subjectId.Trim('"') | |
| if (-not $subjectId) { | |
| Write-Error "Can't resolve Id of the signed-in user!`nThis is needed to resolve eligible role assignments.`nQuiting..." | |
| return | |
| } | |
| $header = @{ | |
| Authorization = "Bearer $(ConvertFrom-SecureString -AsPlainText (Get-AzAccessToken).Token)" | |
| } | |
| # Load eligible roles for the signed-in user and prompt for selection | |
| $eligibleRolesUri = "https://api.azrbac.mspim.azure.com/api/v2/privilegedAccess/aadroles/roleAssignments?`$expand=linkedEligibleRoleAssignment,subject,scopedResource,roleDefinition(`$expand=resource)&`$filter=(subject/id eq '$subjectId') and (assignmentState eq 'Eligible')&`$count=true" | |
| $eligibleRolesRequest = Invoke-RestMethod -Uri $eligibleRolesUri -Headers $header | |
| $roleCount = $eligibleRolesRequest | select -ExpandProperty count | |
| $eligibleRoles = $eligibleRolesRequest | select -ExpandProperty value | |
| $selectedRole = $eligibleRoles | select $fmt_roleName, $fmt_roleScope, roleDefinitionId, scopedResource, roleDefinition, subject | Out-SelectorMenu -Title "Select a role" | |
| if (-not $selectedRole) { | |
| Write-Host "No role selected." | |
| return | |
| } | |
| $reason = Read-Host -Prompt "Reason for activating $($selectedRole.Role)" | |
| if (-not $reason) { | |
| $reason = "No reason entered." | |
| } | |
| function ActivateNow { | |
| # Activate the specified role right now for 8 hours | |
| param ($selectedRole, $reason) | |
| $resourceId = $selectedRole.roleDefinition.resourceId | |
| if ($selectedRole.scopedResource) { | |
| $resourceId = $selectedRole.scopedResource.id | |
| } | |
| $uri = "https://api.azrbac.mspim.azure.com/api/v2/privilegedAccess/aadroles/roleAssignmentRequests" | |
| $header = @{ | |
| Authorization = "Bearer $(ConvertFrom-SecureString -AsPlainText (Get-AzAccessToken).Token)" | |
| } | |
| $body = @" | |
| { | |
| "roleDefinitionId": "$($selectedRole.roleDefinitionId)", | |
| "resourceId": "$resourceId", | |
| "subjectId": "$subjectId", | |
| "assignmentState": "Active", | |
| "type": "UserAdd", | |
| "reason": "$reason", | |
| "ticketNumber": "", | |
| "ticketSystem": "", | |
| "schedule": { | |
| "type": "Once", | |
| "startDateTime": null, | |
| "endDateTime": null, | |
| "duration": "PT8H" | |
| }, | |
| "scopedResourceId": "" | |
| } | |
| "@ | |
| $header = @{ | |
| Authorization = "Bearer $(ConvertFrom-SecureString -AsPlainText (Get-AzAccessToken).Token)" | |
| } | |
| Write-Host Activating role $selectedRole.Role $selectedRole.Scope | |
| Invoke-RestMethod -Method POST -Uri $uri -Body $body -Headers $header -ContentType "application/json" | |
| } | |
| ActivateNow $selectedRole $reason |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment