Collectors/ConditionalAccess.ps1
|
@{ Name = 'ConditionalAccess' FileName = 'conditionalAccess' ApiVersion = 'v1.0' RequiredScopes = @('Policy.Read.All') Description = 'Conditional Access policies with resolved display names for users, groups, roles, applications and locations.' Collect = { $policies = @(Invoke-TLGraphRequest -Uri '/v1.0/identity/conditionalAccess/policies' -All) # Role template id -> display name (CA references roles by template id) $roleNames = @{} try { foreach ($roleDefinition in @(Invoke-TLGraphRequest -Uri '/v1.0/roleManagement/directory/roleDefinitions?$select=templateId,displayName' -All)) { $roleNames[[string]$roleDefinition.templateId] = [string]$roleDefinition.displayName } } catch { Write-Verbose ("Role definitions unavailable for name resolution: {0}" -f $_.Exception.Message) } # Named location id -> display name $locationNames = @{} try { foreach ($location in @(Invoke-TLGraphRequest -Uri '/v1.0/identity/conditionalAccess/namedLocations?$select=id,displayName' -All)) { $locationNames[[string]$location.id] = [string]$location.displayName } } catch { Write-Verbose ("Named locations unavailable for name resolution: {0}" -f $_.Exception.Message) } # Gather every referenced id once, resolve in batches $directoryIds = [System.Collections.Generic.List[string]]::new() $applicationIds = [System.Collections.Generic.List[string]]::new() foreach ($policy in $policies) { $conditions = $policy.conditions if ($null -eq $conditions) { continue } if ($conditions.PSObject.Properties['users'] -and $conditions.users) { foreach ($id in @($conditions.users.includeUsers) + @($conditions.users.excludeUsers) + @($conditions.users.includeGroups) + @($conditions.users.excludeGroups)) { if ($id) { $directoryIds.Add([string]$id) } } } if ($conditions.PSObject.Properties['applications'] -and $conditions.applications) { foreach ($id in @($conditions.applications.includeApplications) + @($conditions.applications.excludeApplications)) { if ($id) { $applicationIds.Add([string]$id) } } } } $directoryMap = Resolve-TLObjectId -Id $directoryIds.ToArray() $applicationMap = Resolve-TLAppId -AppId $applicationIds.ToArray() function Resolve-DirectoryNames { param([object]$Ids, [hashtable]$Map) @(foreach ($id in @($Ids | Where-Object { $_ })) { if ($Map.ContainsKey([string]$id)) { $Map[[string]$id].DisplayName } else { [string]$id } }) } function Resolve-SimpleNames { param([object]$Ids, [hashtable]$Map) @(foreach ($id in @($Ids | Where-Object { $_ })) { if ($Map.ContainsKey([string]$id)) { $Map[[string]$id] } else { [string]$id } }) } foreach ($policy in $policies) { $conditions = $policy.conditions $users = $null; $applications = $null; $locations = $null if ($conditions) { if ($conditions.PSObject.Properties['users']) { $users = $conditions.users } if ($conditions.PSObject.Properties['applications']) { $applications = $conditions.applications } if ($conditions.PSObject.Properties['locations']) { $locations = $conditions.locations } } $resolved = [ordered]@{ usersInclude = @(); usersExclude = @() groupsInclude = @(); groupsExclude = @() rolesInclude = @(); rolesExclude = @() appsInclude = @(); appsExclude = @() locationsInclude = @(); locationsExclude = @() } if ($users) { $resolved['usersInclude'] = Resolve-DirectoryNames -Ids $users.includeUsers -Map $directoryMap $resolved['usersExclude'] = Resolve-DirectoryNames -Ids $users.excludeUsers -Map $directoryMap $resolved['groupsInclude'] = Resolve-DirectoryNames -Ids $users.includeGroups -Map $directoryMap $resolved['groupsExclude'] = Resolve-DirectoryNames -Ids $users.excludeGroups -Map $directoryMap $resolved['rolesInclude'] = Resolve-SimpleNames -Ids $users.includeRoles -Map $roleNames $resolved['rolesExclude'] = Resolve-SimpleNames -Ids $users.excludeRoles -Map $roleNames } if ($applications) { $resolved['appsInclude'] = Resolve-SimpleNames -Ids $applications.includeApplications -Map $applicationMap $resolved['appsExclude'] = Resolve-SimpleNames -Ids $applications.excludeApplications -Map $applicationMap } if ($locations) { $resolved['locationsInclude'] = Resolve-SimpleNames -Ids $locations.includeLocations -Map $locationNames $resolved['locationsExclude'] = Resolve-SimpleNames -Ids $locations.excludeLocations -Map $locationNames } # Raw data stays untouched; resolution is an additive extra field. Add-Member -InputObject $policy -NotePropertyName '_tlResolved' -NotePropertyValue ([pscustomobject]$resolved) -Force } , @($policies) } } |