@@ -415,11 +415,107 @@ function Get-CIPPStandards {
415415 }
416416 Write-Host " We're removing Intune templates as the correct license is not present for this standard. We do this to not run unneeded cycles. If you're reading this don't touch."
417417 foreach ($Key in $IntuneKeys ) { [void ]$ComputedStandards.Remove ($Key ) }
418- # After the license check we're now going to do a compare for the remaining standards.
419- # This compare works by bulk requesting the top=1 entries for intune policies inside of the tenant.
420- # if the 'lastModified' timestamp is the same we skip processing this standard too, there's no need because the tenant hasn't changed anything.
421- # However, we also check the timestamp of our standardTemplate, if that is newer than the cached lastModified timestamp we also process the standard again, because the template has changed.
422- # If our cache for this tenant is blank, we also process the standard.
418+ } else {
419+ # Bulk check policy timestamps per type
420+ $TypeMap = @ { Device = ' deviceManagement/deviceConfigurations' ; Catalog = ' deviceManagement/configurationPolicies' ; Admin = ' deviceManagement/groupPolicyConfigurations' ; deviceCompliancePolicies = ' deviceManagement/deviceCompliancePolicies' ; AppProtection_Android = ' deviceAppManagement/androidManagedAppProtections' ; AppProtection_iOS = ' deviceAppManagement/iosManagedAppProtections' }
421+ $BulkRequests = $TypeMap.GetEnumerator () | ForEach-Object {
422+ @ { id = $_.Key ; url = " $ ( $_.Value ) ?`$ orderby=lastModifiedDateTime desc&`$ select=id,lastModifiedDateTime&`$ top=999" ; method = ' GET' }
423+ }
424+ try {
425+ $TrackingTable = Get-CippTable - tablename ' IntunePolicyTypeTracking'
426+ $BulkResults = New-GraphBulkRequest - Requests $BulkRequests - tenantid $TenantName - NoPaginateIds @ ($BulkRequests.id )
427+ $PolicyTimestamps = @ {}
428+
429+ foreach ($Result in $BulkResults ) {
430+ $GraphTime = $Result.body.value [0 ].lastModifiedDateTime
431+ $GraphId = $Result.body.value [0 ].id
432+ $GraphCount = ($Result.body.value | Measure-Object ).Count
433+ $Cached = Get-CIPPAzDataTableEntity @TrackingTable - Filter " PartitionKey eq '$TenantName ' and RowKey eq '$ ( $Result.id ) '"
434+
435+ # Check if count changed (indicates addition/deletion)
436+ $CountChanged = $false
437+ if ($Cached -and $Cached.PolicyCount -ne $null ) {
438+ $CountChanged = ($GraphCount -ne $Cached.PolicyCount )
439+ if ($CountChanged ) {
440+ Write-Host " Policy count changed for $ ( $Result.id ) : $ ( $Cached.PolicyCount ) -> $GraphCount "
441+ }
442+ }
443+
444+ # Check if ID changed (different policy is now most recent)
445+ $IdChanged = $false
446+ if ($GraphId -and $Cached -and $Cached.LatestPolicyId ) {
447+ $IdChanged = ($GraphId -ne $Cached.LatestPolicyId )
448+ if ($IdChanged ) {
449+ Write-Host " Policy ID changed for $ ( $Result.id ) : $ ( $Cached.LatestPolicyId ) -> $GraphId "
450+ }
451+ }
452+
453+ # Convert both to UTC DateTime for consistent comparison
454+ if ($GraphTime ) {
455+ $GraphTimeUtc = ([DateTime ]$GraphTime ).ToUniversalTime()
456+ if ($Cached -and $Cached.LatestPolicyModified -and -not $IdChanged -and -not $CountChanged ) {
457+ $CachedTimeUtc = ([DateTimeOffset ]$Cached.LatestPolicyModified ).UtcDateTime
458+ $TimeDiff = [Math ]::Abs(($GraphTimeUtc - $CachedTimeUtc ).TotalSeconds)
459+ $Changed = ($TimeDiff -gt 60 ) # Changed if difference > 1 minute
460+ } else {
461+ $Changed = $true # No cache, ID changed, count changed, or treat as changed
462+ }
463+ Add-CIPPAzDataTableEntity @TrackingTable - Entity @ { PartitionKey = $TenantName ; RowKey = $Result.id ; LatestPolicyModified = $GraphTime ; LatestPolicyId = $GraphId ; PolicyCount = $GraphCount } - Force | Out-Null
464+ } else {
465+ $Changed = $true # No Graph data means policies deleted or not yet created - always treat as changed
466+ }
467+
468+ $PolicyTimestamps [$Result.id ] = $Changed
469+ }
470+ # Remove templates whose specific policy type hasn't changed
471+ $TemplateTable = Get-CippTable - tablename ' templates'
472+ $StandardTemplateTable = Get-CippTable - tablename ' templates'
473+ $IntuneKeys = @ ($ComputedStandards.Keys | Where-Object { $_ -like ' *IntuneTemplate*' })
474+ foreach ($Key in $IntuneKeys ) {
475+ $Template = $ComputedStandards [$Key ]
476+ $TemplateEntity = Get-CIPPAzDataTableEntity @TemplateTable - Filter " PartitionKey eq 'IntuneTemplate' and RowKey eq '$ ( $Template.TemplateList.value ) '"
477+
478+ if (-not $TemplateEntity ) { continue }
479+
480+ # Parse JSON to get Type property
481+ $ParsedTemplate = $TemplateEntity.JSON | ConvertFrom-Json
482+ if (-not $ParsedTemplate.Type ) { continue }
483+
484+ $PolicyType = $ParsedTemplate.Type
485+ $PolicyChanged = if ($PolicyType -eq ' AppProtection' ) {
486+ [bool ]($PolicyTimestamps [' AppProtection_Android' ] -or $PolicyTimestamps [' AppProtection_iOS' ])
487+ } else {
488+ [bool ]$PolicyTimestamps [$PolicyType ]
489+ }
490+
491+ # Check if StandardTemplate changed
492+ $StandardTemplate = Get-CIPPAzDataTableEntity @StandardTemplateTable - Filter " PartitionKey eq 'StandardsTemplateV2' and RowKey eq '$ ( $Template.TemplateId ) '"
493+ $StandardTemplateChanged = $false
494+ if ($StandardTemplate ) {
495+ $StandardTimeUtc = ([DateTimeOffset ]$StandardTemplate.Timestamp ).UtcDateTime
496+ $CachedStandardTemplate = Get-CIPPAzDataTableEntity @TrackingTable - Filter " PartitionKey eq '$TenantName ' and RowKey eq 'StandardTemplate_$ ( $Template.TemplateId ) '"
497+
498+ if ($CachedStandardTemplate -and $CachedStandardTemplate.CachedTimestamp ) {
499+ $CachedStandardTimeUtc = ([DateTimeOffset ]$CachedStandardTemplate.CachedTimestamp ).UtcDateTime
500+ $TimeDiff = [Math ]::Abs(($StandardTimeUtc - $CachedStandardTimeUtc ).TotalSeconds)
501+ $StandardTemplateChanged = ($TimeDiff -gt 60 ) # Changed if difference > 1 minute
502+ } else {
503+ $StandardTemplateChanged = $true # No cache, treat as changed
504+ }
505+
506+ Add-CIPPAzDataTableEntity @TrackingTable - Entity @ { PartitionKey = $TenantName ; RowKey = " StandardTemplate_$ ( $Template.TemplateId ) " ; CachedTimestamp = $StandardTemplate.Timestamp } - Force | Out-Null
507+ }
508+
509+ # Remove if BOTH policy unchanged AND StandardTemplate unchanged
510+ if (-not $PolicyChanged -and -not $StandardTemplateChanged ) {
511+ [void ]$ComputedStandards.Remove ($Key )
512+ } else {
513+
514+ }
515+ }
516+ } catch {
517+ Write-Host " Timestamp check failed for $TenantName `: $ ( $_.Exception.Message ) "
518+ }
423519 }
424520 }
425521
@@ -442,4 +538,3 @@ function Get-CIPPStandards {
442538 }
443539 }
444540}
445-
0 commit comments