From c007e3a6be4c77c7232551aacaa7df1e40f4fe20 Mon Sep 17 00:00:00 2001 From: Hussey Date: Wed, 24 Jun 2020 10:11:35 -0700 Subject: [PATCH 1/6] Added RowLimit parameter to Clear-PnPRecycleBinItem (re: #2315) --- Commands/RecycleBin/ClearRecycleBinItem.cs | 55 ++++++++++++++++++---- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/Commands/RecycleBin/ClearRecycleBinItem.cs b/Commands/RecycleBin/ClearRecycleBinItem.cs index 610cad6d2..920881109 100644 --- a/Commands/RecycleBin/ClearRecycleBinItem.cs +++ b/Commands/RecycleBin/ClearRecycleBinItem.cs @@ -21,6 +21,13 @@ namespace SharePointPnP.PowerShell.Commands.RecycleBin Code = @"PS:> Clear-PnpRecycleBinItem -Identity $item -Force", Remarks = "Permanently deletes the recycle bin item stored under variable $item from the recycle bin without asking for confirmation from the end user first", SortOrder = 3)] +#if !SP2013 + [CmdletExample( + Code = @"PS:> Clear-PnPRecycleBinItem -All -RowLimit 10000", + Remarks = "Permanently deletes up to 10,000 items in recycle bin", + SortOrder = 4)] +#endif + public class ClearRecycleBinItem : PnPSharePointCmdlet { [Parameter(Mandatory = true, HelpMessage = "Id of the recycle bin item or the recycle bin item itself to permanently delete", ValueFromPipeline = true, ParameterSetName = "Identity")] @@ -36,6 +43,10 @@ public class ClearRecycleBinItem : PnPSharePointCmdlet [Parameter(Mandatory = false, HelpMessage = "If provided, no confirmation will be asked to permanently delete the recycle bin item")] public SwitchParameter Force; +#if !SP2013 + [Parameter(Mandatory = false, HelpMessage = "Limits deletion to specified number of items", ParameterSetName = "All")] + public int RowLimit = -1; +#endif protected override void ExecuteCmdlet() { @@ -52,21 +63,40 @@ protected override void ExecuteCmdlet() } break; case "All": -#if !ONPREMISES - if (SecondStageOnly) +#if !SP2013 + if (HasRowLimit()) { - if (Force || ShouldContinue(Resources.ClearSecondStageRecycleBin, Resources.Confirm)) - { - ClientContext.Site.RecycleBin.DeleteAllSecondStageItems(); + if (Force || ShouldContinue(SecondStageOnly ? Resources.ClearSecondStageRecycleBin : Resources.ClearBothRecycleBins, Resources.Confirm)) { + RecycleBinItemState recycleBinStage = SecondStageOnly ? RecycleBinItemState.SecondStageRecycleBin : RecycleBinItemState.None; + + RecycleBinItemCollection items = ClientContext.Site.GetRecycleBinItems(null, RowLimit, false, RecycleBinOrderBy.DeletedDate, + recycleBinStage); + ClientContext.Load(items); + ClientContext.ExecuteQueryRetry(); + + items.DeleteAll(); ClientContext.ExecuteQueryRetry(); } } else +#endif { - if (Force || ShouldContinue(Resources.ClearBothRecycleBins, Resources.Confirm)) +#if !ONPREMISES + if (SecondStageOnly) { - ClientContext.Site.RecycleBin.DeleteAll(); - ClientContext.ExecuteQueryRetry(); + if (Force || ShouldContinue(Resources.ClearSecondStageRecycleBin, Resources.Confirm)) + { + ClientContext.Site.RecycleBin.DeleteAllSecondStageItems(); + ClientContext.ExecuteQueryRetry(); + } + } + else + { + if (Force || ShouldContinue(Resources.ClearBothRecycleBins, Resources.Confirm)) + { + ClientContext.Site.RecycleBin.DeleteAll(); + ClientContext.ExecuteQueryRetry(); + } } } break; @@ -76,9 +106,18 @@ protected override void ExecuteCmdlet() ClientContext.Site.RecycleBin.DeleteAll(); ClientContext.ExecuteQueryRetry(); } + } break; #endif } } + +#if !SP2013 + private bool HasRowLimit() + { + return RowLimit > 0; + } +#endif + } } From 6e856e2bd6e5ade3d925cdb491c760d2544010d2 Mon Sep 17 00:00:00 2001 From: Koen Zomers Date: Thu, 25 Jun 2020 00:15:05 +0200 Subject: [PATCH 2/6] Added changelog entry --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6c3f1998..f5815b3c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,10 +8,12 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). ## [3.23.2007.0] (not yet released) ### Added +- Added a `-RowLimit` parameter to `Clear-PnPRecycleBinItem` so that it can be used on recycle bins which hold more than 5000 items [PR #2760](https://github.com/pnp/PnP-PowerShell/pull/2760) ### Changed ### Contributors +- Ellie Hussey [Professr] ## [3.22.2006.2] From 956e8f0c1d0c291a74a89c5997642953d4a9e164 Mon Sep 17 00:00:00 2001 From: Koen Zomers Date: Thu, 25 Jun 2020 00:15:14 +0200 Subject: [PATCH 3/6] Cleanup of code --- Commands/RecycleBin/ClearRecycleBinItem.cs | 39 ++++++++++------------ 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/Commands/RecycleBin/ClearRecycleBinItem.cs b/Commands/RecycleBin/ClearRecycleBinItem.cs index 920881109..c0d583dca 100644 --- a/Commands/RecycleBin/ClearRecycleBinItem.cs +++ b/Commands/RecycleBin/ClearRecycleBinItem.cs @@ -6,8 +6,9 @@ namespace SharePointPnP.PowerShell.Commands.RecycleBin { - [Cmdlet(VerbsCommon.Clear, "PnPRecycleBinItem", DefaultParameterSetName = "All")] + [Cmdlet(VerbsCommon.Clear, "PnPRecycleBinItem", DefaultParameterSetName = PARAMETERSET_ALL)] [CmdletHelp("Permanently deletes all or a specific recycle bin item", + SupportedPlatform = CmdletSupportedPlatform.All, Category = CmdletHelpCategory.RecycleBin)] [CmdletExample( Code = @"PS:> Get-PnPRecycleBinItem | ? FileLeafName -like ""*.docx"" | Clear-PnpRecycleBinItem", @@ -30,47 +31,49 @@ namespace SharePointPnP.PowerShell.Commands.RecycleBin public class ClearRecycleBinItem : PnPSharePointCmdlet { - [Parameter(Mandatory = true, HelpMessage = "Id of the recycle bin item or the recycle bin item itself to permanently delete", ValueFromPipeline = true, ParameterSetName = "Identity")] + const string PARAMETERSET_ALL = "All"; + const string PARAMETERSET_IDENTITY = "Identity"; + + [Parameter(Mandatory = true, HelpMessage = "Id of the recycle bin item or the recycle bin item itself to permanently delete", ValueFromPipeline = true, ParameterSetName = PARAMETERSET_IDENTITY)] public RecycleBinItemPipeBind Identity; - [Parameter(Mandatory = false, ParameterSetName = "All", HelpMessage = "Clears all items")] + [Parameter(Mandatory = false, ParameterSetName = PARAMETERSET_ALL, HelpMessage = "Clears all items")] public SwitchParameter All; #if !ONPREMISES - [Parameter(Mandatory = false, HelpMessage = "If provided, only all the items in the second stage recycle bin will be cleared", ParameterSetName = "All")] + [Parameter(Mandatory = false, HelpMessage = "If provided, only all the items in the second stage recycle bin will be cleared", ParameterSetName = PARAMETERSET_ALL)] public SwitchParameter SecondStageOnly = false; #endif [Parameter(Mandatory = false, HelpMessage = "If provided, no confirmation will be asked to permanently delete the recycle bin item")] public SwitchParameter Force; #if !SP2013 - [Parameter(Mandatory = false, HelpMessage = "Limits deletion to specified number of items", ParameterSetName = "All")] - public int RowLimit = -1; + [Parameter(Mandatory = false, HelpMessage = "Limits deletion to specified number of items", ParameterSetName = PARAMETERSET_ALL)] + public int RowLimit; #endif protected override void ExecuteCmdlet() { switch (ParameterSetName) { - case "Identity": + case PARAMETERSET_IDENTITY: var recycleBinItem = Identity.GetRecycleBinItem(ClientContext.Site); - if (Force || - ShouldContinue(string.Format(Resources.ClearRecycleBinItem, recycleBinItem.LeafName), Resources.Confirm)) + if (Force || ShouldContinue(string.Format(Resources.ClearRecycleBinItem, recycleBinItem.LeafName), Resources.Confirm)) { recycleBinItem.DeleteObject(); ClientContext.ExecuteQueryRetry(); } break; - case "All": + case PARAMETERSET_ALL: #if !SP2013 - if (HasRowLimit()) + if (ParameterSpecified(nameof(RowLimit))) { - if (Force || ShouldContinue(SecondStageOnly ? Resources.ClearSecondStageRecycleBin : Resources.ClearBothRecycleBins, Resources.Confirm)) { + if (Force || ShouldContinue(SecondStageOnly ? Resources.ClearSecondStageRecycleBin : Resources.ClearBothRecycleBins, Resources.Confirm)) + { RecycleBinItemState recycleBinStage = SecondStageOnly ? RecycleBinItemState.SecondStageRecycleBin : RecycleBinItemState.None; - RecycleBinItemCollection items = ClientContext.Site.GetRecycleBinItems(null, RowLimit, false, RecycleBinOrderBy.DeletedDate, - recycleBinStage); + RecycleBinItemCollection items = ClientContext.Site.GetRecycleBinItems(null, RowLimit, false, RecycleBinOrderBy.DeletedDate, recycleBinStage); ClientContext.Load(items); ClientContext.ExecuteQueryRetry(); @@ -111,13 +114,5 @@ protected override void ExecuteCmdlet() #endif } } - -#if !SP2013 - private bool HasRowLimit() - { - return RowLimit > 0; - } -#endif - } } From aff48aedc45a6348e3359287577be81ece1f3dc7 Mon Sep 17 00:00:00 2001 From: Koen Zomers Date: Thu, 25 Jun 2020 00:18:09 +0200 Subject: [PATCH 4/6] Minor changes to align it with Clear-PnPRecycleBinItem --- Commands/RecycleBin/GetRecycleBinItem.cs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/Commands/RecycleBin/GetRecycleBinItem.cs b/Commands/RecycleBin/GetRecycleBinItem.cs index 4d3f80cad..f5c29de61 100644 --- a/Commands/RecycleBin/GetRecycleBinItem.cs +++ b/Commands/RecycleBin/GetRecycleBinItem.cs @@ -57,7 +57,7 @@ public class GetRecycleBinItems : PnPRetrievalsCmdlet [Parameter(Mandatory = false, HelpMessage = "Limits return results to specified amount", ParameterSetName = ParameterSet_FIRSTSTAGE)] [Parameter(Mandatory = false, HelpMessage = "Limits return results to specified amount", ParameterSetName = ParameterSet_SECONDSTAGE)] [Parameter(Mandatory = false, HelpMessage = "Limits return results to specified amount", ParameterSetName = ParameterSet_ALL)] - public int RowLimit = -1; + public int RowLimit; #endif protected override void ExecuteCmdlet() { @@ -73,7 +73,7 @@ protected override void ExecuteCmdlet() else { #if !SP2013 - if (HasRowLimit()) + if (ParameterSpecified(nameof(RowLimit))) { RecycleBinItemState recycleBinStage; switch (ParameterSetName) @@ -148,12 +148,5 @@ protected override void ExecuteCmdlet() #endif } } - -#if !SP2013 - private bool HasRowLimit() - { - return RowLimit > 0; - } -#endif } } From d88e8a800479fbea911229d037f42fed23be5fe9 Mon Sep 17 00:00:00 2001 From: Koen Zomers Date: Thu, 25 Jun 2020 00:37:23 +0200 Subject: [PATCH 5/6] Added RowLimit to Restore-PnPRecycleBinItem as well, ensured the approach is consistent accross all three *-RecycleBinItem cmdlets --- Commands/RecycleBin/ClearRecycleBinItem.cs | 5 +- Commands/RecycleBin/GetRecycleBinItem.cs | 8 +- Commands/RecycleBin/RestoreRecycleBinItem.cs | 80 ++++++++++++++------ 3 files changed, 62 insertions(+), 31 deletions(-) diff --git a/Commands/RecycleBin/ClearRecycleBinItem.cs b/Commands/RecycleBin/ClearRecycleBinItem.cs index c0d583dca..5c76c7ce0 100644 --- a/Commands/RecycleBin/ClearRecycleBinItem.cs +++ b/Commands/RecycleBin/ClearRecycleBinItem.cs @@ -25,7 +25,7 @@ namespace SharePointPnP.PowerShell.Commands.RecycleBin #if !SP2013 [CmdletExample( Code = @"PS:> Clear-PnPRecycleBinItem -All -RowLimit 10000", - Remarks = "Permanently deletes up to 10,000 items in recycle bin", + Remarks = "Permanently deletes up to 10,000 items in the recycle bin", SortOrder = 4)] #endif @@ -44,7 +44,8 @@ public class ClearRecycleBinItem : PnPSharePointCmdlet [Parameter(Mandatory = false, HelpMessage = "If provided, only all the items in the second stage recycle bin will be cleared", ParameterSetName = PARAMETERSET_ALL)] public SwitchParameter SecondStageOnly = false; #endif - [Parameter(Mandatory = false, HelpMessage = "If provided, no confirmation will be asked to permanently delete the recycle bin item")] + [Parameter(Mandatory = false, HelpMessage = "If provided, no confirmation will be asked to restore the recycle bin item", ParameterSetName = PARAMETERSET_IDENTITY)] + [Parameter(Mandatory = false, HelpMessage = "If provided, no confirmation will be asked to restore the recycle bin item", ParameterSetName = PARAMETERSET_ALL)] public SwitchParameter Force; #if !SP2013 diff --git a/Commands/RecycleBin/GetRecycleBinItem.cs b/Commands/RecycleBin/GetRecycleBinItem.cs index f5c29de61..b02690b96 100644 --- a/Commands/RecycleBin/GetRecycleBinItem.cs +++ b/Commands/RecycleBin/GetRecycleBinItem.cs @@ -14,7 +14,7 @@ namespace SharePointPnP.PowerShell.Commands.RecycleBin Category = CmdletHelpCategory.RecycleBin, OutputType = typeof(RecycleBinItem), SupportedPlatform = CmdletSupportedPlatform.All, - OutputTypeLink = "https://docs.microsoft.com/en-us/previous-versions/office/sharepoint-server/ee541897(v=office.15)")] + OutputTypeLink = "https://docs.microsoft.com/previous-versions/office/sharepoint-server/ee541897(v=office.15)")] [CmdletExample( Code = @"PS:> Get-PnPRecycleBinItem", Remarks = "Returns all items in both the first and the second stage recycle bins in the current site collection", @@ -89,14 +89,12 @@ protected override void ExecuteCmdlet() break; } - RecycleBinItemCollection items = ClientContext.Site.GetRecycleBinItems(null, RowLimit, false, RecycleBinOrderBy.DeletedDate, - recycleBinStage); + RecycleBinItemCollection items = ClientContext.Site.GetRecycleBinItems(null, RowLimit, false, RecycleBinOrderBy.DeletedDate, recycleBinStage); ClientContext.Load(items); ClientContext.ExecuteQueryRetry(); List recycleBinItemList = items.ToList(); WriteObject(recycleBinItemList, true); - } else { @@ -107,7 +105,6 @@ protected override void ExecuteCmdlet() switch (ParameterSetName) { - case ParameterSet_FIRSTSTAGE: WriteObject( recycleBinItemList.Where(i => i.ItemState == RecycleBinItemState.FirstStageRecycleBin), true); @@ -121,7 +118,6 @@ protected override void ExecuteCmdlet() WriteObject(recycleBinItemList, true); break; } - } #else ClientContext.Site.Context.Load(ClientContext.Site.RecycleBin, r => r.IncludeWithDefaultProperties(RetrievalExpressions)); diff --git a/Commands/RecycleBin/RestoreRecycleBinItem.cs b/Commands/RecycleBin/RestoreRecycleBinItem.cs index 880419770..72c6e2dec 100644 --- a/Commands/RecycleBin/RestoreRecycleBinItem.cs +++ b/Commands/RecycleBin/RestoreRecycleBinItem.cs @@ -1,4 +1,5 @@ -using System.Management.Automation; +using System; +using System.Management.Automation; using Microsoft.SharePoint.Client; using SharePointPnP.PowerShell.CmdletHelpAttributes; using SharePointPnP.PowerShell.Commands.Base.PipeBinds; @@ -6,8 +7,9 @@ namespace SharePointPnP.PowerShell.Commands.RecycleBin { - [Cmdlet(VerbsData.Restore, "PnPRecycleBinItem")] + [Cmdlet(VerbsData.Restore, "PnPRecycleBinItem", DefaultParameterSetName = PARAMETERSET_ALL)] [CmdletHelp("Restores the provided recycle bin item to its original location", + SupportedPlatform = CmdletSupportedPlatform.All, Category = CmdletHelpCategory.RecycleBin)] [CmdletExample( Code = @"PS:> Restore-PnpRecycleBinItem -Identity 72e4d749-d750-4989-b727-523d6726e442", @@ -17,40 +19,72 @@ namespace SharePointPnP.PowerShell.Commands.RecycleBin Code = @"PS:> Get-PnPRecycleBinItem | ? -Property LeafName -like ""*.docx"" | Restore-PnpRecycleBinItem", Remarks = "Restores all the items in the first and second stage recycle bins to their original location of which the filename ends with the .docx extension", SortOrder = 2)] +#if !SP2013 + [CmdletExample( + Code = @"PS:> Restore-PnPRecycleBinItem -All -RowLimit 10000", + Remarks = "Permanently restores up to 10,000 items in the recycle bin", + SortOrder = 4)] +#endif public class RestoreRecycleBinItem : PnPSharePointCmdlet { - [Parameter(Mandatory = true, HelpMessage = "Id of the recycle bin item or the recycle bin item object itself to restore", ValueFromPipeline = true, ParameterSetName = "Identity")] + const string PARAMETERSET_ALL = "All"; + const string PARAMETERSET_IDENTITY = "Identity"; + + [Parameter(Mandatory = true, HelpMessage = "Id of the recycle bin item or the recycle bin item object itself to restore", ValueFromPipeline = true, ParameterSetName = PARAMETERSET_IDENTITY)] public RecycleBinItemPipeBind Identity; - [Parameter(Mandatory = true, HelpMessage = "If provided all items will be stored ", ValueFromPipeline = true, ParameterSetName = "All")] + [Parameter(Mandatory = false, HelpMessage = "If provided all items will be stored ", ValueFromPipeline = true, ParameterSetName = PARAMETERSET_ALL)] + [Obsolete("No need to add the -All parameter anymore")] public SwitchParameter All; - [Parameter(Mandatory = false, HelpMessage = "If provided, no confirmation will be asked to restore the recycle bin item")] + [Parameter(Mandatory = false, HelpMessage = "If provided, no confirmation will be asked to restore the recycle bin item", ParameterSetName = PARAMETERSET_IDENTITY)] + [Parameter(Mandatory = false, HelpMessage = "If provided, no confirmation will be asked to restore the recycle bin item", ParameterSetName = PARAMETERSET_ALL)] public SwitchParameter Force; +#if !SP2013 + [Parameter(Mandatory = false, HelpMessage = "Limits restoration to specified number of items", ParameterSetName = PARAMETERSET_ALL)] + public int RowLimit; +#endif protected override void ExecuteCmdlet() { - if (ParameterSetName == "Identity") - { - var recycleBinItem = Identity.GetRecycleBinItem(ClientContext.Site); - - if (Force || - ShouldContinue(string.Format(Resources.RestoreRecycleBinItem, recycleBinItem.LeafName), - Resources.Confirm)) - { - recycleBinItem.Restore(); - ClientContext.ExecuteQueryRetry(); - } - } - else + switch (ParameterSetName) { - if (Force || ShouldContinue(Resources.RestoreRecycleBinItems, Resources.Confirm)) - { - ClientContext.Site.RecycleBin.RestoreAll(); - ClientContext.ExecuteQueryRetry(); - } + case PARAMETERSET_IDENTITY: + var recycleBinItem = Identity.GetRecycleBinItem(ClientContext.Site); + + if (Force || ShouldContinue(string.Format(Resources.RestoreRecycleBinItem, recycleBinItem.LeafName), Resources.Confirm)) + { + recycleBinItem.Restore(); + ClientContext.ExecuteQueryRetry(); + } + break; + + case PARAMETERSET_ALL: +#if !SP2013 + if (ParameterSpecified(nameof(RowLimit))) + { + if (Force || ShouldContinue(Resources.RestoreRecycleBinItems, Resources.Confirm)) + { + RecycleBinItemCollection items = ClientContext.Site.GetRecycleBinItems(null, RowLimit, false, RecycleBinOrderBy.DeletedDate, RecycleBinItemState.None); + ClientContext.Load(items); + ClientContext.ExecuteQueryRetry(); + + items.RestoreAll(); + ClientContext.ExecuteQueryRetry(); + } + } + else +#endif + { + if (Force || ShouldContinue(Resources.RestoreRecycleBinItems, Resources.Confirm)) + { + ClientContext.Site.RecycleBin.RestoreAll(); + ClientContext.ExecuteQueryRetry(); + } + } + break; } } } From 371521e0404b683171d79a60f76f689cad8f5b56 Mon Sep 17 00:00:00 2001 From: Koen Zomers Date: Thu, 25 Jun 2020 00:52:27 +0200 Subject: [PATCH 6/6] Updated changelog to include Restore-PnPRecycleBinItem as well --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab9c8de96..6af9c256f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). ## [3.23.2007.0] (not yet released) ### Added -- Added a `-RowLimit` parameter to `Clear-PnPRecycleBinItem` so that it can be used on recycle bins which hold more than 5000 items [PR #2760](https://github.com/pnp/PnP-PowerShell/pull/2760) +- Added a `-RowLimit` parameter to `Clear-PnPRecycleBinItem` and `Restore-PnPRecycleBinItem` so that it can be used on recycle bins which hold more than 5000 items [PR #2760](https://github.com/pnp/PnP-PowerShell/pull/2760) ### Changed - Fixed issue where using `Disconnect-PnPOnline -Connection $variable` after having connected using `$variable = Connect-PnPOnline -CertificatePath -ReturnConnection`, it would not clean up the certificate on that connection instance passed in by $variable, but instead try to do it on the current connection context [PR #2755](https://github.com/pnp/PnP-PowerShell/pull/2755)