136 lines
4.5 KiB
PowerShell
136 lines
4.5 KiB
PowerShell
#!/usr/bin/env pwsh
|
|
|
|
# Add any email addresses that should be purged to the $Addresses array
|
|
|
|
$Addresses = @()
|
|
$MaxDate = "2023-06-30"
|
|
|
|
# No modifications below this point.
|
|
|
|
function Write-Log {
|
|
[CmdletBinding()]
|
|
param
|
|
(
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Message
|
|
)
|
|
|
|
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
|
Write-Output "${timestamp}: $Message"
|
|
}
|
|
|
|
# Build query for ComplianceSearch
|
|
|
|
if (!$Addresses) {
|
|
Write-Output "Search query is empty - make sure that Addresses array is not empty - exiting"
|
|
exit 1
|
|
}
|
|
|
|
$From = "from:" + ($Addresses -join " OR from:")
|
|
$To = "to:" + ($Addresses -join " OR to:")
|
|
$Participants = "$From OR $To"
|
|
|
|
$Query = "($Participants) AND date<=$MaxDate AND (kind:email)"
|
|
|
|
# Ask user for admin credentials
|
|
|
|
$UserCredential = Get-Credential -Title "Office 365 Credentials" -Message "Enter your credentials for Office 365"
|
|
|
|
# Load PowerShell session for Microsoft Exchange
|
|
|
|
Import-Module ExchangeOnlineManagement
|
|
Connect-IPPSSession -Credential $UserCredential
|
|
Connect-ExchangeOnline -Credential $UserCredential
|
|
|
|
# Define folders that should be ignored by ComplianceSearch
|
|
|
|
$folders = "/Recoverable Items", "/Deletions", "/Purges", "/Versions"
|
|
|
|
Write-Output "Finding folders to exclude, this may take a while..."
|
|
|
|
$mailboxes = Get-Mailbox
|
|
|
|
$folderQueries = @()
|
|
|
|
foreach ($mailbox in $mailboxes) {
|
|
$emailAddress = $mailbox.PrimarySmtpAddress
|
|
$folderStatistics = Get-EXOMailboxFolderStatistics $emailAddress
|
|
foreach ($folderStatistic in $folderStatistics) {
|
|
$folderId = $folderStatistic.FolderId;
|
|
$folderPath = $folderStatistic.FolderPath;
|
|
|
|
if ($folders -contains $folderPath) {
|
|
|
|
# Based on / shamelessly stolen from:
|
|
# https://practical365.com/targeted-collection-content-search/
|
|
|
|
$encoding = [System.Text.Encoding]::GetEncoding("us-ascii")
|
|
$nibbler = $encoding.GetBytes("0123456789ABCDEF");
|
|
$folderIdBytes = [Convert]::FromBase64String($folderId);
|
|
$indexIdBytes = New-Object byte[] 48;
|
|
$indexIdIdx = 0;
|
|
$folderIdBytes | Select-Object -skip 23 -First 24 | % { $indexIdBytes[$indexIdIdx++] = $nibbler[$_ -shr 4];
|
|
$indexIdBytes[$indexIdIdx++] = $nibbler[$_ -band 0xF] }
|
|
$folderQuery = "folderid:$($encoding.GetString($indexIdBytes))";
|
|
|
|
$folderStat = New-Object PSObject
|
|
Add-Member -InputObject $folderStat -MemberType NoteProperty -Name Mailbox -Value $emailAddress
|
|
Add-Member -InputObject $folderStat -MemberType NoteProperty -Name FolderPath -Value $folderPath
|
|
Add-Member -InputObject $folderStat -MemberType NoteProperty -Name FolderQuery -Value $folderQuery
|
|
|
|
$folderQueries += $folderStat
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
$Excluded = ""
|
|
|
|
foreach ($folder in $folderQueries) {
|
|
$q = $folder.folderQuery
|
|
$Excluded += " NOT $q"
|
|
}
|
|
|
|
$Query += $Excluded
|
|
|
|
$Looper = $true
|
|
|
|
while ($Looper) {
|
|
try {
|
|
Write-Output "Creating new search"
|
|
New-ComplianceSearch -Name "WAT Remover" -ContentMatchQuery $Query -ExchangeLocation all -AllowNotFoundExchangeLocationsEnabled $true -Force | Out-Null
|
|
Start-ComplianceSearch -Identity "WAT Remover" | Out-Null
|
|
|
|
Write-Output "Waiting for search to complete"
|
|
while (!(Get-ComplianceSearch -Identity "WAT Remover" | Format-List -Property Status | Out-String | Select-String -Pattern "Completed")) {
|
|
Start-Sleep -s 1
|
|
}
|
|
|
|
$Results = (Get-ComplianceSearch "WAT Remover").Items
|
|
if ($Results) {
|
|
Write-Output "$Results results found, deleting"
|
|
for ($i = 0; $i -lt 10; $i++) {
|
|
Write-Output "Starting deletion run $i"
|
|
New-ComplianceSearchAction -SearchName "WAT Remover" -Purge -PurgeType HardDelete -Force -Confirm:$false | Out-Null
|
|
while (!(Get-ComplianceSearchAction -Identity "WAT Remover_Purge" | Out-String | Select-String -Pattern "Completed")) {
|
|
Start-Sleep -s 1
|
|
}
|
|
Write-Output "Results deleted"
|
|
Remove-ComplianceSearchAction -Confirm:$false -Identity "WAT Remover_Purge"
|
|
}
|
|
}
|
|
else {
|
|
Write-Output "No results found, exiting after this run"
|
|
$Looper = $false
|
|
}
|
|
}
|
|
finally {
|
|
Write-Output "Cleaning up"
|
|
Remove-ComplianceSearchAction -Confirm:$false -Identity "WAT Remover_Purge"
|
|
Remove-ComplianceSearch -Identity "WAT Remover" -Confirm:$false
|
|
}
|
|
}
|
|
|
|
Write-Output "Done - exiting"
|
|
|
|
|