Entra/Get-EntraCaRemoteDevicePolicy.ps1

<#
.SYNOPSIS
    Evaluates whether a Conditional Access policy enforces device compliance for
    remote access by requiring compliantDevice and excluding a corporate named location.
.DESCRIPTION
    Queries Conditional Access policies for an enabled policy that both grants access
    only to compliant devices and excludes a named location (corporate network), signaling
    that the policy applies to remote/external access. Satisfies CMMC AC.L2-3.1.13.

    Requires an active Microsoft Graph connection with
    Policy.Read.All permission.
.PARAMETER OutputPath
    Optional path to export results as CSV. If not specified, results are returned
    to the pipeline.
.EXAMPLE
    PS> .\Entra\Get-EntraCaRemoteDevicePolicy.ps1

    Displays CA remote device policy evaluation results.
.EXAMPLE
    PS> .\Entra\Get-EntraCaRemoteDevicePolicy.ps1 -OutputPath '.\entra-caremotedevice.csv'

    Exports the evaluation to CSV.
.NOTES
    Author: Daren9m
    CMMC: AC.L2-3.1.13 — Employ cryptographic mechanisms to protect CUI during transmission
#>

[CmdletBinding()]
param(
    [Parameter()]
    [ValidateNotNullOrEmpty()]
    [string]$OutputPath
)

$ErrorActionPreference = 'Stop'

$_scriptDir = if ($MyInvocation.MyCommand.Path) { Split-Path -Parent $MyInvocation.MyCommand.Path } else { $PSScriptRoot }
. (Join-Path -Path $_scriptDir -ChildPath '..\Common\SecurityConfigHelper.ps1')

$ctx = Initialize-SecurityConfig
$settings = $ctx.Settings
$checkIdCounter = $ctx.CheckIdCounter

function Add-Setting {
    param(
        [string]$Category, [string]$Setting, [string]$CurrentValue,
        [string]$RecommendedValue, [string]$Status,
        [string]$CheckId = '', [string]$Remediation = ''
    )
    $p = @{
        Settings         = $settings
        CheckIdCounter   = $checkIdCounter
        Category         = $Category
        Setting          = $Setting
        CurrentValue     = $CurrentValue
        RecommendedValue = $RecommendedValue
        Status           = $Status
        CheckId          = $CheckId
        Remediation      = $Remediation
    }
    Add-SecuritySetting @p
}

# ------------------------------------------------------------------
# 1. Check CA policies for compliant device enforcement on remote access
# ------------------------------------------------------------------
try {
    Write-Verbose 'Checking CA policies for compliant device enforcement on remote access...'
    $graphParams = @{
        Method      = 'GET'
        Uri         = '/v1.0/identity/conditionalAccess/policies'
        ErrorAction = 'Stop'
    }
    $caResponse = Invoke-MgGraphRequest @graphParams

    $policies = @()
    if ($caResponse -and $caResponse['value']) { $policies = @($caResponse['value']) }

    $passPolicy = $null
    $warnPolicy = $null

    foreach ($policy in $policies) {
        $state = $policy['state']
        if ($state -eq 'disabled') { continue }

        $grantControls = $policy['grantControls']
        if (-not $grantControls) { continue }
        $builtIn = @($grantControls['builtInControls'])
        if ('compliantDevice' -notin $builtIn) { continue }

        $excludeLocations = @()
        $locations = $policy['conditions']['locations']
        if ($locations -and $locations['excludeLocations']) {
            $excludeLocations = @($locations['excludeLocations'])
        }
        if ($excludeLocations.Count -eq 0) { continue }

        if ($state -eq 'enabled') { $passPolicy = $policy; break }
        if ($state -eq 'enabledForReportingButNotEnforced' -and -not $warnPolicy) {
            $warnPolicy = $policy
        }
    }

    if ($passPolicy) {
        $settingParams = @{
            Category         = 'Remote Access'
            Setting          = 'CA Policy: Compliant Device Required for Remote Access'
            CurrentValue     = "Enabled: '$($passPolicy['displayName'])' requires compliantDevice with named location exclusion"
            RecommendedValue = 'Enabled CA policy requiring compliantDevice grant with at least one named location excluded'
            Status           = 'Pass'
            CheckId          = 'CA-REMOTEDEVICE-001'
            Remediation      = 'Verify the CA policy is scoped to all users and targets remote access scenarios.'
        }
        Add-Setting @settingParams
    }
    elseif ($warnPolicy) {
        $settingParams = @{
            Category         = 'Remote Access'
            Setting          = 'CA Policy: Compliant Device Required for Remote Access'
            CurrentValue     = "Report-only: '$($warnPolicy['displayName'])' - not enforced"
            RecommendedValue = 'Enabled CA policy requiring compliantDevice grant with at least one named location excluded'
            Status           = 'Warning'
            CheckId          = 'CA-REMOTEDEVICE-001'
            Remediation      = 'Change the CA policy state from report-only to enabled to enforce compliant device requirements.'
        }
        Add-Setting @settingParams
    }
    else {
        $settingParams = @{
            Category         = 'Remote Access'
            Setting          = 'CA Policy: Compliant Device Required for Remote Access'
            CurrentValue     = 'No CA policy found requiring compliantDevice with a named location exclusion'
            RecommendedValue = 'Enabled CA policy requiring compliantDevice grant with at least one named location excluded'
            Status           = 'Fail'
            CheckId          = 'CA-REMOTEDEVICE-001'
            Remediation      = 'Create a Conditional Access policy that requires device compliance (compliantDevice) and excludes a named corporate network location to enforce remote access controls.'
        }
        Add-Setting @settingParams
    }
}
catch {
    if ($_.Exception.Message -match '403|Forbidden|Authorization') {
        $settingParams = @{
            Category         = 'Remote Access'
            Setting          = 'CA Policy: Compliant Device Required for Remote Access'
            CurrentValue     = 'Insufficient permissions (Policy.Read.All required)'
            RecommendedValue = 'Enabled CA policy requiring compliantDevice grant with at least one named location excluded'
            Status           = 'Review'
            CheckId          = 'CA-REMOTEDEVICE-001'
            Remediation      = 'Requires Policy.Read.All permission and Entra ID P1 or P2 license.'
        }
        Add-Setting @settingParams
    }
    else {
        Write-Warning "Could not check CA remote device policy: $_"
    }
}

# ------------------------------------------------------------------
# Output results
# ------------------------------------------------------------------
Export-SecurityConfigReport -Settings $settings -OutputPath $OutputPath -ServiceLabel 'Entra CA Remote Device'