Skip to content

Commit c1c9391

Browse files
authored
Merge pull request #854 from pbadoni/main
New PNP Sample: Restore Multiple Items
2 parents aec9c6e + 68b8093 commit c1c9391

File tree

4 files changed

+211
-0
lines changed

4 files changed

+211
-0
lines changed
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
2+
# Restore multiple deleted items from the SharePoint Online Recycle Bin based on deletion date and user name
3+
4+
## Summary
5+
6+
This PowerShell script is designed to help SharePoint Online administrators to restore items from the recycle bin that were deleted by a specific account (such as "System Account" or a SharePoint App) within a user-defined number of days.
7+
8+
9+
10+
## Scenario
11+
12+
Sometimes, there's a need to restore files that were accidentally deleted by users. One common scenario is when a user deletes a synced SharePoint folder without properly disconnecting it first.
13+
14+
## Requirements
15+
16+
To run this PowerShell script successfully, ensure the following:
17+
18+
1. PowerShell Version: [PowerShell 7 or later](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-windows?view=powershell-7.5)
19+
2. PnP PowerShell Module: Installed and imported [(Install-Module PnP.PowerShell)](https://pnp.github.io/powershell/articles/installation.html)
20+
3. [App-Only Authentication](https://github.com/pnp/PnP-PowerShell/tree/master/Samples/SharePoint.ConnectUsingAppPermissions): You must have:
21+
+ A registered Azure AD App with appropriate SharePoint permissions
22+
+ A valid Client ID
23+
+ A certificate installed locally with its thumbprint
24+
4. SharePoint Online Access: The app must have access to the target SharePoint site
25+
5. Log Directory: The specified log directory must exist on the local machine
26+
27+
[More about Restore-PnPRecycleBinItem](https://pnp.github.io/powershell/cmdlets/Restore-PnPRecycleBinItem.html)
28+
29+
# [PnP PowerShell](#tab/pnpps)
30+
31+
```powershell
32+
33+
function Get-UserInput {
34+
[CmdletBinding()]
35+
param ()
36+
37+
try {
38+
$inputData = [ordered]@{}
39+
$inputData["siteURL"] = Read-Host "Enter the SharePoint site URL (e.g., https://yourtenant.sharepoint.com/sites/demo)"
40+
$inputData["tenant"] = Read-Host "Enter your tenant domain (e.g., yourtenant.onmicrosoft.com)"
41+
$inputData["clientID"] = Read-Host "Enter the Azure AD App Client ID"
42+
$inputData["thumbprint"] = Read-Host "Enter the certificate thumbprint"
43+
$inputData["deletedByName"] = Read-Host "Enter the name of the account that deleted the items (e.g., System Account)"
44+
$inputData["logLocation"] = Read-Host "Enter the full path to the log directory (e.g., C:\Temp\Logs)"
45+
$inputData["numberOfDays"] = Read-Host "Enter the number of days to look back for deleted items"
46+
47+
return $inputData
48+
} catch {
49+
Write-Error "Error collecting user input: $_"
50+
exit 1
51+
}
52+
}
53+
54+
function Test-LogDirectoryPath {
55+
param ([string]$Path)
56+
try {
57+
if (-not (Test-Path -Path $Path)) {
58+
throw "Log directory does not exist: $Path"
59+
}
60+
Write-Host "Log directory exists: $Path"
61+
} catch {
62+
Write-Error "Log directory validation failed: $_"
63+
exit 1
64+
}
65+
}
66+
67+
function Connect-ToSharePoint {
68+
param (
69+
[string]$Tenant,
70+
[string]$ClientID,
71+
[string]$Thumbprint,
72+
[string]$SiteURL
73+
)
74+
try {
75+
Connect-PnPOnline -Tenant $Tenant -ClientId $ClientID -Thumbprint $Thumbprint -Url $SiteURL
76+
Write-Host "Connected to SharePoint site: $SiteURL"
77+
} catch {
78+
Write-Error "Failed to connect to SharePoint: $_"
79+
exit 1
80+
}
81+
}
82+
83+
function Restore-RecycleBinItems {
84+
param (
85+
[string]$DeletedByName,
86+
[datetime]$TargetDate,
87+
[int]$BatchSize,
88+
[string]$LogFile
89+
)
90+
91+
try {
92+
$count = 0
93+
Write-Host "Retrieving items deleted by '$DeletedByName' since $TargetDate..."
94+
$items = Get-PnPRecycleBinItem -RowLimit $BatchSize | Where-Object {
95+
$_.DeletedByName -eq $DeletedByName -and $_.DeletedDate -gt $TargetDate
96+
}
97+
98+
foreach ($item in $items) {
99+
$count++
100+
Write-Host "$($item.Id) :::: $($item.Title) :::: $($item.ItemType) :::: $($item.DirName)"
101+
try {
102+
# Comment the next line if you want to skip the restoration and just log the items
103+
Restore-PnPRecycleBinItem -Identity $item.ID -Force
104+
105+
106+
$logEntry = "$count. Deleted Date: $($item.DeletedDate) :: Restored item: $($item.Title) from $($item.DirName)"
107+
Write-Host $logEntry
108+
$logEntry | Out-File -FilePath $LogFile -Append
109+
} catch {
110+
$errorEntry = "$count. Deleted Date: $($item.DeletedDate) :: Failed to restore item: $($item.Title) - $_"
111+
Write-Warning $errorEntry
112+
$errorEntry | Out-File -FilePath $LogFile -Append
113+
}
114+
}
115+
116+
Write-Host "Restoration process completed"
117+
} catch {
118+
Write-Error "Error during recycle bin item restoration: $_"
119+
exit 1
120+
}
121+
}
122+
123+
# === MAIN EXECUTION ===
124+
125+
try {
126+
$userInput = Get-UserInput
127+
128+
$batchSize = 999999
129+
$timeStamp = Get-Date -Format "yyyy-MM-dd-HHmmss"
130+
$targetDate = (Get-Date).AddDays(-[int]$userInput.numberOfDays).Date
131+
$logFileName = Join-Path -Path $userInput.logLocation -ChildPath "RestoreFile_$timeStamp.txt"
132+
133+
Test-LogDirectoryPath -Path $userInput.logLocation
134+
Connect-ToSharePoint -Tenant $userInput.tenant -ClientID $userInput.clientID -Thumbprint $userInput.thumbprint -SiteURL $userInput.siteURL
135+
Restore-RecycleBinItems -DeletedByName $userInput.deletedByName -TargetDate $targetDate -BatchSize $batchSize -LogFile $logFileName
136+
} catch {
137+
Write-Error "Unexpected error occurred: $_"
138+
exit 1
139+
} finally {
140+
try {
141+
Disconnect-PnPOnline
142+
Write-Host "Disconnected from SharePoint."
143+
} catch {
144+
Write-Warning "Failed to disconnect from SharePoint: $_"
145+
}
146+
}
147+
# End of script
148+
```
149+
150+
151+
## Contributors
152+
153+
| Author(s) |
154+
|-----------|
155+
| Pankaj Badoni |
156+
157+
158+
[!INCLUDE [DISCLAIMER](../../docfx/includes/DISCLAIMER.md)]
159+
<img src="https://m365-visitor-stats.azurewebsites.net/script-samples/scripts/spo-restore-multiple-items" aria-hidden="true" />
Loading
Loading
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
[
2+
{
3+
"name": "spo-restore-multiple-items",
4+
"source": "pnp",
5+
"title": "SPO Restore Multiple Items",
6+
"shortDescription": "Sometimes, there's a need to restore files that were accidentally deleted by users. ",
7+
"url": "https://pnp.github.io/script-samples/spo-restore-multiple-items/README.html",
8+
"longDescription": [
9+
"Sometimes, there's a need to restore files that were accidentally deleted by users. One common scenario is when a user deletes a synced SharePoint folder without properly disconnecting it first"
10+
],
11+
"creationDateTime": "2025-06-20",
12+
"updateDateTime": "2025-06-20",
13+
"products": [
14+
"SharePoint"
15+
],
16+
"metadata": [
17+
{
18+
"key": "PNP-POWERSHELL",
19+
"value": "1.11.0"
20+
}
21+
],
22+
"categories": [
23+
"Data"
24+
],
25+
"tags": [
26+
"<Cmdlets-Used>"
27+
],
28+
"thumbnails": [
29+
{
30+
"type": "image",
31+
"order": 100,
32+
"url": "https://raw.githubusercontent.com/pnp/script-samples/main/scripts/spo-restore-multiple-items/assets/preview.png",
33+
"alt": "Preview of the sample spo-restore-multiple-items"
34+
}
35+
],
36+
"authors": [
37+
{
38+
"gitHubAccount": "pbadoni",
39+
"company": "",
40+
"pictureUrl": "https://github.com/pbadoni.png",
41+
"name": "Pankaj Badoni"
42+
}
43+
],
44+
"references": [
45+
{
46+
"name": "Want to learn more about PnP PowerShell and the cmdlets",
47+
"description": "Check out the PnP PowerShell site to get started and for the reference to the cmdlets.",
48+
"url": "https://aka.ms/pnp/powershell"
49+
}
50+
]
51+
}
52+
]

0 commit comments

Comments
 (0)