PowerShell sample for Privileged Identity Management (PIM) for Azure Resources


PIM for Azure Resources provides Just in Time (JIT) and Temporary access capabilities for Azure Resources. See more at https://docs.microsoft.com/en-us/azure/active-directory/privileged-identity-management/azure-pim-resource-rbac

How cool would it be if I can use the underlying api’s of PIM api’s to build custom applications. For example, your IT Org has N different resource groups where you want to activate every day. It would be time consuming to activate them one by one. Instead, you can build a custom app using PowerShell or UI so that you can activate to all of these resource groups in one shot.

In this blog, I will share a sample to list all your eligible roles and activate or deactivate them. And a bonus, it will work even if your role requires MFA 😊

I will share the full source code so you can customize it to suit your needs. Just save this as a .ps1 file and run it with PowerShell.

[Disclaimer: This is just a sample and comes with no warranties. The api's are in preview and could change which would break the sample. It would be a best effort to keep the sample up to date.]

Screenshot

 

Source code

#####################################################################Functions##############################################################################################

 

#Loads Active Directory Authentication Library

function Load-ActiveDirectoryAuthenticationLibrary(){

$moduleDirPath = [Environment]::GetFolderPath("MyDocuments") + "\WindowsPowerShell\Modules"

$modulePath = $moduleDirPath + "\AADGraph"

if(-not (Test-Path ($modulePath+"\Nugets"))) {New-Item -Path ($modulePath+"\Nugets") -ItemType "Directory" | out-null}

$adalPackageDirectories = (Get-ChildItem -Path ($modulePath+"\Nugets") -Filter "Microsoft.IdentityModel.Clients.ActiveDirectory*" -Directory)

if($adalPackageDirectories.Length -eq 0){

Write-Host "Active Directory Authentication Library Nuget doesn't exist. Downloading now ..." -ForegroundColor Yellow

if(-not(Test-Path ($modulePath + "\Nugets\nuget.exe")))

{

Write-Host "nuget.exe not found. Downloading from http://www.nuget.org/nuget.exe ..." -ForegroundColor Yellow

$wc = New-Object System.Net.WebClient

$wc.DownloadFile("http://www.nuget.org/nuget.exe",$modulePath + "\Nugets\nuget.exe");

}

$nugetDownloadExpression = $modulePath + "\Nugets\nuget.exe install Microsoft.IdentityModel.Clients.ActiveDirectory -Version 2.14.201151115 -OutputDirectory " + $modulePath + "\Nugets | out-null"

Invoke-Expression $nugetDownloadExpression

}

$adalPackageDirectories = (Get-ChildItem -Path ($modulePath+"\Nugets") -Filter "Microsoft.IdentityModel.Clients.ActiveDirectory*" -Directory)

$ADAL_Assembly = (Get-ChildItem "Microsoft.IdentityModel.Clients.ActiveDirectory.dll" -Path $adalPackageDirectories[$adalPackageDirectories.length-1].FullName -Recurse)

$ADAL_WindowsForms_Assembly = (Get-ChildItem "Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll" -Path $adalPackageDirectories[$adalPackageDirectories.length-1].FullName -Recurse)

if($ADAL_Assembly.Length -gt 0 -and $ADAL_WindowsForms_Assembly.Length -gt 0){

Write-Host "Loading ADAL Assemblies ..." -ForegroundColor Green

[System.Reflection.Assembly]::LoadFrom($ADAL_Assembly[0].FullName) | out-null

[System.Reflection.Assembly]::LoadFrom($ADAL_WindowsForms_Assembly.FullName) | out-null

return $true

}

else{

Write-Host "Fixing Active Directory Authentication Library package directories ..." -ForegroundColor Yellow

$adalPackageDirectories | Remove-Item -Recurse -Force | Out-Null

Write-Host "Not able to load ADAL assembly. Delete the Nugets folder under" $modulePath ", restart PowerShell session and try again ..."

return $false

}

}

 

#Acquire AAD token

function AcquireToken($mfa){

$clientID = "1950a258-227b-4e31-a9cf-717495945fc2"

$redirectUri = "urn:ietf:wg:oauth:2.0:oob"

 

$authority = "https://login.microsoftonline.com/common"

$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority,$false

if($mfa)

{

$authResult = $authContext.AcquireToken("https://management.core.windows.net/",$ClientID,$redirectUri,[Microsoft.IdentityModel.Clients.ActiveDirectory.PromptBehavior]::Auto, [Microsoft.IdentityModel.Clients.ActiveDirectory.UserIdentifier]::AnyUser, "amr_values=mfa")

Set-Variable -Name mfaDone -Value $true -Scope Global

}

else

{

$authResult = $authContext.AcquireToken("https://management.core.windows.net/",$ClientID,$redirectUri,[Microsoft.IdentityModel.Clients.ActiveDirectory.PromptBehavior]::Always)

}

if($authResult -ne $null)

{

Write-Host "User logged in successfully ..." -ForegroundColor Green

}

Set-Variable -Name headerParams -Value @{'Authorization'="$($authResult.AccessTokenType) $($authResult.AccessToken)"} -Scope Global

Set-Variable -Name assigneeId -Value $authResult.UserInfo.UniqueId -Scope Global

}

 

#Gets my jit assignments

function MyJitAssignments(){

$url = $serviceRoot + "roleAssignments?`$expand=linkedAssignment,subject,roleDefinition(`$expand=resource)&`$filter=level+eq+'Eligible'"

$response = Invoke-WebRequest -UseBasicParsing -Headers $headerParams -Uri $url -Method Get

$assignments = ConvertFrom-Json $response.Content

Write-Host ""

Write-Host "Role assignments..." -ForegroundColor Green

$i = 0

$obj = @()

foreach ($assignment in $assignments.value)

{

$item = New-Object psobject -Property @{

id = ++$i

IdGuid =  $assignment.id

ResourceId =  $assignment.roleDefinition.resource.id

OriginalId =  $assignment.roleDefinition.resource.originalId

ResourceName =  $assignment.roleDefinition.resource.displayName

ResourceType =  $assignment.roleDefinition.resource.resourcetype

RoleId = $assignment.roleDefinition.id

RoleName = $assignment.roleDefinition.displayName

ExpirationDate = $assignment.expirationDateTime

SubjectId = $assignment.subject.id

}

$obj = $obj + $item

}

 

return $obj

}

 

#Activates the user

function Activate($isRecursive = $false){

if($isRecursive -eq $false)

{

$assignments = MyJitAssignments

$assignments | Format-Table -AutoSize -Wrap id,RoleName,ResourceName,ResourceType,ExpirationDate

$choice = Read-Host "Enter Id to activate"

[int]$hours = Read-Host "Enter Activation duration in hours"

$reason = Read-Host "Enter Reason"

}

 

$id = $assignments[$choice-1].IdGuid

$resourceId = $assignments[$choice-1].ResourceId

$roleDefinitionId = $assignments[$choice-1].RoleId

$subjectId = $assignments[$choice-1].SubjectId

$url = $serviceRoot + "roleAssignmentRequests"

$postParams = '{"id":"00000000-0000-0000-0000-000000000000","assignmentLevel":"Member","evaluateOnly":false,"requestType":"UserAdd","reason":"' + $reason + '","roleDefinition":{"id":"' + $roleDefinitionId + '","resource":{"id":"' + $resourceId + '"}},"schedule":{"duration":"PT' + $hours + 'H","startDateTime":"' + (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ") + '","type":"Once"},"subject":{"id":"' + $subjectId + '","type":"User"},"targetLinkedRoleAssignmentId":"' + $id + '"}'

try

{

$response = Invoke-WebRequest -UseBasicParsing -Headers $headerParams -Uri $url -Method Post -ContentType "application/json" -Body $postParams

Write-Host "Activation request queued successfully ..." -ForegroundColor Green

$recursive = $false

}

catch

{

$stream = $_.Exception.Response.GetResponseStream()

$stream.Position = 0;

$streamReader = New-Object System.IO.StreamReader($stream)

$err = $streamReader.ReadToEnd()

$streamReader.Close()

$stream.Close()

 

if($mfaDone -eq $false -and $err.Contains("MfaRule"))

{

Write-Host "Prompting the user for mfa ..." -ForegroundColor Green

AcquireToken true

Activate $true

}

else

{

Write-Host $err -ForegroundColor Red

}

}

}

 

