internal/functions/Build-AssignmentIdentityChanges.ps1

function Build-AssignmentIdentityChanges {
    [CmdletBinding()]
    param (
        $Existing,
        $Assignment,
        $ReplacedAssignment,
        $DeployedRoleAssignmentsByPrincipalId
    )

    $existingIdentity = $Existing.identity
    $hasExistingIdentity = $null -ne $Existing -and $null -ne $existingIdentity -and $existingIdentity.type -ne "None"
    $identityRequired = $null -ne $Assignment -and $Assignment.identityRequired

    $existingIdentityType = "None"
    $existingPrincipalId = $null
    $existingUserAssignedIdentity = $null
    $existingLocation = $null
    $existingRoleAssignments = @()

    $definedIdentity = $null
    $definedIdentityType = "None"
    $definedUserAssignedIdentity = $null
    $requiredRoleAssignments = @()

    $existingLocation = $Existing.location 
    $definedLocation = "global"
    if ($hasExistingIdentity) { 
        $existingIdentityType = $existingIdentity.type 
        if ($existingIdentityType -eq "UserAssigned") { 
            $existingUserAssignedIdentity = ($existingIdentity.userAssignedIdentities | get-member)[-1].Name 
        } 
        if ($existingIdentityType -eq "UserAssigned") { 
            $existingPrincipalId = $existingIdentity.userAssignedIdentities.$existingUserAssignedIdentity.principalId 
        }
        else { 
            $existingPrincipalId = $existingIdentity.principalId 
        } 
        if ($DeployedRoleAssignmentsByPrincipalId.ContainsKey($existingPrincipalId)) { 
            $existingRoleAssignments = $DeployedRoleAssignmentsByPrincipalId.$existingPrincipalId 
        } 
    } 
    if ($identityRequired ) { 
        $definedIdentity = $Assignment.identity 
        $definedIdentityType = $definedIdentity.type 
        if ($definedIdentityType -eq "UserAssigned") { 
            $definedUserAssignedIdentity = $definedIdentity.userAssignedIdentities.GetEnumerator().Name
        } 
        $definedLocation = $Assignment.managedIdentityLocation
        $requiredRoleAssignments = $Assignment.requiredRoleAssignments 
    }

    $replaced = $ReplacedAssignment
    $isNewOrDeleted = $false
    $isUserAssigned = $false
    $changedIdentityStrings = @()
    $addedList = [System.Collections.ArrayList]::new()
    $updatedList = [System.Collections.ArrayList]::new()    
    $removedList = [System.Collections.ArrayList]::new()
    if ($hasExistingIdentity -or $identityRequired) {
        # need to check if either an existing identity or a newly added identity or existing and required identity
        if ($null -ne $Existing -and $null -ne $Assignment) {
            # this is an update, not a delete or new Assignment
            if ($hasExistingIdentity -xor $identityRequired) {
                # change (xor) in need for an identity, determine which one
                if ($hasExistingIdentity) {
                    $changedIdentityStrings += "removedIdentity"
                }
                else {
                    $changedIdentityStrings += "addedIdentity"
                }
                $replaced = $true
            }
            else {
                # existing identity and still requires an entity
                if ($existingLocation -ne $definedLocation) {
                    $changedIdentityStrings += "identityLocation $existingLocation->$definedLocation"
                    $replaced = $true
                }
                if ($existingIdentityType -ne $definedIdentityType) {
                    $changedIdentityStrings += "identityType $existingIdentityType->$definedIdentityType"
                    $replaced = $true
                }
                elseif ($existingIdentityType -eq "UserAssigned" -and $existingUserAssignedIdentity -ne $definedUserAssignedIdentity) {
                    $changedIdentityStrings += "changed userAssignedIdentity"
                    $replaced = $true
                }
            }
        }
        else {
            # deleted or new Assignment
            $isNewOrDeleted = $true
        }

        if ($replaced -or $isNewOrDeleted) {
            # replaced, new or deleted Assignment
            if ($hasExistingIdentity -and $existingRoleAssignments.Count -gt 0) {
                if ($existingIdentityType -ne "UserAssigned") {
                    foreach ($deployedRoleAssignment in $existingRoleAssignments) {
                        $null = $removedList.Add($deployedRoleAssignment)
                    }
                }
                else {
                    # note: do not manage role assignments if user-assigned MI
                    $isUserAssigned = $true
                }
            }
            if ($identityRequired) {
                if ($definedIdentityType -ne "UserAssigned") {
                    foreach ($requiredRoleAssignment in $requiredRoleAssignments) {
                        $addedEntry = $null
                        if ($requiredRoleAssignment.crossTenant) {
                            $addedEntry = @{
                                assignmentId          = $Assignment.id
                                assignmentDisplayName = $Assignment.displayName
                                roleDisplayName       = $requiredRoleAssignment.roleDisplayName
                                scope                 = $requiredRoleAssignment.scope
                                properties            = @{
                                    roleDefinitionId = $requiredRoleAssignment.roleDefinitionId
                                    principalId      = $null
                                    principalType    = "ServicePrincipal"
                                    description      = $requiredRoleAssignment.description
                                    crossTenant      = $true
                                }
                            }
                        }
                        else {
                            $addedEntry = @{
                                assignmentId          = $Assignment.id
                                assignmentDisplayName = $Assignment.displayName
                                roleDisplayName       = $requiredRoleAssignment.roleDisplayName
                                scope                 = $requiredRoleAssignment.scope
                                properties            = @{
                                    roleDefinitionId = $requiredRoleAssignment.roleDefinitionId
                                    principalId      = $null
                                    principalType    = "ServicePrincipal"
                                    description      = $requiredRoleAssignment.description
                                }
                            }
                        }
                        $null = $addedList.Add($addedEntry)
                    }
                }
                else {
                    # note: do not manage role assignments if user-assigned MI
                    $isUserAssigned = $true
                }
            }
        }
        else {
            # Updating existing Policy assignment
            if ($existingIdentityType -ne "UserAssigned") {

                # calculate addedList role assignments (rare)
                foreach ($requiredRoleAssignment in $requiredRoleAssignments) {
                    $requiredScope = $requiredRoleAssignment.scope
                    $requiredRoleDefinitionId = $requiredRoleAssignment.roleDefinitionId
                    $requiredDescription = $requiredRoleAssignment.description
                    $deployedRoleAssignmentWithUpdatedDescription = $null
                    $matchFound = $false
                    foreach ($deployedRoleAssignment in $existingRoleAssignments) {
                        $deployedScope = $deployedRoleAssignment.scope
                        $deployedRoleDefinitionId = $deployedRoleAssignment.roleDefinitionId
                        if (($deployedScope -eq $requiredScope) -and ($deployedRoleDefinitionId -eq $requiredRoleDefinitionId)) {
                            $deployedDescription = $deployedRoleAssignment.description
                            if ($deployedDescription -ne $requiredDescription) {
                                $deployedRoleAssignmentWithUpdatedDescription = $deployedRoleAssignment
                            }
                            $matchFound = $true
                            break
                        }
                    }
                    $addedEntry = $null
                    if ($requiredRoleAssignment.crossTenant) {
                        $addedEntry = @{
                            assignmentId          = $Assignment.id
                            assignmentDisplayName = $Assignment.displayName
                            roleDisplayName       = $requiredRoleAssignment.roleDisplayName
                            scope                 = $requiredRoleAssignment.scope
                            properties            = @{
                                roleDefinitionId = $requiredRoleAssignment.roleDefinitionId
                                principalId      = $null
                                principalType    = "ServicePrincipal"
                                description      = $requiredRoleAssignment.description
                                crossTenant      = $true
                            }
                        }
                    }
                    else {
                        $addedEntry = @{
                            assignmentId          = $Assignment.id
                            assignmentDisplayName = $Assignment.displayName
                            roleDisplayName       = $requiredRoleAssignment.roleDisplayName
                            scope                 = $requiredRoleAssignment.scope
                            properties            = @{
                                roleDefinitionId = $requiredRoleAssignment.roleDefinitionId
                                principalId      = $null
                                principalType    = "ServicePrincipal"
                                description      = $requiredRoleAssignment.description
                            }
                        }
                    }
                    if ($matchFound) {
                        if ($null -ne $deployedRoleAssignmentWithUpdatedDescription) {
                            $addedEntry.id = $deployedRoleAssignmentWithUpdatedDescription.id
                            $addedEntry.properties.principalId = $deployedRoleAssignmentWithUpdatedDescription.principalId
                            $null = $updatedList.Add($addedEntry)
                        }
                    }
                    else {
                        $null = $addedList.Add($addedEntry)
                    }
                }

                # calculate obsolete role assignments to be removed (rare event)
                foreach ($deployedRoleAssignment in $existingRoleAssignments) {
                    $deployedScope = $deployedRoleAssignment.scope
                    $deployedRoleDefinitionId = $deployedRoleAssignment.roleDefinitionId
                    $matchFound = $false
                    foreach ($requiredRoleAssignment in $requiredRoleAssignments) {
                        $requiredScope = $requiredRoleAssignment.scope
                        $requiredRoleDefinitionId = $requiredRoleAssignment.roleDefinitionId
                        if (($deployedScope -eq $requiredScope) -and ($deployedRoleDefinitionId -eq $requiredRoleDefinitionId)) {
                            $matchFound = $true
                            break
                        }
                    }
                    if (!$matchFound) {
                        # Obsolete role assignment
                        $null = $removedList.Add($deployedRoleAssignment)
                    }
                }
            }
            else {
                # note: do not manage role assignments if user-assigned MI
                $isUserAssigned = $true
            }
        }
    }
    elseif ($existingLocation -ne $definedLocation) {
        # location change
        if ($null -eq $definedLocation) {
            $definedLocation = "."
        }
        $changedIdentityStrings += "identityLocation $existingLocation->$definedLocation"
        $replaced = $true
    }

    $numberOfChanges = 0
    if ($addedList.Count -gt 0) {
        $numberOfChanges += $addedList.Count
        $changedIdentityStrings += "addedRoleAssignments"
    }
    if ($updatedList.Count -gt 0) {
        $numberOfChanges += $updatedList.Count
        $changedIdentityStrings += "updatedRoleAssignments"
    }
    if ($removedList.Count -gt 0) {
        $numberOfChanges += $removedList.Count
        $changedIdentityStrings += "removedRoleAssignments"
    }
    return @{
        replaced               = $replaced
        requiresRoleChanges    = $numberOfChanges -gt 0
        numberOfChanges        = $numberOfChanges
        changedIdentityStrings = $changedIdentityStrings
        isUserAssigned         = $isUserAssigned
        added                  = $addedList
        updated                = $updatedList
        removed                = $removedList
    }
}