├── CreateGroups.csv ├── LICENSE ├── CreateGroupAndOnboardPIM.ps1 ├── CreateGroups.ps1 ├── AddRolesToGroup.ps1 └── ConfigureGroupPIMSettings.ps1 /CreateGroups.csv: -------------------------------------------------------------------------------- 1 | GroupName;RoleName;Description 2 | Azure AD Group Name;Global Reader;Group Description 3 | Azure AD Group Name;Helpdesk Administrator;Group Description 4 | Azure AD Group Name 2;Compliance Administrator;Group 2 Description -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2022, ricmik 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /CreateGroupAndOnboardPIM.ps1: -------------------------------------------------------------------------------- 1 | function Register-PrivilegedAccessGroupToPIM { 2 | [CmdletBinding()] 3 | param ( 4 | [Parameter(Mandatory)] 5 | [string]$GroupObjectID 6 | ) 7 | 8 | begin { 9 | # Check if token is valid 10 | if(!$pimAPIToken -or $pimAPIToken.ExpiresOn -lt ${Get-Date}) { 11 | $pimAPIToken = Get-AzAccessToken -ResourceUrl 'https://api.azrbac.mspim.azure.com' -ErrorAction Stop 12 | } 13 | 14 | # Create authorization header with token 15 | $headers = @{ 16 | "Authorization" = "Bearer {0}" -f ($($pimAPIToken.Token)) 17 | } 18 | 19 | # PIM register Azure AD Group API endpoint 20 | $pimAPIuri = 'https://api.azrbac.mspim.azure.com/api/v2/privilegedAccess/aadGroups/resources/register' 21 | 22 | } 23 | 24 | process { 25 | # Create JSON payload with group object to be onboarded 26 | $Body = [PSCustomObject]@{ 27 | externalId = $($GroupObjectID) 28 | } | ConvertTo-Json -Compress 29 | 30 | # Invoke request towards API 31 | $PIMonboard = Invoke-WebRequest -Uri $pimAPIuri -Headers $Headers -Method POST -Body $Body -ContentType 'application/json' 32 | 33 | if ($PIMonboard.BaseResponse.IsSuccessStatusCode -eq $true) { 34 | [PSCustomObject]@{ 35 | GroupID = $GroupObjectID 36 | Status = $($PIMonboard.StatusDescription) 37 | } 38 | } 39 | else { 40 | Write-Warning "Failed to onboard group, HTTP status $($PIMonboard.StatusCode) - $($PIMonboard.StatusDescription)" 41 | } 42 | } 43 | 44 | end { 45 | 46 | } 47 | } -------------------------------------------------------------------------------- /CreateGroups.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Version 7 2 | #Requires -Modules Az.Accounts 3 | 4 | # Dotsource required functions (can be converted to a module) 5 | . ./CreateGroupAndOnboardPIM.ps1 6 | . ./AddRolesToGroup.ps1 7 | . ./ConfigureGroupPIMSettings.ps1 8 | 9 | $newgroupsroles = Import-Csv -Path ./CreateGroups.csv -Delimiter ';' 10 | 11 | $newgroups = $newgroupsroles | select -Unique -Property GroupName, Description 12 | Write-Output "Got $($newgroups.count) group(s) and a total of $($newgroupsroles.Length) role(s) from CSV file" 13 | 14 | # Create array list to store all created groups 15 | [System.Collections.ArrayList]$global:CreatedGroups = @() 16 | 17 | # Loop through groups from CSV file and create groups in Azure AD 18 | foreach ($group in $newgroups) { 19 | 20 | # Create role assignable group in Azure AD 21 | $creategroup = New-AzADGroup -DisplayName $($group.GroupName) -Description $($group.Description) -IsAssignableToRole:$true -SecurityEnabled:$true -MailEnabled:$false -MailNickname $($group.GroupName -replace '\s', '') 22 | Write-Output "Created group: $($creategroup.DisplayName) with ID $($creategroup.id)" 23 | 24 | # Add created group to list for onboarding PIM later 25 | [void]$CreatedGroups.Add($creategroup) 26 | 27 | } 28 | Write-Output "Created $($CreatedGroups.Count) group(s) in Azure AD" 29 | 30 | # Wait some seconds for the groups to be available in PIM 31 | Write-Output "Waiting 60 seconds for PIM to be ready" 32 | Start-Sleep -Seconds 60 33 | 34 | # Create array list to store all PIM enabled groups 35 | [System.Collections.ArrayList]$global:pimEnabledGroups = @() 36 | 37 | # Loop through all created groups in Azure AD and onboard to PIM 38 | foreach ($group in $CreatedGroups) { 39 | # Register group to PIM 40 | Write-Output "Registering group $($group.DisplayName) - $($group.Id) to PIM" 41 | $pimenabledgroup = Register-PrivilegedAccessGroupToPIM -GroupObjectID $group.id 42 | if ($pimenabledgroup) { 43 | [void]$pimEnabledGroups.Add($pimenabledgroup) 44 | Write-Output "OK" 45 | } else { 46 | Write-Output "Failed" 47 | } 48 | } 49 | Write-Output "Enabled PIM on $($pimEnabledGroups.count) group(s)" 50 | 51 | # Wait some seconds for PIM to be ready to accept configuration 52 | Write-Output "Waiting 15 seconds for PIM to be ready" 53 | Start-Sleep -Seconds 15 54 | Write-Output "Configuring Member and Owner settings in PIM" 55 | foreach ($group in $pimEnabledGroups) { 56 | Update-PrivilegedAccessGroupRoleSettings -GroupObjectID $group.GroupID 57 | } 58 | 59 | Write-Output "Adding roles to the previously created groups" 60 | 61 | foreach ($createdgroup in $CreatedGroups) { 62 | $newgroupsroles | where { $createdgroup.DisplayName -eq $_.GroupName } | ForEach-Object { 63 | Write-Output "Adding role $($_.RoleName) to group $($createdgroup.DisplayName)" 64 | Add-AADRoleToPrivilegedAccessGroup -GroupObjectID $createdgroup.id -RoleName $_.RoleName 65 | } 66 | } -------------------------------------------------------------------------------- /AddRolesToGroup.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Version 7 2 | #Requires -Modules Az.Accounts 3 | function Add-AADRoleToPrivilegedAccessGroup { 4 | [CmdletBinding(SupportsShouldProcess = $true)] 5 | param ( 6 | [Parameter(Mandatory, ParameterSetName = "RoleName")] 7 | [string]$RoleName, 8 | [Parameter(Mandatory, ParameterSetName = "RoleID")] 9 | [string]$RoleID, 10 | [Parameter(Mandatory)] 11 | [string]$GroupObjectID 12 | ) 13 | 14 | begin { 15 | # Check if Connect-AzAccount is connected 16 | if ([string]::IsNullOrEmpty($((Get-AzContext).Account))) { 17 | Write-Output "Connect to Azure using Connect-AzAccount first" 18 | break 19 | } else { 20 | $pimtoken = (Get-AzAccessToken -ResourceUrl 'https://api.azrbac.mspim.azure.com' -ErrorAction Stop).Token 21 | $Headers = @{ 22 | "Authorization" = "Bearer {0}" -f ($pimtoken) 23 | } 24 | } 25 | # Get all roles from Azure AD 26 | $azureADRoles = ((Invoke-AzRestMethod -Uri 'https://graph.microsoft.com/v1.0/roleManagement/directory/roleDefinitions').Content | ConvertFrom-Json).Value 27 | if ([string]::IsNullOrEmpty($($azureADRoles))) { 28 | Throw "Could not get Azure AD roles from Azure AD." 29 | } 30 | 31 | if ($RoleName) { 32 | $RoleID = ($azureADRoles | Where-Object { $_.displayName -eq $RoleName }).id 33 | } 34 | 35 | # Check if the role exists in Azure AD 36 | $RoleNameFromAAD = ($azureADRoles | Where-Object { $_.id -eq $RoleID }).displayName 37 | if ([string]::IsNullOrEmpty($($RoleNameFromAAD))) { 38 | Throw "The role '$RoleID$RoleName' does not exist in Azure AD. Cannot continue." 39 | } 40 | # URI to the PIM API endpoint for adding role assignments 41 | $AddRolesToGroupURI = "https://api.azrbac.mspim.azure.com/api/v2/privilegedAccess/aadroles/roleAssignmentRequests" 42 | } 43 | 44 | process { 45 | $roleObject = [PSCustomObject]@{ 46 | resourceId = (Get-AzContext).Tenant.Id # Tenant ID 47 | roleDefinitionId = $RoleID # Role definition ID to add from Azure AD 48 | subjectId = $GroupObjectID # Privileged Access Group ID 49 | assignmentState = 'Active' # Create active role assignment for the privileged access group 50 | type = 'AdminAdd' 51 | reason = 'Deployment from script' 52 | schedule = @{ 53 | type = 'Once' 54 | startDateTime = Get-Date 55 | endDateTime = $null 56 | } 57 | scopedResourceId = "" 58 | condition = $null 59 | conditionVersion = $null 60 | } | ConvertTo-Json 61 | Write-Output "Adding role $RoleNameFromAAD with role ID $RoleID to Azure AD Group with ID $GroupObjectID" 62 | Invoke-RestMethod -Uri $AddRolesToGroupURI -Headers $Headers -Method POST -Body $roleObject -ContentType 'application/json' 63 | } 64 | 65 | end { 66 | 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /ConfigureGroupPIMSettings.ps1: -------------------------------------------------------------------------------- 1 | function Get-PrivilegedAccessGroupRoleSettings { 2 | [CmdletBinding()] 3 | param ( 4 | [Parameter(Mandatory)] 5 | [string] 6 | $GroupObjectID 7 | ) 8 | 9 | # Check if token is valid 10 | if (!$pimAPIToken -or $pimAPIToken.ExpiresOn -lt ${Get-Date}) { 11 | $pimAPIToken = Get-AzAccessToken -ResourceUrl 'https://api.azrbac.mspim.azure.com' -ErrorAction Stop 12 | } 13 | 14 | # Create authorization header with token 15 | $headers = @{ 16 | "Authorization" = "Bearer {0}" -f ($($pimAPIToken.Token)) 17 | } 18 | # Get group Member and Owner objects needed to configure both member and owner PIM settings 19 | $groupRoles = Invoke-RestMethod -Uri "https://api.azrbac.mspim.azure.com/api/v2/privilegedAccess/aadGroups/roleSettingsv2?`$expand=roleDefinition(`$expand=resource)&`$filter=(resource/id+eq+'$GroupObjectID')" -Headers $Headers -Method GET -ContentType 'application/json' 20 | 21 | return $groupRoles.value 22 | 23 | } 24 | function Update-PrivilegedAccessGroupRoleSettings { 25 | [CmdletBinding()] 26 | param ( 27 | [Parameter(Mandatory)] 28 | [string]$GroupObjectID 29 | ) 30 | 31 | begin { 32 | # Check if token is valid 33 | if (!$pimAPIToken -or $pimAPIToken.ExpiresOn -lt ${Get-Date}) { 34 | $pimAPIToken = Get-AzAccessToken -ResourceUrl 'https://api.azrbac.mspim.azure.com' -ErrorAction Stop 35 | } 36 | 37 | # Create authorization header with token 38 | $headers = @{ 39 | "Authorization" = "Bearer {0}" -f ($($pimAPIToken.Token)) 40 | } 41 | 42 | # Configure settings for the MEMBER role on the Privileged Access Group 43 | $memberSettings = [PSCustomObject]@{ 44 | lifeCycleManagement = @( 45 | @{ 46 | ## START ELIGIBLE ASSIGNMENT REGION 47 | caller = "Admin" 48 | level = "Eligible" 49 | operation = "ALL" 50 | value = @( 51 | @{ 52 | # Eligible assignment expiration rule 53 | ruleIdentifier = "ExpirationRule" 54 | setting = @{ 55 | permanentAssignment = $false # Allow permanent eligible assignments? 56 | maximumGrantPeriodInMinutes = 525600 # Expire eligible assignments after 1 year (525600 minutes) 57 | } | ConvertTo-Json -Compress # Setting needs to be nested JSON 58 | }, 59 | @{ 60 | # Notification rule for eligible assignment (Send notifications when members are assigned as eligible to this role) 61 | ruleIdentifier = "NotificationRule" 62 | setting = @{ 63 | policies = @( 64 | @{ 65 | deliveryMechanism = "email" 66 | setting = @( 67 | # Notification type: Notification to the assigned user (assignee) 68 | @{ 69 | customreceivers = $null # Null or array of email addresses 70 | isdefaultreceiverenabled = $true # Send to default recipient (Assignee)? 71 | notificationlevel = 2 # 1 = Critical emails only enabled, 2 = Critical emails only disabled 72 | recipienttype = 0 73 | }, 74 | # Notification type: Request to approve a role assignment renewal/extension 75 | @{ 76 | customreceivers = $null # Null or array of email addresses 77 | isdefaultreceiverenabled = $true # Send to default recipient (Approver)? 78 | notificationlevel = 2 # 1 = Critical emails only enabled, 2 = Critical emails only disabled 79 | recipienttype = 1 80 | }, 81 | # Notification type: Role assignment alert 82 | @{ 83 | customreceivers = $null # Null or array of email addresses 84 | isdefaultreceiverenabled = $true # Send to default recipient (Admin)? 85 | notificationlevel = 2 # 1 = Critical emails only enabled, 2 = Critical emails only disabled 86 | recipienttype = 2 87 | } 88 | ) 89 | } 90 | ) 91 | } | ConvertTo-Json -Depth 5 -Compress # Setting needs to be nested JSON 92 | } 93 | ) 94 | } 95 | ## END ELIGIBLE ASSIGNMENT REGION 96 | ## START ACTIVE ASSIGNMENT REGION 97 | @{ 98 | caller = "Admin" 99 | level = "Member" 100 | operation = "ALL" 101 | value = @( 102 | @{ 103 | ruleIdentifier = "ExpirationRule" 104 | setting = @{ 105 | permanentAssignment = $false # Allow permanent active assignments? 106 | maximumGrantPeriodInMinutes = 21600 # Expire active assignments after 15 days (21600 minutes) 107 | } | ConvertTo-Json -Compress 108 | } 109 | @{ 110 | ruleIdentifier = "MfaRule" 111 | setting = @{ 112 | mfaRequired = $true # Require MFA when assigning a user as active? 113 | } | ConvertTo-Json -Compress 114 | } 115 | @{ 116 | ruleIdentifier = "JustificationRule" 117 | setting = @{ 118 | required = $true # Require justification when assigning a user as active? 119 | } | ConvertTo-Json -Compress 120 | } 121 | @{ 122 | # Notification rule for active assignment (Send notifications when members are assigned as active to this role) 123 | ruleIdentifier = "NotificationRule" 124 | setting = @{ 125 | policies = @( 126 | @{ 127 | deliveryMechanism = "email" 128 | setting = @( 129 | # Notification type: Notification to the assigned user (assignee) 130 | @{ 131 | customreceivers = $null # Null or array of email addresses 132 | isdefaultreceiverenabled = $true # Send to default recipient (Assignee)? 133 | notificationlevel = 2 # 1 = Critical emails only enabled, 2 = Critical emails only disabled 134 | recipienttype = 0 135 | }, 136 | # Notification type: Request to approve a role assignment renewal/extension 137 | @{ 138 | customreceivers = $null # Null or array of email addresses 139 | isdefaultreceiverenabled = $true # Send to default recipient (Approver)? 140 | notificationlevel = 2 # 1 = Critical emails only enabled, 2 = Critical emails only disabled 141 | recipienttype = 1 142 | }, 143 | # Notification type: Role assignment alert 144 | @{ 145 | customreceivers = $null # Null or array of email addresses 146 | isdefaultreceiverenabled = $true # Send to default recipient (Admin)? 147 | notificationlevel = 2 # 1 = Critical emails only enabled, 2 = Critical emails only disabled 148 | recipienttype = 2 149 | } 150 | ) 151 | } 152 | ) 153 | } | ConvertTo-Json -Depth 5 -Compress # Setting needs to be nested JSON 154 | } 155 | ) 156 | } 157 | ## END ACTIVE ASSIGNMENT REGION 158 | ## START ELIGIBLE USER ACTIVATING ROLE REGION 159 | @{ 160 | caller = "EndUser" 161 | level = "Member" 162 | operation = "ALL" 163 | value = @( 164 | @{ 165 | ruleIdentifier = "ExpirationRule" 166 | setting = @{ 167 | permanentAssignment = $false 168 | maximumGrantPeriodInMinutes = 480 # Activation maximum duration 8 hours (480 minutes) 169 | } | ConvertTo-Json -Compress 170 | }, 171 | @{ 172 | ruleIdentifier = "MfaRule" 173 | setting = @{ 174 | mfaRequired = $true # Require MFA when user is activating the role? 175 | } | ConvertTo-Json -Compress 176 | }, 177 | @{ 178 | ruleIdentifier = "JustificationRule" 179 | setting = @{ 180 | required = $false # Require justification when user is activating the role? 181 | } | ConvertTo-Json -Compress 182 | }, 183 | @{ 184 | ruleIdentifier = "TicketingRule" 185 | setting = @{ 186 | ticketingRequired = $false # Require ticket number when user is activating the role? 187 | } | ConvertTo-Json -Compress 188 | }, 189 | @{ 190 | ruleIdentifier = "ApprovalRule" 191 | setting = @{ 192 | enabled = $false # Require approval when user is activating the role? 193 | approvers = $null # List of approvers to notify 194 | } | ConvertTo-Json -Compress 195 | }, 196 | @{ 197 | ruleIdentifier = "AcrsRule" 198 | setting = @{ 199 | acrsRequired = $false 200 | acrs = $null 201 | } | ConvertTo-Json -Compress 202 | } 203 | , 204 | @{ 205 | # Notification rule when a user is activating an assignment (Send notifications when eligible members activate this role) 206 | ruleIdentifier = "NotificationRule" 207 | setting = @{ 208 | policies = @( 209 | @{ 210 | deliveryMechanism = "email" 211 | setting = @( 212 | # Notification type: Notification to activated user (requestor) 213 | @{ 214 | customreceivers = $null # Null or array of email addresses 215 | isdefaultreceiverenabled = $true # Send to default recipient (Requestor)? 216 | notificationlevel = 1 # 1 = Critical emails only enabled, 2 = Critical emails only disabled 217 | recipienttype = 0 218 | }, 219 | # Notification type: Request to approve a role assignment renewal/extension 220 | @{ 221 | customreceivers = $null # MUST be null (custom email addresses not allowed) 222 | isdefaultreceiverenabled = $true # Send to default recipient (Approver)? 223 | notificationlevel = 1 # 1 = Critical emails only enabled, 2 = Critical emails only disabled 224 | recipienttype = 1 225 | }, 226 | # Notification type: Role activation alert 227 | @{ 228 | customreceivers = $null # Null or array of email addresses 229 | isdefaultreceiverenabled = $true # Send to default recipient (Admin)? 230 | notificationlevel = 1 # 1 = Critical emails only enabled, 2 = Critical emails only disabled 231 | recipienttype = 2 232 | } 233 | ) 234 | } 235 | ) 236 | } | ConvertTo-Json -Depth 5 -Compress # Setting needs to be nested JSON 237 | } 238 | ) 239 | } 240 | ## END ELIGIBLE USER ACTIVATING ROLE REGION 241 | ) 242 | } | ConvertTo-Json -Depth 10 243 | 244 | # Configure settings for the OWNER role on the Privileged Access Group 245 | $ownerSettings = [PSCustomObject]@{ 246 | lifeCycleManagement = @( 247 | @{ 248 | ## START ELIGIBLE ASSIGNMENT REGION 249 | caller = "Admin" 250 | level = "Eligible" 251 | operation = "ALL" 252 | value = @( 253 | @{ 254 | # Eligible assignment expiration rule 255 | ruleIdentifier = "ExpirationRule" 256 | setting = @{ 257 | permanentAssignment = $false # Allow permanent eligible assignments? 258 | maximumGrantPeriodInMinutes = 525600 # Expire eligible assignments after 1 year (525600 minutes) 259 | } | ConvertTo-Json -Compress # Setting needs to be nested JSON 260 | }, 261 | @{ 262 | # Notification rule for eligible assignment (Send notifications when members are assigned as eligible to this role) 263 | ruleIdentifier = "NotificationRule" 264 | setting = @{ 265 | policies = @( 266 | @{ 267 | deliveryMechanism = "email" 268 | setting = @( 269 | # Notification type: Notification to the assigned user (assignee) 270 | @{ 271 | customreceivers = $null # Null or array of email addresses 272 | isdefaultreceiverenabled = $true # Send to default recipient (Assignee)? 273 | notificationlevel = 2 # 1 = Critical emails only enabled, 2 = Critical emails only disabled 274 | recipienttype = 0 275 | }, 276 | # Notification type: Request to approve a role assignment renewal/extension 277 | @{ 278 | customreceivers = $null # Null or array of email addresses 279 | isdefaultreceiverenabled = $true # Send to default recipient (Approver)? 280 | notificationlevel = 2 # 1 = Critical emails only enabled, 2 = Critical emails only disabled 281 | recipienttype = 1 282 | }, 283 | # Notification type: Role assignment alert 284 | @{ 285 | customreceivers = $null # Null or array of email addresses 286 | isdefaultreceiverenabled = $true # Send to default recipient (Admin)? 287 | notificationlevel = 2 # 1 = Critical emails only enabled, 2 = Critical emails only disabled 288 | recipienttype = 2 289 | } 290 | ) 291 | } 292 | ) 293 | } | ConvertTo-Json -Depth 5 -Compress # Setting needs to be nested JSON 294 | } 295 | ) 296 | } 297 | ## END ELIGIBLE ASSIGNMENT REGION 298 | ## START ACTIVE ASSIGNMENT REGION 299 | @{ 300 | caller = "Admin" 301 | level = "Member" 302 | operation = "ALL" 303 | value = @( 304 | @{ 305 | ruleIdentifier = "ExpirationRule" 306 | setting = @{ 307 | permanentAssignment = $false # Allow permanent active assignments? 308 | maximumGrantPeriodInMinutes = 21600 # Expire active assignments after 15 days (21600 minutes) 309 | } | ConvertTo-Json -Compress 310 | } 311 | @{ 312 | ruleIdentifier = "MfaRule" 313 | setting = @{ 314 | mfaRequired = $true # Require MFA when assigning a user as active? 315 | } | ConvertTo-Json -Compress 316 | } 317 | @{ 318 | ruleIdentifier = "JustificationRule" 319 | setting = @{ 320 | required = $true # Require justification when assigning a user as active? 321 | } | ConvertTo-Json -Compress 322 | } 323 | @{ 324 | # Notification rule for active assignment (Send notifications when members are assigned as active to this role) 325 | ruleIdentifier = "NotificationRule" 326 | setting = @{ 327 | policies = @( 328 | @{ 329 | deliveryMechanism = "email" 330 | setting = @( 331 | # Notification type: Notification to the assigned user (assignee) 332 | @{ 333 | customreceivers = $null # Null or array of email addresses 334 | isdefaultreceiverenabled = $true # Send to default recipient (Assignee)? 335 | notificationlevel = 2 # 1 = Critical emails only enabled, 2 = Critical emails only disabled 336 | recipienttype = 0 337 | }, 338 | # Notification type: Request to approve a role assignment renewal/extension 339 | @{ 340 | customreceivers = $null # Null or array of email addresses 341 | isdefaultreceiverenabled = $true # Send to default recipient (Approver)? 342 | notificationlevel = 2 # 1 = Critical emails only enabled, 2 = Critical emails only disabled 343 | recipienttype = 1 344 | }, 345 | # Notification type: Role assignment alert 346 | @{ 347 | customreceivers = $null # Null or array of email addresses 348 | isdefaultreceiverenabled = $true # Send to default recipient (Admin)? 349 | notificationlevel = 2 # 1 = Critical emails only enabled, 2 = Critical emails only disabled 350 | recipienttype = 2 351 | } 352 | ) 353 | } 354 | ) 355 | } | ConvertTo-Json -Depth 5 -Compress # Setting needs to be nested JSON 356 | } 357 | ) 358 | } 359 | ## END ACTIVE ASSIGNMENT REGION 360 | ## START ELIGIBLE USER ACTIVATING ROLE REGION 361 | @{ 362 | caller = "EndUser" 363 | level = "Member" 364 | operation = "ALL" 365 | value = @( 366 | @{ 367 | ruleIdentifier = "ExpirationRule" 368 | setting = @{ 369 | permanentAssignment = $false 370 | maximumGrantPeriodInMinutes = 60 # Activation maximum duration 1 hour (60 minutes) 371 | } | ConvertTo-Json -Compress 372 | }, 373 | @{ 374 | ruleIdentifier = "MfaRule" 375 | setting = @{ 376 | mfaRequired = $true # Require MFA when user is activating the role? 377 | } | ConvertTo-Json -Compress 378 | }, 379 | @{ 380 | ruleIdentifier = "JustificationRule" 381 | setting = @{ 382 | required = $true # Require justification when user is activating the role? 383 | } | ConvertTo-Json -Compress 384 | }, 385 | @{ 386 | ruleIdentifier = "TicketingRule" 387 | setting = @{ 388 | ticketingRequired = $false # Require ticket number when user is activating the role? 389 | } | ConvertTo-Json -Compress 390 | }, 391 | @{ 392 | ruleIdentifier = "ApprovalRule" 393 | setting = @{ 394 | enabled = $false # Require approval when user is activating the role? 395 | approvers = $null # List of approvers to notify 396 | } | ConvertTo-Json -Compress 397 | }, 398 | @{ 399 | ruleIdentifier = "AcrsRule" 400 | setting = @{ 401 | acrsRequired = $false 402 | acrs = $null 403 | } | ConvertTo-Json -Compress 404 | } 405 | , 406 | @{ 407 | # Notification rule when a user is activating an assignment (Send notifications when eligible members activate this role) 408 | ruleIdentifier = "NotificationRule" 409 | setting = @{ 410 | policies = @( 411 | @{ 412 | deliveryMechanism = "email" 413 | setting = @( 414 | # Notification type: Notification to activated user (requestor) 415 | @{ 416 | customreceivers = $null # Null or array of email addresses 417 | isdefaultreceiverenabled = $true # Send to default recipient (Requestor)? 418 | notificationlevel = 1 # 1 = Critical emails only enabled, 2 = Critical emails only disabled 419 | recipienttype = 0 420 | }, 421 | # Notification type: Request to approve a role assignment renewal/extension 422 | @{ 423 | customreceivers = $null # MUST be null (custom email addresses not allowed) 424 | isdefaultreceiverenabled = $true # Send to default recipient (Approver)? 425 | notificationlevel = 1 # 1 = Critical emails only enabled, 2 = Critical emails only disabled 426 | recipienttype = 1 427 | }, 428 | # Notification type: Role activation alert 429 | @{ 430 | customreceivers = $null # Null or array of email addresses 431 | isdefaultreceiverenabled = $true # Send to default recipient (Admin)? 432 | notificationlevel = 1 # 1 = Critical emails only enabled, 2 = Critical emails only disabled 433 | recipienttype = 2 434 | } 435 | ) 436 | } 437 | ) 438 | } | ConvertTo-Json -Depth 5 -Compress # Setting needs to be nested JSON 439 | } 440 | ) 441 | } 442 | ## END ELIGIBLE USER ACTIVATING ROLE REGION 443 | ) 444 | } | ConvertTo-Json -Depth 10 445 | } 446 | 447 | process { 448 | 449 | $groupRoles = Get-PrivilegedAccessGroupRoleSettings -GroupObjectID $GroupObjectID 450 | $ownerRole = $groupRoles | where { $_.roleDefinition.displayName -eq "Owner" } 451 | 452 | Write-Output "Updating settings for $GroupObjectID - role $($ownerRole.roleDefinition.displayName) ($($ownerRole.id))" 453 | $ownerUpdateURI = "https://api.azrbac.mspim.azure.com/api/v2/privilegedAccess/aadGroups/roleSettingsV2/$($ownerRole.id)" 454 | $updateOwnerPIMSettings = Invoke-WebRequest -Uri $ownerUpdateURI -Headers $Headers -Method PATCH -Body $ownerSettings -ContentType 'application/json' 455 | if ($updateOwnerPIMSettings.BaseResponse.IsSuccessStatusCode -eq $true) { 456 | Write-Output "OK" 457 | } else { 458 | Write-Output "Failed" 459 | } 460 | 461 | $groupRoles = Get-PrivilegedAccessGroupRoleSettings -GroupObjectID $GroupObjectID 462 | $memberRole = $groupRoles | where { $_.roleDefinition.displayName -eq "Member" } 463 | 464 | Write-Output "Updating settings for $GroupObjectID - role $($memberRole.roleDefinition.displayName) ($($memberRole.id))" 465 | $memberUpdateURI = "https://api.azrbac.mspim.azure.com/api/v2/privilegedAccess/aadGroups/roleSettingsV2/$($memberRole.id)" 466 | $updateMemberPIMSettings = Invoke-WebRequest -Uri $memberUpdateURI -Headers $Headers -Method PATCH -Body $memberSettings -ContentType 'application/json' 467 | if ($updateMemberPIMSettings.BaseResponse.IsSuccessStatusCode -eq $true) { 468 | Write-Output "OK" 469 | } else { 470 | Write-Output "Failed" 471 | } 472 | } 473 | 474 | end { 475 | 476 | } 477 | } --------------------------------------------------------------------------------