Private/Get-NSPConditionalAccessTravelDefinition.ps1
|
function Get-NSPConditionalAccessTravelDefinition { <# .SYNOPSIS Generates the TravelMFA policy definitions for a tenant profile's active travel entries. .DESCRIPTION Conditional Access cannot say "block unless in group X and in country Y" in one policy, so: - NSP-TRAVEL-<ISO>-01 / NSP-TRAVEL-TRIP-<NN>: the entry's travel group is blocked everywhere except the home country and the entry's countries (every stop, for a trip). - NSP-TRAVEL-SESSION-01: every active travel group must use MFA, with a sign-in frequency of Travel.SessionHours (default 72, sent as 3 days; whole days are sent as days). NSP-BASE-GEO-01 excludes a travel group only once its travel policy is On ({TravelGroups:Enforced}), so there is never a window without a country restriction. DefaultState is report-only, but the planner creates travel policies On while NSP-BASE-GEO-01 is On: for its members a travel policy blocks less than the baseline already does, so turning it on blocks no one new. The baseline's exclusion then runs after it in the same plan. NSP-TRAVEL-SESSION-01 is created On with them: it reaches only travel group members, and travelers abroad must have it. Definitions are generated in the file format and validated like shipped ones. #> [CmdletBinding()] param( [Parameter(Mandatory)]$TenantProfile, [datetime]$Today = (Get-Date).Date ) $active = @(Get-NSPConditionalAccessTravelEntry -TenantProfile $TenantProfile -Today $Today | Where-Object Status -eq 'Active') foreach ($entry in $active) { $names = @($entry.Countries | ForEach-Object { Get-NSPConditionalAccessCountryName $_ }) -join ', ' $where = if ($entry.Kind -eq 'Trip') { "every stop of the trip ($names)" } else { $names } @{ Id = $entry.PolicyId Name = if ($entry.Kind -eq 'Trip') { "Trip: $($entry.Name)" } else { "Travel: allow $names" } Version = 1 Description = "Members of the travel group are blocked everywhere except the home country and $where." DefaultState = 'reportOnly' Users = @{ IncludeGroups = @("{TravelGroup:$($entry.Key)}") ExcludeUsers = @('{BreakGlass}', '{ServiceAccounts}') } Applications = @{ Include = @('All') } Locations = @{ Include = @('All') Exclude = @(@('{Country:Home}') + @($entry.Countries | ForEach-Object { "{Country:$_}" })) } Grant = @{ Operator = 'OR'; BuiltInControls = @('block') } } } if ($active.Count) { $hours = Get-NSPConditionalAccessMapValue (Get-NSPConditionalAccessMapValue $TenantProfile 'Travel') 'SessionHours' if (-not $hours) { $hours = 72 } # Whole days are sent as days (72 hours -> 3 days), as an operator would set it in the portal. $frequency = if ($hours % 24 -eq 0) { @{ Value = [int]($hours / 24); Type = 'days' } } else { @{ Value = [int]$hours; Type = 'hours' } } $length = "$($frequency.Value) $(if ($frequency.Value -eq 1) { $frequency.Type.TrimEnd('s') } else { $frequency.Type })" @{ Id = 'NSP-TRAVEL-SESSION-01' Name = 'Travel: MFA and session length for travelers' Version = 1 Description = "Every active travel group must use MFA and sign in again every $length." DefaultState = 'reportOnly' Users = @{ IncludeGroups = @('{TravelGroups:Active}') ExcludeUsers = @('{BreakGlass}', '{ServiceAccounts}') } Applications = @{ Include = @('All') } Grant = @{ Operator = 'OR'; BuiltInControls = @('mfa') } Session = @{ SignInFrequency = $frequency } } } } |