#Deactivates the user

function Deactivate($isRecursive = $false){

if($isRecursive -eq $false)

{

$assignments = MyJitAssignments

$assignments | Format-Table -AutoSize -Wrap id,RoleName,ResourceName,ResourceType,ExpirationDate

$choice = Read-Host "Enter Id to deactivate"

}

 

$id = $assignments[$choice-1].IdGuid

$resourceId = $assignments[$choice-1].ResourceId

$roleDefinitionId = $assignments[$choice-1].RoleId

$subjectId = $assignments[$choice-1].SubjectId

$url = $serviceRoot + "roleAssignmentRequests"

$postParams = '{"id":"' + $id + '","assignmentLevel":"Member","evaluateOnly":false,"requestType":"UserRemove","roleDefinition":{"id":"' + $roleDefinitionId + '","resource":{"id":"' + $resourceId + '"}},"subject":{"id":"' + $subjectId + '","type":"User"}}'

$response = Invoke-WebRequest -UseBasicParsing -Headers $headerParams -Uri $url -Method Post -ContentType "application/json" -Body $postParams

Write-Host "Role deactivated successfully ..." -ForegroundColor Green

$recursive = $false

}

 

#Show menu

function ShowMenu()

{

Write-Host ""

Write-Host "Azure RBAC JIT - PowerShell Menu v1.0"

Write-Host "  1. List your eligible role assignments"

Write-Host "  2. Activate an eligible role"

Write-Host "  3. Deactivate an active role"

Write-Host "  4. Exit"

}

 

############################################################################################################################################################################

 

$global:serviceRoot = "https://api.azrbac.mspim.azure.com/api/v1/providers('00000000-0000-0000-0000-000000000002')/"

$global:headerParams = ""

$global:assigneeId = ""

$global:mfaDone = $false;

 

Load-ActiveDirectoryAuthenticationLibrary

AcquireToken

 

do

{

ShowMenu

$input = Read-Host "Enter your selection"

switch ($input)

{

'1'

{

$assignments = MyJitAssignments

$assignments | Format-Table -AutoSize -Wrap id,RoleName,ResourceName,ResourceType,ExpirationDate

}

'2'

{

Activate

}

'3'

{

Deactivate

}

'4'

{

return

}

}

}

until ($input -eq '4')

 

Write-Host ""

 

 

 

Comments (1)

  1. Thanks Anuj for sharing the powershell script. This is very useful!

Skip to main content