Private/M365Monitor/Detections/Test-M365DLPPolicyChange.ps1
|
# PSGuerrilla - Jim Tyler, Microsoft MVP - CC BY 4.0 # https://github.com/jimrtyler/PSGuerrilla | https://creativecommons.org/licenses/by/4.0/ # AI/LLM use: see AI-USAGE.md for required attribution function Test-M365DLPPolicyChange { [CmdletBinding()] param( [PSCustomObject[]]$Events = @() ) $results = [System.Collections.Generic.List[PSCustomObject]]::new() # High-risk operations: deletion, disablement $highRiskPatterns = @( 'Remove-DlpPolicy', 'Remove-DlpCompliancePolicy', 'Remove-DlpComplianceRule', 'Disable-DlpPolicy', 'DlpPolicyRemoved', 'DlpRuleRemoved' ) # Weakening patterns in property changes $weakeningPatterns = @( 'Mode.*(?:Disable|TestWithoutNotifications|Off)' 'IsEnabled.*(?:False|false)' 'BlockAccess.*(?:False|false)' 'NotifyUser.*(?:False|false)' 'GenerateIncidentReport.*(?:False|false)' ) foreach ($event in $Events) { $operationType = $event.OperationType ?? $event.Activity ?? '' $policyName = $event.TargetName ?? '' $isWeakened = $false $isRemoved = $false $changeDetails = [System.Collections.Generic.List[string]]::new() # Check for high-risk operations foreach ($pattern in $highRiskPatterns) { if ($operationType -match [regex]::Escape($pattern) -or $event.Activity -match [regex]::Escape($pattern)) { $isRemoved = $true $changeDetails.Add("DLP policy removed/disabled: $operationType") break } } # Check property changes for weakening if (-not $isRemoved) { foreach ($prop in $event.ModifiedProps) { $propName = $prop.Name ?? '' $newVal = $prop.NewValue ?? '' $oldVal = $prop.OldValue ?? '' $combined = "$propName=$newVal" foreach ($pattern in $weakeningPatterns) { if ($combined -match $pattern) { $isWeakened = $true $changeDetails.Add("$propName changed from '$oldVal' to '$newVal' (weakened)") break } } # Scope reduction (removing protected locations) if ($propName -match 'ExchangeLocation|SharePointLocation|OneDriveLocation|TeamsLocation') { if ($oldVal -and (-not $newVal -or $newVal -eq '' -or $newVal -eq '""')) { $isWeakened = $true $changeDetails.Add("$propName scope removed (was: $oldVal)") } } # Sensitivity label downgrade if ($propName -match 'ContentContainsSensitiveInformation|SensitiveInformationType') { $changeDetails.Add("Sensitive information type changed: $propName") } } } $isDisabling = $isRemoved -or $isWeakened # Severity assessment $severity = if ($isRemoved) { 'Critical' } elseif ($isWeakened) { 'High' } elseif ($operationType -match 'New-Dlp|Create') { 'Low' } else { 'Medium' } $description = if ($isRemoved) { "DLP policy '$policyName' removed by $($event.Actor)" } elseif ($isWeakened) { "DLP policy '$policyName' weakened by $($event.Actor)" } else { "DLP policy '$policyName' modified by $($event.Actor)" } $results.Add([PSCustomObject]@{ Timestamp = $event.Timestamp Actor = $event.Actor DetectionType = 'm365DLPPolicyChange' Description = $description Details = @{ PolicyName = $policyName OperationType = $operationType IsDisabling = $isDisabling IsWeakened = $isWeakened IsRemoved = $isRemoved ChangeNotes = @($changeDetails) ModifiedProps = $event.ModifiedProps } Severity = $severity }) } return @($results) } |