DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1
function Get-TargetResource { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( [Parameter()] [System.String] $Id, [Parameter(Mandatory = $true)] [System.String] $DisplayName, [Parameter()] [System.String] [ValidateSet('disabled', 'enabled', 'enabledForReportingButNotEnforced')] $State, #ConditionalAccessApplicationCondition [Parameter()] [System.String[]] $IncludeApplications, [Parameter()] [System.String[]] $ExcludeApplications, [Parameter()] [System.String] $ApplicationsFilter, [Parameter()] [ValidateSet('include', 'exclude')] [System.String] $ApplicationsFilterMode, [Parameter()] [System.String[]] $IncludeUserActions, #ConditionalAccessUserCondition [Parameter()] [System.String[]] $IncludeUsers, [Parameter()] [System.String[]] $ExcludeUsers, [Parameter()] [System.String[]] $IncludeGroups, [Parameter()] [System.String[]] $ExcludeGroups, [Parameter()] [System.String[]] $IncludeRoles, [Parameter()] [System.String[]] $ExcludeRoles, [Parameter()] [System.String[]] [validateSet('none', 'internalGuest', 'b2bCollaborationGuest', 'b2bCollaborationMember', 'b2bDirectConnectUser', 'otherExternalUser', 'serviceProvider', 'unknownFutureValue')] $IncludeGuestOrExternalUserTypes, [Parameter()] [System.String] [ValidateSet('', 'all', 'enumerated', 'unknownFutureValue')] $IncludeExternalTenantsMembershipKind, [Parameter()] [System.String[]] $IncludeExternalTenantsMembers, [Parameter()] [System.String[]] [validateSet('none', 'internalGuest', 'b2bCollaborationGuest', 'b2bCollaborationMember', 'b2bDirectConnectUser', 'otherExternalUser', 'serviceProvider', 'unknownFutureValue')] $ExcludeGuestOrExternalUserTypes, [Parameter()] [System.String] [ValidateSet('', 'all', 'enumerated', 'unknownFutureValue')] $ExcludeExternalTenantsMembershipKind, [Parameter()] [System.String[]] $ExcludeExternalTenantsMembers, [Parameter()] [System.String[]] $IncludeServicePrincipals, [Parameter()] [System.String[]] $ExcludeServicePrincipals, [Parameter()] [ValidateSet('include', 'exclude')] [System.String] $ServicePrincipalFilterMode, [Parameter()] [System.String] $ServicePrincipalFilterRule, #ConditionalAccessPlatformCondition [Parameter()] [System.String[]] $IncludePlatforms, [Parameter()] [System.String[]] $ExcludePlatforms, #ConditionalAccessLocationCondition [Parameter()] [System.String[]] $IncludeLocations, [Parameter()] [System.String[]] $ExcludeLocations, [Parameter()] [ValidateSet('include', 'exclude')] [System.String] $DeviceFilterMode, [Parameter()] [System.String] $DeviceFilterRule, #Further conditions [Parameter()] [System.String[]] $UserRiskLevels, [Parameter()] [System.String[]] $SignInRiskLevels, [Parameter()] [System.String[]] $ClientAppTypes, #ConditionalAccessGrantControls [Parameter()] [ValidateSet('AND', 'OR')] [System.String] $GrantControlOperator, [Parameter()] [System.String[]] $BuiltInControls, #ConditionalAccessSessionControls [Parameter()] [System.Boolean] $ApplicationEnforcedRestrictionsIsEnabled, [Parameter()] [System.Boolean] $CloudAppSecurityIsEnabled, [Parameter()] [System.String] $CloudAppSecurityType, [Parameter()] [System.Int32] $SignInFrequencyValue, [Parameter()] [ValidateSet('Days', 'Hours', '')] [System.String] $SignInFrequencyType, [Parameter()] [System.Boolean] $SignInFrequencyIsEnabled, [Parameter()] [ValidateSet('timeBased', 'everyTime', 'unknownFutureValue')] [System.String] $SignInFrequencyInterval, [Parameter()] [ValidateSet('Always', 'Never', '')] [System.String] $PersistentBrowserMode, [Parameter()] [System.Boolean] $PersistentBrowserIsEnabled, [Parameter()] [System.String] $TermsOfUse, [Parameter()] [System.String[]] $CustomAuthenticationFactors, [Parameter()] [System.String] $AuthenticationStrength, [Parameter()] [System.String[]] $AuthenticationContexts, [Parameter()] [System.String] $TransferMethods, [Parameter()] [ValidateSet('minor', 'moderate', 'elevated', 'unknownFutureValue')] [System.String] $InsiderRiskLevels, #generic [Parameter()] [ValidateSet('Present', 'Absent')] [System.String] $Ensure = 'Present', [Parameter()] [System.Management.Automation.PSCredential] $Credential, [Parameter()] [System.String] $ApplicationId, [Parameter()] [System.String] $TenantId, [Parameter()] [System.Management.Automation.PSCredential] $ApplicationSecret, [Parameter()] [System.String] $CertificateThumbprint, [Parameter()] [Switch] $ManagedIdentity, [Parameter()] [System.String[]] $AccessTokens ) Write-Verbose -Message 'Getting configuration of AzureAD Conditional Access Policy' $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` -InboundParameters $PSBoundParameters #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies #region Telemetry $ResourceName = $MyInvocation.MyCommand.ModuleName -replace 'MSFT_', '' $CommandName = $MyInvocation.MyCommand $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` -CommandName $CommandName ` -Parameters $PSBoundParameters Add-M365DSCTelemetryEvent -Data $data #endregion if ($PSBoundParameters.ContainsKey('Id')) { Write-Verbose -Message 'PolicyID was specified' try { $Policy = Get-MgBetaIdentityConditionalAccessPolicy -ConditionalAccessPolicyId $Id -ErrorAction Stop } catch { Write-Verbose -Message "Couldn't find existing policy by ID {$Id}" $Policy = Get-MgBetaIdentityConditionalAccessPolicy -Filter "DisplayName eq '$DisplayName'" if ($Policy.Length -gt 1) { throw "Duplicate CA Policies named $DisplayName exist in tenant" } } } else { Write-Verbose -Message 'Id was NOT specified' ## Can retreive multiple CA Policies since displayname is not unique $Policy = Get-MgBetaIdentityConditionalAccessPolicy -Filter "DisplayName eq '$DisplayName'" if ($Policy.Length -gt 1) { throw "Duplicate CA Policies named $DisplayName exist in tenant" } } if ([String]::IsNullOrEmpty($Policy.id)) { Write-Verbose -Message "No existing Policy with name {$DisplayName} were found" $currentValues = $PSBoundParameters $currentValues.Ensure = 'Absent' return $currentValues } Write-Verbose -Message 'Get-TargetResource: Found existing Conditional Access policy' $PolicyDisplayName = $Policy.DisplayName Write-Verbose -Message 'Get-TargetResource: Process IncludeUsers' #translate IncludeUser GUIDs to UPN, except id value is GuestsOrExternalUsers, None or All $IncludeUsers = @() if ($Policy.Conditions.Users.IncludeUsers) { foreach ($IncludeUserGUID in $Policy.Conditions.Users.IncludeUsers) { if ($IncludeUserGUID -notin 'GuestsOrExternalUsers', 'All', 'None') { $IncludeUser = $null try { $IncludeUser = (Get-MgUser -UserId $IncludeUserGUID -ErrorAction Stop).userprincipalname } catch { $message = "Couldn't find IncludedUser '$IncludeUserGUID', that is defined in policy '$PolicyDisplayName'. Skipping user." New-M365DSCLogEntry -Message $message ` -Exception $_ ` -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential continue } if ($IncludeUser) { $IncludeUsers += $IncludeUser } } else { $IncludeUsers += $IncludeUserGUID } } } Write-Verbose -Message 'Get-TargetResource: Process ExcludeUsers' #translate ExcludeUser GUIDs to UPN, except id value is GuestsOrExternalUsers, None or All $ExcludeUsers = @() if ($Policy.Conditions.Users.ExcludeUsers) { foreach ($ExcludeUserGUID in $Policy.Conditions.Users.ExcludeUsers) { if ($ExcludeUserGUID -notin 'GuestsOrExternalUsers', 'All', 'None') { $ExcludeUser = $null try { $ExcludeUser = (Get-MgUser -UserId $ExcludeUserGUID -ErrorAction Stop).userprincipalname } catch { $message = "Couldn't find ExcludedUser '$ExcludeUserGUID', that is defined in policy '$PolicyDisplayName'. Skipping user." New-M365DSCLogEntry -Message $message ` -Exception $_ ` -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential continue } if ($ExcludeUser) { $ExcludeUsers += $ExcludeUser } } else { $ExcludeUsers += $ExcludeUserGUID } } } Write-Verbose -Message 'Get-TargetResource: Process IncludeGroups' #translate IncludeGroup GUIDs to DisplayName $IncludeGroups = @() if ($Policy.Conditions.Users.IncludeGroups) { foreach ($IncludeGroupGUID in $Policy.Conditions.Users.IncludeGroups) { $IncludeGroup = $null try { $IncludeGroup = (Get-MgGroup -GroupId $IncludeGroupGUID -ErrorAction Stop).displayname } catch { $message = "Couldn't find IncludedGroup '$IncludeGroupGUID', that is defined in policy '$PolicyDisplayName'. Skipping group." New-M365DSCLogEntry -Message $message ` -Exception $_ ` -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential continue } if ($IncludeGroup) { $IncludeGroups += $IncludeGroup } } } Write-Verbose -Message 'Get-TargetResource: Process ExcludeGroups' #translate ExcludeGroup GUIDs to DisplayName $ExcludeGroups = @() if ($Policy.Conditions.Users.ExcludeGroups) { foreach ($ExcludeGroupGUID in $Policy.Conditions.Users.ExcludeGroups) { $ExcludeGroup = $null try { $ExcludeGroup = (Get-MgGroup -GroupId $ExcludeGroupGUID -ErrorAction Stop).displayname } catch { $message = "Couldn't find ExcludedGroup '$ExcludeGroupGUID', that is defined in policy '$PolicyDisplayName'. Skipping group." New-M365DSCLogEntry -Message $message ` -Exception $_ ` -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential continue } if ($ExcludeGroup) { $ExcludeGroups += $ExcludeGroup } } } $IncludeRoles = @() $ExcludeRoles = @() #translate role template guids to role name if ($Policy.Conditions.Users.IncludeRoles -or $Policy.Conditions.Users.ExcludeRoles) { Write-Verbose -Message 'Get-TargetResource: Role condition defined, processing' #build role translation table $rolelookup = @{} foreach ($role in Get-MgBetaDirectoryRoleTemplate -All) { $rolelookup[$role.Id] = $role.DisplayName } Write-Verbose -Message 'Get-TargetResource: Processing IncludeRoles' if ($Policy.Conditions.Users.IncludeRoles) { foreach ($IncludeRoleGUID in $Policy.Conditions.Users.IncludeRoles) { if ($null -eq $rolelookup[$IncludeRoleGUID]) { $message = "Couldn't find IncludedRole '$IncludeRoleGUID', that is defined in policy '$PolicyDisplayName'. Skipping role." New-M365DSCLogEntry -Message $message ` -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential } else { $IncludeRoles += $rolelookup[$IncludeRoleGUID] } } } Write-Verbose -Message 'Get-TargetResource: Processing ExcludeRoles' if ($Policy.Conditions.Users.ExcludeRoles) { foreach ($ExcludeRoleGUID in $Policy.Conditions.Users.ExcludeRoles) { if ($null -eq $rolelookup[$ExcludeRoleGUID]) { $message = "Couldn't find ExcludedRole '$ExcludeRoleGUID', that is defined in policy '$PolicyDisplayName'. Skipping role." New-M365DSCLogEntry -Message $message ` -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential } else { $ExcludeRoles += $rolelookup[$ExcludeRoleGUID] } } } } $IncludeLocations = @() $ExcludeLocations = @() #translate Location template guids to Location name if ($Policy.Conditions.Locations) { Write-Verbose -Message 'Get-TargetResource: Location condition defined, processing' #build Location translation table $Locationlookup = @{} foreach ($Location in Get-MgBetaIdentityConditionalAccessNamedLocation) { $Locationlookup[$Location.Id] = $Location.DisplayName } Write-Verbose -Message 'Get-TargetResource: Processing IncludeLocations' if ($Policy.Conditions.Locations.IncludeLocations) { foreach ($IncludeLocationGUID in $Policy.Conditions.Locations.IncludeLocations) { if ($IncludeLocationGUID -in 'All', 'AllTrusted') { $IncludeLocations += $IncludeLocationGUID } elseif ($IncludeLocationGUID -eq '00000000-0000-0000-0000-000000000000') { $IncludeLocations += 'Multifactor authentication trusted IPs' } elseif ($null -eq $Locationlookup[$IncludeLocationGUID]) { $message = "Couldn't find Location $IncludeLocationGUID , couldn't add to policy $PolicyDisplayName" New-M365DSCLogEntry -Message $message ` -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential } else { $IncludeLocations += $Locationlookup[$IncludeLocationGUID] } } } Write-Verbose -Message 'Get-TargetResource: Processing ExcludeLocations' if ($Policy.Conditions.Locations.ExcludeLocations) { foreach ($ExcludeLocationGUID in $Policy.Conditions.Locations.ExcludeLocations) { if ($ExcludeLocationGUID -in 'All', 'AllTrusted') { $ExcludeLocations += $ExcludeLocationGUID } elseif ($ExcludeLocationGUID -eq '00000000-0000-0000-0000-000000000000') { $ExcludeLocations += 'Multifactor authentication trusted IPs' } elseif ($null -eq $Locationlookup[$ExcludeLocationGUID]) { $message = "Couldn't find Location $ExcludeLocationGUID , couldn't add to policy $PolicyDisplayName" New-M365DSCLogEntry -Message $message ` -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential } else { $ExcludeLocations += $Locationlookup[$ExcludeLocationGUID] } } } } if ($Policy.SessionControls.CloudAppSecurity.IsEnabled) { $CloudAppSecurityType = [System.String]$Policy.SessionControls.CloudAppSecurity.CloudAppSecurityType } else { $CloudAppSecurityType = $null } if ($Policy.SessionControls.SignInFrequency.IsEnabled) { $SignInFrequencyType = [System.String]$Policy.SessionControls.SignInFrequency.Type $SignInFrequencyIntervalValue = [System.String]$Policy.SessionControls.SignInFrequency.FrequencyInterval } else { $SignInFrequencyType = $null $SignInFrequencyIntervalValue = $null } if ($Policy.SessionControls.PersistentBrowser.IsEnabled) { $PersistentBrowserMode = [System.String]$Policy.SessionControls.PersistentBrowser.Mode } else { $PersistentBrowserMode = $null } if ($Policy.Conditions.Users.IncludeGuestsOrExternalUsers.GuestOrExternalUserTypes) { [Array]$IncludeGuestOrExternalUserTypes = ($Policy.Conditions.Users.IncludeGuestsOrExternalUsers.GuestOrExternalUserTypes).Split(',') } if ($Policy.Conditions.Users.ExcludeGuestsOrExternalUsers.GuestOrExternalUserTypes) { [Array]$ExcludeGuestOrExternalUserTypes = ($Policy.Conditions.Users.ExcludeGuestsOrExternalUsers.GuestOrExternalUserTypes).Split(',') } $termsOfUseName = $null if ($Policy.GrantControls.TermsOfUse) { $termofUse = Get-MgBetaAgreement | Where-Object -FilterScript { $_.Id -eq $Policy.GrantControls.TermsOfUse } if ($termOfUse) { $termOfUseName = $termOfUse.DisplayName } } $AuthenticationStrengthValue = $null if ($null -ne $Policy.GrantControls -and $null -ne $Policy.GrantControls.AuthenticationStrength -and ` $null -ne $Policy.GrantControls.AuthenticationStrength.Id) { $strengthPolicy = Get-MgBetaPolicyAuthenticationStrengthPolicy -AuthenticationStrengthPolicyId $Policy.GrantControls.AuthenticationStrength.Id if ($null -ne $strengthPolicy) { $AuthenticationStrengthValue = $strengthPolicy.DisplayName } } $AuthenticationContextsValues = @() if ($null -ne $Policy.Conditions.Applications.IncludeAuthenticationContextClassReferences) { foreach ($class in $Policy.Conditions.Applications.IncludeAuthenticationContextClassReferences) { $classReference = Get-MgBetaIdentityConditionalAccessAuthenticationContextClassReference ` -AuthenticationContextClassReferenceId $class ` -ErrorAction SilentlyContinue if ($null -ne $classReference) { $AuthenticationContextsValues += $classReference.DisplayName } } } $result = @{ DisplayName = $Policy.DisplayName Id = $Policy.Id State = $Policy.State IncludeApplications = [System.String[]](@() + $Policy.Conditions.Applications.IncludeApplications) #no translation of Application GUIDs, return empty string array if undefined ExcludeApplications = [System.String[]](@() + $Policy.Conditions.Applications.ExcludeApplications) ApplicationsFilter = $Policy.Conditions.Applications.ApplicationFilter.Rule ApplicationsFilterMode = $Policy.Conditions.Applications.ApplicationFilter.Mode #no translation of GUIDs, return empty string array if undefined IncludeUserActions = [System.String[]](@() + $Policy.Conditions.Applications.IncludeUserActions) #no translation needed, return empty string array if undefined IncludeUsers = $IncludeUsers ExcludeUsers = $ExcludeUsers IncludeGroups = $IncludeGroups ExcludeGroups = $ExcludeGroups IncludeRoles = $IncludeRoles ExcludeRoles = $ExcludeRoles IncludeGuestOrExternalUserTypes = [System.String[]]$IncludeGuestOrExternalUserTypes IncludeExternalTenantsMembershipKind = [System.String]$Policy.Conditions.Users.IncludeGuestsOrExternalUsers.ExternalTenants.MembershipKind IncludeExternalTenantsMembers = [System.String[]](@() + $Policy.Conditions.Users.IncludeGuestsOrExternalUsers.ExternalTenants.AdditionalProperties.members) ExcludeGuestOrExternalUserTypes = [System.String[]]$ExcludeGuestOrExternalUserTypes ExcludeExternalTenantsMembershipKind = [System.String]$Policy.Conditions.Users.ExcludeGuestsOrExternalUsers.ExternalTenants.MembershipKind ExcludeExternalTenantsMembers = [System.String[]](@() + $Policy.Conditions.Users.ExcludeGuestsOrExternalUsers.ExternalTenants.AdditionalProperties.members) IncludeServicePrincipals = $Policy.Conditions.ClientApplications.IncludeServicePrincipals ExcludeServicePrincipals = $Policy.Conditions.ClientApplications.ExcludeServicePrincipals ServicePrincipalFilterMode = $Policy.Conditions.ClientApplications.ServicePrincipalFilter.Mode ServicePrincipalFilterRule = $Policy.Conditions.ClientApplications.ServicePrincipalFilter.Rule IncludePlatforms = [System.String[]](@() + $Policy.Conditions.Platforms.IncludePlatforms) #no translation needed, return empty string array if undefined ExcludePlatforms = [System.String[]](@() + $Policy.Conditions.Platforms.ExcludePlatforms) #no translation needed, return empty string array if undefined IncludeLocations = $IncludeLocations ExcludeLocations = $ExcludeLocations #no translation needed, return empty string array if undefined DeviceFilterMode = [System.String]$Policy.Conditions.Devices.DeviceFilter.Mode #no translation or conversion needed DeviceFilterRule = [System.String]$Policy.Conditions.Devices.DeviceFilter.Rule #no translation or conversion needed UserRiskLevels = [System.String[]](@() + $Policy.Conditions.UserRiskLevels) #no translation needed, return empty string array if undefined SignInRiskLevels = [System.String[]](@() + $Policy.Conditions.SignInRiskLevels) #no translation needed, return empty string array if undefined ClientAppTypes = [System.String[]](@() + $Policy.Conditions.ClientAppTypes) #no translation needed, return empty string array if undefined GrantControlOperator = $Policy.GrantControls.Operator #no translation or conversion needed BuiltInControls = [System.String[]](@() + $Policy.GrantControls.BuiltInControls) CustomAuthenticationFactors = [System.String[]](@() + $Policy.GrantControls.CustomAuthenticationFactors) #no translation needed, return empty string array if undefined ApplicationEnforcedRestrictionsIsEnabled = $false -or $Policy.SessionControls.ApplicationEnforcedRestrictions.IsEnabled #make false if undefined, true if true CloudAppSecurityIsEnabled = $false -or $Policy.SessionControls.CloudAppSecurity.IsEnabled #make false if undefined, true if true CloudAppSecurityType = [System.String]$Policy.SessionControls.CloudAppSecurity.CloudAppSecurityType #no translation needed, return empty string array if undefined SignInFrequencyIsEnabled = $false -or $Policy.SessionControls.SignInFrequency.IsEnabled #make false if undefined, true if true SignInFrequencyValue = $Policy.SessionControls.SignInFrequency.Value #no translation or conversion needed, $null returned if undefined SignInFrequencyType = [System.String]$Policy.SessionControls.SignInFrequency.Type SignInFrequencyInterval = $SignInFrequencyIntervalValue #no translation needed PersistentBrowserIsEnabled = $false -or $Policy.SessionControls.PersistentBrowser.IsEnabled #make false if undefined, true if true PersistentBrowserMode = [System.String]$Policy.SessionControls.PersistentBrowser.Mode #no translation needed AuthenticationStrength = $AuthenticationStrengthValue AuthenticationContexts = $AuthenticationContextsValues TransferMethods = [System.String]$Policy.Conditions.AuthenticationFlows.TransferMethods #Standard part TermsOfUse = $termOfUseName InsiderRiskLevels = $Policy.Conditions.InsiderRiskLevels Ensure = 'Present' Credential = $Credential ApplicationSecret = $ApplicationSecret ApplicationId = $ApplicationId TenantId = $TenantId CertificateThumbprint = $CertificateThumbprint Managedidentity = $ManagedIdentity.IsPresent AccessTokens = $AccessTokens } Write-Verbose -Message "Get-TargetResource Result: `n $(Convert-M365DscHashtableToString -Hashtable $result)" return $result } function Set-TargetResource { [CmdletBinding()] param ( [Parameter()] [System.String] $Id, [Parameter(Mandatory = $true)] [System.String] $DisplayName, [Parameter()] [System.String] [ValidateSet('disabled', 'enabled', 'enabledForReportingButNotEnforced')] $State, #ConditionalAccessApplicationCondition [Parameter()] [System.String[]] $IncludeApplications, [Parameter()] [System.String[]] $ExcludeApplications, [Parameter()] [System.String] $ApplicationsFilter, [Parameter()] [ValidateSet('include', 'exclude')] [System.String] $ApplicationsFilterMode, [Parameter()] [System.String[]] $IncludeUserActions, #ConditionalAccessUserCondition [Parameter()] [System.String[]] $IncludeUsers, [Parameter()] [System.String[]] $ExcludeUsers, [Parameter()] [System.String[]] $IncludeGroups, [Parameter()] [System.String[]] $ExcludeGroups, [Parameter()] [System.String[]] $IncludeRoles, [Parameter()] [System.String[]] $ExcludeRoles, [Parameter()] [System.String[]] [validateSet('none', 'internalGuest', 'b2bCollaborationGuest', 'b2bCollaborationMember', 'b2bDirectConnectUser', 'otherExternalUser', 'serviceProvider', 'unknownFutureValue')] $IncludeGuestOrExternalUserTypes, [Parameter()] [System.String] [ValidateSet('', 'all', 'enumerated', 'unknownFutureValue')] $IncludeExternalTenantsMembershipKind, [Parameter()] [System.String[]] $IncludeExternalTenantsMembers, [Parameter()] [System.String[]] [validateSet('none', 'internalGuest', 'b2bCollaborationGuest', 'b2bCollaborationMember', 'b2bDirectConnectUser', 'otherExternalUser', 'serviceProvider', 'unknownFutureValue')] $ExcludeGuestOrExternalUserTypes, [Parameter()] [System.String] [ValidateSet('', 'all', 'enumerated', 'unknownFutureValue')] $ExcludeExternalTenantsMembershipKind, [Parameter()] [System.String[]] $ExcludeExternalTenantsMembers, [Parameter()] [System.String[]] $IncludeServicePrincipals, [Parameter()] [System.String[]] $ExcludeServicePrincipals, [Parameter()] [ValidateSet('include', 'exclude')] [System.String] $ServicePrincipalFilterMode, [Parameter()] [System.String] $ServicePrincipalFilterRule, #ConditionalAccessPlatformCondition [Parameter()] [System.String[]] $IncludePlatforms, [Parameter()] [System.String[]] $ExcludePlatforms, #ConditionalAccessLocationCondition [Parameter()] [System.String[]] $IncludeLocations, [Parameter()] [System.String[]] $ExcludeLocations, [Parameter()] [ValidateSet('include', 'exclude')] [System.String] $DeviceFilterMode, [Parameter()] [System.String] $DeviceFilterRule, #Further conditions [Parameter()] [System.String[]] $UserRiskLevels, [Parameter()] [System.String[]] $SignInRiskLevels, [Parameter()] [System.String[]] $ClientAppTypes, #ConditionalAccessGrantControls [Parameter()] [ValidateSet('AND', 'OR')] [System.String] $GrantControlOperator, [Parameter()] [System.String[]] $BuiltInControls, #ConditionalAccessSessionControls [Parameter()] [System.Boolean] $ApplicationEnforcedRestrictionsIsEnabled, [Parameter()] [System.Boolean] $CloudAppSecurityIsEnabled, [Parameter()] [System.String] $CloudAppSecurityType, [Parameter()] [System.Int32] $SignInFrequencyValue, [Parameter()] [ValidateSet('Days', 'Hours', '')] [System.String] $SignInFrequencyType, [Parameter()] [System.Boolean] $SignInFrequencyIsEnabled, [Parameter()] [ValidateSet('timeBased', 'everyTime', 'unknownFutureValue')] [System.String] $SignInFrequencyInterval, [Parameter()] [ValidateSet('Always', 'Never', '')] [System.String] $PersistentBrowserMode, [Parameter()] [System.Boolean] $PersistentBrowserIsEnabled, [Parameter()] [System.String] $TermsOfUse, [Parameter()] [System.String[]] $CustomAuthenticationFactors, [Parameter()] [System.String] $AuthenticationStrength, [Parameter()] [System.String[]] $AuthenticationContexts, [Parameter()] [System.String] $TransferMethods, [Parameter()] [ValidateSet('minor', 'moderate', 'elevated', 'unknownFutureValue')] [System.String] $InsiderRiskLevels, #generic [Parameter()] [ValidateSet('Present', 'Absent')] [System.String] $Ensure = 'Present', [Parameter()] [System.Management.Automation.PSCredential] $Credential, [Parameter()] [System.String] $ApplicationId, [Parameter()] [System.String] $TenantId, [Parameter()] [System.Management.Automation.PSCredential] $ApplicationSecret, [Parameter()] [System.String] $CertificateThumbprint, [Parameter()] [Switch] $ManagedIdentity, [Parameter()] [System.String[]] $AccessTokens ) Write-Verbose -Message 'Setting configuration of AzureAD Conditional Access Policy' #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies #region Telemetry $ResourceName = $MyInvocation.MyCommand.ModuleName -replace 'MSFT_', '' $CommandName = $MyInvocation.MyCommand $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` -CommandName $CommandName ` -Parameters $PSBoundParameters Add-M365DSCTelemetryEvent -Data $data #endregion Write-Verbose -Message 'Set-Targetresource: Running Get-TargetResource' $currentPolicy = Get-TargetResource @PSBoundParameters Write-Verbose -Message 'Set-Targetresource: Cleaning up parameters' $currentParameters = $PSBoundParameters $currentParameters.Remove('ApplicationId') | Out-Null $currentParameters.Remove('TenantId') | Out-Null $currentParameters.Remove('CertificateThumbprint') | Out-Null $currentParameters.Remove('ApplicationSecret') | Out-Null $currentParameters.Remove('Ensure') | Out-Null $currentParameters.Remove('Credential') | Out-Null $currentParameters.Remove('ManagedIdentity') | Out-Null $currentParameters.Remove('AccessTokens') | Out-Null if ($Ensure -eq 'Present')#create policy attribute objects { Write-Verbose -Message "Set-Targetresource: Policy $Displayname Ensure Present" $NewParameters = @{} $NewParameters.Add('displayName', $DisplayName) $NewParameters.Add('state', $State) #create Conditions object Write-Verbose -Message 'Set-Targetresource: create Conditions object' $conditions = @{ applications = @{} users = @{} } #create and provision Application Condition object Write-Verbose -Message 'Set-Targetresource: create Application Condition object' if ($currentParameters.ContainsKey('IncludeApplications')) { $IncludeApplicationsValue = @() foreach ($app in $IncludeApplications) { $ObjectGuid = [System.Guid]::empty if ([System.Guid]::TryParse($app, [System.Management.Automation.PSReference]$ObjectGuid)) { $IncludeApplicationsValue += $app } else { $appInfo = Get-MgApplication -Filter "DisplayName eq '$app'" -ErrorAction SilentlyContinue if ($null -ne $appInfo) { $IncludeApplicationsValue += $appInfo.AppId } else { $IncludeApplicationsValue += $app } } } $conditions.Applications.Add('includeApplications', $IncludeApplicationsValue) } if ($currentParameters.ContainsKey('excludeApplications')) { $ExcludeApplicationsValue = @() foreach ($app in $ExcludeApplications) { $ObjectGuid = [System.Guid]::empty if ([System.Guid]::TryParse($app, [System.Management.Automation.PSReference]$ObjectGuid)) { $ExcludeApplicationsValue += $app } else { $appInfo = Get-MgApplication -Filter "DisplayName eq '$app'" -ErrorAction SilentlyContinue if ($null -ne $appInfo) { $ExcludeApplicationsValue += $appInfo.AppId } else { $ExcludeApplicationsValue += $app } } } $conditions.Applications.Add('excludeApplications', $ExcludeApplicationsValue) } if ($ApplicationsFilter -and $ApplicationsFilterMode) { $appFilterValue = @{ rule = $ApplicationsFilter mode = $ApplicationsFilterMode } $conditions.Applications.Add('applicationFilter', $appFilterValue) } if ($IncludeUserActions) { $conditions.Applications.Add('includeUserActions', $IncludeUserActions) } if ($AuthenticationContexts) { # Retrieve the class reference based on display name. $AuthenticationContextsValues = @() $classReferences = Get-MgBetaIdentityConditionalAccessAuthenticationContextClassReference -ErrorAction SilentlyContinue foreach ($authContext in $AuthenticationContexts) { $currentClassId = $classReferences | Where-Object -FilterScript { $_.DisplayName -eq $authContext } if ($null -ne $currentClassId) { $AuthenticationContextsValues += $currentClassId.Id } } $conditions.Applications.Add('includeAuthenticationContextClassReferences', $AuthenticationContextsValues) } #create and provision User Condition object Write-Verbose -Message 'Set-Targetresource: process includeusers' if ($currentParameters.ContainsKey('IncludeUsers')) { $conditions.Users.Add('includeUsers', @()) foreach ($includeuser in $IncludeUsers) { #translate user UPNs to GUID, except id value is GuestsOrExternalUsers, None or All if ($includeuser) { if ($includeuser -notin 'GuestsOrExternalUsers', 'All', 'None') { $userguid = $null try { $userguid = (Get-MgUser -UserId $includeuser -ErrorAction Stop).Id } catch { New-M365DSCLogEntry -Message 'Error updating data:' ` -Exception $_ ` -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential throw $_ } if ($null -eq $userguid) { $message = "Couldn't find user '$includeuser', couldn't add to policy '$DisplayName'" New-M365DSCLogEntry -Message $message ` -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential throw $message } else { $conditions.users.includeUsers += $userguid } } else { $conditions.users.includeUsers += $includeuser } } } } Write-Verbose -Message 'Set-Targetresource: process excludeusers' if ($currentParameters.ContainsKey('ExcludeUsers')) { $conditions.users.Add('excludeUsers', @()) foreach ($excludeuser in $ExcludeUsers) { #translate user UPNs to GUID, except id value is GuestsOrExternalUsers, None or All if ($excludeuser) { if ($excludeuser -notin 'GuestsOrExternalUsers', 'All', 'None') { $userguid = $null try { $userguid = (Get-MgUser -UserId $excludeuser -ErrorAction Stop).Id } catch { New-M365DSCLogEntry -Message 'Error updating data:' ` -Exception $_ ` -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential throw $_ } if ($null -eq $userguid) { $message = "Couldn't find user '$excludeuser', couldn't add to policy '$DisplayName'" New-M365DSCLogEntry -Message $message ` -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential throw $message } else { $conditions.users.excludeUsers += $userguid } } else { $conditions.users.excludeUsers += $excludeuser } } } } Write-Verbose -Message 'Set-Targetresource: process includegroups' if ($currentParameters.ContainsKey('IncludeGroups')) { $conditions.users.Add('includeGroups', @()) foreach ($includegroup in $IncludeGroups) { #translate user Group names to GUID if ($includegroup) { $GroupLookup = $null try { $GroupLookup = Get-MgGroup -Filter "DisplayName eq '$includegroup'" -ErrorAction Stop } catch { New-M365DSCLogEntry -Message 'Error updating data:' ` -Exception $_ ` -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential throw $_ } if ($GroupLookup.Length -gt 1) { $message = "Duplicate group found with displayname '$includegroup', couldn't add to policy '$DisplayName'" New-M365DSCLogEntry -Message $message ` -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential throw $message } elseif ($null -eq $GroupLookup) { $message = "Couldn't find group '$includegroup', couldn't add to policy '$DisplayName'" New-M365DSCLogEntry -Message $message ` -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential throw $message } else { Write-Verbose -Message 'Adding group to includegroups' $conditions.Users.IncludeGroups += $GroupLookup.Id } } } } Write-Verbose -Message 'Set-Targetresource: process excludegroups' if ($currentParameters.ContainsKey('ExcludeGroups')) { $conditions.users.Add('excludeGroups', @()) foreach ($ExcludeGroup in $ExcludeGroups) { #translate user Group names to GUID if ($ExcludeGroup) { $GroupLookup = $null try { $GroupLookup = Get-MgGroup -Filter "DisplayName eq '$ExcludeGroup'" -ErrorAction Stop } catch { New-M365DSCLogEntry -Message 'Error updating data:' ` -Exception $_ ` -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential throw $_ } if ($GroupLookup.Length -gt 1) { $message = "Duplicate group found with displayname '$ExcludeGroup', couldn't add to policy '$DisplayName'" New-M365DSCLogEntry -Message $message ` -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential throw $message } elseif ($null -eq $GroupLookup) { $message = "Couldn't find group '$ExcludeGroup', couldn't add to policy '$DisplayName'" New-M365DSCLogEntry -Message $message ` -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential throw $message } else { Write-Verbose -Message 'Adding group to ExcludeGroups' $conditions.users.excludeGroups += $GroupLookup.Id } } } } Write-Verbose -Message 'Set-Targetresource: process includeroles' if ($currentParameters.ContainsKey('IncludeRoles')) { $conditions.Users.Add('includeRoles', @()) if ($IncludeRoles) { #translate role names to template guid if defined $rolelookup = @{} foreach ($role in Get-MgBetaDirectoryRoleTemplate -All) { $rolelookup[$role.DisplayName] = $role.Id } foreach ($IncludeRole in $IncludeRoles) { if ($IncludeRole) { if ($null -eq $rolelookup[$IncludeRole]) { $message = "Couldn't find role '$IncludeRole', couldn't add to policy '$DisplayName'" New-M365DSCLogEntry -Message $message ` -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential throw $message } else { $conditions.users.includeRoles += $rolelookup[$IncludeRole] } } } } } Write-Verbose -Message 'Set-Targetresource: process excluderoles' if ($currentParameters.ContainsKey('ExcludeRoles')) { $conditions.users.Add('excludeRoles', @()) if ($ExcludeRoles) { #translate role names to template guid if defined $rolelookup = @{} foreach ($role in Get-MgBetaDirectoryRoleTemplate -All) { $rolelookup[$role.DisplayName] = $role.Id } foreach ($ExcludeRole in $ExcludeRoles) { if ($ExcludeRole) { if ($null -eq $rolelookup[$ExcludeRole]) { $message = "Couldn't find role '$ExcludeRole', couldn't add to policy '$DisplayName'" New-M365DSCLogEntry -Message $message ` -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential throw $message } else { $conditions.users.excludeRoles += $rolelookup[$ExcludeRole] } } } } } Write-Verbose -Message 'Set-Targetresource: process includeGuestOrExternalUser' If ($currentParameters.ContainsKey('IncludeGuestOrExternalUserTypes')) { $includeGuestsOrExternalUsers = $null if ($IncludeGuestOrExternalUserTypes.Count -ne 0) { if ($IncludeGuestOrExternalUserTypes -ne 'None') { $includeGuestsOrExternalUsers = @{} [string]$IncludeGuestOrExternalUserTypes = $IncludeGuestOrExternalUserTypes -join ',' $includeGuestsOrExternalUsers.Add('guestOrExternalUserTypes', $IncludeGuestOrExternalUserTypes) $externalTenants = @{} if ($IncludeExternalTenantsMembershipKind -eq 'All') { $externalTenants.Add('@odata.type', '#microsoft.graph.conditionalAccessAllExternalTenants') } elseif ($IncludeExternalTenantsMembershipKind -eq 'enumerated') { $externalTenants.Add('@odata.type', '#microsoft.graph.conditionalAccessEnumeratedExternalTenants') } $externalTenants.Add('membershipKind', $IncludeExternalTenantsMembershipKind) if ($IncludeExternalTenantsMembers) { $externalTenants.Add('members', $IncludeExternalTenantsMembers) } $includeGuestsOrExternalUsers.Add('externalTenants', $externalTenants) } } $conditions.Users.Add('includeGuestsOrExternalUsers', $includeGuestsOrExternalUsers) } Write-Verbose -Message 'Set-Targetresource: process excludeGuestsOrExternalUsers' If ($currentParameters.ContainsKey('ExcludeGuestOrExternalUserTypes')) { $excludeGuestsOrExternalUsers = $null if ($ExcludeGuestOrExternalUserTypes.Count -ne 0) { if ($ExcludeGuestOrExternalUserTypes -ne 'None') { $excludeGuestsOrExternalUsers = @{} [string]$ExcludeGuestOrExternalUserTypes = $ExcludeGuestOrExternalUserTypes -join ',' $excludeGuestsOrExternalUsers.Add('guestOrExternalUserTypes', $ExcludeGuestOrExternalUserTypes) $externalTenants = @{} if ($ExcludeExternalTenantsMembershipKind -eq 'All') { $externalTenants.Add('@odata.type', '#microsoft.graph.conditionalAccessAllExternalTenants') } elseif ($ExcludeExternalTenantsMembershipKind -eq 'enumerated') { $externalTenants.Add('@odata.type', '#microsoft.graph.conditionalAccessEnumeratedExternalTenants') } $externalTenants.Add('membershipKind', $ExcludeExternalTenantsMembershipKind) if ($ExcludeExternalTenantsMembers) { $externalTenants.Add('members', $ExcludeExternalTenantsMembers) } $excludeGuestsOrExternalUsers.Add('externalTenants', $externalTenants) } } $conditions.Users.Add('excludeGuestsOrExternalUsers', $excludeGuestsOrExternalUsers) } Write-Verbose -Message 'Set-Targetresource: process includeServicePrincipals' if ($currentParameters.ContainsKey('IncludeServicePrincipals')) { if (-not $conditions.ContainsKey('clientApplications')) { $conditions.Add('clientApplications', @{}) } $conditions.clientApplications.Add('includeServicePrincipals', $IncludeServicePrincipals) } Write-Verbose -Message 'Set-Targetresource: process excludeServicePrincipals' if ($currentParameters.ContainsKey('ExcludeServicePrincipals')) { if (-not $conditions.ContainsKey('clientApplications')) { $conditions.Add('clientApplications', @{}) } $conditions.clientApplications.Add('excludeServicePrincipals', $ExcludeServicePrincipals) } Write-Verbose -Message 'Set-Targetresource: process servicePrincipalFilter' if ($currentParameters.ContainsKey('ServicePrincipalFilterMode') -and $currentParameters.ContainsKey('ServicePrincipalFilterRule')) { #check if the custom attribute exist. $customattribute = Invoke-MgGraphRequest -Method GET -Uri ((Get-MSCloudLoginConnectionProfile -Workload MicrosoftGraph).ResourceUrl + 'v1.0/directory/customSecurityAttributeDefinitions') $ServicePrincipalFilterRule -match 'CustomSecurityAttribute.(?<attribute>.*) -.*' $attrinrule = $matches.attribute if ($customattribute.value.id -contains $attrinrule) { if (-not $conditions.ContainsKey('clientApplications')) { $conditions.Add('clientApplications', @{}) } $conditions.clientApplications.Add('servicePrincipalFilter', @{}) $conditions.clientApplications.servicePrincipalFilter.Add('mode', $ServicePrincipalFilterMode) $conditions.clientApplications.servicePrincipalFilter.Add('rule', $ServicePrincipalFilterRule) } else { $message = "Couldn't find the custom attribute $attrinrule in the tenant, couldn't add the filter to policy $DisplayName" Write-Verbose -Message $message New-M365DSCLogEntry -Message $message ` -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential } } Write-Verbose -Message 'Set-Targetresource: process platform condition' if ($currentParameters.ContainsKey('IncludePlatforms') -or $currentParameters.ContainsKey('ExcludePlatforms')) { if ($IncludePlatforms -or $ExcludePlatforms) { #create and provision Platform condition object if used if (-not $conditions.Contains('platforms')) { $conditions.Add('platforms', @{ includePlatforms = @() }) } else { $conditions.platforms.Add('includePlatforms', @()) } Write-Verbose -Message "Set-Targetresource: IncludePlatforms: $IncludePlatforms" if (([Array]$IncludePlatforms).Length -eq 0) { $conditions.platforms.includePlatforms = @('all') } else { $conditions.platforms.includePlatforms = @() + $IncludePlatforms } #no translation or conversion needed if (([Array]$ExcludePlatforms).Length -ne 0) { $conditions.platforms.Add('excludePlatforms', @()) $conditions.platforms.excludePlatforms = @() + $ExcludePlatforms } #no translation or conversion needed } else { Write-Verbose -Message 'Set-Targetresource: setting platform condition to null' $conditions.platforms = $null } } Write-Verbose -Message 'Set-Targetresource: process include and exclude locations' if ($currentParameters.ContainsKey('IncludeLocations') -or $currentParameters.ContainsKey('ExcludeLocations')) { if ($IncludeLocations -or $ExcludeLocations) { $conditions.Add('locations', @{ excludeLocations = @() includeLocations = @() }) $conditions.locations.includeLocations = @() $conditions.locations.excludeLocations = @() Write-Verbose -Message 'Set-Targetresource: locations specified' #create and provision Location condition object if used, translate Location names to guid $LocationLookup = @{} foreach ($Location in Get-MgBetaIdentityConditionalAccessNamedLocation) { $LocationLookup[$Location.displayName] = $Location.Id } foreach ($IncludeLocation in $IncludeLocations) { if ($IncludeLocation) { if ($IncludeLocation -in 'All', 'AllTrusted') { $conditions.locations.includeLocations += $IncludeLocation } elseif ($IncludeLocation -eq 'Multifactor authentication trusted IPs') { $conditions.locations.includeLocations += '00000000-0000-0000-0000-000000000000' } elseif ($null -eq $LocationLookup[$IncludeLocation]) { $message = "Couldn't find Location $IncludeLocation , couldn't add to policy $DisplayName" New-M365DSCLogEntry -Message $message ` -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential } else { $conditions.locations.includeLocations += $LocationLookup[$IncludeLocation] } } } foreach ($ExcludeLocation in $ExcludeLocations) { if ($ExcludeLocation) { if ($ExcludeLocation -eq 'All' -or $ExcludeLocation -eq 'AllTrusted') { $conditions.locations.excludeLocations += $ExcludeLocation } elseif ($ExcludeLocation -eq 'Multifactor authentication trusted IPs') { $conditions.locations.excludeLocations += '00000000-0000-0000-0000-000000000000' } elseif ($null -eq $LocationLookup[$ExcludeLocation]) { $message = "Couldn't find Location $ExcludeLocation , couldn't add to policy $DisplayName" New-M365DSCLogEntry -Message $message ` -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential } else { $conditions.locations.excludeLocations += $LocationLookup[$ExcludeLocation] } } } } } Write-Verbose -Message 'Set-Targetresource: process device filter' if ($currentParameters.ContainsKey('DeviceFilterMode') -and $currentParameters.ContainsKey('DeviceFilterRule')) { if ($DeviceFilterMode -and $DeviceFilterRule) { if (-not $conditions.Contains('Devices')) { $conditions.Add('devices', @{}) $conditions.devices.Add('deviceFilter', @{}) $conditions.devices.deviceFilter.Add('mode', $DeviceFilterMode) $conditions.devices.deviceFilter.Add('rule', $DeviceFilterRule) } else { if (-not $conditions.Devices.Contains('DeviceFilter')) { $conditions.devices.Add('DeviceFilter', @{}) $conditions.devices.deviceFilter.Add('mode', $DeviceFilterMode) $conditions.devices.deviceFilter.Add('rule', $DeviceFilterRule) } else { if (-not $conditions.devices.deviceFilter.Contains('mode')) { $conditions.devices.deviceFilter.Add('mode', $DeviceFilterMode) } else { $conditions.devices.deviceFilter.mode = $DeviceFilterMode } if (-not $conditions.devices.deviceFilter.Contains('rule')) { $conditions.devices.deviceFilter.Add('rule', $DeviceFilterRule) } else { $conditions.devices.deviceFilter.rule = $DeviceFilterRule } } } } } if ([String]::IsNullOrEmpty($InsiderRiskLevels) -eq $false) { $conditions.Add('insiderRiskLevels', $InsiderRiskLevels) } Write-Verbose -Message 'Set-Targetresource: process risk levels and app types' Write-Verbose -Message "Set-Targetresource: UserRiskLevels: $UserRiskLevels" If ($currentParameters.ContainsKey('UserRiskLevels')) { $Conditions.Add('userRiskLevels', $UserRiskLevels) #no translation or conversion needed } Write-Verbose -Message "Set-Targetresource: SignInRiskLevels: $SignInRiskLevels" If ($currentParameters.ContainsKey('SignInRiskLevels')) { $Conditions.Add('signInRiskLevels', $SignInRiskLevels) #no translation or conversion needed } Write-Verbose -Message "Set-Targetresource: ClientAppTypes: $ClientAppTypes" If ($currentParameters.ContainsKey('ClientAppTypes')) { $Conditions.Add('clientAppTypes', $ClientAppTypes) #no translation or conversion needed } Write-Verbose -Message "Set-Targetresource: authenticationFlows transferMethods: $TransferMethods" if ($currentParameters.ContainsKey('TransferMethods')) { #create and provision TransferMethods condition object if used $authenticationFlows = if ([System.String]::IsNullOrEmpty($TransferMethods)) { $null } else { @{ transferMethods = $TransferMethods } } if (-not $conditions.Contains('authenticationFlows')) { $conditions.Add('authenticationFlows', $authenticationFlows) } else { $conditions.authenticationFlows = $authenticationFlows } } Write-Verbose -Message 'Set-Targetresource: Adding processed conditions' #add all conditions to the parameter list $NewParameters.Add('conditions', $Conditions) #create and provision Grant Control object Write-Verbose -Message 'Set-Targetresource: create and provision Grant Control object' if ($GrantControlOperator -and ($BuiltInControls -or $TermsOfUse -or $CustomAuthenticationFactors -or $AuthenticationStrength)) { $grantControls = @{ operator = $GrantControlOperator } if ($BuiltInControls) { $GrantControls.Add('builtInControls', $BuiltInControls) } if ($customAuthenticationFactors) { $GrantControls.Add('customAuthenticationFactors', $CustomAuthenticationFactors) } if ($AuthenticationStrength) { $strengthPolicy = Get-MgBetaPolicyAuthenticationStrengthPolicy | Where-Object -FilterScript { $_.DisplayName -eq $AuthenticationStrength } -ErrorAction SilentlyContinue if ($null -ne $strengthPolicy) { $authenticationStrengthInstance = @{ id = $strengthPolicy.Id '@odata.type' = '#microsoft.graph.authenticationStrengthPolicy' } $GrantControls.Add('authenticationStrength', $authenticationStrengthInstance) } } if ($TermsOfUse) { Write-Verbose -Message "Gettign Terms of Use {$TermsOfUse}" $TermsOfUseObj = Get-MgBetaAgreement | Where-Object -FilterScript { $_.DisplayName -eq $TermsOfUse } $GrantControls.Add('termsOfUse', $TermsOfUseObj.Id) } #no translation or conversion needed Write-Verbose -Message 'Set-Targetresource: Adding processed grant controls' $NewParameters.Add('grantControls', $GrantControls) } if ($ApplicationEnforcedRestrictionsIsEnabled -or $CloudAppSecurityIsEnabled -or $SignInFrequencyIsEnabled -or $PersistentBrowserIsEnabled) { Write-Verbose -Message 'Set-Targetresource: process session controls' $sessioncontrols = $null Write-Verbose -Message 'Set-Targetresource: create provision Session Control object' $sessioncontrols = @{} if ($ApplicationEnforcedRestrictionsIsEnabled -eq $true) { $sessioncontrols.Add('applicationEnforcedRestrictions', @{}) #create and provision ApplicationEnforcedRestrictions object if used $sessioncontrols.applicationEnforcedRestrictions.Add('IsEnabled', $true) } if ($CloudAppSecurityIsEnabled) { $cloudAppSecurityValue = @{ isEnabled = $false cloudAppSecurityType = $null } $sessioncontrols.Add('cloudAppSecurity', $CloudAppSecurityValue) #create and provision CloudAppSecurity object if used $sessioncontrols.cloudAppSecurity.isEnabled = $true $sessioncontrols.cloudAppSecurity.cloudAppSecurityType = $CloudAppSecurityType } if ($SignInFrequencyIsEnabled) { $signinFrequencyProp = @{ isEnabled = $true type = $null value = $null frequencyInterval = $null } $sessioncontrols.Add('signInFrequency', $SigninFrequencyProp) #create and provision SignInFrequency object if used $sessioncontrols.signInFrequency.isEnabled = $true if ($SignInFrequencyType -ne '') { $sessioncontrols.signInFrequency.type = $SignInFrequencyType } else { $sessioncontrols.signInFrequency.Remove('type') | Out-Null } if ($SignInFrequencyValue -gt 0) { $sessioncontrols.signInFrequency.value = $SignInFrequencyValue } else { $sessioncontrols.signInFrequency.Remove('value') | Out-Null } $sessioncontrols.signInFrequency.frequencyInterval = $SignInFrequencyInterval } if ($PersistentBrowserIsEnabled) { $persistentBrowserValue = @{ isEnabled = $false mode = $false } $sessioncontrols.Add('persistentBrowser', $PersistentBrowserValue) Write-Verbose -Message "Set-Targetresource: Persistent Browser settings defined: PersistentBrowserIsEnabled:$PersistentBrowserIsEnabled, PersistentBrowserMode:$PersistentBrowserMode" #create and provision PersistentBrowser object if used $sessioncontrols.persistentBrowser.isEnabled = $true $sessioncontrols.persistentBrowser.mode = $PersistentBrowserMode } $NewParameters.Add('sessionControls', $sessioncontrols) #add SessionControls to the parameter list } } Write-Host "newparameters: $($NewParameters | ConvertTo-Json -Depth 5)" if ($Ensure -eq 'Present' -and $currentPolicy.Ensure -eq 'Present') { Write-Verbose -Message "Set-Targetresource: Change policy $DisplayName" $NewParameters.Add('ConditionalAccessPolicyId', $currentPolicy.Id) try { Write-Verbose -Message "Updating existing policy with values: $(Convert-M365DscHashtableToString -Hashtable $NewParameters)" $Uri = (Get-MSCloudLoginConnectionProfile -Workload MicrosoftGraph).ResourceUrl + "beta/identity/conditionalAccess/policies/$($currentPolicy.Id)" Invoke-MgGraphRequest -Method PATCH -Uri $Uri -Body $NewParameters } catch { New-M365DSCLogEntry -Message 'Error updating data:' ` -Exception $_ ` -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential Write-Error -Message "Set-Targetresource: Failed changing policy $DisplayName" } } elseif ($Ensure -eq 'Present' -and $currentPolicy.Ensure -eq 'Absent') { Write-Verbose -Message "Set-Targetresource: create policy $DisplayName" Write-Verbose -Message 'Create Parameters:' Write-Verbose -Message (Convert-M365DscHashtableToString $NewParameters) if ($newparameters.Conditions.applications.count -gt 0 -and $newparameters.Conditions.Users.count -gt 0 -and ($newparameters.GrantControls.count -gt 0 -or $newparameters.SessionControls.count -gt 0)) { try { $Uri = (Get-MSCloudLoginConnectionProfile -Workload MicrosoftGraph).ResourceUrl + 'beta/identity/conditionalAccess/policies' Invoke-MgGraphRequest -Method POST -Uri $Uri -Body $NewParameters } catch { New-M365DSCLogEntry -Message 'Error creating new policy:' ` -Exception $_ ` -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential Write-Error -Message 'Set-Targetresource: Failed creating new policy' } } else { New-M365DSCLogEntry -Message 'Error creating new policy:' ` -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential Write-Error -Message 'Set-Targetresource: Failed creating new policy. At least a user rule, application rule and grant or session control is required' } } elseif ($Ensure -eq 'Absent' -and $currentPolicy.Ensure -eq 'Present') { Write-Verbose -Message "Set-Targetresource: delete policy $DisplayName" try { Remove-MgBetaIdentityConditionalAccessPolicy -ConditionalAccessPolicyId $currentPolicy.ID } catch { New-M365DSCLogEntry -Message 'Error updating data:' ` -Exception $_ ` -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential Write-Error -Message "Set-Targetresource: Failed deleting policy $DisplayName" } } Write-Verbose -Message "Set-Targetresource: Finished processing Policy $Displayname" } function Test-TargetResource { [CmdletBinding()] [OutputType([System.Boolean])] param ( [Parameter()] [System.String] $Id, [Parameter(Mandatory = $true)] [System.String] $DisplayName, [Parameter()] [System.String] [ValidateSet('disabled', 'enabled', 'enabledForReportingButNotEnforced')] $State, #ConditionalAccessApplicationCondition [Parameter()] [System.String[]] $IncludeApplications, [Parameter()] [System.String[]] $ExcludeApplications, [Parameter()] [System.String] $ApplicationsFilter, [Parameter()] [ValidateSet('include', 'exclude')] [System.String] $ApplicationsFilterMode, [Parameter()] [System.String[]] $IncludeUserActions, #ConditionalAccessUserCondition [Parameter()] [System.String[]] $IncludeUsers, [Parameter()] [System.String[]] $ExcludeUsers, [Parameter()] [System.String[]] $IncludeGroups, [Parameter()] [System.String[]] $ExcludeGroups, [Parameter()] [System.String[]] $IncludeRoles, [Parameter()] [System.String[]] $ExcludeRoles, [Parameter()] [System.String[]] [validateSet('none', 'internalGuest', 'b2bCollaborationGuest', 'b2bCollaborationMember', 'b2bDirectConnectUser', 'otherExternalUser', 'serviceProvider', 'unknownFutureValue')] $IncludeGuestOrExternalUserTypes, [Parameter()] [System.String] [ValidateSet('', 'all', 'enumerated', 'unknownFutureValue')] $IncludeExternalTenantsMembershipKind, [Parameter()] [System.String[]] $IncludeExternalTenantsMembers, [Parameter()] [System.String[]] [validateSet('none', 'internalGuest', 'b2bCollaborationGuest', 'b2bCollaborationMember', 'b2bDirectConnectUser', 'otherExternalUser', 'serviceProvider', 'unknownFutureValue')] $ExcludeGuestOrExternalUserTypes, [Parameter()] [System.String] [ValidateSet('', 'all', 'enumerated', 'unknownFutureValue')] $ExcludeExternalTenantsMembershipKind, [Parameter()] [System.String[]] $ExcludeExternalTenantsMembers, [Parameter()] [System.String[]] $IncludeServicePrincipals, [Parameter()] [System.String[]] $ExcludeServicePrincipals, [Parameter()] [ValidateSet('include', 'exclude')] [System.String] $ServicePrincipalFilterMode, [Parameter()] [System.String] $ServicePrincipalFilterRule, #ConditionalAccessPlatformCondition [Parameter()] [System.String[]] $IncludePlatforms, [Parameter()] [System.String[]] $ExcludePlatforms, #ConditionalAccessLocationCondition [Parameter()] [System.String[]] $IncludeLocations, [Parameter()] [System.String[]] $ExcludeLocations, [Parameter()] [ValidateSet('include', 'exclude')] [System.String] $DeviceFilterMode, [Parameter()] [System.String] $DeviceFilterRule, #Further conditions [Parameter()] [System.String[]] $UserRiskLevels, [Parameter()] [System.String[]] $SignInRiskLevels, [Parameter()] [System.String[]] $ClientAppTypes, #ConditionalAccessGrantControls [Parameter()] [ValidateSet('AND', 'OR')] [System.String] $GrantControlOperator, [Parameter()] [System.String[]] $BuiltInControls, #ConditionalAccessSessionControls [Parameter()] [System.Boolean] $ApplicationEnforcedRestrictionsIsEnabled, [Parameter()] [System.Boolean] $CloudAppSecurityIsEnabled, [Parameter()] [System.String] $CloudAppSecurityType, [Parameter()] [System.Int32] $SignInFrequencyValue, [Parameter()] [ValidateSet('Days', 'Hours', '')] [System.String] $SignInFrequencyType, [Parameter()] [System.Boolean] $SignInFrequencyIsEnabled, [Parameter()] [ValidateSet('timeBased', 'everyTime', 'unknownFutureValue')] [System.String] $SignInFrequencyInterval, [Parameter()] [ValidateSet('Always', 'Never', '')] [System.String] $PersistentBrowserMode, [Parameter()] [System.Boolean] $PersistentBrowserIsEnabled, [Parameter()] [System.String] $TermsOfUse, [Parameter()] [System.String[]] $CustomAuthenticationFactors, [Parameter()] [System.String] $AuthenticationStrength, [Parameter()] [System.String[]] $AuthenticationContexts, [Parameter()] [System.String] $TransferMethods, [Parameter()] [ValidateSet('minor', 'moderate', 'elevated', 'unknownFutureValue')] [System.String] $InsiderRiskLevels, #generic [Parameter()] [ValidateSet('Present', 'Absent')] [System.String] $Ensure = 'Present', [Parameter()] [System.Management.Automation.PSCredential] $Credential, [Parameter()] [System.String] $ApplicationId, [Parameter()] [System.String] $TenantId, [Parameter()] [System.Management.Automation.PSCredential] $ApplicationSecret, [Parameter()] [System.String] $CertificateThumbprint, [Parameter()] [Switch] $ManagedIdentity, [Parameter()] [System.String[]] $AccessTokens ) Write-Verbose -Message 'Testing configuration of AzureAD CA Policies' $CurrentValues = Get-TargetResource @PSBoundParameters Write-Verbose -Message "Current Values: $(Convert-M365DscHashtableToString -Hashtable $CurrentValues)" Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $PSBoundParameters)" $ValuesToCheck = $PSBoundParameters $ValuesToCheck.Remove('Id') | Out-Null # If no TransferMethod is specified, ignore it # If a TransferMethod is specified, check if it is equal to the current value # while ignoring the order of the values if (-not $PSBoundParameters.ContainsKey('TransferMethods') -or $null -eq (Compare-Object -ReferenceObject $TransferMethods.Split(',') -DifferenceObject $CurrentValues.TransferMethods.Split(','))) { $ValuesToCheck.Remove('TransferMethods') | Out-Null $TestResult = $true } else { Write-Verbose -Message "TransferMethods are not equal: [$TransferMethods] - [$($CurrentValues.TransferMethods)]" $TestResult = $false } if ($TestResult) { $TestResult = Test-M365DSCParameterState -CurrentValues $CurrentValues ` -Source $($MyInvocation.MyCommand.Source) ` -DesiredValues $PSBoundParameters ` -ValuesToCheck $ValuesToCheck.Keys } Write-Verbose -Message "Test-TargetResource returned $TestResult" return $TestResult } function Export-TargetResource { [CmdletBinding()] [OutputType([System.String])] param ( [Parameter()] [System.String] $Filter, [Parameter()] [System.Management.Automation.PSCredential] $Credential, [Parameter()] [System.String] $ApplicationId, [Parameter()] [System.String] $TenantId, [Parameter()] [System.Management.Automation.PSCredential] $ApplicationSecret, [Parameter()] [System.String] $CertificateThumbprint, [Parameter()] [Switch] $ManagedIdentity, [Parameter()] [System.String[]] $AccessTokens ) #Ensure the proper dependencies are installed in the current environment. Confirm-M365DSCDependencies #region Telemetry $ResourceName = $MyInvocation.MyCommand.ModuleName -replace 'MSFT_', '' $CommandName = $MyInvocation.MyCommand $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` -CommandName $CommandName ` -Parameters $PSBoundParameters Add-M365DSCTelemetryEvent -Data $data #endregion $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` -InboundParameters $PSBoundParameters try { [array] $Policies = Get-MgBetaIdentityConditionalAccessPolicy -Filter $Filter -All:$true -ErrorAction Stop $i = 1 $dscContent = '' if ($Policies.Length -eq 0) { Write-Host $Global:M365DSCEmojiGreenCheckMark } else { Write-Host "`r`n" -NoNewline foreach ($Policy in $Policies) { if ($null -ne $Global:M365DSCExportResourceInstancesCount) { $Global:M365DSCExportResourceInstancesCount++ } Write-Host " |---[$i/$($Policies.Count)] $($Policy.DisplayName)" -NoNewline $Params = @{ DisplayName = $Policy.DisplayName Id = $Policy.Id ApplicationId = $ApplicationId TenantId = $TenantId ApplicationSecret = $ApplicationSecret CertificateThumbprint = $CertificateThumbprint Credential = $Credential Managedidentity = $ManagedIdentity.IsPresent AccessTokens = $AccessTokens } $Results = Get-TargetResource @Params if ([System.String]::IsNullOrEmpty($Results.DeviceFilterMode)) { $Results.Remove('DeviceFilterMode') | Out-Null } $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` -Results $Results $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName ` -ConnectionMode $ConnectionMode ` -ModulePath $PSScriptRoot ` -Results $Results ` -Credential $Credential $dscContent += $currentDSCBlock Save-M365DSCPartialExport -Content $currentDSCBlock ` -FileName $Global:PartialExportFileName Write-Host $Global:M365DSCEmojiGreenCheckMark $i++ } } return $dscContent } catch { Write-Host $Global:M365DSCEmojiRedX New-M365DSCLogEntry -Message 'Error during Export:' ` -Exception $_ ` -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId ` -Credential $Credential return '' } } Export-ModuleMember -Function *-TargetResource |