Introduction: When SharePoint Retention Becomes a Storage Problem
If you manage Microsoft 365 long enough, you’ll eventually hit this problem:
“Why is our SharePoint storage still growing even though we deleted everything?”
In my case, the culprit was the Preservation Hold Library—a hidden SharePoint document library that silently ballooned due to a retention policy. Even after users deleted content and emptied recycle bins, storage usage kept climbing.
This article explains what the Preservation Hold Library is, why it grows, when it’s safe to clear, and—most importantly—how to permanently delete its contents using PowerShell, bypassing the recycle bin.
This is not theory. This is a field-tested solution for IT professionals responsible for SharePoint storage, compliance, and Microsoft 365 governance.
What Is the Preservation Hold Library (PHL)?
The Preservation Hold Library is a hidden system library created automatically when:
- A retention policy applies to a SharePoint site
- A retention label with “retain” behavior is used
- Legal hold or eDiscovery retention is enforced
When users delete files under retention, SharePoint does not actually remove them. Instead:
- The content is copied into the Preservation Hold Library
- The file is retained until the retention period expires
- The user believes the file is gone, but storage continues to be consumed
This design ensures compliance—but it comes with a cost.
Why the Preservation Hold Library Grows Out of Control
From real-world experience, this happens most often when:
- Retention policies are removed or reconfigured
- Sites are heavily used for collaboration or file churn
- Migration projects bring in large volumes of temporary data
- Retention labels were applied too broadly
The key problem:
SharePoint does not automatically clean up the Preservation Hold Library immediately after retention changes.
In some tenants, content can remain indefinitely unless explicitly removed.
Important Warning: This Is a Permanent Action
Before going any further, this must be crystal clear:
⚠️ Deleting content from the Preservation Hold Library permanently removes retained data and bypasses the recycle bin.
You should only proceed if:
- The retention policy has been removed or expired
- Legal, compliance, and records teams have approved the deletion
- You understand the regulatory implications for your organization
In regulated industries (finance, health, government), this step should be documented and approved formally.
Why Microsoft Doesn’t Provide a “Clean Up” Button
A common question I get is:
“Why isn’t there a Microsoft-supported way to clean this up?”
The answer is risk.
Microsoft deliberately avoids providing UI-based deletion tools for retained data because:
- Retention is often tied to legal obligations
- Accidental deletion could invalidate legal holds
- Automation could conflict with eDiscovery processes
That leaves experienced IT admins with PowerShell as the only viable option.
The Approach: Using PnP.PowerShell
The PnP.PowerShell module provides the necessary control to:
- Access hidden SharePoint system libraries
- Enumerate large numbers of list items
- Permanently delete items without recycling
This script is designed to:
- Process items in batches
- Provide clear warnings
- Require explicit confirmation
- Permanently delete items (Recycle Bin bypassed)
PowerShell Script: Empty the Preservation Hold Library
Prerequisites
- PowerShell 7+ recommended
- PnP.PowerShell module
- SharePoint Administrator or Site Collection Administrator permissions
Install the module if required:
Install-Module PnP.PowerShell -Scope CurrentUser
The Script
# Empty SharePoint Preservation Hold Library (Permanent Delete - Bypasses Recycle Bin)
# Requires PnP.PowerShell module: Install-Module PnP.PowerShell -Scope CurrentUser
param(
[Parameter(Mandatory=$true)]
[string]$SiteUrl,
[int]$BatchSize = 500
)
# Connect to SharePoint (will prompt for authentication)
try {
Connect-PnPOnline -Url $SiteUrl -Interactive -ErrorAction Stop
}
catch {
Write-Host "Failed to connect to SharePoint: $_" -ForegroundColor Red
exit 1
}
# Verify we have a valid connection
$ctx = Get-PnPContext
if ($null -eq $ctx) {
Write-Host "No valid SharePoint connection. Exiting." -ForegroundColor Red
exit 1
}
Write-Host "Connected successfully to $SiteUrl" -ForegroundColor Green
# The Preservation Hold Library has a fixed internal name
$libraryName = "PreservationHoldLibrary"
Write-Host "`nWARNING: This will PERMANENTLY delete items (bypassing recycle bin)!" -ForegroundColor Red
Write-Host "Site: $SiteUrl" -ForegroundColor Yellow
$confirm = Read-Host "Type 'YES' to continue"
if ($confirm -ne "YES") {
Write-Host "Aborted." -ForegroundColor Yellow
Disconnect-PnPOnline
exit
}
Write-Host "`nFetching items from Preservation Hold Library..." -ForegroundColor Cyan
$itemCount = 0
do {
# Get items in batches
$items = Get-PnPListItem -List $libraryName -PageSize $BatchSize
if ($items.Count -eq 0) {
Write-Host "No more items to delete." -ForegroundColor Green
break
}
Write-Host "Processing batch of $($items.Count) items..." -ForegroundColor Yellow
foreach ($item in $items) {
try {
# -Recycle:$false = permanent delete, bypasses recycle bin
Remove-PnPListItem -List $libraryName -Identity $item.Id -Force -Recycle:$false
$itemCount++
if ($itemCount % 100 -eq 0) {
Write-Host "Permanently deleted $itemCount items so far..." -ForegroundColor Gray
}
}
catch {
Write-Host "Failed to delete item $($item.Id): $_" -ForegroundColor Red
}
}
} while ($items.Count -gt 0)
Write-Host "`nComplete! Permanently deleted $itemCount total items." -ForegroundColor Green
Disconnect-PnPOnline
How to Run the Script
- Save the script as:
Clear-PreservationHoldLibrary.ps1 - Open PowerShell as your admin account
- Run the script:
.\Clear-PreservationHoldLibrary.ps1 -SiteUrl https://tenant.sharepoint.com/sites/SiteName - Type YES when prompted
Real-World Observations and Lessons Learned
Storage Doesn’t Drop Immediately
In my experience, SharePoint storage metrics can take 24–72 hours to reflect changes. Don’t panic if usage doesn’t drop instantly.
Batch Size Matters
If you hit throttling or timeouts:
- Reduce batch size to 100–200
- Run during off-peak hours
Always Document the Action
Treat this like deleting backups:
- Record approval
- Capture before/after storage metrics
- Keep script output for audit purposes
When You Should NOT Use This Script
Do not use this script if:
- Retention policies are still active
- Legal hold or litigation is ongoing
- You are unsure which data is retained
- Compliance teams have not approved deletion
This script is a scalpel, not a broom.
Final Thoughts
The Preservation Hold Library is one of those SharePoint features that works exactly as designed, yet still catches IT teams off guard.
Understanding how retention actually behaves—and how to safely clean up after it—is a mark of a senior Microsoft 365 administrator, not a junior one.
Used responsibly, this script can:
- Reclaim terabytes of storage
- Reduce licensing costs
- Restore confidence in your SharePoint governance model
Just remember:
Compliance first. Cleanup second.

From my early days on the helpdesk through roles as a service desk manager, systems administrator, and network engineer, I’ve spent more than 25 years in the IT world. As I transition into cyber security, my goal is to make tech a little less confusing by sharing what I’ve learned and helping others wherever I can.
