1

A user has over 40 GB of emails in her deleted items. She has already confirmed she does not need them to be recoverable.

I have run a search to pull her deleted items folder id using the method outlined here

https://learn.microsoft.com/en-us/microsoft-365/compliance/use-content-search-for-targeted-collections?view=o365-worldwide

I then created a search in the compliance center for her user, searching with the folder id as the search terms, and before 3/30/2020. The search returns 20+ GB of results

I connect to the compliance service with 2fa using Connect-IPPSSession and run the following

New-ComplianceSearchAction -SearchName "Deleted Items before 3/30/2020" -Purge -PurgeType HardDelete

The action completes instantly showing

Results : Purge Type: HardDelete; Item count: 0; Total size 0; Details: {}

The users mailbox did not shrink in size at all, and all deleted items are still there. Runing the search again returns the same 20+ GB of results

I have tried the action with both soft and hard delete options, the results are the same, nothing happens.

I have confirmed with Get-ComplianceSearch that the estimated 20GB of data shows in powershell for that search name, so why is HardDelete not deleting anything?

Gummby8
  • 85
  • 1
  • 2
  • 9
  • Having the same issue, will post an answer if I find a solution! – neildeadman Jul 27 '20 at 14:25
  • I eventually found something that worked and have posted it as an answer below as promised. I am still working on amending the script, this is just the version I have that is working initially. Hope it helps you! – neildeadman Jul 28 '20 at 12:10

1 Answers1

2

So I have learned that a Purge action can only delete 10 items at a time. As to why you and I saw no emails being removed I never fully got to the bottom of. I suspect it was deleting the 10 on each run, but since I was searching multiple mailboxes (as per my requirement) the results weren't clear. I have since managed to get success by using a script (below) which I adjusted for my requirements from a script I found through this blog post.

Many thanks to Tony Redmond whose script I amended...

Clear-Host

# Connect to Exchange Online
$credentials = get-credential;
Connect-ExchangeOnline -Credential $credentials
$SccSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.compliance.protection.outlook.com/powershell-liveid/ -Credential $credentials -Authentication "Basic" -AllowRedirection;
Import-PSSession $SccSession

$mailboxes = @("mailbox1@example.net", "mailbox2@example.net")

$monthsToKeep = 3

$sourceDate = (Get-Date).AddMonths(-$monthsToKeep)

$searchName = "PurgeEmails"

$contentQuery = "received<=$($sourcDeate) AND kind:email"

# Clean-up any old searches from failed runs of this script
if (Get-ComplianceSearch -Identity $searchName) {
    Write-Host "Cleaning up any old searches from failed runs of this script"

    try {
        Remove-ComplianceSearch -Identity $searchName -Confirm:$false | Out-Null
    }
    catch {
        Write-Host "Clean-up of old script runs failed!" -ForegroundColor Red
        break
    }
}

Write-Host "Creating new search for emails older than $($sourceate)"

New-ComplianceSearch -Name $searchName -ContentMatchQuery $contentQuery -ExchangeLocation $mailboxes -AllowNotFoundExchangeLocationsEnabled $true | Out-Null
                                                                            
Start-ComplianceSearch -Identity $searchName | Out-Null

Write-Host "Searching..."

while ((Get-ComplianceSearch -Identity $searchName).Status -ne "Completed") {
    Write-Host "." -NoNewline
    Start-Sleep -Seconds 2
}

$items = (Get-ComplianceSearch -Identity $searchName).Items

if ($items -gt 0) {
    $searchStatistics = Get-ComplianceSearch -Identity $searchName | Select-Object -Expand SearchStatistics | Convertfrom-JSON

    $sources = $searchStatistics.ExchangeBinding.Sources | Where-Object { $_.ContentItems -gt 0 }

    Write-Host ""
    Write-Host "Total Items found matching query:" $items 
    Write-Host ""
    Write-Host "Items found in the following mailboxes"
    Write-Host "--------------------------------------"

    foreach ($source in $sources) {
        Write-Host $source.Name "has" $source.ContentItems "items of size" $source.ContentSize
    }

    Write-Host ""

    $iterations = 0;
    
    $itemsProcessed = 0
    
    while ($itemsProcessed -lt $items) {
        $iterations++

        Write-Host "Deleting items iteration $($iterations)"

        New-ComplianceSearchAction -SearchName $searchName -Purge -PurgeType HardDelete -Confirm:$false | Out-Null

        while ((Get-ComplianceSearchAction -Identity "$($searchName)_Purge").Status -ne "Completed") { 
            Start-Sleep -Seconds 2
        }

        $itemsProcessed = $itemsProcessed + 10
        
        # Remove the search action so we can recreate it
        Remove-ComplianceSearchAction -Identity "$($searchName)_Purge" -Confirm:$false  
    }
} else {
    Write-Host "No items found"
}

Write-Host ""
Write-Host "COMPLETED!"
neildeadman
  • 3,974
  • 13
  • 42
  • 55