Private/Get-NSPConditionalAccessDefinitionSummary.ps1
|
function Get-NSPConditionalAccessDefinitionSummary { <# .SYNOPSIS A policy definition in plain words, for the dashboard: who, which apps, where, on which devices, and what it requires. .DESCRIPTION Offline. Returns ordered label/text pairs. With -TenantProfile, group slots also name the tenant's bound groups. Nothing is resolved against Graph. #> [CmdletBinding()] [OutputType([System.Collections.Specialized.OrderedDictionary])] param( [Parameter(Mandatory)]$Definition, $TenantProfile ) function Get-Value { param($Object, [string]$Key) Get-NSPConditionalAccessMapValue $Object $Key } $boundProfile = $TenantProfile $pattern = (Get-NSPConditionalAccessDefinitionSchema).ReferencePattern function Get-Phrase { param([string]$Value) switch -Regex ($Value) { '^All$' { return 'everyone' } '^None$' { return 'no one' } '^GuestsOrExternalUsers$' { return 'guests and external users' } '^AllTrusted$' { return 'trusted locations (the office)' } '^Office365$' { return 'Office 365' } '^MicrosoftAdminPortals$' { return 'Microsoft admin portals' } '^urn:user:registersecurityinfo$' { return 'registering security info (setting up MFA)' } '^urn:user:registerdevice$' { return 'registering or joining a device' } } if ($Value -notmatch $pattern) { return $Value } $kind = $Matches['kind'] $name = $Matches['name'] switch ($kind) { 'BreakGlass' { 'breakglass accounts' } 'ServiceAccounts' { 'service accounts' } 'Group' { $bound = Get-Value (Get-Value (Get-Value $boundProfile 'Groups') $name) 'Labels' $label = if ($bound) { " ($(@($bound) -join ', '))" } else { '' } "group $name$label" } 'TravelGroups' { if ($name -eq 'Enforced') { 'travel groups whose travel policy is On' } else { 'every active travel group' } } 'TravelGroup' { $entry = Get-Value (Get-Value (Get-Value $boundProfile 'Travel') 'Entries') $name $label = @(Get-Value $entry 'Labels') + @(Get-Value $entry 'DefaultName') | Where-Object { $_ } | Select-Object -First 1 if ($label) { "travel group $label" } else { "travel group $name" } } 'Role' { "role $name" } 'App' { $name } 'Country' { if ($name -eq 'Home') { "the home country ($(Get-Value $boundProfile 'HomeCountry'))" } else { $country = try { ([System.Globalization.RegionInfo]::new($name)).EnglishName } catch { $null } if ($country) { "$name ($country)" } else { $name } } } 'Location' { "location $name" } 'Strength' { switch ($name) { 'TapOnly' { 'a Temporary Access Pass (one-time or multi-use)' } 'PhishingResistant' { 'phishing-resistant MFA (security key, Windows Hello, passkey)' } 'PasswordlessMfa' { 'passwordless MFA' } 'Mfa' { 'MFA' } default { "authentication strength $name" } } } default { $Value } } } function Join-Phrase { param([object[]]$Values, [int]$Max = 4) $phrases = @($Values | Where-Object { $_ } | ForEach-Object { Get-Phrase ([string]$_) }) if ($phrases.Count -gt $Max) { return (($phrases[0..($Max - 1)]) -join ', ') + " and $($phrases.Count - $Max) more" } $phrases -join ', ' } $out = [ordered]@{} $users = Get-Value $Definition 'Users' $roles = @(Get-Value $users 'IncludeRoles' | Where-Object { $_ }) $who = @(@(Get-Value $users 'IncludeUsers') + @(Get-Value $users 'IncludeGroups') | Where-Object { $_ }) $out['Who'] = Join-Phrase $who if ($roles.Count) { $names = @($roles | ForEach-Object { if ($_ -match $pattern) { $Matches['name'] } else { $_ } }) $roleText = if ($names.Count -gt 3) { "$($names.Count) administrator roles ($(@($names | Where-Object { $_ -in 'GlobalAdministrator', 'SecurityAdministrator', 'UserAdministrator' }) -join ', '), ...)" } else { "role $($names -join ', role ')" } $out['Who'] = (@($out['Who'], $roleText) | Where-Object { $_ }) -join ', ' } $except = @(@(Get-Value $users 'ExcludeUsers') + @(Get-Value $users 'ExcludeGroups') + @(Get-Value $users 'ExcludeRoles') | Where-Object { $_ }) if ($except.Count) { $out['Except'] = Join-Phrase $except 6 } # Additions in the tenant profile (Add-NSPConditionalAccessPolicyTarget), by name. $added = Get-Value (Get-Value $TenantProfile 'PolicyTargets') ([string](Get-Value $Definition 'Id')) $alsoIn = @(foreach ($field in 'IncludeUsers', 'IncludeGroups') { @(Get-Value $added $field) | Where-Object { $_ } | ForEach-Object { Get-Value $_ 'Label' } }) $alsoOut = @(foreach ($field in 'ExcludeUsers', 'ExcludeGroups') { @(Get-Value $added $field) | Where-Object { $_ } | ForEach-Object { Get-Value $_ 'Label' } }) if ($alsoIn.Count) { $out['Also for'] = $alsoIn -join ', ' } if ($alsoOut.Count) { $out['Also except'] = $alsoOut -join ', ' } $apps = Get-Value $Definition 'Applications' $actions = @(Get-Value $apps 'UserActions' | Where-Object { $_ }) if ($actions.Count) { $out['When'] = Join-Phrase $actions } else { $text = Join-Phrase @(Get-Value $apps 'Include') if ($text -eq 'everyone') { $text = 'every cloud app' } $notApps = @(Get-Value $apps 'Exclude' | Where-Object { $_ }) if ($notApps.Count) { $text += " except $(Join-Phrase $notApps)" } $out['Apps'] = $text } $locations = Get-Value $Definition 'Locations' if ($locations) { $text = Join-Phrase @(Get-Value $locations 'Include') if ($text -eq 'everyone') { $text = 'anywhere' } $notHere = @(Get-Value $locations 'Exclude' | Where-Object { $_ }) if ($notHere.Count) { $text += " except $(Join-Phrase $notHere)" } $out['Where'] = $text } $platforms = Get-Value $Definition 'Platforms' if ($platforms) { $out['Devices'] = (@(Get-Value $platforms 'Include') -join ', ') } $grant = Get-Value $Definition 'Grant' $controls = @(Get-Value $grant 'BuiltInControls' | Where-Object { $_ }) $strength = Get-Value $grant 'AuthenticationStrength' $names = @{ block = 'BLOCKED'; mfa = 'MFA'; compliantDevice = 'a compliant device'; domainJoinedDevice = 'a hybrid-joined device'; approvedApplication = 'an approved app'; compliantApplication = 'an app-protection-policy app'; passwordChange = 'a password change' } $required = @($controls | ForEach-Object { if ($names.ContainsKey($_)) { $names[$_] } else { $_ } }) if ($strength) { $required += Get-Phrase $strength } if ($controls -contains 'block') { $out['Result'] = 'Sign-in is BLOCKED' } elseif ($required.Count) { $joiner = if ((Get-Value $grant 'Operator') -eq 'AND') { ' and ' } else { ' or ' } $out['Requires'] = $required -join $joiner } $session = Get-Value $Definition 'Session' $frequency = Get-Value $session 'SignInFrequency' if ($frequency) { $out['Session'] = "sign in again every $(Get-Value $frequency 'Value') $(Get-Value $frequency 'Type')" } $option = Get-Value $Definition 'Option' if ($option) { $out['Used when'] = "the tenant option $(($option -replace '=', ' is ') -replace ',', ' or ')" } $out } |