Three Things That Broke When an Admin Ran Priority Cleanup on Held Data

A GDPR ticket was closed in forty minutes. Four weeks later, outside counsel asked for files that should have been preserved. Priority Cleanup had deleted them.

The ticket said “GDPR erasure — former contractor, OneDrive plus three project sites.” It was closed in about forty minutes. The problem took four weeks to surface, which is roughly how long it takes outside counsel to ask a tenant admin for the files they assumed were still there.

They weren’t. A retention policy had been preserving them. Priority Cleanup went straight through it, which is the entire point of Priority Cleanup, and now a deletion meant to satisfy a privacy request had also wiped the only copy of content relevant to an active dispute. No one broke a rule. The rules just stopped meaning what everyone assumed they meant.

This is the part of the GA announcement that doesn’t make the blog headline. So let’s walk the failure, then pull out what actually bit.

What the feature actually does

Priority Cleanup in Microsoft Purview lets you permanently delete specific SharePoint and OneDrive content even when a retention policy or retention label is preserving it. You scope a cleanup to sites, OneDrive accounts, or a query, and when it runs the matched items are permanently removed — bypassing the preservation a retention policy would normally enforce, and skipping the Recycle Bin and Preservation Hold Library paths you’d rely on to get content back.

Read that again. The design goal is to defeat preservation. For a decade the mental model was simple: if content is under a retention policy, it cannot be destroyed until the policy says so. Priority Cleanup inverts that. Retention stops being a floor and becomes a default you can override.

But there’s a hard boundary, and it’s the most important sentence in this piece. Priority Cleanup overrides retention policies and retention labels. It does not override an eDiscovery hold. Content locked by an eDiscovery (legal) hold is skipped — the cleanup leaves it alone until the hold is removed. That single distinction is the entire safety model of the feature, and it is exactly the distinction the contractor ticket fell through: those files were preserved by a retention policy, not an eDiscovery hold, so nothing stopped the delete.

Scope matters too, and Microsoft is specific about it: this is a SharePoint and OneDrive capability. Do not assume it reaches Exchange, Teams chat, or anything else. And do not assume it’s a substitute for designing retention properly — it’s an exception tool, not a lifecycle strategy. If you find yourself reaching for it monthly, your retention schedule is wrong, not your cleanup process.

The licensing and the roles — the two gates that should slow you down

Priority Cleanup is a premium data lifecycle capability, so it sits behind the same E5-tier compliance licensing that gates Purview’s other advanced retention features — Microsoft 365 E5 or the equivalent E5 compliance licensing. If your tenant is on E3 with no compliance add-on, you won’t see it, which is its own form of protection.

The harder gate is the role model. Creating and running a cleanup should not be something a general SharePoint admin does on a Tuesday. In Purview, the ability to build and manage these policies lives with the Compliance Administrator and Compliance Data Administrator role groups — the ones that carry the Retention Management role. On top of that, Priority Cleanup requires a separate approver: the policy does not execute when it’s submitted. A designated approver has to sign off before anything is deleted.

Treat both as privileged, separately granted functions — the same tier of trust you’d put around eDiscovery or records disposition. Grant them to named individuals, review the membership, and pull it when the project ends. And keep the submitter and the approver as different people. If everyone who can edit a retention policy can also override one with a single approval they grant themselves, you’ve built a loaded gun with the safety taped down.

How you actually run one

The flow is portal-driven, by design — there’s no convenient one-liner to pull this trigger, and the approval gate is built into the workflow rather than bolted on after. In the Purview portal:

  1. Go to Data Lifecycle Management → Priority cleanup and create a new policy.
  2. Name it something a reviewer will understand in six months. “Cleanup 3” is how you end up in the postmortem.
  3. Choose the locations explicitly: named SharePoint sites, specific OneDrive accounts, or both. This is not an org-wide switch.
  4. Define what gets deleted with a KQL query — keywords, date ranges, properties. Run that query as a content search first and read the results by hand. The query is the blast radius.
  5. Assign the approver. Submission routes the policy to them; it does not delete anything yet.
  6. On approval, the matched items are permanently deleted — no Recycle Bin, no Preservation Hold Library behind them.

The PowerShell below is for watching what happened afterwards, not for firing the cleanup.

