Bulk-restoring the SharePoint recycle bin: the PnP PowerShell script, and when you want something else

If you've landed here from a search for Get-PnPRecycleBinItem or "restore thousands of files SharePoint", you already know the native recycle bin can't do this. Here is the script that can, exactly where it stops working, and an honest comparison with Undelete365 — which we make, so read the last section with that in mind.

The script

This is the standard approach, and it works. It restores everything one person deleted after a given date, from the recycle bin of one site:

# Requires PowerShell 7 and the PnP.PowerShell module
Install-Module PnP.PowerShell -Scope CurrentUser

# Since 2024 you need your own Entra app registration for -Interactive
Connect-PnPOnline -Url "https://contoso.sharepoint.com/sites/finance" `
  -Interactive -ClientId "<your-app-client-id>"

$since = Get-Date "2026-09-16"
$who   = "[email protected]"

Get-PnPRecycleBinItem -RowLimit 5000 |
  Where-Object { $_.DeletedByEmail -eq $who -and $_.DeletedDate -ge $since } |
  Restore-PnPRecycleBinItem -Force

Run it without Restore-PnPRecycleBinItem -Force first and you get a preview of what would be restored. That's your dry-run.

Where it breaks

None of these are the script's fault. They are SharePoint's limits, and every admin who has used this pipeline on a real incident has hit at least one:

Side by side

PnP PowerShell scriptUndelete365
CostFreeSearch free · restore €249 once per tenant
Where it runsYour machine, PowerShell 7In the browser, on a SharePoint page, as the signed-in user
SetupModule install + Entra app registration + consentAdmin uploads one .sppkg to the App Catalog; no app registration, zero API permissions
Find items byAny property you can write a Where-Object forName, who deleted it, date range, original location
Preview before restoreRun without the restore stepMandatory dry-run showing the exact matches
Large bins2,000-row paging; threshold errors on very large binsPages in batches, built for 100,000+ items
Throttling (429/503)Fails the item; you add sleepsWaits exactly as Retry-After instructs, then continues
Resume after interruptionRe-run from the startRe-run the same criteria; already-restored items are gone from the bin, so it continues where it stopped
FailuresConsole outputPer-item reason, exportable as CSV
Second-stage bin-SecondStageOnly, needs site collection adminSeparate tab, same admin requirement (SharePoint's rule)
Can it delete anything?Yes — the same module has Clear-PnPRecycleBinItem; a typo awayNo — no removal endpoint exists in the code or the compiled bundle, and a verifier script proves it
Automation / schedulingYesNo — it's an interactive tool
Works with custom scripting disabledN/A (runs outside SharePoint)Yes — standard SPFx, requiresCustomScript: false

When the script is the right choice

Genuinely, not as a courtesy:

When a web part is the right choice

Neither is a backup. Both only work while items are still in the recycle bin — 93 days across both stages. After that, only a backup product that was already capturing the tenant can help. If you need that, look at Microsoft 365 Backup or a third-party backup vendor, not at either of these.

Try the free tier first. Searching and filtering the whole bin is free, with no form and no key, so you can confirm it finds your files before deciding whether the restore is worth €249.

Download the free package Read the FAQ