Wednesday, March 25, 2026

Auto-Activate All Azure PIM Roles with One PowerShell Script

Auto-Activate All Azure PIM Roles with One PowerShell Script

Category: Azure | Microsoft Entra | PowerShell
Tags: PIM, Privileged Identity Management, PowerShell, Microsoft Graph, Azure AD


The Problem

If your organization uses Azure Privileged Identity Management (PIM), you know the drill:

  1. Open Azure Portal
  2. Go to PIM
  3. Click your role
  4. Click Activate
  5. Enter justification
  6. Set duration
  7. Click Activate again
  8. Repeat for every single role

If you have 7–8 eligible roles, that's a painful click-fest every single morning. There had to be a better way.


The Solution

A simple PowerShell script using the Microsoft Graph module that:

  • Connects to your Microsoft 365 tenant
  • Fetches all your eligible PIM roles automatically
  • Reads each role's policy-allowed maximum duration
  • Activates all roles in one shot — no prompts, no manual input

Prerequisites

Install the Microsoft Graph PowerShell module if you haven't already:

Install-Module Microsoft.Graph -Scope CurrentUser

The Script

# ============================================================
#  Azure PIM Role Activator - Auto Activate All Roles
#  Requires: Microsoft.Graph PowerShell Module
# ============================================================

$justification = "Using PowerShell"

Connect-MgGraph -Scopes "RoleManagement.ReadWrite.Directory", "RoleAssignmentSchedule.ReadWrite.Directory" -NoWelcome

$user = Get-MgUser -Filter "userPrincipalName eq '$(( Get-MgContext).Account)'"
Write-Host "Logged in as: $($user.UserPrincipalName)" -ForegroundColor Green

$eligibleRoles = Get-MgRoleManagementDirectoryRoleEligibilitySchedule `
    -Filter "principalId eq '$($user.Id)'" -ExpandProperty RoleDefinition

if (-not $eligibleRoles) { Write-Warning "No eligible PIM roles found. Exiting."; exit }

Write-Host "`n===== ACTIVATING ALL ROLES =====" -ForegroundColor Yellow
foreach ($role in $eligibleRoles) {
    try {
        $rawDuration = ((Get-MgPolicyRoleManagementPolicyAssignment `
            -Filter "scopeId eq '/' and scopeType eq 'DirectoryRole' and roleDefinitionId eq '$($role.RoleDefinitionId)'" `
            -ExpandProperty "Policy(`$expand=Rules)").Policy.Rules | Where-Object {
                $_.Id -eq "Expiration_EndUser_Assignment"
        }).AdditionalProperties["maximumDuration"]

        $hours = if ($rawDuration -match "PT(\d+)H")  { [int]$Matches[1] }
               elseif ($rawDuration -match "P(\d+)D") { [int]$Matches[1] * 24 }
               else                                    { 8 }

        New-MgRoleManagementDirectoryRoleAssignmentScheduleRequest -BodyParameter @{
            Action           = "selfActivate"
            PrincipalId      = $user.Id
            RoleDefinitionId = $role.RoleDefinitionId
            DirectoryScopeId = $role.DirectoryScopeId
            Justification    = $justification
            ScheduleInfo     = @{
                StartDateTime = (Get-Date).ToUniversalTime()
                Expiration    = @{ Type = "AfterDuration"; Duration = "PT${hours}H" }
            }
        } | Out-Null

        Write-Host "  ✔ Activated : $($role.RoleDefinition.DisplayName) for $hours hour(s)" -ForegroundColor Green
    }
    catch {
        Write-Host "  ✘ Failed    : $($role.RoleDefinition.DisplayName) — $($_.Exception.Message)" -ForegroundColor Red
    }
}

Write-Host "`nDone!" -ForegroundColor Cyan

How It Works — Step by Step

1. Connect to Microsoft Graph

Connect-MgGraph -Scopes "RoleManagement.ReadWrite.Directory", "RoleAssignmentSchedule.ReadWrite.Directory"

This opens a browser login prompt. Sign in with your M365 account. Two permissions are requested:

  • RoleManagement.ReadWrite.Directory — to read eligible roles
  • RoleAssignmentSchedule.ReadWrite.Directory — to activate them

2. Fetch Your Eligible Roles

Get-MgRoleManagementDirectoryRoleEligibilitySchedule -Filter "principalId eq '$($user.Id)'" -ExpandProperty RoleDefinition

This pulls every role you are eligible for in PIM — the same list you'd see in the Azure Portal under My Roles.

3. Read the Policy Max Duration

Instead of hardcoding a duration like 8 hours, the script reads the PIM policy configured for each role:

Get-MgPolicyRoleManagementPolicyAssignment ... -ExpandProperty "Policy(`$expand=Rules)"

It then looks for the rule named Expiration_EndUser_Assignment and extracts maximumDuration. This is the max hours your admin has configured for that role.

Why does this matter?
Different roles can have different max durations set by your admin. If you hardcode 8 hours but a role only allows 4 hours, the activation fails with an ExpirationRule error.

The script handles both ISO 8601 formats:

  • PT4H → 4 hours
  • P1D → 24 hours

4. Activate All Roles

New-MgRoleManagementDirectoryRoleAssignmentScheduleRequest -BodyParameter @{ ... }

This is the Graph API call that does the actual PIM activation — same as clicking Activate in the portal, but done programmatically for every role in a single loop.


Sample Output

Logged in as: sreekanthreddy@contoso.com

