Entra / Microsoft 365 · Exchange Online
Purge messages with content search
Purge messages from Exchange Online using a Compliance Search and a purge action applied to the search results.
Connect & set up
Run these once per session. All scopes are read-only unless the script makes changes.
Connect-ExchangeOnline -SkipLoadingCmdletHelp
Run it
The main script. Copy it, or download the .ps1 and run it from your console.
param([string] $StartDate = "1-July-2020",[string] $EndDate = "4-Jan-2024")$Status = Get-ConnectionInformation -ErrorAction SilentlyContinueIf (!($Status)) {Connect-ExchangeOnline -SkipLoadingCmdletHelp}# Connect to the compliance endpointConnect-IPPSSession# Some information to identify the messages we want to purge$BadSender = "badactor@badboys.com"$Subject = "Special Offer for you"# Note - if the subject contains a special character like a $ sign, make sure that you escape that character otherwise it won't# be used in the search$ComplianceSearch = "Remove Offensive Information"# Date range for the search - make this as precise as possible$Start = (Get-Date $StartDate).ToString('yyyy-MM-dd')$End = (Get-Date $EndDate).ToString('yyyy-MM-dd')$ContentQuery = '(c:c)(received=' + $Start + '..' + $End +')(senderauthor=' + $BadSender + ')(subjecttitle="' + $Subject + '")'Clear-HostIf (Get-ComplianceSearch -Identity $ComplianceSearch -ErrorAction SilentlyContinue ) {Write-Host "Cleaning up old search"Try {$Status = Remove-ComplianceSearch -Identity $ComplianceSearch -Confirm:$False}Catch {Write-Host "We can't clean up the old search" ; break}}Write-Host "Starting Compliance Search..."New-ComplianceSearch -Name $ComplianceSearch -ContentMatchQuery $ContentQuery -ExchangeLocation All -AllowNotFoundExchangeLocationsEnabled $True | Out-NullStart-ComplianceSearch -Identity $ComplianceSearch | Out-Null[int]$Seconds = 10Start-Sleep -Seconds $Seconds# Loop until the search finishesWhile ((Get-ComplianceSearch -Identity $ComplianceSearch).Status -ne "Completed") {Write-Host ("Still searching after {0} seconds..." -f $Seconds)$Seconds = $Seconds + 10Start-Sleep -Seconds $Seconds}[int]$ItemsFound = (Get-ComplianceSearch -Identity $ComplianceSearch).ItemsIf ($ItemsFound -gt 0) {$Stats = Get-ComplianceSearch -Identity $ComplianceSearch | Select-Object -Expand SearchStatistics | Convertfrom-JSON$Data = $Stats.ExchangeBinding.Sources | Where-Object {$_.ContentItems -gt 0}Write-Host ""Write-Host "Total Items found matching query:" $ItemsFoundWrite-Host ""Write-Host "Items found in the following mailboxes"Write-Host "--------------------------------------"Foreach ($D in $Data) {Write-Host ("{0} has {1} items of size {2}" -f $D.Name, $D.ContentItems, $D.ContentSize)}Write-Host " "[int]$Iterations = 0; [int]$ItemsProcessed = 0While ($ItemsProcessed -lt $ItemsFound) {$Iterations++Write-Host ("Deleting items...({0})" -f $Iterations)New-ComplianceSearchAction -SearchName $ComplianceSearch -Purge -PurgeType HardDelete -Confirm:$False | Out-Null$SearchActionName = $ComplianceSearch + "_Purge"While ((Get-ComplianceSearchAction -Identity $SearchActionName).Status -ne "Completed") { # Let the search action completeStart-Sleep -Seconds 5 }$ItemsProcessed = $ItemsProcessed + 10 # Can remove a maximum of 10 items per mailbox# Remove the search action so we can recreate itRemove-ComplianceSearchAction -Identity $SearchActionName -Confirm:$False -ErrorAction SilentlyContinue }} Else {Write-Host "The search didn't find any items..."}Write-Host "All done!"
Parameters
ParameterDefaultNotes
-StartDate1-July-2020Start of the reporting window.-EndDate4-Jan-2024End of the reporting window.Attribution
Author
Office365itpros