Exchange scheduled message removal using search.
Recently i had a task to delete obsolete antispam email notification in our environment.
I made a bit of researching on the matter, and, alas, the tool MS suggested to use, ComplianceSearchAction -Purge, only supported deleting 10 messages per mailbox, though i had quite a lot of daily spam notification incoming on some of our accounts.
So, i decided i’ll use ComplianceSearch to purge mailboxes where 10 or less messages matched the criteria, and for others i use Search-Mailbox -DeleteContent commandlet.
So, below script will allow to do that on a regular basis.
To run this script seamlessly using Task Scheduler, i use the following syntax in Actions
Command: powershell.exe
Arguments: -command “. ‘C:\Program Files\Microsoft\Exchange Server\V15\bin\RemoteExchange.ps1’; Connect-ExchangeServer -auto; . ‘”E:\Scripts\Remove-SpamNotificationMessages.ps1″‘”
$exceptions = "mail1@contoso.com","mail2@contoso.com" $Sender = "sender@contoso.com" # Used in Search query $Name = "ComplianceSearchNameHere" # Used in Search query $date = (get-date).AddDays(-7).tostring("MM/dd/yyyy") # Format can vary, this works fine for me when running on Exchange Server locally $msgTreshold = 10 # Hardcoded treshold for New-ComplianceSearchAction -Purge https://docs.microsoft.com/en-us/microsoft-365/compliance/search-for-and-delete-messages-in-your-organization?view=o365-worldwide $logpath = "E:\Scripts\logs\" $debug = $true # Enables Transcript to $($logpath)test.txt filter timestamp {"$(Get-Date -Format G): $_"} if ($debug) {Start-Transcript -path "$($logpath)test.txt" -append} "Starting Remove-SpamNotificationMessages" | timestamp | Out-File -filepath "$($logpath)purge-log.txt" -Append -noClobber # Start with ComplianceSearch to soft clean up to 10 messages per mailbox that match the cryteria. Get-ComplianceSearch $Name if (-not $?) { Write-Output "ComplianceSearch with name :$($Name) not found, creating new..." | timestamp "ComplianceSearch with name :$($Name) not found, creating new..." | timestamp | Out-File -filepath "$($logpath)purge-log.txt" -Append -noClobber New-ComplianceSearch -Name $Name -ContentMatchQuery "Received<$date AND from:$Sender" } else { Write-Output "Modifying ComplianceSearch $($Name) settings..." | timestamp "Modifying ComplianceSearch $($Name) settings..." | timestamp | Out-File -filepath "$($logpath)purge-log.txt" -Append -noClobber Set-ComplianceSearch -Identity $Name -ContentMatchQuery "Received<$date AND from:$Sender" } # Waiting for ComplianceSearch to complete Start-ComplianceSearch -Identity $name $state = "Running" do { sleep -s 30 $state = (Get-ComplianceSearch $Name).Status Write-Output "Waiting for ComplianceSearch $($Name) to finish" | timestamp "Waiting for ComplianceSearch $($Name) to finish" | timestamp | Out-File -filepath "$($logpath)purge-log.txt" -Append -noClobber } while ($state -ne "Completed") Write-Output "ComplianceSearch $($Name) completed, processing results..." | timestamp "ComplianceSearch $($Name) completed, processing results..." | timestamp | Out-File -filepath "$($logpath)purge-log.txt" -Append -noClobber $search = Get-ComplianceSearch $Name # Processing ComplianceSearch results $results = $search.SuccessResults; $results | Out-File -filepath "$($logpath)lastComplianceSearchResults.txt" -Force; if (($search.Items -le 0) -or ([string]::IsNullOrWhiteSpace($results))) { "The compliance search " + $SearchName + " didn't return any useful results." | Out-File -filepath "$($logpath)purge-log.txt" -Append -noClobber; break; } $mailboxes = @(); $lines = $results -split '[\r\n]+'; foreach ($line in $lines) { if ($line -match 'Location: (\S+),.+Item count: (\d+)' -and [int]$matches[2] -gt $msgTreshold) { $mailboxes += $matches[1]; } } "Number of mailboxes that have search hits greater then $($msgTreshold): " + $mailboxes.Count | Out-File -filepath "$($logpath)purge-log.txt" -Append -noClobber New-ComplianceSearchAction -SearchName $Name -Purge -PurgeType SoftDelete -Confirm:$false # Processing list of mailboxes that has matched item count greater than ComplianceSearchAction purge limit $msgTreshold foreach ($mailbox in $mailboxes) { if (-not $exceptions.Contains($mailbox)) { Write-Output "Delete content process for mailbox $($mailbox) started..." | timestamp "Delete content process for mailbox $($mailbox) started..." | timestamp | Out-File -filepath "$($logpath)purge-log.txt" -Append -noClobber $result = Search-Mailbox -Identity $mailbox -SearchQuery "Received<$date AND from:$Sender" -SearchDumpster -DeleteContent -Confirm:$false -Force if (-not $?) { Write-Output "Delete content process for mailbox $($mailbox) FAILED..." | timestamp "Delete content process for mailbox $($mailbox) FAILED..." | timestamp | Out-File -filepath "$($logpath)purge-log.txt" -Append -noClobber } else { Write-Output "Delete content process for mailbox $($mailbox) finished. Deleted $($result.ResultItemsCount) items" | timestamp "Delete content process for mailbox $($mailbox) finished. Deleted $($result.ResultItemsCount) items" | timestamp | Out-File -filepath "$($logpath)purge-log.txt" -Append -noClobber } } } if ($debug) {Stop-Transcript}