Bulk-Restore from a Recycle Bin using SharePoint PnP PowerShell
-
16-02-2021 - |
문제
We are trying restore a lot of items from a SharePoint Online recycle bin (100K - 1M ). Is there a PowerShell script that can restore files from a recycle bin in bulk? Ideally, using SharePoint PnP PowerShell.
We are trying to use the
Invoke-PnPSPRestMethod -Method Post -Url $apiCall -Content $BodyAsJson
approach, but it throws an error:
Invoke-PnPSPRestMethod : {"odata.error":{"code":"-1, Microsoft.SharePoint.Client.InvalidClientQueryException", "message":{"lang":"en-us","value":"The parameter CliXml does not exist in method RestoreByIds."}}} at line: 1 char: 1
Current restore script that does not work due to the "CliXml does not exist" error
$SiteURL = "https://contoso.sharepoint.com/sites/Test-LargeRecycleBin"
Connect-PnPOnline -Url $SiteURL -UseWebLogin
# =================================================================== #
# RESTORE RECYCE BIN IN BATCHES USING REST API (Does not work)
# =================================================================== #
$firstLevelItems = @(Get-PnPRecycleBinItem -FirstStage -RowLimit 99999999 | ? DeletedByName -eq 'System Account')
$secondLevelItems = @(Get-PnPRecycleBinItem -SecondStage -RowLimit 99999999 | ? DeletedByName -eq 'System Account')
Write-Host First Stage Recycle Bin Items: $firstLevelItems.Count -ForegroundColor Cyan
Write-Host Second Stage Recycle Bin Items: $secondLevelItems.Count -ForegroundColor Yellow
$restoreSet = $firstLevelItems + $secondLevelItems
Write-Host Both Stages Recycle Bin Items: $restoreSet.Count -ForegroundColor Cyan
$restoreFileSorted = $restoreSet | ?{$_.ItemType -eq "File"} | sort DirName, LeafName
Write-Host Both Stages Recycle Bin, Documents count: $restoreSet.Count -ForegroundColor Yellow
$ErrorActionPreference = "Stop"
$stopWatch = [system.diagnostics.stopwatch]::StartNew()
# TODO: Sample implementation using Azure App registration and OneDrive for Business https://gist.github.com/Smalls1652/048173273fde5d8f87b37700c987915c
# Batch restore up to 200 at a time
$restoreList = $restoreFileSorted | select Id, ItemType, LeafName, DirName
$apiCall = $siteUrl + "/_api/site/RecycleBin/RestoreByIds"
$restoreListCount = $restoreList.count
$start = 0
$leftToProcess = $restoreListCount - $start
while($leftToProcess -gt 0){
If($leftToProcess -lt 200){$numToProcess = $leftToProcess} Else {$numToProcess = 200}
Write-Host -ForegroundColor Yellow "Building statement to restore the following $numToProcess files"
$Ids = @()
for($i=0; $i -lt $numToProcess; $i++){
$cur = $start + $i
$curItem = $restoreList[$cur]
Write-Host -ForegroundColor Green "Adding ", $curItem.ItemType, ": ", $curItem.DirName, "//", $curItem.LeafName
$Ids+=$curItem.Id
}
$Body = @{
"ids" = @($Ids)
}
$BodyAsJson = $Body | ConvertTo-Json
Write-Host -ForegroundColor Yellow $BodyAsJson
Write-Host -ForegroundColor Yellow "Performing API Call to Restore items from RecycleBin..."
try {
Invoke-PnPSPRestMethod -Method Post -Url $apiCall -Content $BodyAsJson ContentType "application/json" | Out-Null
}
catch {
Write-Error "Unable to Restore"
}
$start += 200
$leftToProcess = $restoreListCount - $start
}
$stopWatch.Stop()
Write-Host Time it took to restore $restoreListCount documents from the $($SiteURL+$DestinationFolderUrl) -ForegroundColor Cyan
$stopWatch
I would appreciate any help or pointers!
해결책
OK, this method seems to be working. I hope it's useful for someone else as well.
# =================================================================== #
# Load SharePoint PnP PowerShell Module
# =================================================================== #
Save-module SharePointPnPPowerShellOnline -literalPath .
Import-Module (Get-ChildItem -Recurse -Filter "*.psd1").FullName
$SiteURL = "https://contoso.sharepoint.com/sites/Restore-Test"
Connect-PnPOnline -Url $SiteURL -UseWebLogin
# =================================================================== #
# RESTORE RECYCE BIN IN BATCHES USING REST API
# =================================================================== #
$firstLevelItems = @(Get-PnPRecycleBinItem -FirstStage -RowLimit 99999999 )
$secondLevelItems = @(Get-PnPRecycleBinItem -SecondStage -RowLimit 99999999 )
Write-Host First Stage Recycle Bin Items: $firstLevelItems.Count -ForegroundColor Cyan
Write-Host Second Stage Recycle Bin Items: $secondLevelItems.Count -ForegroundColor Yellow
$restoreSet = $firstLevelItems + $secondLevelItems
Write-Host Both Stages Recycle Bin Items: $restoreSet.Count -ForegroundColor Cyan
$restoreFileSorted = $restoreSet | ?{$_.ItemType -eq "File"} | sort DirName, LeafName
Write-Host Both Stages Recycle Bin, Documents count: $restoreSet.Count -ForegroundColor Yellow
$ErrorActionPreference = "Stop"
function Restore-RecycleBinItem {
param(
[Parameter(Mandatory)]
[String]
$Ids
)
$siteUrl = (Get-PnPSite).Url
$apiCall = $siteUrl + "/_api/site/RecycleBin/RestoreByIds"
$body = "{""ids"":[$($Ids)]}"
Invoke-PnPSPRestMethod -Method Post -Url $apiCall -Content $body
}
$stopWatch = [system.diagnostics.stopwatch]::StartNew()
# Batch restore up to 200 at a time
$restoreList = $restoreFileSorted | select Id, ItemType, LeafName, DirName
$restoreListCount = $restoreList.count
$start = 0
$leftToProcess = $restoreListCount - $start
$stopWatch = [system.diagnostics.stopwatch]::StartNew()
while($leftToProcess -gt 0){
If($leftToProcess -lt 200){$numToProcess = $leftToProcess} Else {$numToProcess = 200}
Write-Host -ForegroundColor Yellow "Building statement to restore the following $numToProcess files"
$Ids = @()
for($i=0; $i -lt $numToProcess; $i++){
$cur = $start + $i
$curItem = $restoreList[$cur]
$Ids+=$curItem.Id
}
Write-Host -ForegroundColor Yellow "Performing API Call to Restore items from RecycleBin..."
$Ids_As_string = [System.String]::Join(",", $($Ids | % {'"'+ $_.tostring() + '"'}))
Restore-RecycleBinItem -Ids $Ids_As_string
$start += 200
$leftToProcess = $restoreListCount - $start
}
$stopWatch.Stop()
Write-Host Time it took to restore $restoreListCount documents from the $($SiteURL+$DestinationFolderUrl) -ForegroundColor Cyan
$stopWatch