private/graph/Find-ZtProfilesLinkedToPolicy.ps1
|
function Find-ZtProfilesLinkedToPolicy { <# .SYNOPSIS Finds filtering profiles that are linked to a specific policy and evaluates if they meet pass criteria. .DESCRIPTION This function searches through Global Secure Access filtering profiles to find those linked to a specific policy. It evaluates whether each linked profile meets the pass criteria based on profile type: - Baseline Profile (priority = 65000): Passes automatically regardless of link state - Security Profile (priority < 65000): Passes only if linked to an enabled Conditional Access policy .PARAMETER PolicyId The ID of the filtering policy to search for. .PARAMETER FilteringProfiles Collection of all filtering profiles to search through. .PARAMETER CAPolicies Collection of Conditional Access policies for Security Profile validation. .PARAMETER BaselinePriority The priority value that identifies the Baseline Profile (typically 65000). .PARAMETER PolicyLinkType The type of policy link to search for. Valid values: - filteringPolicyLink (Web Content Filtering) - tlsInspectionPolicyLink (TLS Inspection) - filePolicyLink (File Policy) - promptPolicyLink (Prompt Policy) .PARAMETER PolicyRules Collection of policy rules associated with the policy (e.g., webCategory rules, TLS inspection rules). .EXAMPLE $findParams = @{ PolicyId = $policyId FilteringProfiles = $filteringProfiles CAPolicies = $caPolicies BaselinePriority = 65000 PolicyLinkType = 'filteringPolicyLink' PolicyRules = $webCategoryRules } $linkedProfiles = Find-ZtProfilesLinkedToPolicy @findParams .OUTPUTS Array of PSCustomObject with the following properties: - ProfileId: The profile ID - ProfileName: The profile name - ProfileType: 'Baseline Profile' or 'Security Profile' - ProfileState: The profile state - ProfilePriority: The profile priority value - PolicyLinkState: The state of the policy link (enabled/disabled/unknown) - PassesCriteria: Boolean indicating if the profile meets pass criteria - CAPolicy: Linked Conditional Access policies (for Security Profiles only) - PolicyRules: The policy rules passed in .NOTES This function is used by Global Secure Access assessment tests to evaluate policy enforcement. #> [CmdletBinding()] param( [Parameter(Mandatory)] [string]$PolicyId, [Parameter(Mandatory)] [AllowEmptyCollection()] [object[]]$FilteringProfiles, [Parameter(Mandatory)] [AllowEmptyCollection()] [object[]]$CAPolicies, [Parameter(Mandatory)] [int]$BaselinePriority, [Parameter(Mandatory)] [ValidateSet('filteringPolicyLink', 'tlsInspectionPolicyLink', 'filePolicyLink', 'promptPolicyLink')] [string]$PolicyLinkType, [Parameter(Mandatory)] [AllowEmptyCollection()] [object[]]$PolicyRules ) # OData type lookup for type safety $odataTypeMap = @{ 'filteringPolicyLink' = '#microsoft.graph.networkaccess.filteringPolicyLink' 'tlsInspectionPolicyLink' = '#microsoft.graph.networkaccess.tlsInspectionPolicyLink' 'filePolicyLink' = '#microsoft.graph.networkaccess.filePolicyLink' 'promptPolicyLink' = '#microsoft.graph.networkaccess.promptPolicyLink' } $odataType = $odataTypeMap[$PolicyLinkType] if (-not $odataType) { Write-PSFMessage "Unknown PolicyLinkType: $PolicyLinkType" -Tag Test -Level Warning return @() } $linkedProfiles = [System.Collections.Generic.List[PSCustomObject]]::new() foreach ($filteringProfile in $FilteringProfiles) { # Get profile policies safely $profilePolicies = @() if ($null -ne $filteringProfile.policies) { # Force array to handle both scalar and array returns from Graph API $profilePolicies = @($filteringProfile.policies) } foreach ($policyLink in $profilePolicies) { $plinkType = $policyLink.'@odata.type' $linkedPolicyId = $null # Only process the specified policy link type if ($plinkType -eq $odataType -and $null -ne $policyLink.policy) { $linkedPolicyId = $policyLink.policy.id } if ($null -ne $linkedPolicyId -and $linkedPolicyId -eq $PolicyId) { # Determine profile type based on priority $priority = if ($null -ne $filteringProfile.priority) { [int]$filteringProfile.priority } else { $null } # Per spec: Only process Baseline Profile (priority = 65000) or Security Profile (priority < 65000) if ($null -eq $priority) { Write-PSFMessage "Skipping profile '$($filteringProfile.name)' (ID: $($filteringProfile.id)) - missing priority property" -Tag Test -Level Debug continue } $linkState = if ($null -ne $policyLink.state) { $policyLink.state } else { 'unknown' } if ($priority -eq $BaselinePriority) { # Baseline Profile: passes regardless of enabled state per spec $profileInfo = [PSCustomObject]@{ ProfileId = $filteringProfile.id ProfileName = $filteringProfile.name ProfileType = 'Baseline Profile' ProfileState = $filteringProfile.state ProfilePriority = $priority PolicyLinkState = $linkState PassesCriteria = $true CAPolicy = $null PolicyRules = $PolicyRules } $linkedProfiles.Add($profileInfo) | Out-Null } elseif ($priority -lt $BaselinePriority) { # Security Profile: check if linked to enabled CA policy $linkedCAPolicies = $CAPolicies | Where-Object { # Use null-conditional operator for safe navigation $_.sessionControls?.globalSecureAccessFilteringProfile?.profileId -eq $filteringProfile.id -and $_.sessionControls?.globalSecureAccessFilteringProfile?.isEnabled -eq $true } $profileInfo = [PSCustomObject]@{ ProfileId = $filteringProfile.id ProfileName = $filteringProfile.name ProfileType = 'Security Profile' ProfileState = $filteringProfile.state ProfilePriority = $priority PolicyLinkState = $linkState PassesCriteria = $false CAPolicy = $null PolicyRules = $PolicyRules } if ($linkedCAPolicies) { # Check if at least one CA policy is enabled $enabledCAPolicies = $linkedCAPolicies | Where-Object { $_.state -eq 'enabled' } if ($enabledCAPolicies) { $profileInfo.PassesCriteria = $true } $profileInfo.CAPolicy = $linkedCAPolicies } $linkedProfiles.Add($profileInfo) | Out-Null } else { # Priority > BaselinePriority Write-PSFMessage "Skipping profile '$($filteringProfile.name)' (ID: $($filteringProfile.id)) - unexpected priority value: $priority (expected <= $BaselinePriority)" -Tag Test -Level Debug } } } } return $linkedProfiles } |