Lab 07: PIM - CLI/PowerShell Solution
Note: PIM has excellent PowerShell/Graph API support for automation
Prerequisites
powershell
# Install Microsoft Graph PowerShell SDK
Install-Module Microsoft.Graph -Scope CurrentUser -Force
# Connect with required scopes for PIM
Connect-MgGraph -Scopes @(
"RoleManagement.ReadWrite.Directory",
"RoleAssignmentSchedule.ReadWrite.Directory",
"RoleEligibilitySchedule.ReadWrite.Directory",
"PrivilegedAccess.ReadWrite.AzureResources",
"Directory.ReadWrite.All"
)
# Verify connection
Get-MgContextTask 1: Explore PIM Dashboard
List All Entra ID Roles
powershell
# Get all directory role definitions
Get-MgRoleManagementDirectoryRoleDefinition |
Select-Object DisplayName, Id, IsBuiltIn |
Sort-Object DisplayName |
Format-Table
# Get specific role ID (you'll need this later)
$globalAdminRole = Get-MgRoleManagementDirectoryRoleDefinition -Filter "displayName eq 'Global Administrator'"
Write-Host "Global Administrator Role ID: $($globalAdminRole.Id)"
$userAdminRole = Get-MgRoleManagementDirectoryRoleDefinition -Filter "displayName eq 'User Administrator'"
Write-Host "User Administrator Role ID: $($userAdminRole.Id)"List Current Role Assignments
powershell
# Get all active role assignments
Get-MgRoleManagementDirectoryRoleAssignment -All | ForEach-Object {
$role = Get-MgRoleManagementDirectoryRoleDefinition -UnifiedRoleDefinitionId $_.RoleDefinitionId
$principal = Get-MgDirectoryObject -DirectoryObjectId $_.PrincipalId
[PSCustomObject]@{
Role = $role.DisplayName
Principal = $principal.AdditionalProperties.displayName
Scope = $_.DirectoryScopeId
}
} | Format-Table -AutoSize
# Get all eligible (PIM) role assignments
Get-MgRoleManagementDirectoryRoleEligibilitySchedule -All | ForEach-Object {
$role = Get-MgRoleManagementDirectoryRoleDefinition -UnifiedRoleDefinitionId $_.RoleDefinitionId
$principal = Get-MgDirectoryObject -DirectoryObjectId $_.PrincipalId
[PSCustomObject]@{
Role = $role.DisplayName
Principal = $principal.AdditionalProperties.displayName
StartDateTime = $_.StartDateTime
EndDateTime = $_.EndDateTime
Status = $_.Status
}
} | Format-Table -AutoSizeTask 2: Configure PIM Role Settings
Get Current Role Settings
powershell
# Get role policy assignment (PIM settings) for Global Administrator
$globalAdminRole = Get-MgRoleManagementDirectoryRoleDefinition -Filter "displayName eq 'Global Administrator'"
$policyAssignment = Get-MgPolicyRoleManagementPolicyAssignment -Filter "scopeId eq '/' and scopeType eq 'DirectoryRole' and roleDefinitionId eq '$($globalAdminRole.Id)'"
# Get the policy rules
$policy = Get-MgPolicyRoleManagementPolicy -UnifiedRoleManagementPolicyId $policyAssignment.PolicyId
Get-MgPolicyRoleManagementPolicyRule -UnifiedRoleManagementPolicyId $policyAssignment.PolicyId |
Select-Object Id, @{N='Type';E={$_.'@odata.type'}} |
Format-TableUpdate Role Settings (Advanced)
powershell
# Update PIM settings for a role
# This is complex - each rule type needs specific update
$globalAdminRole = Get-MgRoleManagementDirectoryRoleDefinition -Filter "displayName eq 'Global Administrator'"
$policyAssignment = Get-MgPolicyRoleManagementPolicyAssignment -Filter "scopeId eq '/' and scopeType eq 'DirectoryRole' and roleDefinitionId eq '$($globalAdminRole.Id)'"
$policyId = $policyAssignment.PolicyId
# Get current rules
$rules = Get-MgPolicyRoleManagementPolicyRule -UnifiedRoleManagementPolicyId $policyId
# Example: Update expiration rule for activation (max duration)
$expirationRule = $rules | Where-Object { $_.Id -eq "Expiration_EndUser_Assignment" }
$params = @{
"@odata.type" = "#microsoft.graph.unifiedRoleManagementPolicyExpirationRule"
id = "Expiration_EndUser_Assignment"
isExpirationRequired = $true
maximumDuration = "PT4H" # 4 hours in ISO 8601 format
}
Update-MgPolicyRoleManagementPolicyRule `
-UnifiedRoleManagementPolicyId $policyId `
-UnifiedRoleManagementPolicyRuleId "Expiration_EndUser_Assignment" `
-BodyParameter $paramsTask 3: Create an Eligible Assignment
PowerShell - Create Eligible Assignment
powershell
# Get the role definition ID
$userAdminRole = Get-MgRoleManagementDirectoryRoleDefinition -Filter "displayName eq 'User Administrator'"
$roleId = $userAdminRole.Id
# Get the user's ID
$user = Get-MgUser -Filter "userPrincipalName eq 'user1@yourdomain.com'"
$userId = $user.Id
# Create eligible assignment request
$params = @{
action = "adminAssign"
justification = "Assigning eligible role for lab exercise"
roleDefinitionId = $roleId
directoryScopeId = "/"
principalId = $userId
scheduleInfo = @{
startDateTime = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
expiration = @{
type = "afterDateTime"
endDateTime = (Get-Date).AddMonths(6).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
}
}
}
New-MgRoleManagementDirectoryRoleEligibilityScheduleRequest -BodyParameter $paramsVerify the Assignment
powershell
# List eligible assignments for the user
$userId = (Get-MgUser -Filter "userPrincipalName eq 'user1@yourdomain.com'").Id
Get-MgRoleManagementDirectoryRoleEligibilitySchedule -Filter "principalId eq '$userId'" |
ForEach-Object {
$role = Get-MgRoleManagementDirectoryRoleDefinition -UnifiedRoleDefinitionId $_.RoleDefinitionId
[PSCustomObject]@{
Role = $role.DisplayName
StartDateTime = $_.StartDateTime
EndDateTime = $_.EndDateTime
Status = $_.Status
}
} | Format-Table -AutoSizeTask 4: Configure User Administrator Role Settings
powershell
# This follows the same pattern as Task 2
# Get role and policy
$userAdminRole = Get-MgRoleManagementDirectoryRoleDefinition -Filter "displayName eq 'User Administrator'"
$policyAssignment = Get-MgPolicyRoleManagementPolicyAssignment -Filter "scopeId eq '/' and scopeType eq 'DirectoryRole' and roleDefinitionId eq '$($userAdminRole.Id)'"
$policyId = $policyAssignment.PolicyId
# Update maximum activation duration to 8 hours
$params = @{
"@odata.type" = "#microsoft.graph.unifiedRoleManagementPolicyExpirationRule"
id = "Expiration_EndUser_Assignment"
isExpirationRequired = $true
maximumDuration = "PT8H" # 8 hours
}
Update-MgPolicyRoleManagementPolicyRule `
-UnifiedRoleManagementPolicyId $policyId `
-UnifiedRoleManagementPolicyRuleId "Expiration_EndUser_Assignment" `
-BodyParameter $params
Write-Host "Updated User Administrator role settings"Task 5: Activate a Role
As the Eligible User - Request Activation
powershell
# Connect as the eligible user (User1)
Connect-MgGraph -Scopes "RoleAssignmentSchedule.ReadWrite.Directory"
# Get my eligible roles
Get-MgRoleManagementDirectoryRoleEligibilitySchedule -Filter "principalId eq '$((Get-MgContext).Account)'"
# Request role activation
$userAdminRole = Get-MgRoleManagementDirectoryRoleDefinition -Filter "displayName eq 'User Administrator'"
$params = @{
action = "selfActivate"
principalId = (Get-MgUser -UserId (Get-MgContext).Account).Id
roleDefinitionId = $userAdminRole.Id
directoryScopeId = "/"
justification = "Creating test users for Project Alpha development environment"
scheduleInfo = @{
startDateTime = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
expiration = @{
type = "afterDuration"
duration = "PT2H" # 2 hours
}
}
}
New-MgRoleManagementDirectoryRoleAssignmentScheduleRequest -BodyParameter $paramsCheck Activation Status
powershell
# Get my active role assignments
Get-MgRoleManagementDirectoryRoleAssignmentSchedule -Filter "principalId eq '$((Get-MgContext).Account)'" |
ForEach-Object {
$role = Get-MgRoleManagementDirectoryRoleDefinition -UnifiedRoleDefinitionId $_.RoleDefinitionId
[PSCustomObject]@{
Role = $role.DisplayName
Status = $_.Status
StartDateTime = $_.StartDateTime
EndDateTime = $_.EndDateTime
}
} | Format-Table -AutoSizeTask 6: PIM for Azure Resources
Azure CLI for Azure RBAC PIM
bash
# List eligible role assignments for Azure resources
az role assignment list --assignee "user2@yourdomain.com" --include-inherited --output table
# Using REST API for PIM Azure Resources
az rest --method GET \
--uri "https://management.azure.com/providers/Microsoft.Authorization/roleEligibilityScheduleRequests?api-version=2020-10-01" \
--output jsonPowerShell for Azure PIM
powershell
# Connect to Azure
Connect-AzAccount
# Get eligible assignments at subscription level
$subscriptionId = (Get-AzContext).Subscription.Id
# List role eligibility schedules
$uri = "https://management.azure.com/subscriptions/$subscriptionId/providers/Microsoft.Authorization/roleEligibilitySchedules?api-version=2020-10-01"
$token = (Get-AzAccessToken).Token
$headers = @{
Authorization = "Bearer $token"
"Content-Type" = "application/json"
}
$response = Invoke-RestMethod -Uri $uri -Headers $headers -Method GET
$response.value | ForEach-Object {
[PSCustomObject]@{
RoleId = $_.properties.roleDefinitionId.Split('/')[-1]
PrincipalId = $_.properties.principalId
Status = $_.properties.status
EndDateTime = $_.properties.endDateTime
}
} | Format-TableTask 7: Approve/Deny PIM Requests
List Pending Approval Requests
powershell
# Get pending approval requests for Entra ID roles
$pendingRequests = Get-MgRoleManagementDirectoryRoleAssignmentScheduleRequest -Filter "status eq 'PendingApproval'"
$pendingRequests | ForEach-Object {
$role = Get-MgRoleManagementDirectoryRoleDefinition -UnifiedRoleDefinitionId $_.RoleDefinitionId
$principal = Get-MgUser -UserId $_.PrincipalId
[PSCustomObject]@{
RequestId = $_.Id
Role = $role.DisplayName
Requester = $principal.DisplayName
Justification = $_.Justification
RequestedOn = $_.CreatedDateTime
}
} | Format-Table -AutoSizeApprove a Request
powershell
# Note: Approval requires the Identity Governance API
# This is a complex operation involving approval steps
$requestId = "your-request-id"
# Get the approval object
$approval = Get-MgIdentityGovernancePrivilegedAccessGroupAssignmentApproval -ApprovalId $requestId
# Approve
$params = @{
reviewResult = "Approve"
justification = "Approved for project work"
}
# Update the approval stage
# This requires specific API calls based on the approval workflowTask 8: Create Access Review
PowerShell - Create Access Review
powershell
# Create an access review for User Administrator role
$userAdminRole = Get-MgRoleManagementDirectoryRoleDefinition -Filter "displayName eq 'User Administrator'"
$params = @{
displayName = "Quarterly User Admin Review"
descriptionForAdmins = "Quarterly review of User Administrator role assignments"
descriptionForReviewers = "Please review whether these users still need User Administrator access"
scope = @{
"@odata.type" = "#microsoft.graph.principalResourceMembershipsScope"
principalScopes = @(
@{
"@odata.type" = "#microsoft.graph.accessReviewQueryScope"
query = "/roleManagement/directory/roleAssignments?`$filter=roleDefinitionId eq '$($userAdminRole.Id)'"
queryType = "MicrosoftGraph"
}
)
resourceScopes = @(
@{
"@odata.type" = "#microsoft.graph.accessReviewQueryScope"
query = "/roleManagement/directory/roleDefinitions/$($userAdminRole.Id)"
queryType = "MicrosoftGraph"
}
)
}
reviewers = @(
@{
query = "/users/me"
queryType = "MicrosoftGraph"
}
)
settings = @{
mailNotificationsEnabled = $true
reminderNotificationsEnabled = $true
justificationRequiredOnApproval = $true
defaultDecisionEnabled = $true
defaultDecision = "Deny"
instanceDurationInDays = 14
autoApplyDecisionsEnabled = $true
recommendationsEnabled = $true
recurrence = @{
pattern = @{
type = "absoluteMonthly"
interval = 3 # Quarterly
}
range = @{
type = "noEnd"
startDate = (Get-Date).ToString("yyyy-MM-dd")
}
}
}
}
New-MgIdentityGovernanceAccessReviewDefinition -BodyParameter $paramsTask 9: Review PIM Audit Logs
Get PIM Audit Events
powershell
# Get PIM-related audit logs
$startDate = (Get-Date).AddDays(-30).ToString("yyyy-MM-ddTHH:mm:ssZ")
Get-MgAuditLogDirectoryAudit -Filter "activityDateTime ge $startDate" -Top 100 |
Where-Object { $_.Category -eq "RoleManagement" } |
Select-Object ActivityDateTime,
ActivityDisplayName,
@{N='Actor';E={$_.InitiatedBy.User.UserPrincipalName}},
Result,
@{N='Target';E={$_.TargetResources[0].DisplayName}} |
Format-Table -AutoSizeExport to CSV
powershell
# Export PIM audit logs for compliance
$auditLogs = Get-MgAuditLogDirectoryAudit -Filter "category eq 'RoleManagement'" -Top 1000
$auditLogs | Select-Object `
ActivityDateTime,
ActivityDisplayName,
@{N='Actor';E={$_.InitiatedBy.User.UserPrincipalName}},
@{N='ActorIP';E={$_.InitiatedBy.User.IpAddress}},
Result,
ResultReason,
@{N='Target';E={$_.TargetResources[0].DisplayName}} |
Export-Csv -Path "PIM_Audit_$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation
Write-Host "Exported audit logs to PIM_Audit_$(Get-Date -Format 'yyyyMMdd').csv"Task 10: Check PIM Alerts
List PIM Alerts
powershell
# Get PIM alerts
Get-MgPrivilegedAccessResourceRoleSettingAlert -PrivilegedAccessId "aadRoles" |
Select-Object AlertType, AlertDescription, IsActive |
Format-Table -AutoSize
# Alternative: Use direct API call
$uri = "https://graph.microsoft.com/v1.0/privilegedAccess/aadRoles/resources/tenant/alerts"
Invoke-MgGraphRequest -Uri $uri -Method GETChallenge: List Over-Activated Users
powershell
# Find users who have had roles active for extended periods
$activationHistory = Get-MgAuditLogDirectoryAudit -Filter "activityDisplayName eq 'Add member to role completed (PIM activation)'" -Top 500
$userActivations = $activationHistory | Group-Object -Property {$_.InitiatedBy.User.UserPrincipalName}
$userActivations | ForEach-Object {
[PSCustomObject]@{
User = $_.Name
ActivationCount = $_.Count
LastActivation = ($_.Group | Sort-Object ActivityDateTime -Descending | Select-Object -First 1).ActivityDateTime
}
} | Sort-Object ActivationCount -Descending | Format-Table -AutoSizeSummary: CLI/PowerShell Capabilities
| Task | PowerShell/CLI Support | Notes |
|---|---|---|
| List role definitions | ✅ Full | Easy |
| List eligible/active assignments | ✅ Full | Easy |
| Create eligible assignments | ✅ Full | Supported |
| Configure role settings | ⚠️ Complex | Requires policy rule updates |
| Activate roles | ✅ Full | selfActivate action |
| Process approvals | ⚠️ Limited | Complex API |
| Create access reviews | ✅ Full | Supported |
| View audit logs | ✅ Full | Easy |
| Manage alerts | ⚠️ Limited | Some API support |