In Blogs, Techblog

When you remove an item within SharePoint it is not directly gone, it’s safely stored in your recycle bin. Nowadays with the boundaries in SharePoint it is stored in the recycle bin for up to 93 days depending on several factors. Restoring an item is as simple as browsing to the recycle bin, selecting the item and clicking the restore button.

When you have removed more items, you can use the infinite scroll in the modern UI or paging in the classic UI to locate the item and restore it manually. This is no problem when you have a couple of hundred files in there, it requires some time, but it is possible.

Now imagine that one of the users in your tenant has synced several libraries with the OneDrive client to their local machine. One day they decide it is time to clean-up as there is not a lot of disk space left, instead of stopping the synchronization before removing the files they just remove them. Now suddenly the recycle bin, that already had a lot of items, has a couple of thousand more files in there. Even to the point that SharePoint is not telling you how many items are in there and display’s 0 as the number of items in there.

Opening the recycle bin will show a lot of items, now it is your task to restore them, but just the items that are removed by that specific user between a specific time range.

First run

As it is a lot of items you need to restore you can use scripts in PowerShell to help you out. The first attempt could be to use CSOM in PowerShell and try to read the site collection recycle bin

$recycleBin = $clientcontext.Site.RecycleBin
$clientcontext.Load($recycleBin) 
$clientcontext.ExecuteQuery()

Again, this will not give you any problems loading the items if you stay within the boundaries and limits of SharePoint. Exceeding these will give you an error on calling the ExecuteQuery method on loading the $recycleBin.

Page through the recycle bin

Searching for a solution will probably bring you to the methods GetRecycleBinItems and GetRecycleBinItemsByQueryInfo on the Web object. The first method requests a couple of parameters where the second one requests an object with the same parameters appended with some extra options. Most properties are straight forward and by checking out some enumeration give a clear indication on how to use them.

Using the PagingInfo property

There is one property, the “PagingInfo”, that requests a string value without any explanation on how to format this string. I was not able to find any documentation on the value required to successfully execute the method. This required some digging into how the recycle bin page in SharePoint handled this kind of requests.

Starting out in the classic experience, so the recycle bin provides the paging controls, and the developer tool bar it turns out a JavaScript function named NextPage is called. This function is submitting a form “document.forms[“usrpage”]” from the page. This form seems to hold the answer for the PagingInfo property.

The usrpage form has a hidden input “nextItemCollectionPosition” with a value that is build with an id, title and searchvalue. These values are added to the input with url encoding.

id=<last-item-id>&title=<last-item-title>&searchValue=<last-item-deletion-datetime>

The data for the id and title are of the last item visible on the current page, the searchValue contains a datetime value with the deletion time of the last item.

Modify the PowerShell script

Using the id and title bit for the PagingInfo property seems to do the trick to get past the first page, as the first page accepts an empty value.

Calling the first batch of items will be:

$recycleBinQuery = New-Object Microsoft.SharePoint.Client.RecycleBinQueryInformation
$recycleBinQuery.ShowOnlyMyItems = $false
$recycleBinQuery.IsAscending = $false

$recycledItems = $clientContext.Web.GetRecycleBinItemsByQueryInfo($recycleBinQuery)
$clientContext.Load($recycledItems)
$clientContext.ExecuteQuery()

Using the results of this call will enable you to get the id and title value for your next call. To get the results of the second page you can use the following code

#Code for the last item in the result set
$nextId = $recycledItem.Id
$nextTitle = [System.Web.HttpUtility]::UrlEncode($recycledItem.Title)

#Code to fetch page 2
$recycleBinQuery = New-Object Microsoft.SharePoint.Client.RecycleBinQueryInformation
$recycleBinQuery.ShowOnlyMyItems = $false
$recycleBinQuery.IsAscending = $false
$recycleBinQuery.PagingInfo = "id=$($nextId)&title=$($nextTitle)"

$recycledItems = $clientContext.Web.GetRecycleBinItemsByQueryInfo($recycleBinQuery)
$clientContext.Load($recycledItems)
$clientContext.ExecuteQuery()

Restore items

While using the GetRecycleBinItemsByQueryInfo, or the GetRecycleBinItems, will give you the possibility to page through the recycle bin it will deliver restore issues. Items that you deleted yourself can be restored from the objects in the returned collection. When you try to restore an item that is removed by someone else it will present you an error.

The collection of items from the recycle bin does contain the item id. The initial thought is to then use the (Site/Web).RecycleBin.GetById method to retrieve that specific item and to then restore it. This works perfectly if you do not exceed the view thresholds in the recycle bin. If you exceed these an error will be thrown telling you that you exceed the thresholds.

As you have a client context you can request authentication cookies so you can call REST endpoints. However, if you call the “_api/site/RecycleBin(‘$($itemGuid)’)/Restore” endpoint it will give you an internal server error when you exceed the threshold. When you stay within the thresholds is will succeed and restore the item.

Conclusion

Using paging in the recycle bin to restore items when the thresholds are exceeded works fine if you only need to restore the items you removed yourself. The challenge will be a lot harder when you need to restore items removed by another person.

Vul je zoekopdracht in.