Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save merill/6bbe292d74c63602b5ac9844ef89d527 to your computer and use it in GitHub Desktop.

Select an option

Save merill/6bbe292d74c63602b5ac9844ef89d527 to your computer and use it in GitHub Desktop.
Create access packages with AutoAssignPolicyAndCustomExtension
# Version 1.2
# Collect parameters at the command line.
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[String]
$TenantID,
[Parameter(Mandatory=$true)]
[String]
$InFile
)
# Logging function
Function Write-Log {
[CmdletBinding()]
Param (
[Parameter(
Mandatory=$true,
ValueFromPipeline=$true,
Position=0)]
[ValidateNotNullorEmpty()]
[String]$Message,
[Parameter(Position=1)]
[ValidateSet("Information","Warning","Error","Debug","Verbose")]
[String]$Level = 'Information',
[String]$Path
)
Process {
$DateFormat = "%m/%d/%Y %H:%M:%S"
Add-Content -Path $Path -Value ("[{0}] ({1}) {2}" -F (Get-Date -UFormat $DateFormat), $Level, $Message)
}
}
$logFile = Join-Path -Path (Get-Location).Path -ChildPath "Create-AccessPackages.log"
Write-Log -Message "Starting Access Package creation" -Level Information -Path $logFile
# Connect to Microsoft Graph.
try
{
Connect-MgGraph -TenantId $TenantID -Scopes "User.ReadWrite.All", "Group.ReadWrite.All", "EntitlementManagement.ReadWrite.All", "Application.ReadWrite.All"
Write-Log -Message "Connected to Microsoft Graph." -Level Information -Path $logFile
}
catch
{
Write-Log -Message "Failed to connect to Microsoft Graph." -Level Error -Path $logFile
Break
}
# Retrieve Entitlement Management details from the input file.
try
{
$emDetails = Import-Csv -Path $InFile
Write-Log -Message "Successfully imported input file." -Level Information -Path $logFile
}
catch
{
Write-Log -Message "Failed to open the input file." -Level Error -Path $logFile
Break
}
# Add columns to $emDetails required for object creation in the tenant.
try
{
$emDetails = $emDetails | Select-Object -Property *,catalogId,resourceId,apId
Write-Log -Message "Expanded property set of inputs." -Level Information -Path $logFile
}
catch
{
Write-Log -Message "Failed to expand the property set of inputs." -Level Error -Path $logFile
Break
}
# Iterate through $emDetails and create objects.
foreach ($emDetail in $emDetails)
{
# Create the catalog if not already present and harvest the catalog ID.
try
{
$emDetail.catalogId = (Get-MgEntitlementManagementCatalog -DisplayNameEq $emDetail.catalogName).Id
Write-Log -Message "Successfully read catalog information from Microsoft Graph." -Level Information -Path $logFile
}
catch
{
Write-Log -Message "Failed to read catalog information from Microsoft Graph." -Level Error -Path $logFile
Break
}
if (!($emDetail.catalogId))
{
try
{
$emDetail.catalogId = New-MgEntitlementManagementCatalog -DisplayName $emDetail.catalogName -Description $emDetail.catalogDesc | Select-Object -ExpandProperty Id
Write-Log -Message ("Created new catalog " + $emDetail.catalogName + ".") -Level Information -Path $logFile
}
catch
{
Write-Log -Message ("Failed to create catalog " + $emDetail.catalogName + ".") -Level Error -Path $logFile
Break
}
}
# If the resource type is "Group", create it if not already present and harvest the group ID.
if ($emDetail.resourceType -eq "Group")
{
$originSystem = "AadGroup"
$grpFilter = "DisplayName eq '" + $emDetail.resourceName + "'"
$emDetail.resourceId = (Get-MgGroup -Filter $grpFilter).Id
# If the group doesn't exist, create it.
if (!($emDetail.resourceId))
{
try
{
$emDetail.resourceId = (New-MgGroup -DisplayName $emDetail.resourceName -Description $emDetail.resourceDesc -MailEnabled:$false -MailNickname $emDetail.resourceInfo -SecurityEnabled).Id
Write-Log -Message ("Created new group " + $emDetail.resourceName + ".") -Level Information -Path $logFile
Start-Sleep 60
}
catch
{
Write-Log -Message ("Failed to create group " + $emDetail.resourceName + ".") -Level Error -Path $logFile
Break
}
}
}
# Else if the resource type is "Application" harvest its resource ID.
elseif ($emDetail.resourceType -eq "Application")
{
$originSystem = "AadApplication"
$appFilter = "DisplayName eq '" + $emDetail.resourceName + "'"
$emDetail.resourceId = (Get-MgServicePrincipal -Filter $appFilter).Id
}
# If the resource exists (we're not creating the applications in this script).
If ($emDetail.resourceId)
{
# If the resource is not already added to the catalog, add it.
if (!(Get-MgEntitlementManagementCatalogResource -AccessPackageCatalogId $emDetail.catalogId | where {$_.OriginId -eq $emDetail.resourceId}))
{
$params = @{
requestType = "adminAdd"
resource = @{
displayName = $emDetail.resourceName
originId = $emDetail.resourceId
originSystem = $originSystem
}
catalog = @{
id = $emDetail.catalogId
}
}
try
{
New-MgEntitlementManagementResourceRequest -BodyParameter $params
Write-Log -Message ("Resource " + $emDetail.resourceName + " added to catalog " + $emDetail.catalogName + ".") -Level Information -Path $logFile
}
catch
{
Write-Log -Message ("Failed to add resource " + $emDetail.resourceName + " to catalog " + $emDetail.catalogName + ".") -Level Error -Path $logFile
Break
}
}
# Create the access package if it doesn't already exist.
$apFilter = "DisplayName eq '" + $emDetail.accessPackageName + "'"
$emDetail.apId = (Get-MgEntitlementManagementAccessPackage -Filter $apFilter).Id
if (!($emDetail.apId))
{
$params = @{
displayName = $emDetail.accessPackageName
description = $emDetail.accessPackageDesc
isHidden = $false
catalog = @{
id = $emDetail.catalogId
}
}
try
{
$emDetail.apId = (New-MgEntitlementManagementAccessPackage -BodyParameter $params).Id
Write-Log -Message ("Created access package " + $emDetail.accessPackageName + ".") -Level Information -Path $logFile
}
catch
{
Write-Log -Message ("Failed to create access package " + $emDetail.accessPackageName + ".") -Level Error -Path $logFile
Break
}
}
# Add the resource to the access package
try
{
$resourceFilter = "OriginId eq '" + $emDetail.resourceId + "'"
$resource = Get-MgEntitlementManagementCatalogResource -AccessPackageCatalogId $emDetail.catalogId -Filter $resourceFilter -ExpandProperty Roles,Scopes
$rUri = "https://graph.microsoft.com/beta/identityGovernance/entitlementManagement/accesspackagecatalogs/" + $emDetail.catalogId + "/accessPackageResourceRoles?`$filter=(originSystem+eq+%27" + $originSystem + "%27+and+accessPackageResource/id+eq+%27" + $resource.Id + "%27)&`$expand=accessPackageResource"
$sUri = "https://graph.microsoft.com/beta/identityGovernance/entitlementManagement/accessPackageCatalogs/" + $emDetail.catalogId + "/accessPackageResources?`$expand=accessPackageResourceScopes,accessPackageResourceRoles"
$resourceRole = (Invoke-GraphRequest -Uri $rUri -OutputType PSObject).value | where {$_.DisplayName -eq $emDetail.resourceRole}
$resourceScope = (Invoke-GraphRequest -Uri $sUri -OutputType PSObject).value | where {$_.OriginId -eq $emDetail.resourceId}
Write-Log -Message ("Retrieved catalog representation of resource " + $emDetail.resourceName + ".") -Level Information -Path $logFile
}
catch
{
Write-Log -Message ("Failed to retrieve catalog representation of resource " + $emDetail.resourceName + ".") -Level Error -Path $logFile
Break
}
# Define the resource role parameters.
$resourceRoleParams = $null
if ($emDetail.resourceType -eq "Group")
{
$resourceRoleParams = @{
role = @{
id = $resourceRole.Id
displayName = $emDetail.resourceRole
originSystem = $originSystem
originId = $resourceRole.OriginId
resource = @{
id = $resource.Id
displayName = $emDetail.resourceName
description = $emDetail.resourceDesc
originId = $r.OriginId
originSystem = $originSystem
}
}
scope = @{
id = $resourceScope.Id
displayName = "Root"
description = "Root Scope"
originId = $r.OriginId
originSystem = $originSystem
isRootScope = $true
}
}
}
elseif ($emDetail.resourceType -eq "Application")
{
$resourceRoleParams = @{
role = @{
id = $resourceRole.Id
displayName = $emDetail.resourceRole
description = $emDetail.resourceRole
originSystem = $originSystem
originId = $resourceRole.OriginId
resource = @{
id = $resource.Id
originId = $r.OriginId
originSystem = $originSystem
}
}
scope = @{
id = $resourceScope.Id
originId = $resourceScope.OriginId
originSystem = $originSystem
isRootScope = $true
}
}
}
# Assign the resource to the access package with the specified role scope.
try
{
New-MgEntitlementManagementAccessPackageResourceRoleScope -AccessPackageId $emDetail.apId -BodyParameter $resourceRoleParams | Out-Null
Write-Log -Message ("Added resource role " + $emDetail.resourceRole + " for resource " + $emDetail.resourceName + " to access package " + $emDetail.accessPackageName + ".") -Level Information -Path $logFile
}
catch
{
Write-Log -Message ("Failed to add resource role " + $emDetail.resourceRole + " for resource " + $emDetail.resourceName + " to access package " + $emDetail.accessPackageName + ".") -Level Error -Path $logFile
Break
}
# If the assignment policy doesn't already exist, create it.
If ($emDetail.policyName)
{
If (!(Get-MgEntitlementManagementAssignmentPolicy | where {$_.DisplayName -eq $emDetail.policyName}))
{
$params = @{
id = ""
displayName = $emDetail.policyName
description = $emDetail.policyDesc
allowedTargetScope = "specificDirectoryUsers"
specificAllowedTargets = @(
@{
"@odata.type" = "#Microsoft.IGAELM.EC.FrontEnd.ExternalModel.attributeRuleMembers"
description = $emDetail.policyTargetDesc
membershipRule = $emDetail.membershipQuery
}
)
automaticRequestSettings = @{
requestAccessForAllowedTargets = $true
removeAccessWhenTargetLeavesAllowedTargets = $true
gracePeriodBeforeAccessRemoval = $null
}
customExtensionHandlers = @(
@{
stage = "assignmentRequestGranted"
customExtension = @{
id = "9719bc16-fb72-40a4-acb0-2ff6e045f36e"
}
}
@{
stage = "assignmentRequestRemoved"
customExtension = @{
id = "a6231ef6-94fa-4376-b75d-b847c652b8c8"
}
}
)
accessPackageId = $emDetail.apId
}
$body = $params | ConvertTo-Json -Depth 10
# You need to get everything in the "-Headers @{" }array below from the browser's developer tools when making some change in the Entra poral and then choose "Copy as PowerShell" from the context menu and paste it here.
# The bearer token will expire after 1 hour so you need to get a new one before running the script.
$session = New-Object Microsoft.PowerShell.Commands.WebRequestSession
$session.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0"
Invoke-WebRequest -UseBasicParsing -Uri "https://elm.iga.azure.com/api/v1/accessPackageAssignmentPolicies" `
-Method "POST" `
-WebSession $session `
-Headers @{
"x-ms-client-session-id"="6fa6d3b330514a1480767e2bfb182651"
"Accept-Language"="en"
"Authorization"="Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IkwxS2ZLRklfam5YYndXYzIyeFp4dzFzVUhIMCIsImtpZCI6IkwxS2ZLRklfam5YYndXYzIyeFp4dzFzVUhIMCJ9.eyJhdWQiOiJodHRwczovL2VsbS5pZ2EuYXp1cmUuY29tLyIsImlzcyI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0LzMzZGRiOGVkLTdhMzUtNGE0Zi05NDk4LTc0YmQ2MzhlM2UxOC8iLCJpYXQiOjE3MTUxNjYzNzgsIm5iZiI6MTcxNTE2NjM3OCwiZXhwIjoxNzE1MTcxODc2LCJhY2N0IjowLCJhY3IiOiIxIiwiYWlvIjoiQVhRQWkvOFdBQUFBSXJKdkxnNmp4VEovb0Q2c2R6a09aL2h6ZnFuNjdRQVRkenUxVjBiRnpqVjFpZmJRb2tvRTZMY2RMMXRDWVR5SW1saGMzaUh2NUJVVU9NSEpkQTIvZUg4ZUdXQjY5SGZaQ2RaSTB3MXdocTg3eG45S2hmQ3gwdVFWQ0s3a21BS3ZLUzdWb0hMWkZubDR2cW1USXRabGVnPT0iLCJhbXIiOlsicHdkIiwibWZhIl0sImFwcF9kaXNwbGF5bmFtZSI6Ik1pY3Jvc29mdF9BenVyZV9FTE1BZG1pbiIsImFwcGlkIjoiMDAzMjU5M2QtNmEwNS00ODQ3LThjYTQtNGI2MjIwZWQyYTFlIiwiYXBwaWRhY3IiOiIwIiwiZ2l2ZW5fbmFtZSI6IkFkbWluIiwiZ3JvdXBzIjpbImIyZjkyMzEyLTM4ZTctNDFlZC1iMTFkLTYyMzZhYWY2NWRhNiIsImRmNjBhZjY1LWEwOGQtNDYxMy04MDFmLTM5NjRhODBjOGI2ZCIsIjFhZjMwZGNiLTdhOWQtNGQyZC1hODAyLTUwYjBiMWY0NDczNiIsImFiZTNmZmIzLTFkNjEtNDM0OS04MzM2LTRmZTEwNWExYWUyMSIsImJlNTEzZmY4LTlhMjMtNGZmZS1iZTRiLTdiYzQ5MzIxYmM4YSIsIjcxYWU3YjFmLWQxMWEtNGE5NS05MTlkLTg0ZjdmYmRjMGM1ZiIsImE3YmE5MTMwLWZjNTMtNGRiZS1hZDllLTk0M2FjN2M5ZDcyMiIsIjRhMDA5NGZlLTU2ZjEtNGMxZS05MjdkLWQ2Y2YxYjhiZmJmZCIsImEwNGM5ZGQ0LWYzYzgtNDAxMC1iOTk5LTE0NGZjZDdlYTA2ZSIsIjgxNjc5NWJlLWRhOTctNDUzYy1hNmJmLWI2NmIyYjhjZDI4MiIsIjNiMDcxNTUzLTNlNjYtNGY0ZC1iODVlLTZhZTdkNzEyYjU0MCIsIjdlZTI1OTM4LTkzMDQtNDVmZS04ZWM4LTgzOWIxMDI3YzNkOCIsIjI2MGRkM2I1LWE4ZTQtNDM1Ny1iNzU3LWUzNTA2YTU5MDhhYSJdLCJpcGFkZHIiOiIxNTkuMTk2LjEyMC4yMDgiLCJuYW1lIjoiQWRtaW4iLCJvaWQiOiI1MTQ5MWI2Zi1jZWM1LTRkZjYtYTFjYi0xNmYyNWQ2YjMwNjQiLCJvbnByZW1fc2lkIjoiUy0xLTUtMjEtMTA4MDMzNzQ1Ni0xNjcwNDE1ODg5LTM0NzA2MzkzNTctNTExNiIsInB1aWQiOiIxMDAzQkZGRDkwQkVDMkUzIiwicmgiOiIwLkFVRUE3YmpkTXpWNlQwcVVtSFM5WTQ0LUdCVFBEWUZZR1BKTGdUUk1OcC1qSTF0QkFPby4iLCJzY3AiOiJFbnRpdGxlbWVudE1hbmFnZW1lbnQuUmVhZFdyaXRlLkFsbCIsInNpZCI6ImZiNGQ3YjFjLWFlODYtNDA0MC1hNGNjLWFmYjgwNGRiZDBiNSIsInN1YiI6InVlS1AtLXVIbzZ0RFVUdTFMajRMYkZDanY0dUVHZ2I0aWhNQ194b2UyRFUiLCJ0aWQiOiIzM2RkYjhlZC03YTM1LTRhNGYtOTQ5OC03NGJkNjM4ZTNlMTgiLCJ1bmlxdWVfbmFtZSI6ImFkbWluQHRoZWtsdWQuY29tIiwidXBuIjoiYWRtaW5AdGhla2x1ZC5jb20iLCJ1dGkiOiJpd29JdjU3R3gwaUJDVU1ZOEdrOEFBIiwidmVyIjoiMS4wIiwidmVyaWZpZWRfcHJpbWFyeV9lbWFpbCI6WyJhZG1pbkB0aGVrbHVkLmNvbSJdLCJ3aWRzIjpbIjU4YTEzZWEzLWM2MzItNDZhZS05ZWUwLTljMGQ0M2NkN2YzZCIsIjYyZTkwMzk0LTY5ZjUtNDIzNy05MTkwLTAxMjE3NzE0NWUxMCIsIjdiZTQ0YzhhLWFkYWYtNGUyYS04NGQ2LWFiMjY0OWUwOGExMyIsIjE3MzE1Nzk3LTEwMmQtNDBiNC05M2UwLTQzMjA2MmNhY2ExOCIsImU4NjExYWI4LWMxODktNDZlOC05NGUxLTYwMjEzYWIxZjgxNCIsImM0ZTM5YmQ5LTExMDAtNDZkMy04YzY1LWZiMTYwZGEwMDcxZiIsIjE5NGFlNGNiLWIxMjYtNDBiMi1iZDViLTYwOTFiMzgwOTc3ZCIsIjg0MjRjNmYwLWExODktNDk5ZS1iYmQwLTI2YzE3NTNjOTZkNCIsIjlmMDYyMDRkLTczYzEtNGQ0Yy04ODBhLTZlZGI5MDYwNmZkOCIsImI3OWZiZjRkLTNlZjktNDY4OS04MTQzLTc2YjE5NGU4NTUwOSJdfQ.QoWJ02ERJufmseVg2q8jBMI6mLRSBB6dswlorJsAiTHms3imiyjEapCMvFhtRD3sWIDwNbP4yfr6kjSlrQei0nIjd2-oQf8RuSTNtl9fAYQwjxz0ua6cNEDINl-66TgxwOA3k6m8LKSYO4MV8B_iuvJKla_-vyga_CWDPeOitU5KS9gLbid6awb1sebw4HBQ0Qzps_pjolVIG3dwASM1SXQ5K_ZHZDSVaxYdA8EIOHlkuxvJdyv3_an7VG1aWYjaYv_hdf7Lak7cHcZvYC2DZFjy5sU0-5WP6fNoZVaP60vpM3J9d_VfqOABKUv8PiDyQhJSGwNbU5fDi-SPKE1quQ"
"x-ms-effective-locale"="en.en-us"
"Accept"="*/*"
"Referer"=""
"x-ms-client-request-id"="93fdac23-60d2-4952-83c7-8bfd25aa08b3"
} `
-ContentType "application/json" `
-Body $body -SkipHeaderValidation
try
{
Write-Log -Message ("Added assignment policy " + $emDetail.policyName + " to access package " + $emDetail.accessPackageName + ".") -Level Information -Path $logFile
}
catch
{
Write-Log -Message ("Failed to add assignment policy " + $emDetail.policyName + " to access package " + $emDetail.accessPackageName + ".") -Level Error -Path $logFile
Break
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment