diff --git a/Binaries/SharePointPnP.Modernization.Framework.dll b/Binaries/SharePointPnP.Modernization.Framework.dll index 4c1019ef7..bf92de04e 100644 Binary files a/Binaries/SharePointPnP.Modernization.Framework.dll and b/Binaries/SharePointPnP.Modernization.Framework.dll differ diff --git a/Binaries/SharePointPnP.Modernization.Framework.xml b/Binaries/SharePointPnP.Modernization.Framework.xml index 9c14de428..cbe1c6eeb 100644 --- a/Binaries/SharePointPnP.Modernization.Framework.xml +++ b/Binaries/SharePointPnP.Modernization.Framework.xml @@ -1664,14 +1664,14 @@ Order inside the row/column A web part entity to add to the collection - + Does the tree of nodes somewhere contain a web part? Html content to analyze True if it contains a web part - + Strips the div holding the web part from the html @@ -1714,7 +1714,7 @@ - + Gets the tag prefixes from the document @@ -1845,7 +1845,7 @@ element to check true if embedded in a already processed element - + Analyzes the wiki page to determine which layout was used diff --git a/Binaries/release/SharePointPnP.Modernization.Framework.dll b/Binaries/release/SharePointPnP.Modernization.Framework.dll index 4b3804fa2..6b675c741 100644 Binary files a/Binaries/release/SharePointPnP.Modernization.Framework.dll and b/Binaries/release/SharePointPnP.Modernization.Framework.dll differ diff --git a/Binaries/release/SharePointPnP.Modernization.Framework.xml b/Binaries/release/SharePointPnP.Modernization.Framework.xml index 9c14de428..cbe1c6eeb 100644 --- a/Binaries/release/SharePointPnP.Modernization.Framework.xml +++ b/Binaries/release/SharePointPnP.Modernization.Framework.xml @@ -1664,14 +1664,14 @@ Order inside the row/column A web part entity to add to the collection - + Does the tree of nodes somewhere contain a web part? Html content to analyze True if it contains a web part - + Strips the div holding the web part from the html @@ -1714,7 +1714,7 @@ - + Gets the tag prefixes from the document @@ -1845,7 +1845,7 @@ element to check true if embedded in a already processed element - + Analyzes the wiki page to determine which layout was used diff --git a/CHANGELOG.md b/CHANGELOG.md index b3b34297b..c7a4a6b3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,23 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). -## [3.26.2010.0 - unreleased] +## [3.28.2012.0] + +### Added + +### Changed +- Small fixes to README.md +- Fixed several issues with `Get-PnPSubwebs` and introduced optional parameter `-IncludeRootWeb` to include the rootweb in the results +- Change in `Copy-PnPFile` which should resolve some issues you may run into when copying files [PR #2796](https://github.com/pnp/PnP-PowerShell/pull/2796) +- Changed fallback scenario for 'Get-PnPFile' where downloading a file created by a user that no longer exists would try a different technique to download the file. This only worked on English environments though. With this fix, it should work for any language. [PR #2852](https://github.com/pnp/PnP-PowerShell/pull/2852) + +### Contributors +- David Blaszyk [acornsoft] +- Koen Zomers [koenzomers] +- Carlos Marins Jr [kadu-jr] +- Heinrich Ulbricht [heinrich-ulbricht] + +## [3.26.2010.0] ### Added - Added `Set-PnPTenant -EnableAutoNewsDigest` option to disable the automatic news digest mails sent to end users [PR #2901](https://github.com/pnp/PnP-PowerShell/pull/2901) diff --git a/Commands/Base/ConnectOnline.cs b/Commands/Base/ConnectOnline.cs index 2b9e93a36..086277883 100644 --- a/Commands/Base/ConnectOnline.cs +++ b/Commands/Base/ConnectOnline.cs @@ -656,6 +656,14 @@ protected void Connect() Url = Url.Substring(0, Url.Length - 1); } +#if !ONPREMISES + if (!PnPConnectionHelper.LegacyMessageShown) + { + WriteUpdateMessage("\nYou are running the legacy version of PnP PowerShell.\nThis version will be archived soon which means that while staying available, no updates or fixes will be released.\nConsider installing the newer prereleased cross-platform version of PnP PowerShell:\n\nUninstall-Module -Name SharePointPnPPowerShellOnline -AllVersions -Force\nInstall-Module -Name PnP.PowerShell -AllowPrerelease\n\nRead more about the new cross-platform version of PnP PowerShell at\n\nhttps://pnp.github.io/powershell\n\nThe new version of PnP PowerShell will be released as 1.0 in January 2021.\n"); + PnPConnectionHelper.LegacyMessageShown = true; + } +#endif + PnPConnection connection = null; var latestVersion = PnPConnectionHelper.GetLatestVersion(); diff --git a/Commands/Base/PnPConnectionHelper.cs b/Commands/Base/PnPConnectionHelper.cs index 07934887b..9498fd4f1 100644 --- a/Commands/Base/PnPConnectionHelper.cs +++ b/Commands/Base/PnPConnectionHelper.cs @@ -36,6 +36,7 @@ internal class PnPConnectionHelper private static readonly Uri VersionCheckUrl = new Uri("https://raw.githubusercontent.com/pnp/PnP-PowerShell/master/version.txt"); #endif private static bool VersionChecked; + internal static bool LegacyMessageShown; #if !PNPPSCORE public static AuthenticationContext AuthContext { get; set; } diff --git a/Commands/Base/RegisterPnPManagementShellAccess.cs b/Commands/Base/RegisterPnPManagementShellAccess.cs index a2dc165af..bdfbabfce 100644 --- a/Commands/Base/RegisterPnPManagementShellAccess.cs +++ b/Commands/Base/RegisterPnPManagementShellAccess.cs @@ -20,17 +20,15 @@ public class RegisterPnPManagementShellAccess : PSCmdlet public AzureEnvironment AzureEnvironment = AzureEnvironment.Production; [Parameter(Mandatory = true)] + [Obsolete("This parameter will be ignored")] public string SiteUrl; protected override void ProcessRecord() { var endPoint = GenericToken.GetAzureADLoginEndPoint(AzureEnvironment); - var uri = new Uri(SiteUrl); - var scopes = new[] { $"{uri.Scheme}://{uri.Authority}//.default" }; - + var application = PublicClientApplicationBuilder.Create(PnPConnection.PnPManagementShellClientId).WithAuthority($"{endPoint}/organizations/").WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient").Build(); - var result = application.AcquireTokenInteractive(scopes).ExecuteAsync().GetAwaiter().GetResult(); - result = application.AcquireTokenInteractive(new[] { "https://graph.microsoft.com/.default" }).ExecuteAsync().GetAwaiter().GetResult(); + application.AcquireTokenInteractive(new[] { "https://graph.microsoft.com/.default" }).ExecuteAsync().GetAwaiter().GetResult(); } } diff --git a/Commands/Fields/AddField.cs b/Commands/Fields/AddField.cs index bd85eef3d..202e987cf 100644 --- a/Commands/Fields/AddField.cs +++ b/Commands/Fields/AddField.cs @@ -70,6 +70,10 @@ public class AddField : PnPWebCmdlet, IDynamicParameters [Parameter(Mandatory = false, ParameterSetName = ParameterSet_ADDFIELDBYXMLTOLIST, HelpMessage = "The group name to where this field belongs to")] public string Group; + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_ADDFIELDTOLIST, HelpMessage = "Switch Parameter if this field must be added to all content types")] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_ADDFIELDBYXMLTOLIST, HelpMessage = "Switch Parameter if this field must be added to all content types")] + public SwitchParameter AddToAllContentTypes; + #if !ONPREMISES [Parameter(Mandatory = false, ParameterSetName = ParameterSet_ADDFIELDTOLIST, HelpMessage = "The Client Side Component Id to set to the field")] [Parameter(Mandatory = false, ParameterSetName = ParameterSet_ADDFIELDTOWEB, HelpMessage = "The Client Side Component Id to set to the field")] @@ -122,6 +126,10 @@ protected override void ExecuteCmdlet() Group = Group, AddToDefaultView = AddToDefaultView }; + + if (AddToAllContentTypes) + fieldCI.FieldOptions |= AddFieldOptions.AddToAllContentTypes; + #if !ONPREMISES if (ClientSideComponentId != null) { diff --git a/Commands/Files/CopyFile.cs b/Commands/Files/CopyFile.cs index 5782231ad..82fff2323 100644 --- a/Commands/Files/CopyFile.cs +++ b/Commands/Files/CopyFile.cs @@ -109,8 +109,9 @@ protected override void ExecuteCmdlet() TargetUrl = UrlUtility.Combine(webServerRelativeUrl, TargetUrl); } + string sourceFolder = SourceUrl.Substring(0, SourceUrl.LastIndexOf('/')); Uri currentContextUri = new Uri(ClientContext.Url); - Uri sourceUri = new Uri(currentContextUri, SourceUrl); + Uri sourceUri = new Uri(currentContextUri, sourceFolder); Uri sourceWebUri = Microsoft.SharePoint.Client.Web.WebUrlFromFolderUrlDirect(ClientContext, sourceUri); Uri targetUri = new Uri(currentContextUri, TargetUrl); Uri targetWebUri = Microsoft.SharePoint.Client.Web.WebUrlFromFolderUrlDirect(ClientContext, targetUri); diff --git a/Commands/Files/GetFile.cs b/Commands/Files/GetFile.cs index 2b3849c75..b14af3b53 100644 --- a/Commands/Files/GetFile.cs +++ b/Commands/Files/GetFile.cs @@ -128,8 +128,9 @@ protected override void ExecuteCmdlet() ClientContext.Load(file, f => f.Author, f => f.Length, f => f.ModifiedBy, f => f.Name, f => f.TimeCreated, f => f.TimeLastModified, f => f.Title); ClientContext.ExecuteQueryRetry(); } - catch (ServerException e) when (e.Message == "User cannot be found.") + catch (ServerException) { + // Assume the cause of the exception is that a principal cannot be found and try again without: // Fallback in case the creator or person having last modified the file no longer exists in the environment such that the file can still be downloaded ClientContext.Load(file, f => f.Length, f => f.Name, f => f.TimeCreated, f => f.TimeLastModified, f => f.Title); ClientContext.ExecuteQueryRetry(); diff --git a/Commands/Model/AzureApp.cs b/Commands/Model/AzureApp.cs index 687792a7e..dcc11bb80 100644 --- a/Commands/Model/AzureApp.cs +++ b/Commands/Model/AzureApp.cs @@ -130,6 +130,12 @@ public PermissionScopes() Id = "3db89e36-7fa6-4012-b281-85f3d9d9fd2e", Identifier = "MSGraph.AppCatalog.Submit" }); + scopes.Add(new PermissionScope() + { + resourceAppId = "00000003-0000-0000-c000-000000000000", + Id = "19dbc75e-c2e2-444c-a770-ec69d8559fc7", + Identifier = "MSGraph.Directory.ReadWrite.All" + }); #endregion #region SPO // SPO diff --git a/Commands/PnP.PowerShell.Commands.csproj b/Commands/PnP.PowerShell.Commands.csproj index df26e5ec1..9d8eb619c 100644 --- a/Commands/PnP.PowerShell.Commands.csproj +++ b/Commands/PnP.PowerShell.Commands.csproj @@ -402,8 +402,11 @@ - - ..\packages\AngleSharp.0.9.9\lib\net45\AngleSharp.dll + + ..\packages\AngleSharp.0.14.0\lib\net461\AngleSharp.dll + + + ..\packages\AngleSharp.Css.0.14.2\lib\net461\AngleSharp.Css.dll ..\packages\Microsoft.ApplicationInsights.2.8.1\lib\net45\Microsoft.ApplicationInsights.dll @@ -535,6 +538,9 @@ ..\packages\System.Spatial.5.8.4\lib\net40\System.Spatial.dll + + ..\packages\System.Text.Encoding.CodePages.4.5.0\lib\net461\System.Text.Encoding.CodePages.dll + ..\packages\System.Text.Encodings.Web.4.7.1\lib\net461\System.Text.Encodings.Web.dll diff --git a/Commands/Properties/AssemblyInfo.cs b/Commands/Properties/AssemblyInfo.cs index 093ba319b..529e6e0b5 100644 --- a/Commands/Properties/AssemblyInfo.cs +++ b/Commands/Properties/AssemblyInfo.cs @@ -51,8 +51,8 @@ // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] #if !PNPPSCORE -[assembly: AssemblyVersion("3.26.2010.0")] -[assembly: AssemblyFileVersion("3.26.2010.0")] +[assembly: AssemblyVersion("3.28.2012.0")] +[assembly: AssemblyFileVersion("3.28.2012.0")] #else [assembly: AssemblyVersion("4.0.0.0")] [assembly: AssemblyFileVersion("4.0.0.0")] diff --git a/Commands/Search/GetSearchConfiguration.cs b/Commands/Search/GetSearchConfiguration.cs index b14e98cd1..63e604636 100644 --- a/Commands/Search/GetSearchConfiguration.cs +++ b/Commands/Search/GetSearchConfiguration.cs @@ -156,7 +156,7 @@ RefinableString100 1000000900 */ int p; if (!int.TryParse(pid, out p)) return pid; - if (p <= 1000000000) return pid; + if (p < 1000000000) return pid; var autoMpNum = pid.Substring(pid.Length - 2); var mpName = pid; diff --git a/Commands/Utilities/TeamsUtility.cs b/Commands/Utilities/TeamsUtility.cs index 1426ce4a3..f66202058 100644 --- a/Commands/Utilities/TeamsUtility.cs +++ b/Commands/Utilities/TeamsUtility.cs @@ -458,7 +458,7 @@ public static async Task AddChannelAsync(string accessToken, HttpCl channel.Type = "#Microsoft.Teams.Core.channel"; var user = await GraphHelper.GetAsync(httpClient, $"v1.0/users/{ownerUPN}", accessToken); channel.Members = new List(); - channel.Members.Add(new TeamChannelMember() { Roles = new List { "owner" }, UserIdentifier = $"https://graph.microsoft.com/beta/users/('{user.Id}')" }); + channel.Members.Add(new TeamChannelMember() { Roles = new List { "owner" }, UserIdentifier = $"https://graph.microsoft.com/beta/users('{user.Id}')" }); return await GraphHelper.PostAsync(httpClient, $"beta/teams/{groupId}/channels", channel, accessToken); } else diff --git a/Commands/Web/GetSubwebs.cs b/Commands/Web/GetSubwebs.cs index a8d8f2f26..cfe4f62d9 100644 --- a/Commands/Web/GetSubwebs.cs +++ b/Commands/Web/GetSubwebs.cs @@ -13,7 +13,7 @@ namespace PnP.PowerShell.Commands [CmdletHelp("Returns the subwebs of the current web", Category = CmdletHelpCategory.Webs, OutputType = typeof(Web), - OutputTypeLink = "https://msdn.microsoft.com/en-us/library/microsoft.sharepoint.client.web.aspx")] + OutputTypeLink = "https://docs.microsoft.com/previous-versions/office/sharepoint-server/ee537040(v=office.15)")] [CmdletExample( Code = @"PS:> Get-PnPSubWebs", Remarks = "Retrieves all subsites of the current context returning the Id, Url, Title and ServerRelativeUrl of each subsite in the output", @@ -28,8 +28,12 @@ namespace PnP.PowerShell.Commands SortOrder = 3)] [CmdletExample( Code = @"PS:> Get-PnPSubWebs -Identity Team1 -Recurse", - Remarks = "Retrieves all subsites of the subsite Team1 and all of its nested child subsites returning the Id, Url, Title and ServerRelativeUrl of each subsite in the output", + Remarks = "Retrieves all subsites of the subsite Team1 and all of its nested child subsites", SortOrder = 4)] + [CmdletExample( + Code = @"PS:> Get-PnPSubWebs -Identity Team1 -Recurse -IncludeRootWeb", + Remarks = "Retrieves the rootweb, all subsites of the subsite Team1 and all of its nested child subsites", + SortOrder = 5)] public class GetSubWebs : PnPWebRetrievalsCmdlet { [Parameter(Mandatory = false, ValueFromPipeline = true, Position = 0, HelpMessage = "If provided, only the subsite with the provided Id, GUID or the Web instance will be returned")] @@ -38,29 +42,69 @@ public class GetSubWebs : PnPWebRetrievalsCmdlet [Parameter(Mandatory = false, HelpMessage = "If provided, recursion through all subsites and their children will take place to return them as well")] public SwitchParameter Recurse; + [Parameter(Mandatory = false, HelpMessage = "If provided, the results will also contain the rootweb")] + public SwitchParameter IncludeRootWeb; + protected override void ExecuteCmdlet() { DefaultRetrievalExpressions = new Expression>[] { w => w.Id, w => w.Url, w => w.Title, w => w.ServerRelativeUrl }; Web parentWeb = SelectedWeb; + List results = new List(); + if(IncludeRootWeb) + { + parentWeb.EnsureProperties(RetrievalExpressions); + results.Add(parentWeb); + } + if (Identity != null) { - if (Identity.Id != Guid.Empty) + try { - parentWeb = parentWeb.GetWebById(Identity.Id); + if (Identity.Id != Guid.Empty) + { + parentWeb = parentWeb.GetWebById(Identity.Id); + } + else if (Identity.Web != null) + { + parentWeb = Identity.Web; + } + else if (Identity.Url != null) + { + parentWeb = parentWeb.GetWebByUrl(Identity.Url); + } } - else if (Identity.Web != null) + catch(ServerException e) when (e.ServerErrorTypeName.Equals("System.IO.FileNotFoundException")) { - parentWeb = Identity.Web; + throw new PSArgumentException($"No subweb found with the provided id or url", nameof(Identity)); } - else if (Identity.Url != null) + + if (parentWeb != null) { - parentWeb = parentWeb.GetWebByUrl(Identity.Url); + if (Recurse) + { + results.Add(parentWeb); + results.AddRange(GetSubWebsInternal(parentWeb.Webs, Recurse)); + } + else + { + results.Add(parentWeb); + } } + else + { + throw new PSArgumentException($"No subweb found with the provided id or url", nameof(Identity)); + } + } + else + { + ClientContext.Load(parentWeb.Webs); + ClientContext.ExecuteQueryRetry(); + + results.AddRange(GetSubWebsInternal(parentWeb.Webs, Recurse)); } - var allWebs = GetSubWebsInternal(parentWeb.Webs, Recurse); - WriteObject(allWebs, true); + WriteObject(results, true); } private List GetSubWebsInternal(WebCollection subsites, bool recurse) diff --git a/Commands/packages.config b/Commands/packages.config index 94d1da130..b98c4c509 100644 --- a/Commands/packages.config +++ b/Commands/packages.config @@ -1,6 +1,7 @@  - + + @@ -47,6 +48,7 @@ + diff --git a/README.md b/README.md index 99a1c7ddd..32f504cc6 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,13 @@ This solution contains a library of PowerShell commands that allows you to perfo ![SharePoint Patterns and Practices](https://devofficecdn.azureedge.net/media/Default/PnP/sppnp.png) > **Important:** -> This repository will be retired by the end of 2020. As of the GA of the Cross-Platform [PnP.PowerShell](https://github.com/pnp/pnp.powershell) we will only maintain that version going forward. +> This repository will be retired by the end of 2020. As of the GA of the Cross-Platform [PnP.PowerShell](https://github.com/pnp/powershell) we will only maintain that version going forward. ![PnP PowerShell RoadMap](PnP_PowerShell_Roadmap.png) # I've found a bug, where do I need to log an issue or create a PR -Between now and the end of 2020 both [PnP-PowerShell](https://github.com/pnp/pnp-powershell) and [PnP.PowerShell](https://github.com/pnp/powershell) are actively maintained. Once the new PnP PowerShell becomes generally available (GA) we will stop mainting the old repository. +Between now and the end of 2020 both [PnP-PowerShell](https://github.com/pnp/pnp-powershell) and [PnP.PowerShell](https://github.com/pnp/powershell) are actively maintained. Once the new PnP PowerShell becomes generally available (GA) we will stop maintaining the old repository. Given that the cross-platform PnP PowerShell is our future going forward we would prefer issues and PRs being created in the new https://github.com/pnp/powershell repository. If you want your PR to apply to both then it is recommend to create the PR in both repositories for the time being. diff --git a/version.txt b/version.txt index 639fcf7a9..c705f8e91 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -3.26.2010.0 \ No newline at end of file +3.28.2012.0 \ No newline at end of file