Private/Compare-CustomDetection.ps1
|
function Compare-CustomDetection { <# .SYNOPSIS Compares a local detection rule body against the remote rule. .DESCRIPTION Both sides are projected into the same canonical shape, so legacy and current property names compare as equals and collection order is ignored. Returns $true when any managed property differs. #> [CmdletBinding()] [OutputType([bool])] param( [Parameter(Mandatory)] [PSObject]$Local, [Parameter(Mandatory)] [PSObject]$Remote ) $localState = Get-CustomDetectionComparableState -Rule $Local $remoteState = Get-CustomDetectionComparableState -Rule $Remote # Enumerations and device group names are matched by the API without case. Everything else, column names included, is case-sensitive $caseInsensitiveKeys = @('status', 'severity', 'tactics', 'deviceGroups') foreach ($key in $localState.Keys) { $localValue = "$($localState[$key])" $remoteValue = "$($remoteState[$key])" if ($localValue -eq '[]' -or $localValue -eq '{}') { $localValue = '' } if ($remoteValue -eq '[]' -or $remoteValue -eq '{}') { $remoteValue = '' } # The API offers no way to clear custom details, so an unset local value is not a change if ($key -eq 'customDetails' -and $localValue -eq '' -and $remoteValue -ne '') { Write-Warning "The rule carries customDetails that the file does not set. The API cannot remove them, so they stay: $remoteValue" continue } # The platform sets autoDisabled when the query keeps failing. Enabling it again without a change would only repeat the failure if ($key -eq 'status' -and $remoteValue -eq 'autoDisabled' -and $localValue -eq 'enabled') { Write-Warning 'The rule is autoDisabled in the tenant. Change the file or use -Force to enable it again.' continue } # A description or recommended action the file does not set stays on the rule. The API offers no way to clear it either if ($key -in @('description', 'recommendedActions') -and $localValue -eq '' -and $remoteValue -ne '') { Write-Warning "The rule carries a $key that the file does not set. The API cannot remove it, so it stays: $remoteValue" continue } $differs = if ($key -in $caseInsensitiveKeys) { $localValue -ne $remoteValue } else { $localValue -cne $remoteValue } if ($differs) { Write-Verbose "Difference found on '$key': local='$localValue' remote='$remoteValue'" return $true } } return $false } |