Import-Module ExchangeOnlineManagement
# Connect using Search-Only Session mode
Connect-IPPSSession -EnableSearchOnlySession
# --- 1. Dynamic Variables & Interactive Prompts ---
$Today = Get-Date
$BaseName = "Phishing-$($Today.ToString('yyyy-MM-dd'))"
$SearchName = $BaseName
$Counter = 1
# Check if a search with today's date already exists and increment suffix if needed
while (Get-ComplianceSearch -Identity $SearchName -ErrorAction SilentlyContinue) {
$SearchName = "$BaseName-$Counter"
$Counter++
}
# Prompt for From address (Required)
$Sender = Read-Host "Enter the sender email address (From)"
while ([string]::IsNullOrWhiteSpace($Sender)) {
Write-Warning "Sender address cannot be blank."
$Sender = Read-Host "Enter the sender email address (From)"
}
# Prompt for Subject (Optional)
$Subject = Read-Host "Enter the subject text to match (leave blank to skip subject filter)"
# Date padding for UTC index shifts (Yesterday to Tomorrow)
$StartDate = $Today.AddDays(-1).ToString("MM/dd/yyyy")
$EndDate = $Today.AddDays(1).ToString("MM/dd/yyyy")
# --- 2. Build KQL Query Dynamically ---
$KqlParts = @("(Received:$StartDate..$EndDate)", "(From:`"$Sender`")")
if (-not [string]::IsNullOrWhiteSpace($Subject)) {
# Escape inner quotes for KQL (" -> "") and apply wildcard substring match
$EscapedSubject = $Subject.Replace('"', '""')
$KqlParts += "(Subject:`"*$EscapedSubject*`")"
}
$KqlQuery = $KqlParts -join " AND "
Write-Host "`nSearch Name : $SearchName" -ForegroundColor Cyan
Write-Host "KQL Query : $KqlQuery`n" -ForegroundColor Gray
# --- 3. Create & Execute Search ---
$s = New-ComplianceSearch -Name $SearchName -ExchangeLocation All -ContentMatchQuery $KqlQuery
if ($null -ne $s) {
Start-ComplianceSearch -Identity $SearchName
while ((Get-ComplianceSearch -Identity $SearchName).Status -ne "Completed") {
Start-Sleep -Seconds 5
Write-Host "Searching mailboxes across tenant..." -ForegroundColor Yellow
}
} else {
Write-Error "Failed to initialize compliance search."
return
}
# --- 4. Retrieve & Display Item Count ---
$SearchStats = Get-ComplianceSearch -Identity $SearchName
Write-Host "`n========================================" -ForegroundColor Green
Write-Host " SEARCH RESULTS COUNT" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Green
Write-Host "Search Name : $SearchName"
Write-Host "Items Found : $($SearchStats.Items)"
Write-Host "Total Size : $([math]::Round($SearchStats.Size / 1MB, 2)) MB"
Write-Host "========================================`n"
if ($SearchStats.Items -eq 0) {
Write-Warning "0 matching items found. Purge process aborted."
return
}
# --- 5. User Confirmation ---
$Confirmation = Read-Host "Do you want to proceed with SoftDelete for $($SearchStats.Items) item(s)? Type 'YES' to purge"
# --- 6. SoftDelete Purge Loop ---
if ($Confirmation -eq 'YES' -or $Confirmation -eq 'Y') {
$RemainingItems = $SearchStats.Items
$RunNumber = 1
while ($RemainingItems -gt 0) {
Write-Host "`nStarting Purge Action (Pass $RunNumber)..." -ForegroundColor Cyan
$PurgeAction = New-ComplianceSearchAction -SearchName $SearchName -Purge -PurgeType SoftDelete
while ((Get-ComplianceSearchAction -Identity $PurgeAction.Identity).Status -ne "Completed") {
Start-Sleep -Seconds 5
Write-Host "Purging in progress..." -ForegroundColor Yellow
}
# Re-index search stats to handle the 10-item-per-mailbox cap
Start-ComplianceSearch -Identity $SearchName
while ((Get-ComplianceSearch -Identity $SearchName).Status -ne "Completed") {
Start-Sleep -Seconds 5
}
$RemainingItems = (Get-ComplianceSearch -Identity $SearchName).Items
Write-Host "Pass $RunNumber complete. Remaining items: $RemainingItems" -ForegroundColor Green
$RunNumber++
}
Write-Host "`nAll matching items successfully soft-deleted!" -ForegroundColor Green
} else {
Write-Host "Purge action canceled by user." -ForegroundColor Yellow
}Was this article helpful?
That’s Great!
Thank you for your feedback
Sorry! We couldn't be helpful
Thank you for your feedback
Feedback sent
We appreciate your effort and will try to fix the article