Last active
June 10, 2024 21:30
-
-
Save merill/6bbe292d74c63602b5ac9844ef89d527 to your computer and use it in GitHub Desktop.
Create access packages with AutoAssignPolicyAndCustomExtension
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # 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