modules/Azure/Discovery/Private/InvokeCIEMAzureEffectiveRoleAssignmentBuild.ps1
|
function InvokeCIEMAzureEffectiveRoleAssignmentBuild { param( [Parameter(Mandatory)] [AllowEmptyCollection()] [object[]]$ArmResources, [Parameter(Mandatory)] [AllowEmptyCollection()] [object[]]$EntraResources, [Parameter(Mandatory)] [AllowEmptyCollection()] [object[]]$Relationships, [Parameter(Mandatory)] [object]$Connection, [Parameter(Mandatory)] [string]$ComputedAt ) $ErrorActionPreference = 'Stop' # 1. Build role definition lookup: roleDefId -> { RoleName, PermissionsJson } $roleDefLookup = @{} foreach ($r in $ArmResources) { if ($r.Type -eq 'microsoft.authorization/roledefinitions' -and $r.Properties) { try { $props = $r.Properties | ConvertFrom-Json -ErrorAction Stop } catch { $props = $null } if ($props) { $roleDefLookup[$r.Id] = @{ RoleName = $props.roleName PermissionsJson = if ($props.permissions) { $props.permissions | ConvertTo-Json -Depth 10 -Compress } else { $null } } } } } # 2. Build Entra display name lookup: principalId -> displayName $displayNameLookup = @{} foreach ($e in $EntraResources) { if ($e.Id -and $e.DisplayName) { $displayNameLookup[$e.Id] = $e.DisplayName } } # 3. Build transitive membership lookup: groupId -> list of { Id, Type } # transitive_member_of: source=leaf member, target=group $groupMembersLookup = @{} foreach ($rel in $Relationships) { if ($rel.Relationship -eq 'transitive_member_of') { $groupId = $rel.TargetId if (-not $groupMembersLookup.ContainsKey($groupId)) { $groupMembersLookup[$groupId] = [System.Collections.Generic.List[object]]::new() } $groupMembersLookup[$groupId].Add(@{ Id = $rel.SourceId Type = $rel.SourceType }) } } # 4. Process role assignments — build rows list, then save all at once $roleAssignments = @($ArmResources | Where-Object { $_.Type -eq 'microsoft.authorization/roleassignments' -and $_.Properties }) $rows = [System.Collections.Generic.List[CIEMAzureEffectiveRoleAssignment]]::new() foreach ($ra in $roleAssignments) { try { $props = $ra.Properties | ConvertFrom-Json -ErrorAction Stop } catch { continue } if (-not $props) { continue } $principalId = $props.principalId $principalType = $props.principalType $roleDefinitionId = $props.roleDefinitionId $scope = $props.scope if (-not $principalId -or -not $roleDefinitionId -or -not $scope) { continue } $roleDef = $roleDefLookup[$roleDefinitionId] $roleName = if ($roleDef) { $roleDef.RoleName } else { $null } $permissionsJson = if ($roleDef) { $roleDef.PermissionsJson } else { $null } if ($principalType -eq 'Group') { # Expand to all transitive members $members = $groupMembersLookup[$principalId] if ($members) { foreach ($member in $members) { $row = [CIEMAzureEffectiveRoleAssignment]::new() $row.PrincipalId = $member.Id $row.PrincipalType = $member.Type $row.PrincipalDisplayName = $displayNameLookup[$member.Id] $row.OriginalPrincipalId = $principalId $row.OriginalPrincipalType = 'Group' $row.RoleDefinitionId = $roleDefinitionId $row.RoleName = $roleName $row.Scope = $scope $row.PermissionsJson = $permissionsJson $row.ComputedAt = $ComputedAt $rows.Add($row) } } # Group self-row (direct assignment record) $row = [CIEMAzureEffectiveRoleAssignment]::new() $row.PrincipalId = $principalId $row.PrincipalType = $principalType $row.PrincipalDisplayName = $displayNameLookup[$principalId] $row.OriginalPrincipalId = $principalId $row.OriginalPrincipalType = $principalType $row.RoleDefinitionId = $roleDefinitionId $row.RoleName = $roleName $row.Scope = $scope $row.PermissionsJson = $permissionsJson $row.ComputedAt = $ComputedAt $rows.Add($row) } else { # Direct assignment (user, SP, managed identity) $row = [CIEMAzureEffectiveRoleAssignment]::new() $row.PrincipalId = $principalId $row.PrincipalType = $principalType $row.PrincipalDisplayName = $displayNameLookup[$principalId] $row.OriginalPrincipalId = $principalId $row.OriginalPrincipalType = $principalType $row.RoleDefinitionId = $roleDefinitionId $row.RoleName = $roleName $row.Scope = $scope $row.PermissionsJson = $permissionsJson $row.ComputedAt = $ComputedAt $rows.Add($row) } } if ($rows.Count -gt 0) { Save-CIEMAzureEffectiveRoleAssignment -InputObject $rows -Connection $Connection } $rows.Count } |