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:
- Large bins.
Get-PnPRecycleBinItempages through the bin, but very large bins (the PnP script samples warn from roughly 400,000 items) start throwing list-view-threshold errors, and the cmdlet's own paging caps at 2,000 rows per call. The incident that needs bulk restore is usually the incident with a huge bin. - Throttling. Restoring items one by one at PowerShell speed gets you HTTP 429 and 503 responses. The script has no back-off; it just fails on those items. You add
Start-Sleep, rerun, and hope. - No resume. Close the window, lose the network, or hit an unhandled error at item 2,140 of 4,800 and you're re-running the filter and re-scanning the bin from the start.
- Setup on a bad day. The module install, the app registration (the shared "PnP Management Shell" app was retired in 2024, so every tenant now needs its own), and the "Connect-SPOService is not recognized" round on Microsoft Q&A all happen while the files are still missing.
- Two-stage bins. Items that have already dropped to the second-stage (site collection) bin need
-SecondStageOnlyand site collection admin rights. Easy to miss, easy to double-count. - Name conflicts. If someone recreated a folder with the same name in the meantime, the restore fails for that item and the script moves on. You find out by reading the console.
Side by side
| PnP PowerShell script | Undelete365 | |
|---|---|---|
| Cost | Free | Search free · restore €249 once per tenant |
| Where it runs | Your machine, PowerShell 7 | In the browser, on a SharePoint page, as the signed-in user |
| Setup | Module install + Entra app registration + consent | Admin uploads one .sppkg to the App Catalog; no app registration, zero API permissions |
| Find items by | Any property you can write a Where-Object for | Name, who deleted it, date range, original location |
| Preview before restore | Run without the restore step | Mandatory dry-run showing the exact matches |
| Large bins | 2,000-row paging; threshold errors on very large bins | Pages in batches, built for 100,000+ items |
| Throttling (429/503) | Fails the item; you add sleeps | Waits exactly as Retry-After instructs, then continues |
| Resume after interruption | Re-run from the start | Re-run the same criteria; already-restored items are gone from the bin, so it continues where it stopped |
| Failures | Console output | Per-item reason, exportable as CSV |
| Second-stage bin | -SecondStageOnly, needs site collection admin | Separate tab, same admin requirement (SharePoint's rule) |
| Can it delete anything? | Yes — the same module has Clear-PnPRecycleBinItem; a typo away | No — no removal endpoint exists in the code or the compiled bundle, and a verifier script proves it |
| Automation / scheduling | Yes | No — it's an interactive tool |
| Works with custom scripting disabled | N/A (runs outside SharePoint) | Yes — standard SPFx, requiresCustomScript: false |
When the script is the right choice
Genuinely, not as a courtesy:
- You're comfortable in PowerShell and the bin is small enough that the limits above don't bite.
- You need to run it on a schedule or as part of an automated process.
- You need one pass across many site collections at once — Undelete365 works per site, on the page where you add it.
- You can't get a package into your App Catalog, or you don't want to.
When a web part is the right choice
- The person doing the restore is a site owner, not a PowerShell user — the "too scared to play with scripts" case is the most common one we hear.
- The bin is large, the restore is urgent, and you don't want to discover the throttling and threshold limits mid-incident.
- You want the preview, the resume, and the failure report without writing them yourself.
- A security reviewer wants to know exactly what the tool can and cannot do to the tenant. The published list of every SharePoint call it makes is here.
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