Public/Get-MsecIntuneCompliancePolicy.ps1

function Get-MsecIntuneCompliancePolicy {
    <#
    .SYNOPSIS
        Lists Intune compliance policies - what defines whether a device is "compliant"
        (and therefore allowed through Conditional Access).

    .DESCRIPTION
        Compliance policies are *separate from* configuration policies in Intune:
          - Configurations enforce a state on a device (e.g. "BitLocker on").
          - Compliance policies measure whether a state is met (e.g. "Encryption required"),
            and report compliant/non-compliant per device. Conditional Access then gates
            access on that.

        Queries /v1.0/deviceManagement/deviceCompliancePolicies, including assignments via
        $expand (one call, no extra round trip). Per-policy device check-in counts are opt-in
        via -IncludeStatus (one extra Graph call per policy).

        Required Graph permission: DeviceManagementConfiguration.Read.All (Application) -
        the same permission Get-MsecIntuneConfigurationProfile uses.

    .PARAMETER IncludeStatus
        Fetch the per-policy device check-in counts. Off by default to keep the call cheap
        on large tenants.

    .EXAMPLE
        # Quick inventory:
        Get-MsecIntuneCompliancePolicy | Format-Table -AutoSize

    .EXAMPLE
        # Compliance policies with devices failing:
        Get-MsecIntuneCompliancePolicy -IncludeStatus |
            Where-Object SuccessPercent -lt 100 |
            Sort-Object SuccessPercent |
            Select-Object DisplayName, Platform, SuccessPercent, ErrorCount

    .OUTPUTS
        PSCustomObject: Id, DisplayName, Description, Platform, Type, AssignmentCount,
        CreatedDateTime, LastModifiedDateTime; with -IncludeStatus also Status, SuccessCount,
        ErrorCount, ConflictCount, NotApplicableCount, PendingCount, SuccessPercent.
        See Get-MsecIntuneConfigurationProfile for Status value semantics.
    #>

    [CmdletBinding()]
    param(
        [Parameter()]
        [switch] $IncludeStatus
    )

    Assert-MsecSession

    Write-Verbose 'Loading compliance policies (/v1.0/deviceManagement/deviceCompliancePolicies)'
    $path = '/v1.0/deviceManagement/deviceCompliancePolicies?$expand=assignments'
    foreach ($c in (Invoke-MsecGraphRequest -Path $path -All)) {
        $odataType = $c.'@odata.type'
        $typeShort = if ($odataType) { $odataType -replace '^#microsoft\.graph\.', '' } else { $null }

        # Platform derived from the type name, same pattern as classic device configurations.
        $platform = $null
        switch -Wildcard ($typeShort) {
            'windows10*'           { $platform = 'windows10';          break }
            'windows*'             { $platform = 'windows';            break }
            'macOS*'               { $platform = 'macOS';              break }
            'ios*'                 { $platform = 'iOS';                break }
            'androidWorkProfile*'  { $platform = 'androidWorkProfile'; break }
            'androidDeviceOwner*'  { $platform = 'androidDeviceOwner'; break }
            'androidForWork*'      { $platform = 'androidForWork';     break }
            'android*'             { $platform = 'android';            break }
        }

        $assignmentCount = @($c.assignments).Count
        $obj = [ordered]@{
            Id              = $c.id
            DisplayName     = $c.displayName
            Description     = $c.description
            Platform        = $platform
            Type            = $typeShort
            AssignmentCount = $assignmentCount
        }

        if ($IncludeStatus) {
            # Skip the per-policy status call when AssignmentCount=0 - the answer is
            # "all zeros / NotDeployed" regardless. Saves an API round-trip per row.
            $status = if ($assignmentCount -gt 0) {
                Get-MsecPolicyStatus -Id $c.id -Source 'CompliancePolicy'
            }
            else { $null }

            # Status rollup - see Get-MsecIntuneConfigurationProfile for the same semantics.
            $obj.Status = if ($assignmentCount -eq 0) {
                'NotDeployed'
            }
            elseif ($null -eq $status.SuccessPercent) {
                'NotReporting'
            }
            elseif ($status.SuccessPercent -eq 100 -and $status.ErrorCount -eq 0 -and $status.ConflictCount -eq 0) {
                'Healthy'
            }
            else {
                'Degraded'
            }
        }

        $obj.CreatedDateTime      = if ($c.createdDateTime)      { [datetime]$c.createdDateTime }      else { $null }
        $obj.LastModifiedDateTime = if ($c.lastModifiedDateTime) { [datetime]$c.lastModifiedDateTime } else { $null }

        if ($IncludeStatus) {
            # NotDeployed / NotReporting -> all counts 0 (see Get-MsecIntuneConfigurationProfile).
            if ($obj.Status -in 'NotDeployed', 'NotReporting') {
                $obj.SuccessCount       = 0
                $obj.ErrorCount         = 0
                $obj.ConflictCount      = 0
                $obj.NotApplicableCount = 0
                $obj.PendingCount       = 0
                $obj.SuccessPercent     = 0
            }
            else {
                $obj.SuccessCount       = $status.SuccessCount
                $obj.ErrorCount         = $status.ErrorCount
                $obj.ConflictCount      = $status.ConflictCount
                $obj.NotApplicableCount = $status.NotApplicableCount
                $obj.PendingCount       = $status.PendingCount
                $obj.SuccessPercent     = $status.SuccessPercent
            }
        }

        [PSCustomObject]$obj
    }
}