Where the trail lives — and why it’s a trail, not an undo

Every cleanup action lands in the unified audit log, searchable from Purview Audit and surfaced in the Defender portal. That’s good. What it is not is a safety net. The audit log tells you, after the fact, that content was destroyed and by whom. It does not bring the content back. By the time an entry appears, the files are gone in a way that doesn’t round-trip through a Recycle Bin.

Pull those events on a schedule rather than waiting for a nasty surprise. This runs read-only against the unified audit log — no changes, safe to run against production:

audit.ps1PowerShell
# Read-only: surface recent permanent-deletion activity for review.
# Requires the Exchange Online management module and an account with audit access.
Connect-IPPSSession -UserPrincipalName compliance-admin@contoso.com
​
$results = [System.Collections.Generic.List[object]]::new()
$session = [guid]::NewGuid().ToString()
​
do {
    try {
        $page = Search-UnifiedAuditLog `
            -StartDate (Get-Date).AddDays(-30) `
            -EndDate   (Get-Date) `
            -RecordType SharePointFileOperation `
            -Operations 'FileDeleted','FileDeletedFirstStageRecycleBin','FileDeletedSecondStageRecycleBin' `
            -SessionId  $session `
            -SessionCommand ReturnLargeSet `
            -ResultSize 5000
    }
    catch {
        Write-Warning "Audit query failed: $($_.Exception.Message)"
        break
    }
​
    if ($page) { $results.AddRange($page) }
}
while ($page.Count -gt 0)   # paginate until the session is exhausted
​
# NOTE: these Operations are GENERAL deletion events, not a dedicated
# "priority cleanup" operation name. A priority cleanup and an ordinary
# user delete can both land here. You must open the AuditData JSON on each
# record to confirm which deletions actually came from a cleanup policy -
# do not assume the Operations column alone tells you the cleanup path.
$results |
    Select-Object CreationDate, UserIds, Operations,
        @{N='Detail';E={ $_.AuditData }} |
    Sort-Object CreationDate |
    Export-Csv .\deletion-review.csv -NoTypeInformation -Encoding UTF8
​
Write-Host "$($results.Count) deletion events exported for review."

Export, review by hand, and only then decide what the data is telling you. Don’t pipe a live audit query into anything that acts on it.

When the override is genuinely the right call

There are real scenarios where you want this. A GDPR or UK GDPR erasure request where a broad retention policy would otherwise block compliance. Confidential or regulated data that leaked into the wrong site and needs to be gone, not just inaccessible. A litigation posture that has formally changed and legal has signed off on disposition. Each of those has one thing in common: a decision made outside the admin console, in writing, by someone whose job is the legal consequence.

The contractor ticket had none of that. It had a service-desk note and an admin with the right role. That’s the whole story.

So, the three things that broke

  1. A retention policy was doing a legal hold’s job. Retention policies preserve content; they are not a legal hold, and they were never meant to be the system of record for “do not destroy, ever.” Priority Cleanup exposed that shortcut instantly — because it respects an eDiscovery hold and happily overrides a retention policy. Had those files been under an eDiscovery hold, the cleanup would have skipped them. They weren’t, so it didn’t. If your legal preservation strategy is “we have a retention policy,” an eDiscovery hold is the control you actually needed, and the gap between the two just cost you a document.
  2. One person could do a permanent, unrecoverable thing effectively alone. The approval step exists precisely to put a second person in the path. In this case the submitter and the approver were the same trusted compliance role, so “approval” was a formality one person completed in both chairs. Permanent deletion should require more hands than a mailbox permission change — real separation of duties, not a checkbox the same admin ticks twice.
  3. The audit trail recorded the loss instead of preventing it. Everyone treated “it’s all in the audit log” as reassurance. It’s evidence, not insurance. For an action with no Recycle Bin and no Preservation Hold Library behind it, the only real control is the gate before execution — scope review, a genuinely independent approver, legal sign-off. After the cleanup runs, your logs tell a very clean story about something you can’t take back.

Priority Cleanup is a legitimate tool for a narrow set of problems, and GA means it’s going to show up in tenants whether you plan for it or not. The feature isn’t the hazard. The hazard is every assumption your organisation quietly built on retention being permanent — and the day someone with the right role proves it isn’t.