Automating Azure PIM Requests with PowerShell

Privileged Identity Management (PIM) is made to be a secure authentication method to assign user permissions via groups and monitor the access.  This enables short time requests for the permissions that can require fields like reason for access, how long to have access and who is having access. This can typically be used for engineers’ access to higher environments, normally only needed for deployment and fixes. 

However, I had a situation where it was implemented on all environments including development. Lower environments are not normally covered with this level of security due to the nature of the activities required in them environments for debugging, development and testing. This is also not a bad practice as it ensures good security and auditing for high profile companies. 

For myself as an engineer though it was tiresome to remember to request my access every day, as the max it would stay active was 24 hours. Therefore, I as a DevOps engineer looked to automate everything, including this. I was unable to find how to do it using my preference of Azure CLI or REST API but found a solution using the Azure PowerShell Modules. 

Solution 

First you need to install the required Azure PowerShell Module, which are ‘AzureAD` to connect to the subscription and AzureADPreview to use the PIM requests command. The below script will see if they are already existing before trying to download again, else it will install. 

if (-not $(Get-Module AzureADPreview -ListAvailable)) {  
  Write-Host "Not got AzureADPreview Installed"  
  Write-Host "Installing now" 
  Install-Module -Name AzureADPreview -Scope CurrentUser -Force 
} 
if (-not $(Get-Module AzureAD -ListAvailable)) {  
  Write-Host "Not got AzureAD Installed"  
  Write-Host "Installing now" 
  Install-Module -Name AzureAD -Scope CurrentUser -Force 
} 

Next, we want to check if we are logged in, and if not then we can do that. The snippet below will attempt to get the current session and if it fails it will run the login command instead. 

try { 
  Write-Host "Checking Connection"  
  Get-AzureADCurrentSessionInfo 
  Write-Host "Connection Found"  
} 
catch { 
  Write-Host "Making Connection" 
  Connect-AzureAD 
} 

From there we can start setting the variables up. The access_reason is the text reason as to why you require this access, which will then be stored for the monitoring. I would add a valid reason in here but something repeatable like the example. The `user_id` is the user that is requesting access’ object ID, so we know who to grant the access to. Finally, you have the requested_roles this is an array of the roles looking to be requested. 

The resource_id is the ID GUID of the group requesting access to, role_definition_id is the ID of the role in PIM you are requesting and `name` is just the display name of the role for debugging reasons. If you have multiple roles you can add to the array of objects. 

$access_reason = "DevOps Development Work"  
$user_id = (Get-AzADUser -UserPrincipalName (Get-AzContext).Account).Id 
$requested_roles = @(  
  @{   
    resource_id       = ""  
    role_definition_id = ""  
    name             = ""  
  }  
)  

The last set of variables are the schedule. This is used to setup when the access starts and for how long. This can vary depending on what the PIM is setup to allow. For example, the policy might be setup to only allow a maximum of 2 hours, so you would only be able to request that. 

The Type is what kind of schedule we are requesting. The duration is a calculated time from the start. For example, PT1M indicates 1 minute from start, PT30M is 30 minutes from start, PT1H hour from start. Then we have the start date and time when the request is, which for this is the current date and time. 

$schedule = New-Object Microsoft.Open.MSGraph.Model.AzureADMSPrivilegedSchedule  
$schedule.Type = "Once"  
$schedule.Duration = "PT480M"  
$schedule.StartDateTime = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ")  

Now we have all the parameters set we just need to call the Open-AzureADMSPrivilegedRoleAssignmentRequest that sets the request. In this below we are looping through each of the configured roles and requesting access to them. It does fail in the background, so if one fails it will continue. 

 
foreach ($role in $roles) { 
    Write-host "Setting $($role.name)" 
    Open-AzureADMSPrivilegedRoleAssignmentRequest -ProviderId "aadGroups" -Schedule $schedule -ResourceId $role.resourceId -RoleDefinitionId $role.roleDefinitionId -SubjectId $subjectId -AssignmentState "Active" -Type "UserAdd" -Reason $reason 
} 
 

Final Thoughts 

This is a great method to request the PIM access with minimal portal interaction and could also be used in automation if you had a service account running automated tasks. 

There are plenty more setting configurations you could do differently to my scenario, like the Type might not be UserAdd but instead UserRenew that could require different parameters. You will need to play around to get the correct setup for you. 

The Final Script 

I always like to then give the completed script from top to bottom. 

 
if (-not $(Get-Module AzureADPreview -ListAvailable)) {  
  Write-Host "Not got AzureADPreview Installed"  
  Write-Host "Installing now" 
  Install-Module -Name AzureADPreview -Scope CurrentUser -Force 
} 
if (-not $(Get-Module AzureAD -ListAvailable)) {  
  Write-Host "Not got AzureAD Installed"  
  Write-Host "Installing now" 
  Install-Module -Name AzureAD -Scope CurrentUser -Force 
} 
 
 
try { 
  Write-Host "Checking Connection"  
  Get-AzureADCurrentSessionInfo 
  Write-Host "Connection Found"  
} 
catch { 
  Write-Host "Making Connection" 
  Connect-AzureAD 
} 
 
 
 
$access_reason = "DevOps Development Work"  
$user_id = (Get-AzADUser -UserPrincipalName (Get-AzContext).Account).Id 
$requested_roles = @(  
  @{   
    resource_id       = ""  
    role_definition_id = ""  
    name             = ""  
  }  
)  
  
$schedule = New-Object Microsoft.Open.MSGraph.Model.AzureADMSPrivilegedSchedule  
$schedule.Type = "Once"  
$schedule.Duration = "PT480M"  
$schedule.StartDateTime = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ")  
  
foreach ($role in $requested_roles) {  
  Write-host "Setting $($role.name)"  
  Open-AzureADMSPrivilegedRoleAssignmentRequest -ProviderId "aadGroups" -Schedule $schedule -ResourceId $role.resource_id -RoleDefinitionId $role.role_definition_id -SubjectId $user_id -AssignmentState "Active" -Type "UserAdd" -Reason $access_reason  
}  

Published by Chris Pateman - PR Coder

A Digital Technical Lead, constantly learning and sharing the knowledge journey.

One thought on “Automating Azure PIM Requests with PowerShell

Leave a message please

This site uses Akismet to reduce spam. Learn how your comment data is processed.