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
 
许可以下: CC-BY-SA归因
scroll top