Collaborate, Innovate, Automate

Search-RecycleBin

This PnP PowerShell script searches a SharePoint Online site collection's recycle bin — both first-stage (user-deleted) and second-stage (site collection recycle bin) — for items whose name, title, or original path contains a given search string. It's a quicker way to confirm whether a specific file or folder was deleted, when, and by whom, than paging through the recycle bin UI, and it works right up until the 93-day retention window closes the second-stage bin out for good. For background on why that window matters and what it doesn't cover, see SharePoint and OneDrive: Archive vs Backup — What Each Solves (and What They Don't).

Purpose

Scope

Prerequisites

PowerShell Script

# ============================================================
# Search-RecycleBin.ps1
# Searches a SharePoint Online site collection recycle bin
# (first and second stage) for items whose name, title, or
# original path contains a given string.
# ============================================================

<#
.SYNOPSIS
    Searches a SharePoint Online site collection recycle bin (first and second stage)
    for items whose name, title or original path contains a given string.
#>

# ===================== CONFIG — change these =====================
$SiteUrl      = "https://tenantName.sharepoint.com/sites/siteName"
$ClientId     = ""
$SearchString = ""          # text to look for (case-insensitive)
$ExportCsv    = $true             # set to $false to skip CSV export
$CsvPath      = ".\RecycleBinSearch_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv"
# =================================================================

try {
    Connect-PnPOnline -Url $SiteUrl -ClientId $ClientId -Interactive -ErrorAction Stop
    Write-Host "Connected to $SiteUrl" -ForegroundColor Green
}
catch {
    Write-Error "Failed to connect: $($_.Exception.Message)"
    return
}

Write-Host "Retrieving recycle bin items (first + second stage)..." -ForegroundColor Cyan
$allItems = Get-PnPRecycleBinItem -RowLimit 999999

Write-Host "Total items in recycle bin: $($allItems.Count)" -ForegroundColor Cyan

$pattern = "*$SearchString*"
$matches = $allItems | Where-Object {
    $_.LeafName -like $pattern -or
    $_.Title    -like $pattern -or
    $_.DirName  -like $pattern
}

if (-not $matches) {
    Write-Host "No items found matching '$SearchString'." -ForegroundColor Yellow
    Disconnect-PnPOnline
    return
}

$results = $matches | Select-Object `
    @{ N = 'Name';         E = { $_.LeafName } },
    @{ N = 'Title';        E = { $_.Title } },
    @{ N = 'OriginalPath'; E = { $_.DirName } },
    @{ N = 'ItemType';     E = { $_.ItemType } },
    @{ N = 'Stage';        E = { $_.ItemState } },
    @{ N = 'DeletedBy';    E = { $_.DeletedByEmail } },
    @{ N = 'DeletedDate';  E = { $_.DeletedDate } },
    @{ N = 'SizeKB';       E = { [math]::Round($_.Size / 1KB, 1) } },
    @{ N = 'Id';           E = { $_.Id } }

Write-Host "Found $($results.Count) matching item(s):" -ForegroundColor Green
$results | Sort-Object DeletedDate -Descending | Format-Table Name, OriginalPath, ItemType, Stage, DeletedBy, DeletedDate -AutoSize

if ($ExportCsv) {
    $results | Export-Csv -Path $CsvPath -NoTypeInformation -Encoding UTF8
    Write-Host "Exported to $CsvPath" -ForegroundColor Green
}

# ---- Optional: restore the matches (uncomment to use) ----
# $matches | ForEach-Object { Restore-PnPRecycleBinItem -Identity $_.Id -Force }

Disconnect-PnPOnline

Usage Notes

Related