tests/Test-Assessment.25394.ps1

<#
.SYNOPSIS
    Checks that Quick Access is bound to a Conditional Access policy.
 
.DESCRIPTION
    Verifies that the Quick Access application in Entra Private Access is protected by at least one enabled
    Conditional Access policy with meaningful security controls (MFA, device compliance, or authentication strength).
    Quick Access without Conditional Access enforcement allows compromised credentials to access private resources
    without additional verification, creating security risks for internal resources.
 
.NOTES
    Test ID: 25394
    Category: Global Secure Access
    Required API: servicePrincipals (beta), identity/conditionalAccess/policies (beta), applications/{AppID}/onPremisesPublishing (beta)
#>


function Test-Assessment-25394 {
    [ZtTest(
        Category = 'Global Secure Access',
        ImplementationCost = 'Low',
        MinimumLicense = ('Entra_Premium_Private_Access', 'AAD_PREMIUM'),
        Pillar = 'Network',
        RiskLevel = 'High',
        SfiPillar = 'Protect networks',
        TenantType = ('Workforce', 'External'),
        TestId = '25394',
        Title = 'Quick Access is bound to a Conditional Access policy',
        UserImpact = 'Medium'
    )]
    [CmdletBinding()]
    param()

    #region Data Collection
    Write-PSFMessage '🟦 Start' -Tag Test -Level VeryVerbose
    $activity = 'Checking Quick Access Conditional Access policy protection'
    Write-ZtProgress -Activity $activity -Status 'Querying Quick Access application'

    # Q1: Get Quick Access application
    $quickAccessApp = Invoke-ZtGraphRequest -RelativeUri 'servicePrincipals' -Filter "tags/any(c:c eq 'NetworkAccessQuickAccessApplication')" -Select 'appId,displayName,id' -ApiVersion beta
    $quickAccessAppId = $null
    if ($quickAccessApp -and $quickAccessApp.Count -gt 0) {
        $quickAccessAppId = $quickAccessApp.appId
    }

    # Q2: Get all enabled Conditional Access policies
    $caPolicies = $null
    if ($null -ne $quickAccessApp -and $quickAccessApp.Count -gt 0) {
        Write-ZtProgress -Activity $activity -Status 'Checking Conditional Access policies for Quick Access'
        $allCAPolicies = Get-ZtConditionalAccessPolicy
        $caPolicies = $allCAPolicies | Where-Object { $_.state -eq 'enabled' }
    }

    #endregion Data Collection

    #region Assessment Logic
    # Initialize test variables
    $testResultMarkdown = ''
    $passed = $false
    $applicablePolicies = @()

    # Check if Quick Access application exists
    if (-not $quickAccessApp -or $quickAccessApp.Count -eq 0) {
        $testResultMarkdown = "⚠️ No Quick Access application is configured, review the documentation on how to enable Quick Access if needed.`n`n%TestResult%"
    }
    else {
        # Check Conditional Access policy coverage
        if ($null -eq $caPolicies -or $caPolicies.Count -eq 0) {
            Write-PSFMessage 'Failed to retrieve Conditional Access policies or no policies are enabled' -Level Warning
            $passed = $false
            $testResultMarkdown = "❌ Quick Access application found without Conditional Access policy enforcement.`n`n%TestResult%"
        }
        else {
            foreach ($policy in $caPolicies) {
                $policyTargetsQuickAccess = $false
                # Check if "All" apps are targeted
                if ($policy.conditions.applications.includeApplications -contains 'All') {
                    $policyTargetsQuickAccess = $true
                }
                # Check if Quick Access appId is explicitly included
                elseif ($policy.conditions.applications.includeApplications -contains $quickAccessAppId) {
                    $policyTargetsQuickAccess = $true
                }

                if ($policyTargetsQuickAccess) {
                    # Verify meaningful grant controls
                    $hasMeaningfulControls = $false
                    $grantControlsList = @()

                    if ($null -ne $policy.grantControls) {
                        # Check for meaningful built-in controls
                        if ($null -ne $policy.grantControls.builtInControls -and $policy.grantControls.builtInControls.Count -gt 0) {
                            foreach ($control in $policy.grantControls.builtInControls) {
                                if ($control -in @('mfa', 'compliantDevice', 'domainJoinedDevice', 'approvedApplication')) {
                                    $hasMeaningfulControls = $true
                                }
                                $grantControlsList += $control
                            }
                        }

                        # Check for authentication strength
                        if ($null -ne $policy.grantControls.authenticationStrength) {
                            $hasMeaningfulControls = $true
                            if ($null -ne $policy.grantControls.authenticationStrength.displayName) {
                                $grantControlsList += "AuthenticationStrength: $($policy.grantControls.authenticationStrength.displayName)"
                            }
                        }
                    }

                    if ($hasMeaningfulControls) {
                        $policyInfo = [PSCustomObject]@{
                            DisplayName = $policy.displayName
                            Id = $policy.id
                            GrantControls = $grantControlsList
                        }
                        $applicablePolicies += $policyInfo
                    }
                }
            }
        }

        # Determine pass/fail status
        if ($applicablePolicies.Count -gt 0) {
            $passed = $true
            $testResultMarkdown = "✅ Quick Access application is protected by Conditional Access policies with authentication controls.`n`n%TestResult%"
        }
        else {
            $passed = $false
            $testResultMarkdown = "❌ Quick Access application found without Conditional Access policy enforcement.`n`n%TestResult%"
        }
    }
    #endregion Assessment Logic

    #region Report Generation
    # Build detailed markdown information
    $mdInfo = ''

    if ($null -ne $quickAccessApp -and $quickAccessApp.Count -gt 0) {
        $appPortalLink = "https://entra.microsoft.com/#view/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/~/overview/appId/$($quickAccessApp.appId)"
        $mdInfo += "**Quick Access application name:** [$(Get-SafeMarkdown -Text $quickAccessApp.displayName)]($appPortalLink)`n`n"

        # Show applicable policies if any
        if ($applicablePolicies.Count -gt 0) {
            $mdInfo += "### [Applicable Conditional Access policies](https://entra.microsoft.com/#view/Microsoft_AAD_IAM/QuickAccessMenuBlade/~/GlobalSecureAccess)`n`n"
            $mdInfo += "| Policy name | Grant controls configured |`n"
            $mdInfo += "| :---------- | :------------------------ |`n"

            foreach ($policy in $applicablePolicies) {
                $grantControlsStr = $([string]::Join(', ', $policy.GrantControls))
                # blade link for Conditional Access policy (fixed: no ~/ before policyId)
                $policyPortalLink = "https://entra.microsoft.com/#view/Microsoft_AAD_ConditionalAccess/PolicyBlade/policyId/$($policy.Id)"
                $mdInfo += "| [$(Get-SafeMarkdown -Text $policy.DisplayName)]($policyPortalLink) | $grantControlsStr |`n"
            }
            $mdInfo += "`n"
        }
    }

    # Replace the placeholder with detailed information
    $testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $mdInfo
    #endregion Report Generation

    $params = @{
        TestId = '25394'
        Title  = 'Quick Access is protected by Conditional Access policies'
        Status = $passed
        Result = $testResultMarkdown
    }

    # Add Investigate status if Quick Access is not configured
    if (-not $quickAccessApp -or $quickAccessApp.Count -eq 0) {
        $params.CustomStatus = 'Investigate'
    }

    # Add test result details
    Add-ZtTestResultDetail @params

}