diff --git a/src/Commands/RecycleBin/GetRecycleBinItem.cs b/src/Commands/RecycleBin/GetRecycleBinItem.cs index 8b0b4361a..877441023 100644 --- a/src/Commands/RecycleBin/GetRecycleBinItem.cs +++ b/src/Commands/RecycleBin/GetRecycleBinItem.cs @@ -1,11 +1,9 @@ -using System; +using Microsoft.SharePoint.Client; +using PnP.PowerShell.Commands.Utilities; +using System; using System.Collections.Generic; -using System.Linq; using System.Linq.Expressions; using System.Management.Automation; -using Microsoft.SharePoint.Client; - -using PnP.PowerShell.Commands.Base.PipeBinds; namespace PnP.PowerShell.Commands.RecycleBin { @@ -44,7 +42,6 @@ protected override void ExecuteCmdlet() } else { - if (ParameterSpecified(nameof(RowLimit))) { RecycleBinItemState recycleBinStage; @@ -61,51 +58,31 @@ protected override void ExecuteCmdlet() break; } - if (FirstStage.IsPresent || SecondStage.IsPresent) - { - RecycleBinItemCollection items = ClientContext.Site.GetRecycleBinItems(null, RowLimit, false, RecycleBinOrderBy.DeletedDate, recycleBinStage); - ClientContext.Load(items); - ClientContext.ExecuteQueryRetry(); - - List recycleBinItemList = items.ToList(); - WriteObject(recycleBinItemList, true); - } - else - { - ClientContext.Site.Context.Load(ClientContext.Site.RecycleBin, r => r.IncludeWithDefaultProperties(RetrievalExpressions)); - ClientContext.Site.Context.ExecuteQueryRetry(); - - List recycleBinItemList = ClientContext.Site.RecycleBin.ToList(); - recycleBinItemList = recycleBinItemList.Take(RowLimit).ToList(); - WriteObject(recycleBinItemList, true); - } - - + List recycleBinItemList = RecycleBinUtility.GetRecycleBinItems(ClientContext, RowLimit, recycleBinStage); + WriteObject(recycleBinItemList, true); } else { - ClientContext.Site.Context.Load(ClientContext.Site.RecycleBin, r => r.IncludeWithDefaultProperties(RetrievalExpressions)); - ClientContext.Site.Context.ExecuteQueryRetry(); - - List recycleBinItemList = ClientContext.Site.RecycleBin.ToList(); - + List recycleBinItemList; switch (ParameterSetName) { case ParameterSet_FIRSTSTAGE: - WriteObject( - recycleBinItemList.Where(i => i.ItemState == RecycleBinItemState.FirstStageRecycleBin), true); + recycleBinItemList = RecycleBinUtility.GetRecycleBinItems(ClientContext, RowLimit, RecycleBinItemState.FirstStageRecycleBin); + WriteObject(recycleBinItemList, true); break; case ParameterSet_SECONDSTAGE: - WriteObject( - recycleBinItemList.Where(i => i.ItemState == RecycleBinItemState.SecondStageRecycleBin), - true); + recycleBinItemList = RecycleBinUtility.GetRecycleBinItems(ClientContext, RowLimit, RecycleBinItemState.SecondStageRecycleBin); + WriteObject(recycleBinItemList, true); break; default: + recycleBinItemList = RecycleBinUtility.GetRecycleBinItems(ClientContext, RowLimit); WriteObject(recycleBinItemList, true); break; } } } } + + } } diff --git a/src/Commands/Utilities/RecycleBinUtility.cs b/src/Commands/Utilities/RecycleBinUtility.cs new file mode 100644 index 000000000..0b5587ef0 --- /dev/null +++ b/src/Commands/Utilities/RecycleBinUtility.cs @@ -0,0 +1,65 @@ +using Microsoft.SharePoint.Client; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; + +namespace PnP.PowerShell.Commands.Utilities +{ + internal static class RecycleBinUtility + { + internal static List GetRecycleBinItems(ClientContext ctx, int? rowLimit = null, RecycleBinItemState recycleBinStage = RecycleBinItemState.None) + { + var recycleBinItems = new List(); + string pagingInfo = null; + RecycleBinItemCollection items; + + // This part is only here to make debugging easier if you ever run into issues with this code :) + //ctx.Load(ctx.Site.RecycleBin); + //ctx.ExecuteQueryRetry(); + //var totalRecyclebinContentsCount = ctx.Site.RecycleBin.Count; + + do + { + // We don't actually know what the List View Threshold for the Recycle Bin is, so we'll use the safe number (5000) and implement paging. + int iterationRowLimit; + if (rowLimit.HasValue && rowLimit.Value >= 5000) + { + // Subtract this page's count from the rowLimit (we don't want duplicates or go out of bounds) + if (rowLimit.HasValue) rowLimit -= 5000; + + iterationRowLimit = 5000; + } + else if (rowLimit.HasValue && rowLimit.Value > 0 && rowLimit.Value < 5000) + { + iterationRowLimit = rowLimit.Value; + } + else // rowLimit was not set, just fetch a "whole page" + { + iterationRowLimit = 5000; + } + + items = ctx.Site.GetRecycleBinItems(pagingInfo, iterationRowLimit, false, RecycleBinOrderBy.DefaultOrderBy, recycleBinStage); + ctx.Load(items); + ctx.ExecuteQueryRetry(); + recycleBinItems.AddRange(items.ToList()); + + // Paging magic (if needed) + // Based on this work our good friends at Portiva did ❤ + // https://www.portiva.nl/portiblog/blogs-cat/paging-through-sharepoint-recycle-bin + if (items.Count > 0) + { + var nextId = items.Last().Id; + //var nextTitle = items.Last().Title; + var nextTitle = WebUtility.UrlEncode(items.Last().Title); + //var deletionTime = items.Last().DeletedDate; + pagingInfo = $"id={nextId}&title={nextTitle}"; // &searchValue=${deletionTime} + } + } + while (items?.Count == 5000); // if items had 5000 items, there might be more since that's the page size we're using + + return recycleBinItems; + } + } +}