===== ACTIVATING ALL ROLES =====
  ✔ Activated : User Administrator for 8 hour(s)
  ✔ Activated : Exchange Administrator for 8 hour(s)
  ✔ Activated : SharePoint Administrator for 8 hour(s)
  ✔ Activated : Teams Administrator for 8 hour(s)
  ✔ Activated : Groups Administrator for 4 hour(s)
  ✔ Activated : Power Platform Administrator for 8 hour(s)
  ✔ Activated : Office Apps Administrator for 8 hour(s)

Done!

Notice Groups Administrator activated for only 4 hours — that's because its PIM policy max is 4 hours. The script respected it automatically instead of failing.


Customization

What to change Where
Justification text $justification = "Using PowerShell"
Fallback duration (if policy unreadable) else { 8 } at the end of the hours block

Common Error & Fix

Error: ExpirationRule — RoleAssignmentRequestPolicyValidationFailed

Cause: You requested more hours than the role's PIM policy allows.

Fix: Use this script — it reads the policy max per role and uses that automatically.


Conclusion

This script cuts your daily PIM activation from a 5-minute portal click-fest down to a single PowerShell run. It's policy-aware, handles multiple roles gracefully, and clearly tells you what was activated and for how long.

Save it, schedule it, or just run it each morning. Either way — one command and you're done.



# ============================================================

#  Azure PIM Role Activator

#  Requires: Microsoft.Graph PowerShell Module

#  Install : Install-Module Microsoft.Graph -Scope CurrentUser

# ============================================================

# ---------- CONFIGURATION ----------

$justification = "Activating role via PowerShell script"

$durationHours = 8   # Set activation duration (hours)

# -----------------------------------

# Step 1: Install Graph module if missing

if (-not (Get-Module -ListAvailable -Name Microsoft.Graph)) {

    Write-Host "Installing Microsoft.Graph module..." -ForegroundColor Yellow

    Install-Module Microsoft.Graph -Scope CurrentUser -Force

}

# Step 2: Connect to Microsoft Graph

Write-Host "`nConnecting to Microsoft Graph..." -ForegroundColor Cyan

Connect-MgGraph -Scopes "RoleManagement.ReadWrite.Directory", "RoleAssignmentSchedule.ReadWrite.Directory" -NoWelcome

 

# Step 3: Get current user

$userId = (Get-MgContext).Account

$user   = Get-MgUser -Filter "userPrincipalName eq '$userId'"

Write-Host "Logged in as: $userId" -ForegroundColor Green

 

# Step 4: Get all eligible roles for the user

Write-Host "`nFetching eligible PIM roles..." -ForegroundColor Cyan

$eligibleRoles = Get-MgRoleManagementDirectoryRoleEligibilitySchedule `

    -Filter "principalId eq '$($user.Id)'" -ExpandProperty RoleDefinition

 

if (-not $eligibleRoles) {

    Write-Warning "No eligible PIM roles found for this user. Exiting."

    exit

}

 

# Step 5: Display eligible roles

Write-Host "`n===== ELIGIBLE ROLES =====" -ForegroundColor Yellow

$index = 1

$roleList = @()

foreach ($role in $eligibleRoles) {

    $roleName  = $role.RoleDefinition.DisplayName

    $scopeId   = $role.DirectoryScopeId

    Write-Host "  [$index] $roleName  (Scope: $scopeId)"

    $roleList += [PSCustomObject]@{

        Index            = $index

        RoleName         = $roleName

        RoleDefinitionId = $role.RoleDefinitionId

        DirectoryScopeId = $scopeId

    }

    $index++

}

# Step 6: Prompt user to select roles

Write-Host "`nEnter role numbers to activate (comma-separated), or type 'ALL' to activate all:"

$input = Read-Host "Your selection"

 

if ($input.Trim().ToUpper() -eq "ALL") {

    $selectedRoles = $roleList

} else {

    $selectedIndexes = $input -split "," | ForEach-Object { $_.Trim() -as [int] }

    $selectedRoles   = $roleList | Where-Object { $_.Index -in $selectedIndexes }

}

if (-not $selectedRoles) {

    Write-Warning "No valid roles selected. Exiting."

    exit

}
 

# Step 7: Activate selected roles

Write-Host "`n===== ACTIVATING ROLES =====" -ForegroundColor Yellow

foreach ($role in $selectedRoles) {

    try {

        $params = @{

            Action           = "selfActivate"

            PrincipalId      = $user.Id

            RoleDefinitionId = $role.RoleDefinitionId

            DirectoryScopeId = $role.DirectoryScopeId

            Justification    = $justification

            ScheduleInfo     = @{

                StartDateTime = (Get-Date).ToUniversalTime()

                Expiration    = @{

                    Type     = "AfterDuration"

                    Duration = "PT${durationHours}H"

                }

            }

        }


        New-MgRoleManagementDirectoryRoleAssignmentScheduleRequest -BodyParameter $params | Out-Null

        Write-Host "  Activated : $($role.RoleName) for $durationHours hour(s)" -ForegroundColor Green

    }

    catch {

        Write-Host "  Failed    : $($role.RoleName) — $($_.Exception.Message)" -ForegroundColor Red

    }

}

Write-Host "`nDone! Active roles will expire after $durationHours hour(s)." -ForegroundColor Cyan

 

No comments:

Post a Comment

Featured Post

How to Get Table → Security Role Mapping in Power Platform (PowerShell + Web API)

How to Get Table → Security Role Mapping in Power Platform Power Platform   |   Dataverse   |   Security & Governance   When a...

Popular posts