Private/Conditions/Test-ServicePrincipalInScope.ps1
function Test-ServicePrincipalInScope { <# .SYNOPSIS Tests if a service principal is in scope for a Conditional Access policy. .DESCRIPTION This function evaluates if a service principal is in scope for a Conditional Access policy based on inclusion and exclusion rules specified in the policy. .PARAMETER Policy The Conditional Access policy to evaluate. .PARAMETER ServicePrincipalContext The service principal context for evaluation, containing ID, AppId, and other relevant properties. .EXAMPLE Test-ServicePrincipalInScope -Policy $policy -ServicePrincipalContext $servicePrincipalContext #> [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( [Parameter(Mandatory = $true)] [object]$Policy, [Parameter(Mandatory = $true)] [object]$ServicePrincipalContext ) $result = @{ InScope = $false Reason = $null } # Extract service principal context information $servicePrincipalId = $ServicePrincipalContext.Id $servicePrincipalAppId = $ServicePrincipalContext.AppId $servicePrincipalDisplayName = $ServicePrincipalContext.DisplayName # First, check if the policy even applies to service principals # If policy only applies to users, then service principal is not in scope if ($Policy.Conditions.Users.IncludeUsers -and -not (Test-SpecialValue -Collection $Policy.Conditions.Users.IncludeUsers -ValueType "AllUsers") -and -not $Policy.Conditions.Users.IncludeServicePrincipals -and -not (Test-SpecialValue -Collection $Policy.Conditions.Users.IncludeServicePrincipals -ValueType "AllServicePrincipals")) { $result.Reason = "Policy only applies to users, not service principals" return $result } # Check exclusions first (always take precedence) # Check if service principal is explicitly excluded if ($Policy.Conditions.Users.ExcludeServicePrincipals -and ($Policy.Conditions.Users.ExcludeServicePrincipals -contains $servicePrincipalId -or $Policy.Conditions.Users.ExcludeServicePrincipals -contains $servicePrincipalAppId)) { $result.Reason = "Service principal explicitly excluded" return $result } # For the inclusion checks, we need to determine if the service principal is included # Case 1: All service principals are included if ((Test-SpecialValue -Collection $Policy.Conditions.Users.IncludeServicePrincipals -ValueType "AllServicePrincipals") -or (Test-SpecialValue -Collection $Policy.Conditions.Users.IncludeUsers -ValueType "AllUsers")) { $result.InScope = $true $result.Reason = "All service principals are included" return $result } # Case 2: Specific service principals are included if ($Policy.Conditions.Users.IncludeServicePrincipals -and ($Policy.Conditions.Users.IncludeServicePrincipals -contains $servicePrincipalId -or $Policy.Conditions.Users.IncludeServicePrincipals -contains $servicePrincipalAppId)) { $result.InScope = $true $result.Reason = "Service principal explicitly included" return $result } # Case 3: Policy has inclusion criteria, but this service principal doesn't match any if ($Policy.Conditions.Users.IncludeServicePrincipals -and $Policy.Conditions.Users.IncludeServicePrincipals.Count -gt 0) { $result.Reason = "Service principal not in any explicit inclusions" return $result } # If we made it here, the policy doesn't specifically include or exclude this service principal # Default to not in scope if there are specific inclusion criteria for other subjects if ($Policy.Conditions.Users.IncludeUsers -and $Policy.Conditions.Users.IncludeUsers.Count -gt 0 -and -not (Test-SpecialValue -Collection $Policy.Conditions.Users.IncludeUsers -ValueType "AllUsers")) { $result.Reason = "Policy includes specific users but not this service principal" return $result } # By default, if no specific inclusion criteria, assume in scope $result.InScope = $true $result.Reason = "No specific exclusion or inclusion criteria for service principals" return $result } # Export the function Export-ModuleMember -Function Test-ServicePrincipalInScope |