Public/Get-IntuneDeviceComplianceReport.ps1

function Get-IntuneDeviceComplianceReport {
    <#
    .SYNOPSIS
        Reports on Intune managed device compliance status.
    .DESCRIPTION
        Pulls all Intune managed devices and evaluates compliance state, OS version currency,
        encryption status, last check-in time, and ownership type. Flags non-compliant devices,
        stale devices that haven't checked in, and devices running outdated OS versions.
    .PARAMETER StaleDays
        Days since last check-in before flagging as stale. Defaults to 30.
    .PARAMETER OSFilter
        Filter to a specific OS platform (Windows, iOS, Android, macOS).
    .EXAMPLE
        Get-IntuneDeviceComplianceReport -StaleDays 14 -OSFilter Windows
    #>

    [CmdletBinding()]
    param(
        [Parameter()]
        [ValidateRange(1, 180)]
        [int]$StaleDays = 30,

        [Parameter()]
        [ValidateSet('Windows', 'iOS', 'Android', 'macOS', 'All')]
        [string]$OSFilter = 'All'
    )

    begin {
        Test-GraphConnection
        $results = [System.Collections.Generic.List[PSObject]]::new()
    }

    process {
        $devices = Get-MgDeviceManagementManagedDevice -All -Property @(
            'id', 'deviceName', 'userPrincipalName', 'operatingSystem',
            'osVersion', 'complianceState', 'lastSyncDateTime',
            'enrolledDateTime', 'managementAgent', 'ownerType',
            'isEncrypted', 'model', 'manufacturer', 'serialNumber'
        )

        if ($OSFilter -ne 'All') {
            $devices = $devices | Where-Object { $_.OperatingSystem -eq $OSFilter }
        }

        foreach ($device in $devices) {
            $findings = @()

            # Compliance state
            if ($device.ComplianceState -ne 'compliant') {
                $findings += "NON-COMPLIANT ($($device.ComplianceState))"
            }

            # Last sync check
            $daysSinceSync = if ($device.LastSyncDateTime) {
                [math]::Round(((Get-Date) - $device.LastSyncDateTime).TotalDays)
            } else { -1 }

            if ($daysSinceSync -gt $StaleDays) {
                $findings += "STALE ($daysSinceSync days since sync)"
            }

            # Encryption check
            if (-not $device.IsEncrypted -and $device.OperatingSystem -in @('Windows', 'macOS')) {
                $findings += 'NOT ENCRYPTED'
            }

            # OS version staleness (flag very old versions)
            $osVersionFlag = $false
            if ($device.OperatingSystem -eq 'Windows' -and $device.OsVersion) {
                # Flag Windows 10 devices (should be on 11 or at least recent 10 build)
                if ($device.OsVersion -match '^10\.0\.(1[0-8]\d{3})') {
                    $findings += "OUTDATED OS ($($device.OsVersion))"
                    $osVersionFlag = $true
                }
            }

            $results.Add([PSCustomObject]@{
                DeviceName      = $device.DeviceName
                UserPrincipalName = $device.UserPrincipalName
                OS              = $device.OperatingSystem
                OSVersion       = $device.OsVersion
                ComplianceState = $device.ComplianceState
                IsEncrypted     = $device.IsEncrypted
                OwnerType       = $device.OwnerType
                Manufacturer    = $device.Manufacturer
                Model           = $device.Model
                SerialNumber    = $device.SerialNumber
                LastSync        = $device.LastSyncDateTime
                DaysSinceSync   = $daysSinceSync
                EnrolledDate    = $device.EnrolledDateTime
                ManagementAgent = $device.ManagementAgent
                Finding         = if ($findings.Count -gt 0) { $findings -join ' | ' } else { 'OK' }
            })
        }
    }

    end {
        $flagged = $results | Where-Object { $_.Finding -ne 'OK' }
        $nonCompliant = $results | Where-Object { $_.ComplianceState -ne 'compliant' }
        Write-Host " Devices scanned: $($results.Count) | Non-compliant: $($nonCompliant.Count) | Findings: $($flagged.Count)" -ForegroundColor Gray
        $results | Sort-Object Finding, DeviceName
    }
}