private/tests/Test-Assessment.21808.ps1
<# .SYNOPSIS Checks if device code flow is restricted in the tenant using Conditional Access policies. #> function Test-Assessment-21808{ [CmdletBinding()] param() Write-PSFMessage '🟦 Start' -Tag Test -Level VeryVerbose $activity = "Checking Restrict device code flow" Write-ZtProgress -Activity $activity -Status "Getting conditional access policies" # Get all CA policies from the tenant $allCAPolicies = Invoke-ZtGraphRequest -RelativeUri "identity/conditionalAccess/policies" -ApiVersion 'beta' # Filter enabled policies locally $enabledPolicies = $allCAPolicies | Where-Object { $_.state -eq 'enabled' } $disabledPolicies = $allCAPolicies | Where-Object { $_.state -ne 'enabled' } # Find policies that target device code flow authentication - handle comma-separated values $deviceCodeFlowPolicies = $enabledPolicies | Where-Object { # Check if transferMethods contains deviceCodeFlow (handle comma-separated values) if ($_.conditions.authenticationFlows.transferMethods) { # Split by comma and check if deviceCodeFlow is in the array $transferMethods = $_.conditions.authenticationFlows.transferMethods -split ',' $transferMethods -contains "deviceCodeFlow" } else { $false } } # Find inactive policies that target device code flow - for reporting if test fails $inactiveDeviceCodePolicies = $disabledPolicies | Where-Object { if ($_. conditions.authenticationFlows.transferMethods) { $transferMethods = $_.conditions.authenticationFlows.transferMethods -split ',' $transferMethods -contains "deviceCodeFlow" } else { $false } } # Determine pass/fail status based on requirements $result = $false if ($deviceCodeFlowPolicies.Count -gt 0) { # Check if any policy has block control (only block is considered valid) $properlyConfiguredPolicies = $deviceCodeFlowPolicies | Where-Object { $policy = $_ # Check for block control only $hasBlockControl = $policy.grantControls.builtInControls -contains "block" # If the policy has block control, set result to true if ($hasBlockControl) { $result = $true return $true } return $false } } # Prepare the markdown output, starting with the main check result $testResultMarkdown = "" if ($result) { $testResultMarkdown += "Device code flow is properly restricted in the tenant.%TestResult%" } else { if ($deviceCodeFlowPolicies.Count -eq 0) { $testResultMarkdown += "No enabled Conditional Access policies found that target device code flow authentication.%TestResult%" } else { $testResultMarkdown += "Device code flow policies exist but none are configured to block device code flow.%TestResult%" } } # Build the detailed sections of the markdown $mdInfo = "" # Include CA policies information $mdInfo += "`n## Conditional Access Policies targeting Device Code Flow`n`n" if ($deviceCodeFlowPolicies.Count -gt 0) { $mdInfo += "| Policy Name | Status | Target Users | Target Resources | Grant Controls |`n" $mdInfo += "| :---------- | :----- | :----------- | :--------------- | :------------ |`n" foreach ($policy in $deviceCodeFlowPolicies) { $portalLink = "https://entra.microsoft.com/#view/Microsoft_AAD_ConditionalAccess/PolicyBlade/policyId/{0}" -f $policy.id # Format target users $targetUsers = "All Users" if ($policy.conditions.users.includeUsers -contains "All") { $targetUsers = "All Users" } elseif ($policy.conditions.users.includeUsers.Count -gt 0) { $targetUsers = "Included: $($policy.conditions.users.includeUsers.Count) users/groups" } if ($policy.conditions.users.excludeUsers.Count -gt 0) { $targetUsers += ", Excluded: $($policy.conditions.users.excludeUsers.Count) users/groups" } # Format target resources $targetResources = "All Apps" if ($policy.conditions.applications.includeApplications -contains "All") { $targetResources = "All Applications" } elseif ($policy.conditions.applications.includeApplications.Count -gt 0) { $targetResources = "Included: $($policy.conditions.applications.includeApplications.Count) apps" } if ($policy.conditions.applications.excludeApplications.Count -gt 0) { $targetResources += ", Excluded: $($policy.conditions.applications.excludeApplications.Count) apps" } # Format grant controls $grantControls = "None" if ($policy.grantControls.builtInControls -contains "block") { $grantControls = "Block" } elseif ($policy.grantControls.builtInControls.Count -gt 0) { $grantControls = $policy.grantControls.builtInControls -join ", " } if ($policy.grantControls.operator -eq "OR") { $grantControls += " (ANY)" } else { $grantControls += " (ALL)" } $mdInfo += "| [$(Get-SafeMarkdown($policy.displayName))]($portalLink) | Enabled | $targetUsers | $targetResources | $grantControls |`n" } } else { $mdInfo += "No enabled Conditional Access policies targeting device code flow authentication were found.`n" } # If the test failed and there are inactive policies, show them if (!$result && $inactiveDeviceCodePolicies.Count -gt 0) { $mdInfo += "`n## Inactive Conditional Access Policies targeting Device Code Flow`n" $mdInfo += "These policies are not contributing to your security posture because they are not enabled:`n`n" $mdInfo += "| Policy Name | Status | Target Users | Target Resources | Grant Controls |`n" $mdInfo += "| :---------- | :----- | :----------- | :--------------- | :------------ |`n" foreach ($policy in $inactiveDeviceCodePolicies) { $portalLink = "https://entra.microsoft.com/#view/Microsoft_AAD_ConditionalAccess/PolicyBlade/policyId/{0}" -f $policy.id # Format policy status $status = if ($policy.state -eq "enabledForReportingButNotEnforced") { "Report-only" } else { "Disabled" } # Format target users $targetUsers = "All Users" if ($policy.conditions.users.includeUsers -contains "All") { $targetUsers = "All Users" } elseif ($policy.conditions.users.includeUsers.Count -gt 0) { $targetUsers = "Included: $($policy.conditions.users.includeUsers.Count) users/groups" } if ($policy.conditions.users.excludeUsers.Count -gt 0) { $targetUsers += ", Excluded: $($policy.conditions.users.excludeUsers.Count) users/groups" } # Format target resources $targetResources = "All Apps" if ($policy.conditions.applications.includeApplications -contains "All") { $targetResources = "All Applications" } elseif ($policy.conditions.applications.includeApplications.Count -gt 0) { $targetResources = "Included: $($policy.conditions.applications.Count) apps" } if ($policy.conditions.applications.excludeApplications.Count -gt 0) { $targetResources += ", Excluded: $($policy.conditions.applications.excludeApplications.Count) apps" } # Format grant controls $grantControls = "None" if ($policy.grantControls.builtInControls -contains "block") { $grantControls = "Block" } elseif ($policy.grantControls.builtInControls.Count -gt 0) { $grantControls = $policy.grantControls.builtInControls -join ", " } if ($policy.grantControls.operator -eq "OR") { $grantControls += " (ANY)" } else { $grantControls += " (ALL)" } $mdInfo += "| [$(Get-SafeMarkdown($policy.displayName))]($portalLink) | $status | $targetUsers | $targetResources | $grantControls |`n" } } # Replace the placeholder with the detailed information $testResultMarkdown = $testResultMarkdown -replace "%TestResult%", $mdInfo $passed = $result Add-ZtTestResultDetail -TestId '21808' -Title "Restrict device code flow" ` -UserImpact Medium -Risk High -ImplementationCost Low ` -AppliesTo Identity -Tag ConditionalAccess ` -Status $passed -Result $testResultMarkdown } |