Skip to content

[Feature Request]: Non-compliant setting CacheType for Custom Tests #796

Description

Please confirm:

  • I have searched existing feature requests (open and closed) and found no duplicates.
  • **Me or my organization currently has an active subscription to the product at the €99/month level.

Problem Statement

Im using this custom test to report on noncompliant devices and understand where we need to manually remediate vs what we can automate. However, the setting that shows why the device is not compliant is not avialable as a cache type. Can we add it as a cachetype so we can have something like Compliance State and Non-compliance Setting (ie secureboot, bitlocker etc) ?

# Non-compliant devices, primary user, last sync
$Devices = Get-CIPPTestData -Type 'ManagedDevices'

$NonCompliant = $Devices | Where-Object {
    $_.complianceState -notin @('compliant', 'unknown')
}

$Results = $NonCompliant | Select-Object @{Name='DeviceId'; Expression={ $_.id }},
    @{Name='DeviceName'; Expression={ $_.deviceName }},
    @{Name='PrimaryUser'; Expression={ if ($_.userDisplayName) { $_.userDisplayName } else { $_.userPrincipalName } }},
    @{Name='UserPrincipalName'; Expression={ $_.userPrincipalName }},
    @{Name='Ownership'; Expression={
        if ($_.ownerType -eq 'company') { 'Corporate' }
        elseif ($_.ownerType -eq 'personal') { 'Personal' }
        elseif ($_.ownerType) { $_.ownerType }
        else { $null }
    }},
    @{Name='ComplianceState'; Expression={ $_.complianceState }},
    @{Name='OS'; Expression={ "$($_.operatingSystem) $($_.osVersion)" }},
    @{Name='LastSync'; Expression={ $_.lastSyncDateTime }},
    @{Name='DaysSinceLastSync'; Expression={
        if ($_.lastSyncDateTime) {
            $span = New-TimeSpan -Start (Get-Date $_.lastSyncDateTime) -End (Get-Date)
            $span.Days
        } else {
            $null
        }
    }},
    @{Name='EnrolledDate'; Expression={ $_.enrolledDateTime }},
    @{Name='GracePeriodExpires'; Expression={ $_.complianceGracePeriodExpirationDateTime }},
    @{Name='DeviceLink'; Expression={ "https://cipp.empower.net.au/endpoint/MEM/devices/device?deviceId=$($_.id)" }}

$Results = @($Results | Sort-Object -Property @{Expression='LastSync'; Descending=$true})

# Split into stale (>30 days since sync) vs recent
$StaleResults  = @($Results | Where-Object { $null -ne $_.DaysSinceLastSync -and $_.DaysSinceLastSync -gt 30 })
$RecentResults = @($Results | Where-Object { $null -eq $_.DaysSinceLastSync -or $_.DaysSinceLastSync -le 30 })

# Summary by compliance state (own table)
$StateGroups = $Results | Group-Object -Property ComplianceState
$StateCounts = $StateGroups | Select-Object @{Name='State'; Expression={ $_.Name }},
    @{Name='Count'; Expression={ $_.Count }}

$stateHeader = "| State | Count |
|---|---|"
$stateRows = $StateCounts | ForEach-Object {
    "| $($_.State) | $($_.Count) |"
}
$stateTable = @($stateHeader) + @($stateRows) -join "
"

# Summary by sync recency (separate table)
$syncHeader = "| Sync Status | Count |
|---|---|"
$syncRows = @(
    "| Recent (synced within 30 days) | $(@($RecentResults).Count) |"
    "| Stale (no sync in over 30 days) | $(@($StaleResults).Count) |"
)
$syncTable = @($syncHeader) + @($syncRows) -join "
"

$header = "### %tenantname%: Non-Compliant Devices

Non-compliant devices: $(@($Results).Count)

**By Compliance State**

$stateTable

**By Sync Recency**

$syncTable"

$detailHeader = "| Device | Primary User | Link | Days Since Sync | Ownership | Compliance State | OS | Last Sync | Grace Period Expires |
|---|---|---|---|---|---|---|---|---|"

$recentRows = $RecentResults | ForEach-Object {
    $device = if ($_.DeviceName) { ([string]$_.DeviceName) -replace '\|','\|' -replace '\r?\n',' ' } else { '_(none)_' }
    $user   = if ($_.PrimaryUser) { ([string]$_.PrimaryUser) -replace '\|','\|' -replace '\r?\n',' ' } else { '_(none)_' }
    $link   = if ($_.DeviceLink) { "[View Device]($($_.DeviceLink))" } else { '_(none)_' }
    $days   = if ($null -ne $_.DaysSinceLastSync) { [string]$_.DaysSinceLastSync } else { '_(none)_' }
    $owner  = if ($_.Ownership) { ([string]$_.Ownership) -replace '\|','\|' -replace '\r?\n',' ' } else { '_(none)_' }
    $state  = if ($_.ComplianceState) { ([string]$_.ComplianceState) -replace '\|','\|' -replace '\r?\n',' ' } else { '_(none)_' }
    $os     = if ($_.OS) { ([string]$_.OS) -replace '\|','\|' -replace '\r?\n',' ' } else { '_(none)_' }
    $sync   = if ($_.LastSync) { ([string]$_.LastSync) -replace '\|','\|' -replace '\r?\n',' ' } else { '_(none)_' }
    $grace  = if ($_.GracePeriodExpires) { ([string]$_.GracePeriodExpires) -replace '\|','\|' -replace '\r?\n',' ' } else { '_(none)_' }
    "| $device | $user | $link | $days | $owner | $state | $os | $sync | $grace |"
}
$recentTable = @($detailHeader) + @($recentRows) -join "
"

$staleRows = $StaleResults | ForEach-Object {
    $device = if ($_.DeviceName) { ([string]$_.DeviceName) -replace '\|','\|' -replace '\r?\n',' ' } else { '_(none)_' }
    $user   = if ($_.PrimaryUser) { ([string]$_.PrimaryUser) -replace '\|','\|' -replace '\r?\n',' ' } else { '_(none)_' }
    $link   = if ($_.DeviceLink) { "[View Device]($($_.DeviceLink))" } else { '_(none)_' }
    $days   = if ($null -ne $_.DaysSinceLastSync) { [string]$_.DaysSinceLastSync } else { '_(none)_' }
    $owner  = if ($_.Ownership) { ([string]$_.Ownership) -replace '\|','\|' -replace '\r?\n',' ' } else { '_(none)_' }
    $state  = if ($_.ComplianceState) { ([string]$_.ComplianceState) -replace '\|','\|' -replace '\r?\n',' ' } else { '_(none)_' }
    $os     = if ($_.OS) { ([string]$_.OS) -replace '\|','\|' -replace '\r?\n',' ' } else { '_(none)_' }
    $sync   = if ($_.LastSync) { ([string]$_.LastSync) -replace '\|','\|' -replace '\r?\n',' ' } else { '_(none)_' }
    $grace  = if ($_.GracePeriodExpires) { ([string]$_.GracePeriodExpires) -replace '\|','\|' -replace '\r?\n',' ' } else { '_(none)_' }
    "| $device | $user | $link | $days | $owner | $state | $os | $sync | $grace |"
}
$staleTable = @($detailHeader) + @($staleRows) -join "
"

$md = if (@($Results).Count -gt 0) {
    $recentSection = if (@($RecentResults).Count -gt 0) {
        "### Recent — Synced Within 30 Days ($(@($RecentResults).Count))

" + $recentTable
    } else {
        "### Recent — Synced Within 30 Days (0)

None."
    }

    $staleSection = if (@($StaleResults).Count -gt 0) {
        "### Stale — No Sync in Over 30 Days ($(@($StaleResults).Count))

" + $staleTable
    } else {
        "### Stale — No Sync in Over 30 Days (0)

None."
    }

    $header + "

---

" + $recentSection + "

---

" + $staleSection
} else {
    "### %tenantname%: Non-Compliant Devices

All devices report compliant."
}

@{
    CIPPStatus         = if (@($Results).Count -gt 0) { 'Failed' } else { 'Passed' }
    CIPPResults        = $Results
    CIPPResultMarkdown = $md
}

Benefits for MSPs

Easily report on noncompliant devices for huge fleets/multiple customers

Value or Importance

Easily report on noncompliant devices for huge fleets/multiple customers

PowerShell Commands (Optional)

Easily report on noncompliant devices for huge fleets/multiple customers

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions