diff --git a/CHANGELOG.md b/CHANGELOG.md index 211bcf726..d0451ccf5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,52 @@ 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.2.1810.0] Unreleased +## [3.4.1812.0] + +### Added + +### Changed + +### Deprecated + +### Contributors + +## [3.3.1811.0] +### Added + +### Changed +- Copy-PnPFile now supports special characters like '&' in file names +- Updated New-PnPSite to support language/locale for new sites. +- Updated documentation for New-PnPTenantSite +- Fixed documentation for Measure-PnPWeb, Set-PnPSite +- Updated samples +- Fixes issue with Set-PnPUnifiedGroup where if you only change for instance the displayname a private group would be marked as public. +- Renamed (and created aliases for the old cmdlet name) Apply-PnPProvisioningHierarchy to Apply-PnPTenantTemplate +- Renamed (and created aliases for the old cmdlet name) Add-PnPProvisioningSequence to Add-PnPTenantSequence +- Renamed (and created aliases for the old cmdlet name) Add-PnPProvisioningSite to Add-PnPTenantSequenceSite +- Renamed (and created aliases for the old cmdlet name) Add-PnPPnPProvisioningSubSite to Add-PnPTenantSequenceSubSite +- Renamed (and created aliases for the old cmdlet name) Get-PnPProvisioningSequence to Get-PnPTenantSequence +- Renamed (and created aliases for the old cmdlet name) Get-PnPProvisioningSite to Get-PnPTenantSequenceSite +- Renamed (and created aliases for the old cmdlet name) New-PnPProvisioningSequence to New-PnPTenantSequence +- Renamed (and created aliases for the old cmdlet name) New-PnPProvisioningTeamSite to New-PnPTenantSequenceTeamSite +- Renamed (and created aliases for the old cmdlet name) New-PnPProvisioningCommunicationSite to New-PnPTenantSequenceCommunicationSite +- Renamed (and created aliases for the old cmdlet name) New-PnPProvisioningTeamNoGroupSite to New-PnPTenantSequenceTeamNoGroupSite +- Renamed (and created aliases for the old cmdlet name) New-PnPProvisioningTeamNoGroupSubSite to New-PnPTenantSequenceTeamNoGroupSubSite +- Renamed (and created aliases for the old cmdlet name) New-PnPProvisioningHierarchy to New-PnPTenantTemplate +- Renamed (and created aliases for the old cmdlet name) Read-PnPProvisioningHierarchy to Read-PnPTenantTemplate +- Renamed (and created aliases for the old cmdlet name) Save-PnPProvisioningHierarchy to Save-PnPTenantTemplate +- Renamed (and created aliases for the old cmdlet name) Test-PnPProvisioningHierarchy to Test-PnPTenantTemplate + +### Deprecated +- Marked Get-PnPProvisioningTemplateFromGallery as deprecated as the PnP Template Gallery has been shut down. + +### Contributors +- Paul Bullock (pkbullock) +- François-Xavier Cat (lazywinadmin) +- Koen Zomers (KoenZomers) +- Kevin McDonnell (kevmcdonk) + +## [3.2.1810.0] Released ### Added - Add-PnPProvisioningSequence : Adds an in-memory sequence to an in-memory provisioning hierarchy - Add-PnPProvisioningSite : Adds an in-memory site definition to a in-memory sequence diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a6e7bfd2b..6cf0de83c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,6 +14,8 @@ Please see following page for additional insights on the model. ## Building the source code ## +Once you have downloaded the code, in the folder with the PnP PowerShell source code, open the solution file SharePointPnP.PowerShell.sln. + If you have set up up the projects and you are ready to build the source code, make sure to build the SharePointPnP.PowerShellModuleFilesGenerator project first. This project will be executed after every build and it will generate the required PSD1 and XML files with cmdlet documentation in them. When you build the solution a postbuild script will copy the required files to a folder in your users folder called @@ -23,7 +25,7 @@ To debug the cmdlets: launch PowerShell and attach Visual Studio to the powershe ## Code contributions In order to succesfully compile the PnP PowerShell solution you will _also_ have to download *and build in Visual Studio* the [PnP-Sites-Core](https://github.com/OfficeDev/PnP-Sites-Core) repository and make the dev branch available. The PowerShell solution depends on it. In order to succesfully -compile it, make sure that PnP-Sites-Core is located at the same level as PnP-PowerShell. +compile it, make sure that PnP-Sites-Core is located at the same level as PnP-PowerShell and you open the solution file OfficeDevPnP.Core.sln located in the Core subfolder of the sourcecode. So: ``` diff --git a/Commands/Admin/GrantHubSiteRights.cs b/Commands/Admin/GrantHubSiteRights.cs index a514cc949..796da63aa 100644 --- a/Commands/Admin/GrantHubSiteRights.cs +++ b/Commands/Admin/GrantHubSiteRights.cs @@ -4,26 +4,26 @@ using SharePointPnP.PowerShell.CmdletHelpAttributes; using SharePointPnP.PowerShell.Commands.Base; using SharePointPnP.PowerShell.Commands.Base.PipeBinds; -using System; using System.Management.Automation; namespace SharePointPnP.PowerShell.Commands.Admin { [Cmdlet(VerbsSecurity.Grant, "PnPHubSiteRights")] - [CmdletHelp(@"Grant Permissions to associate sites to Hub Sites.", + [CmdletHelp(@"Grant additional permissions to the permissions already in place to associate sites to Hub Sites for one or more specific users", Category = CmdletHelpCategory.TenantAdmin, SupportedPlatform = CmdletSupportedPlatform.Online)] - [CmdletExample(Code = @"PS:> Grant-PnPHubSiteRights -Identity https://contoso.sharepoint.com/sites/hubsite -Principals ""myuser@mydomain.com"",""myotheruser@mydomain.com"" -Rights Join", Remarks = "This example shows how to grant right to myuser and myotheruser to associate their sites with hubsite", SortOrder = 1)] + [CmdletExample(Code = @"PS:> Grant-PnPHubSiteRights -Identity https://contoso.sharepoint.com/sites/hubsite -Principals ""myuser@mydomain.com"",""myotheruser@mydomain.com"" -Rights Join", Remarks = "This example shows how to grant rights to myuser and myotheruser to associate their sites with the provided Hub Site", SortOrder = 1)] + [CmdletExample(Code = @"PS:> Grant-PnPHubSiteRights -Identity https://contoso.sharepoint.com/sites/hubsite -Principals ""myuser@mydomain.com"" -Rights None", Remarks = "This example shows how to revoke rights from myuser to associate their sites with the provided Hub Site", SortOrder = 2)] public class GrantHubSiteRights : PnPAdminCmdlet { - [Parameter(Position = 0, ValueFromPipeline = true, Mandatory = true)] + [Parameter(Position = 0, ValueFromPipeline = true, Mandatory = true, HelpMessage = "The Hub Site to set the permissions on to associate another site with this Hub Site")] [Alias("HubSite")] public HubSitePipeBind Identity { get; set; } - [Parameter(Mandatory = true)] + [Parameter(Mandatory = true, HelpMessage = "One or more usernames that will be given or revoked the permission to associate a site with this Hub Site. It does not replace permissions given out before but adds to the already existing permissions.")] public string[] Principals { get; set; } - [Parameter(Mandatory = true)] + [Parameter(Mandatory = true, HelpMessage = "Provide Join to give permissions to associate a site with this Hub Site or use None to revoke the permissions for the user(s) specified with the Principals argument")] public SPOHubSiteUserRights Rights { get; set; } protected override void ExecuteCmdlet() diff --git a/Commands/Admin/NewSite.cs b/Commands/Admin/NewSite.cs index 17c4fc725..e71d09c1b 100644 --- a/Commands/Admin/NewSite.cs +++ b/Commands/Admin/NewSite.cs @@ -1,20 +1,15 @@ #if !ONPREMISES -using System; using System.Management.Automation; using Microsoft.SharePoint.Client; -using OfficeDevPnP.Core; -using OfficeDevPnP.Core.Entities; using SharePointPnP.PowerShell.CmdletHelpAttributes; -using SharePointPnP.PowerShell.Commands.Base; -using Resources = SharePointPnP.PowerShell.Commands.Properties.Resources; -using System.Threading.Tasks; using SharePointPnP.PowerShell.Commands.Base.PipeBinds; using SharePointPnP.PowerShell.Commands.Enums; +using System; namespace SharePointPnP.PowerShell.Commands { [Cmdlet(VerbsCommon.New, "PnPSite")] - [CmdletHelp("BETA: This cmdlet is using early release APIs. Notice that functionality and parameters can change. Creates a new site collection", + [CmdletHelp("Creates a new site collection", "The New-PnPSite cmdlet creates a new site collection for the current tenant. Currently only 'modern' sites like Communication Site and the Modern Team Site are supported. If you want to create a classic site, use New-PnPTenantSite.", OutputType = typeof(string), OutputTypeDescription = "Returns the url of the newly created site collection", @@ -36,17 +31,25 @@ namespace SharePointPnP.PowerShell.Commands Remarks = @"This will create a new Communications Site collection with the title 'Contoso' and the url 'https://tenant.sharepoint.com/sites/contoso'. The classification for the site will be set to ""HBI""", SortOrder = 4)] [CmdletExample( - Code = @"PS:> New-PnPSite -Type CommunicationSite -Title Contoso -Url https://tenant.sharepoint.com/sites/contoso -AllowFileSharingForGuestUsers", - Remarks = @"This will create a new Communications Site collection with the title 'Contoso' and the url 'https://tenant.sharepoint.com/sites/contoso'. File sharing for guest users will be enabled.", + Code = @"PS:> New-PnPSite -Type CommunicationSite -Title Contoso -Url https://tenant.sharepoint.com/sites/contoso -ShareByEmailEnabled", + Remarks = @"This will create a new Communications Site collection with the title 'Contoso' and the url 'https://tenant.sharepoint.com/sites/contoso'. Allows owners to invite users outside of the organization.", SortOrder = 5)] + [CmdletExample( + Code = @"PS:> New-PnPSite -Type CommunicationSite -Title Contoso -Url https://tenant.sharepoint.com/sites/contoso -Lcid 1044", + Remarks = @"This will create a new Communications Site collection with the title 'Contoso' and the url 'https://tenant.sharepoint.com/sites/contoso' and sets the default language to Italian.", + SortOrder = 6)] [CmdletExample( Code = @"PS:> New-PnPSite -Type TeamSite -Title 'Team Contoso' -Alias contoso", Remarks = @"This will create a new Modern Team Site collection with the title 'Team Contoso' and the url 'https://tenant.sharepoint.com/sites/contoso' or 'https://tenant.sharepoint.com/teams/contoso' based on the managed path configuration in the SharePoint Online Admin portal.", - SortOrder = 6)] + SortOrder = 7)] [CmdletExample( Code = @"PS:> New-PnPSite -Type TeamSite -Title 'Team Contoso' -Alias contoso -IsPublic", Remarks = @"This will create a new Modern Team Site collection with the title 'Team Contoso' and the url 'https://tenant.sharepoint.com/sites/contoso' or 'https://tenant.sharepoint.com/teams/contoso' based on the managed path configuration in the SharePoint Online Admin portal and sets the site to public.", - SortOrder = 7)] + SortOrder = 8)] + [CmdletExample( + Code = @"PS:> New-PnPSite -Type TeamSite -Title 'Team Contoso' -Alias contoso -Lcid 1040", + Remarks = @"This will create a new Modern Team Site collection with the title 'Team Contoso' and the url 'https://tenant.sharepoint.com/sites/contoso' or 'https://tenant.sharepoint.com/teams/contoso' based on the managed path configuration in the SharePoint Online Admin portal and sets the default language of the site to Italian.", + SortOrder = 9)] [CmdletAdditionalParameter(ParameterType = typeof(string), ParameterName = "Title", Mandatory = true, HelpMessage = @"Specifies the title of the new site collection", ParameterSetName = ParameterSet_COMMUNICATIONBUILTINDESIGN)] [CmdletAdditionalParameter(ParameterType = typeof(string), ParameterName = "Title", Mandatory = true, HelpMessage = @"Specifies the title of the new site collection", ParameterSetName = ParameterSet_COMMUNICATIONCUSTOMDESIGN)] [CmdletAdditionalParameter(ParameterType = typeof(string), ParameterName = "Url", Mandatory = true, HelpMessage = @"Specifies the full url of the new site collection", ParameterSetName = ParameterSet_COMMUNICATIONBUILTINDESIGN)] @@ -61,6 +64,7 @@ namespace SharePointPnP.PowerShell.Commands [CmdletAdditionalParameter(ParameterType = typeof(GuidPipeBind), ParameterName = "SiteDesignId", Mandatory = true, HelpMessage = @"Specifies the site design id to use for the new site collection. If specified will override SiteDesign", ParameterSetName = ParameterSet_COMMUNICATIONCUSTOMDESIGN)] [CmdletAdditionalParameter(ParameterType = typeof(uint), ParameterName = "Lcid", Mandatory = false, HelpMessage = @"Specifies the language of the new site collection. Defaults to the current language of the web connected to.", ParameterSetName = ParameterSet_COMMUNICATIONBUILTINDESIGN)] [CmdletAdditionalParameter(ParameterType = typeof(uint), ParameterName = "Lcid", Mandatory = false, HelpMessage = @"Specifies the language of the new site collection. Defaults to the current language of the web connected to.", ParameterSetName = ParameterSet_COMMUNICATIONCUSTOMDESIGN)] + [CmdletAdditionalParameter(ParameterType = typeof(uint), ParameterName = "Lcid", Mandatory = false, HelpMessage = @"Specifies the language of the new site collection. Defaults to the current language of the web connected to.", ParameterSetName = ParameterSet_TEAM)] [CmdletAdditionalParameter(ParameterType = typeof(string), ParameterName = "Title", Mandatory = true, HelpMessage = @"Specifies the title of the new site collection", ParameterSetName = ParameterSet_TEAM)] [CmdletAdditionalParameter(ParameterType = typeof(string), ParameterName = "Alias", Mandatory = true, HelpMessage = @"Specifies the alias of the new site collection which represents the part of the URL that will be assigned to the site behind 'https://tenant.sharepoint.com/sites/' or 'https://tenant.sharepoint.com/teams/' based on the managed path configuration in the SharePoint Online Admin portal", ParameterSetName = ParameterSet_TEAM)] [CmdletAdditionalParameter(ParameterType = typeof(string), ParameterName = "Description", Mandatory = false, HelpMessage = @"Specifies the description of the new site collection", ParameterSetName = ParameterSet_TEAM)] @@ -110,7 +114,9 @@ protected override void ExecuteCmdlet() creationInformation.Url = _communicationSiteParameters.Url; creationInformation.Description = _communicationSiteParameters.Description; creationInformation.Classification = _communicationSiteParameters.Classification; - creationInformation.AllowFileSharingForGuestUsers = _communicationSiteParameters.AllowFileSharingForGuestUsers; +#pragma warning disable CS0618 // Type or member is obsolete + creationInformation.ShareByEmailEnabled = _communicationSiteParameters.AllowFileSharingForGuestUsers || _communicationSiteParameters.ShareByEmailEnabled; +#pragma warning restore CS0618 // Type or member is obsolete creationInformation.Lcid = _communicationSiteParameters.Lcid; if (ParameterSetName == "CommunicationCustomInDesign") { @@ -132,6 +138,7 @@ protected override void ExecuteCmdlet() creationInformation.Classification = _teamSiteParameters.Classification; creationInformation.Description = _teamSiteParameters.Description; creationInformation.IsPublic = _teamSiteParameters.IsPublic; + creationInformation.Lcid = _teamSiteParameters.Lcid; var results = ClientContext.CreateSiteAsync(creationInformation); var returnedContext = results.GetAwaiter().GetResult(); @@ -157,10 +164,16 @@ public class CommunicationSiteParameters [Parameter(Mandatory = false, ParameterSetName = ParameterSet_COMMUNICATIONCUSTOMDESIGN)] public string Classification; + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_COMMUNICATIONBUILTINDESIGN)] [Parameter(Mandatory = false, ParameterSetName = ParameterSet_COMMUNICATIONCUSTOMDESIGN)] + [Obsolete("Use ShareByEmailEnabled instead.")] public SwitchParameter AllowFileSharingForGuestUsers; + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_COMMUNICATIONBUILTINDESIGN)] + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_COMMUNICATIONCUSTOMDESIGN)] + public SwitchParameter ShareByEmailEnabled; + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_COMMUNICATIONBUILTINDESIGN)] public OfficeDevPnP.Core.Sites.CommunicationSiteDesign SiteDesign = OfficeDevPnP.Core.Sites.CommunicationSiteDesign.Topic; @@ -188,6 +201,9 @@ public class TeamSiteParameters [Parameter(Mandatory = false, ParameterSetName = ParameterSet_TEAM)] public SwitchParameter IsPublic; + + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_TEAM)] + public uint Lcid; } } } diff --git a/Commands/Admin/NewTenantSite.cs b/Commands/Admin/NewTenantSite.cs index cff1d74d1..18dab78a1 100644 --- a/Commands/Admin/NewTenantSite.cs +++ b/Commands/Admin/NewTenantSite.cs @@ -46,10 +46,10 @@ public class NewTenantSite : PnPAdminCmdlet [Parameter(Mandatory = true, HelpMessage = @"Specifies the user name of the site collection's primary owner. The owner must be a user instead of a security group or an email-enabled security group.")] public string Owner = string.Empty; - [Parameter(Mandatory = false, HelpMessage = @"Specifies the language of this site collection. For more information, see Locale IDs Assigned by Microsoft: https://msdn.microsoft.com/en-us/library/microsoft.sharepoint.splanguage.lcid.aspx")] + [Parameter(Mandatory = false, HelpMessage = @"Specifies the language of this site collection. For more information, see Locale IDs Assigned by Microsoft: https://msdn.microsoft.com/en-us/library/microsoft.sharepoint.splanguage.lcid.aspx. To get the list of supported languages use: (Get-PnPWeb -Includes RegionalSettings.InstalledLanguages).RegionalSettings.InstalledLanguages ")] public uint Lcid = 1033; - [Parameter(Mandatory = false, HelpMessage = @"Specifies the site collection template type. Use the Get-PnPWebTemplate cmdlet to get the list of valid templates. If no template is specified, one can be added later. The Template and LocaleId parameters must be a valid combination as returned from the Get-PnPWebTemplates cmdlet.")] + [Parameter(Mandatory = false, HelpMessage = @"Specifies the site collection template type. Use the Get-PnPWebTemplates cmdlet to get the list of valid templates. If no template is specified, one can be added later. The Template and LocaleId parameters must be a valid combination as returned from the Get-PnPWebTemplates cmdlet.")] public string Template = "STS#0"; [Parameter(Mandatory = true, HelpMessage = "Use Get-PnPTimeZoneId to retrieve possible timezone values")] diff --git a/Commands/Apps/PublishApp.cs b/Commands/Apps/PublishApp.cs index 181d0fda3..c91b05c78 100644 --- a/Commands/Apps/PublishApp.cs +++ b/Commands/Apps/PublishApp.cs @@ -11,10 +11,10 @@ namespace SharePointPnP.PowerShell.Commands.Apps [CmdletHelp("Publishes/Deploys/Trusts an available app in the app catalog", Category = CmdletHelpCategory.Apps, SupportedPlatform = CmdletSupportedPlatform.Online)] [CmdletExample( - Code = @"PS:> Publish-PnPApp -Identity -Identity 2646ccc3-6a2b-46ef-9273-81411cbbb60f", + Code = @"PS:> Publish-PnPApp -Identity 2646ccc3-6a2b-46ef-9273-81411cbbb60f", Remarks = @"This will deploy/trust an app into the app catalog. Notice that the app needs to be available in the tenant scoped app catalog", SortOrder = 1)] [CmdletExample( - Code = @"PS:> Publish-PnPApp -Identity -Identity 2646ccc3-6a2b-46ef-9273-81411cbbb60f -Scope Site", + Code = @"PS:> Publish-PnPApp -Identity 2646ccc3-6a2b-46ef-9273-81411cbbb60f -Scope Site", Remarks = @"This will deploy/trust an app into the app catalog. Notice that the app needs to be available in the site collection scoped app catalog", SortOrder = 1)] public class PublishApp : PnPCmdlet { diff --git a/Commands/Diagnostic/MeasurePnPWeb.cs b/Commands/Diagnostic/MeasurePnPWeb.cs index be68e7d34..c5261f14d 100644 --- a/Commands/Diagnostic/MeasurePnPWeb.cs +++ b/Commands/Diagnostic/MeasurePnPWeb.cs @@ -19,8 +19,8 @@ namespace SharePointPnP.PowerShell.Commands.Diagnostic Remarks = @"Gets statistics on the current web", SortOrder = 1)] [CmdletExample( - Code = @"PS:> Measure-PnPList $web -Recursive", - Remarks = @"Gets statistics on the chosen including all sub webs", + Code = @"PS:> Measure-PnPWeb $web -Recursive", + Remarks = @"Gets statistics on the provided web including all its subwebs", SortOrder = 2)] public class MeasurePnPWeb : PnPCmdlet diff --git a/Commands/Files/CopyFile.cs b/Commands/Files/CopyFile.cs index f997d7afb..35010b1e7 100644 --- a/Commands/Files/CopyFile.cs +++ b/Commands/Files/CopyFile.cs @@ -255,9 +255,45 @@ private void UploadFile(File srcFile, Folder targetFolder, string filename = "") { var binaryStream = srcFile.OpenBinaryStream(); _sourceContext.ExecuteQueryRetry(); - if (string.IsNullOrWhiteSpace(filename)) filename = srcFile.Name; - targetFolder.UploadFile(filename, binaryStream.Value, OverwriteIfAlreadyExists); + if (string.IsNullOrWhiteSpace(filename)) + { + filename = srcFile.Name; + } + this.UploadFileWithSpecialCharacters(targetFolder, filename, binaryStream.Value, OverwriteIfAlreadyExists); _targetContext.ExecuteQueryRetry(); } + + + private File UploadFileWithSpecialCharacters(Folder folder, string fileName, System.IO.Stream stream, bool overwriteIfExists) + { + if (fileName == null) + { + throw new ArgumentNullException(nameof(fileName)); + } + + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + if (string.IsNullOrWhiteSpace(fileName)) + { + throw new ArgumentException("Filename is required"); + } + + // Create the file + var newFileInfo = new FileCreationInformation() + { + ContentStream = stream, + Url = fileName, + Overwrite = overwriteIfExists + }; + + var file = folder.Files.Add(newFileInfo); + folder.Context.Load(file); + folder.Context.ExecuteQueryRetry(); + + return file; + } } } diff --git a/Commands/Graph/SetUnifiedGroup.cs b/Commands/Graph/SetUnifiedGroup.cs index bee867431..604aa900e 100644 --- a/Commands/Graph/SetUnifiedGroup.cs +++ b/Commands/Graph/SetUnifiedGroup.cs @@ -5,7 +5,6 @@ using SharePointPnP.PowerShell.Commands.Base.PipeBinds; using System; using System.IO; -using System.Linq; using System.Management.Automation; namespace SharePointPnP.PowerShell.Commands.Graph @@ -78,10 +77,15 @@ protected override void ExecuteCmdlet() } groupLogoStream = new FileStream(GroupLogoPath, FileMode.Open, FileAccess.Read); } - + bool? isPrivateGroup = null; + if(IsPrivate.IsPresent) + { + isPrivateGroup = IsPrivate.ToBool(); + } UnifiedGroupsUtility.UpdateUnifiedGroup(group.GroupId, AccessToken, displayName: DisplayName, - description: Description, owners: Owners, members: Members, groupLogo: groupLogoStream, isPrivate: IsPrivate); - } else + description: Description, owners: Owners, members: Members, groupLogo: groupLogoStream, isPrivate: isPrivateGroup); + } + else { WriteError(new ErrorRecord(new Exception("Group not found"), "GROUPNOTFOUND", ErrorCategory.ObjectNotFound, this)); } diff --git a/Commands/Properties/AssemblyInfo.cs b/Commands/Properties/AssemblyInfo.cs index 727af4580..7fdd7e484 100644 --- a/Commands/Properties/AssemblyInfo.cs +++ b/Commands/Properties/AssemblyInfo.cs @@ -44,6 +44,6 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.2.1810.0")] -[assembly: AssemblyFileVersion("3.2.1810.0")] +[assembly: AssemblyVersion("3.3.1811.0")] +[assembly: AssemblyFileVersion("3.3.1811.0")] [assembly: InternalsVisibleTo("SharePointPnP.PowerShell.Tests")] \ No newline at end of file diff --git a/Commands/Provisioning/AddProvisioningSequence.cs b/Commands/Provisioning/AddProvisioningSequence.cs deleted file mode 100644 index 2ed6fabdf..000000000 --- a/Commands/Provisioning/AddProvisioningSequence.cs +++ /dev/null @@ -1,43 +0,0 @@ -#if !ONPREMISES -using OfficeDevPnP.Core.Framework.Provisioning.Model; -using SharePointPnP.PowerShell.CmdletHelpAttributes; -using System; -using System.Linq; -using System.Management.Automation; - -namespace SharePointPnP.PowerShell.Commands.Provisioning -{ - [Cmdlet(VerbsCommon.Add, "PnPProvisioningSequence", SupportsShouldProcess = true)] - [CmdletHelp("Adds a provisioning sequence object to a provisioning hierarchy", - Category = CmdletHelpCategory.Provisioning, SupportedPlatform = CmdletSupportedPlatform.Online)] - [CmdletExample( - Code = @"PS:> Add-PnPProvisioningSequence -Hierarchy $myhierarchy -Sequence $mysequence", - Remarks = "Adds an existing sequence object to an existing hierarchy object", - SortOrder = 1)] - [CmdletExample( - Code = @"PS:> New-PnPProvisioningSequence -Id ""MySequence"" | Add-PnPProvisioningSequence -Hierarchy $hierarchy", - Remarks = "Creates a new instance of a provisioning sequence object and sets the Id to the value specified, then the sequence is added to an existing hierarchy object", - SortOrder = 2)] - public class AddProvisioningSequence : PSCmdlet - { - [Parameter(Mandatory = true, HelpMessage = "The hierarchy to add the sequence to", ParameterSetName = ParameterAttribute.AllParameterSets)] - public ProvisioningHierarchy Hierarchy; - - [Parameter(Mandatory = true, HelpMessage = "Optional Id of the sequence", ParameterSetName = ParameterAttribute.AllParameterSets, ValueFromPipeline = true)] - public ProvisioningSequence Sequence; - - protected override void ProcessRecord() - { - if (Hierarchy.Sequences.FirstOrDefault(s => s.ID == Sequence.ID) == null) - { - Hierarchy.Sequences.Add(Sequence); - WriteObject(Hierarchy); - } - else - { - WriteError(new ErrorRecord(new Exception($"Sequence with ID {Sequence.ID} already exists in hierarchy"), "DUPLICATESEQUENCEID", ErrorCategory.InvalidData, Sequence)); - } - } - } -} -#endif \ No newline at end of file diff --git a/Commands/Provisioning/AddProvisioningTemplate.cs b/Commands/Provisioning/AddProvisioningTemplate.cs deleted file mode 100644 index 215ff1a1c..000000000 --- a/Commands/Provisioning/AddProvisioningTemplate.cs +++ /dev/null @@ -1,37 +0,0 @@ -#if !ONPREMISES -using OfficeDevPnP.Core.Framework.Provisioning.Model; -using SharePointPnP.PowerShell.CmdletHelpAttributes; -using SharePointPnP.PowerShell.Commands.Base.PipeBinds; -using System; -using System.Linq; -using System.Management.Automation; - -namespace SharePointPnP.PowerShell.Commands.Provisioning -{ - [Cmdlet(VerbsCommon.Add, "PnPProvisioningTemplate", SupportsShouldProcess = true)] - [CmdletHelp("Adds a provisioning template object to a provisioning hierarchy", - Category = CmdletHelpCategory.Provisioning, SupportedPlatform = CmdletSupportedPlatform.Online)] - [CmdletExample( - Code = @"PS:> Add-PnPProvisioningTemplate -Hierarchy $myhierarchy -Template $mytemplate", - Remarks = "Adds an existing sequence object to an existing hierarchy object", - SortOrder = 1)] - public class AddProvisioningTemplate : PSCmdlet - { - [Parameter(Mandatory = true, HelpMessage = "The template to add to the hierarchy")] - public ProvisioningTemplate Template; - - [Parameter(Mandatory = true, HelpMessage = "The hierarchy to add the template to", ValueFromPipeline = true)] - public ProvisioningHierarchy Hierarchy; - - protected override void ProcessRecord() - { - if(Hierarchy.Templates.FirstOrDefault(t => t.Id == Template.Id) == null) - { - Hierarchy.Templates.Add(Template); - } else { - WriteError(new ErrorRecord(new Exception($"Template with ID {Template.Id} already exists in hierarchy"), "DUPLICATETEMPLATE", ErrorCategory.InvalidData, Template)); - } - } - } -} -#endif \ No newline at end of file diff --git a/Commands/Provisioning/AddDataRowsToProvisioningTemplate.cs b/Commands/Provisioning/Site/AddDataRowsToProvisioningTemplate.cs similarity index 98% rename from Commands/Provisioning/AddDataRowsToProvisioningTemplate.cs rename to Commands/Provisioning/Site/AddDataRowsToProvisioningTemplate.cs index c377d47a2..50585e5e9 100644 --- a/Commands/Provisioning/AddDataRowsToProvisioningTemplate.cs +++ b/Commands/Provisioning/Site/AddDataRowsToProvisioningTemplate.cs @@ -15,7 +15,7 @@ using System.Text.RegularExpressions; using SPSite = Microsoft.SharePoint.Client.Site; -namespace SharePointPnP.PowerShell.Commands.Provisioning +namespace SharePointPnP.PowerShell.Commands.Provisioning.Site { [Cmdlet(VerbsCommon.Add, "PnPDataRowsToProvisioningTemplate")] [CmdletHelp("Adds datarows to a list inside a PnP Provisioning Template", @@ -30,7 +30,7 @@ namespace SharePointPnP.PowerShell.Commands.Provisioning SortOrder = 2)] public class AddDataRowsToProvisioningTemplate : PnPWebCmdlet { - [Parameter(Mandatory = true, Position = 0, HelpMessage = "Filename of the .PNP Open XML provisioning template to read from, optionally including full path.")] + [Parameter(Mandatory = true, Position = 0, HelpMessage = "Filename of the .PNP Open XML site template to read from, optionally including full path.")] public string Path; [Parameter(Mandatory = true, HelpMessage = "The list to query")] diff --git a/Commands/Provisioning/AddFileToProvisioningTemplate.cs b/Commands/Provisioning/Site/AddFileToProvisioningTemplate.cs similarity index 90% rename from Commands/Provisioning/AddFileToProvisioningTemplate.cs rename to Commands/Provisioning/Site/AddFileToProvisioningTemplate.cs index dcc1fd08e..ad972c19c 100644 --- a/Commands/Provisioning/AddFileToProvisioningTemplate.cs +++ b/Commands/Provisioning/Site/AddFileToProvisioningTemplate.cs @@ -11,31 +11,31 @@ using System.Text; using System.Threading.Tasks; -namespace SharePointPnP.PowerShell.Commands.Provisioning +namespace SharePointPnP.PowerShell.Commands.Provisioning.Site { [Cmdlet(VerbsCommon.Add, "PnPFileToProvisioningTemplate")] [CmdletHelp("Adds a file to a PnP Provisioning Template", Category = CmdletHelpCategory.Provisioning)] [CmdletExample( Code = @"PS:> Add-PnPFileToProvisioningTemplate -Path template.pnp -Source $sourceFilePath -Folder $targetFolder", - Remarks = "Adds a file to a PnP Provisioning Template", + Remarks = "Adds a file to a PnP Site Template", SortOrder = 1)] [CmdletExample( Code = @"PS:> Add-PnPFileToProvisioningTemplate -Path template.xml -Source $sourceFilePath -Folder $targetFolder", - Remarks = "Adds a file reference to a PnP Provisioning XML Template", + Remarks = "Adds a file reference to a PnP Site XML Template", SortOrder = 2)] [CmdletExample( Code = @"PS:> Add-PnPFileToProvisioningTemplate -Path template.pnp -Source ""./myfile.png"" -Folder ""folderinsite"" -FileLevel Published -FileOverwrite:$false", - Remarks = "Adds a file to a PnP Provisioning Template, specifies the level as Published and defines to not overwrite the file if it exists in the site.", + Remarks = "Adds a file to a PnP Site Template, specifies the level as Published and defines to not overwrite the file if it exists in the site.", SortOrder = 3)] [CmdletExample( Code = @"PS:> Add-PnPFileToProvisioningTemplate -Path template.pnp -Source $sourceFilePath -Folder $targetFolder -Container $container", - Remarks = "Adds a file to a PnP Provisioning Template with a custom container for the file", + Remarks = "Adds a file to a PnP Site Template with a custom container for the file", SortOrder = 4)] public class AddFileToProvisioningTemplate : PSCmdlet { - [Parameter(Mandatory = true, Position = 0, HelpMessage = "Filename of the .PNP Open XML provisioning template to read from, optionally including full path.")] + [Parameter(Mandatory = true, Position = 0, HelpMessage = "Filename of the .PNP Open XML site template to read from, optionally including full path.")] public string Path; [Parameter(Mandatory = true, Position = 1, HelpMessage = "The file to add to the in-memory template, optionally including full path.")] diff --git a/Commands/Provisioning/AddListFoldersToProvisioningTemplate.cs b/Commands/Provisioning/Site/AddListFoldersToProvisioningTemplate.cs similarity index 95% rename from Commands/Provisioning/AddListFoldersToProvisioningTemplate.cs rename to Commands/Provisioning/Site/AddListFoldersToProvisioningTemplate.cs index 8b1a81a79..b3aa0aee1 100644 --- a/Commands/Provisioning/AddListFoldersToProvisioningTemplate.cs +++ b/Commands/Provisioning/Site/AddListFoldersToProvisioningTemplate.cs @@ -14,29 +14,28 @@ using System.Threading.Tasks; using Microsoft.SharePoint.Client; -namespace SharePointPnP.PowerShell.Commands.Provisioning +namespace SharePointPnP.PowerShell.Commands.Provisioning.Site { [Cmdlet(VerbsCommon.Add, "PnPListFoldersToProvisioningTemplate")] - [CmdletHelp("Adds folders to a list in a PnP Provisioning Template", Category = CmdletHelpCategory.Provisioning)] [CmdletExample( Code = @"PS:> Add-PnPListFoldersToProvisioningTemplate -Path template.pnp -List 'PnPTestList'", - Remarks = "Adds top level folders from a list to an existing template and returns an in-memory PnP Provisioning Template", + Remarks = "Adds top level folders from a list to an existing template and returns an in-memory PnP Site Template", SortOrder = 1)] [CmdletExample( Code = @"PS:> Add-PnPListFoldersToProvisioningTemplate -Path template.pnp -List 'PnPTestList' -Recursive", - Remarks = "Adds all folders from a list to an existing template and returns an in-memory PnP Provisioning Template", + Remarks = "Adds all folders from a list to an existing template and returns an in-memory PnP Site Template", SortOrder = 2)] [CmdletExample( Code = @"PS:> Add-PnPListFoldersToProvisioningTemplate -Path template.pnp -List 'PnPTestList' -Recursive -IncludeSecurity", - Remarks = "Adds all folders from a list with unique permissions to an in-memory PnP Provisioning Template", + Remarks = "Adds all folders from a list with unique permissions to an in-memory PnP Site Template", SortOrder = 3)] public class AddListFoldersToProvisioningTemplate : PnPWebCmdlet { - [Parameter(Mandatory = true, Position = 0, HelpMessage = "Filename of the .PNP Open XML provisioning template to read from, optionally including full path.")] + [Parameter(Mandatory = true, Position = 0, HelpMessage = "Filename of the .PNP Open XML site template to read from, optionally including full path.")] public string Path; [Parameter(Mandatory = true, HelpMessage = "The list to query", Position = 2)] diff --git a/Commands/Provisioning/ApplyProvisioningTemplate.cs b/Commands/Provisioning/Site/ApplyProvisioningTemplate.cs similarity index 92% rename from Commands/Provisioning/ApplyProvisioningTemplate.cs rename to Commands/Provisioning/Site/ApplyProvisioningTemplate.cs index a09a567d7..4e313c85a 100644 --- a/Commands/Provisioning/ApplyProvisioningTemplate.cs +++ b/Commands/Provisioning/Site/ApplyProvisioningTemplate.cs @@ -14,36 +14,36 @@ using System.Collections.Generic; using SharePointPnP.PowerShell.Commands.Utilities; -namespace SharePointPnP.PowerShell.Commands.Provisioning +namespace SharePointPnP.PowerShell.Commands.Provisioning.Site { [Cmdlet("Apply", "PnPProvisioningTemplate")] - [CmdletHelp("Applies a provisioning template to a web", + [CmdletHelp("Applies a site template to a web", Category = CmdletHelpCategory.Provisioning)] [CmdletExample( Code = @"PS:> Apply-PnPProvisioningTemplate -Path template.xml", - Remarks = @"Applies a provisioning template in XML format to the current web.", + Remarks = @"Applies a site template in XML format to the current web.", SortOrder = 1)] [CmdletExample( - Code = @"PS:> Apply-PnPProvisioningTemplate -Path template.xml -ResourceFolder c:\provisioning\resources", - Remarks = @"Applies a provisioning template in XML format to the current web. Any resources like files that are referenced in the template will be retrieved from the folder as specified with the ResourceFolder parameter.", + Code = @"PS:> Apply-PnPSPnPProvisioningTemplateiteTemplate -Path template.xml -ResourceFolder c:\provisioning\resources", + Remarks = @"Applies a site template in XML format to the current web. Any resources like files that are referenced in the template will be retrieved from the folder as specified with the ResourceFolder parameter.", SortOrder = 2)] [CmdletExample( Code = @"PS:> Apply-PnPProvisioningTemplate -Path template.xml -Parameters @{""ListTitle""=""Projects"";""parameter2""=""a second value""}", - Remarks = @"Applies a provisioning template in XML format to the current web. It will populate the parameter in the template the values as specified and in the template you can refer to those values with the {parameter:} token. + Remarks = @"Applies a site template in XML format to the current web. It will populate the parameter in the template the values as specified and in the template you can refer to those values with the {parameter:} token. For instance with the example above, specifying {parameter:ListTitle} in your template will translate to 'Projects' when applying the template. These tokens can be used in most string values in a template.", SortOrder = 3)] [CmdletExample( Code = @"PS:> Apply-PnPProvisioningTemplate -Path template.xml -Handlers Lists, SiteSecurity", - Remarks = @"Applies a provisioning template in XML format to the current web. It will only apply the lists and site security part of the template.", + Remarks = @"Applies a site template in XML format to the current web. It will only apply the lists and site security part of the template.", SortOrder = 4)] [CmdletExample( Code = @"PS:> Apply-PnPProvisioningTemplate -Path template.pnp", - Remarks = @"Applies a provisioning template from a pnp package to the current web.", + Remarks = @"Applies a site template from a pnp package to the current web.", SortOrder = 5)] [CmdletExample( Code = @"PS:> Apply-PnPProvisioningTemplate -Path https://tenant.sharepoint.com/sites/templatestorage/Documents/template.pnp", - Remarks = @"Applies a provisioning template from a pnp package stored in a library to the current web.", + Remarks = @"Applies a site template from a pnp package stored in a library to the current web.", SortOrder = 6)] [CmdletExample( Code = @" @@ -54,7 +54,7 @@ namespace SharePointPnP.PowerShell.Commands.Provisioning SortOrder = 7)] [CmdletExample( Code = @"PS:> Apply-PnPProvisioningTemplate -Path .\ -InputInstance $template", - Remarks = @"Applies a provisioning template from an in-memory instance of a ProvisioningTemplate type of the PnP Core Component, reading the supporting files, if any, from the current (.\) path. The syntax can be used together with any other supported parameters.", + Remarks = @"Applies a site template from an in-memory instance of a ProvisioningTemplate type of the PnP Core Component, reading the supporting files, if any, from the current (.\) path. The syntax can be used together with any other supported parameters.", SortOrder = 8)] public class ApplyProvisioningTemplate : PnPWebCmdlet diff --git a/Commands/Provisioning/ConvertFolderToProvisioningTemplate.cs b/Commands/Provisioning/Site/ConvertFolderToProvisioningTemplate.cs similarity index 96% rename from Commands/Provisioning/ConvertFolderToProvisioningTemplate.cs rename to Commands/Provisioning/Site/ConvertFolderToProvisioningTemplate.cs index 9ca412ff5..6e1276de8 100644 --- a/Commands/Provisioning/ConvertFolderToProvisioningTemplate.cs +++ b/Commands/Provisioning/Site/ConvertFolderToProvisioningTemplate.cs @@ -1,11 +1,11 @@ -using System; +using OfficeDevPnP.Core.Framework.Provisioning.Connectors.OpenXML; +using OfficeDevPnP.Core.Framework.Provisioning.Connectors.OpenXML.Model; +using SharePointPnP.PowerShell.CmdletHelpAttributes; +using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Management.Automation; -using OfficeDevPnP.Core.Framework.Provisioning.Connectors.OpenXML; -using OfficeDevPnP.Core.Framework.Provisioning.Connectors.OpenXML.Model; -using SharePointPnP.PowerShell.CmdletHelpAttributes; namespace SharePointPnP.PowerShell.Commands.Provisioning { @@ -20,7 +20,7 @@ namespace SharePointPnP.PowerShell.Commands.Provisioning Code = @"PS:> Convert-PnPFolderToProvisioningTemplate -Out template.pnp -Folder c:\temp", Remarks = "Creates a pnp package file of an existing template xml, and includes all files in the c:\\temp folder", SortOrder = 2)] - public class ConvertProvisioningTemplateFromFolder : PSCmdlet + public class ConvertFolderToProvisioningTemplate : PSCmdlet { [Parameter(Mandatory = true, Position = 0, HelpMessage = "Filename to write to, optionally including full path.")] public string Out; @@ -96,6 +96,8 @@ private byte[] CreatePnPPackageFile() bool templateFileMissing = dirInfo.GetFiles(templateFileName, SearchOption.TopDirectoryOnly).Length == 0; if (templateFileMissing) throw new InvalidOperationException("You need an xml template file (" + templateFileName + ") with the same name as the .pnp outfile in order to pack a folder to a .pnp package file."); + info.Properties.TemplateFileName = templateFileName; + foreach (var currentFile in dirInfo.GetFiles("*.*", SearchOption.AllDirectories)) { var folder = GetFolderName(currentFile, dirInfo); diff --git a/Commands/Provisioning/ConvertProvisioningTemplate.cs b/Commands/Provisioning/Site/ConvertProvisioningTemplate.cs similarity index 93% rename from Commands/Provisioning/ConvertProvisioningTemplate.cs rename to Commands/Provisioning/Site/ConvertProvisioningTemplate.cs index aa6ea8e4b..c9a056eb3 100644 --- a/Commands/Provisioning/ConvertProvisioningTemplate.cs +++ b/Commands/Provisioning/Site/ConvertProvisioningTemplate.cs @@ -25,9 +25,9 @@ namespace SharePointPnP.PowerShell.Commands.Provisioning [CmdletRelatedLink( Text ="Encoding", Url = "https://msdn.microsoft.com/en-us/library/system.text.encoding_properties.aspx")] - public class ConvertProvisioningTemplate : PSCmdlet + public class ConvertSiteTemplate : PSCmdlet { - [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true, ValueFromPipeline = true, HelpMessage = "Path to the xml file containing the provisioning template")] + [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true, ValueFromPipeline = true, HelpMessage = "Path to the xml file containing the site template")] public string Path; [Parameter(Mandatory = false, HelpMessage = "Filename to write to, optionally including full path")] @@ -104,7 +104,9 @@ protected override void BeginProcessing() } case XMLPnPSchemaVersion.V201605: { +#pragma warning disable CS0618 // Type or member is obsolete formatter = XMLPnPSchemaFormatter.GetSpecificFormatter(XMLConstants.PROVISIONING_SCHEMA_NAMESPACE_2016_05); +#pragma warning restore CS0618 // Type or member is obsolete break; } case XMLPnPSchemaVersion.V201705: @@ -122,6 +124,11 @@ protected override void BeginProcessing() formatter = XMLPnPSchemaFormatter.GetSpecificFormatter(XMLConstants.PROVISIONING_SCHEMA_NAMESPACE_2018_05); break; } + case XMLPnPSchemaVersion.V201807: + { + formatter = XMLPnPSchemaFormatter.GetSpecificFormatter(XMLConstants.PROVISIONING_SCHEMA_NAMESPACE_2018_07); + break; + } } if (!string.IsNullOrEmpty(Out)) diff --git a/Commands/Provisioning/GetProvisioningTemplate.cs b/Commands/Provisioning/Site/GetProvisioningTemplate.cs similarity index 99% rename from Commands/Provisioning/GetProvisioningTemplate.cs rename to Commands/Provisioning/Site/GetProvisioningTemplate.cs index 0995ac510..c0d3fffca 100644 --- a/Commands/Provisioning/GetProvisioningTemplate.cs +++ b/Commands/Provisioning/Site/GetProvisioningTemplate.cs @@ -13,10 +13,10 @@ using Resources = SharePointPnP.PowerShell.Commands.Properties.Resources; using System.Collections; -namespace SharePointPnP.PowerShell.Commands.Provisioning +namespace SharePointPnP.PowerShell.Commands.Provisioning.Site { [Cmdlet(VerbsCommon.Get, "PnPProvisioningTemplate", SupportsShouldProcess = true)] - [CmdletHelp("Generates a provisioning template from a web", + [CmdletHelp("Generates a provisioning site template from a web", Category = CmdletHelpCategory.Provisioning)] [CmdletExample( Code = @"PS:> Get-PnPProvisioningTemplate -Out template.pnp", @@ -416,7 +416,9 @@ private void ExtractTemplate(XMLPnPSchemaVersion schema, string path, string pac } case XMLPnPSchemaVersion.V201605: { +#pragma warning disable CS0618 // Type or member is obsolete formatter = XMLPnPSchemaFormatter.GetSpecificFormatter(XMLConstants.PROVISIONING_SCHEMA_NAMESPACE_2016_05); +#pragma warning restore CS0618 // Type or member is obsolete break; } case XMLPnPSchemaVersion.V201705: diff --git a/Commands/Provisioning/GetProvisioningTemplateFromGallery.cs b/Commands/Provisioning/Site/GetProvisioningTemplateFromGallery.cs similarity index 97% rename from Commands/Provisioning/GetProvisioningTemplateFromGallery.cs rename to Commands/Provisioning/Site/GetProvisioningTemplateFromGallery.cs index 2d47fc5c7..7a08516f0 100644 --- a/Commands/Provisioning/GetProvisioningTemplateFromGallery.cs +++ b/Commands/Provisioning/Site/GetProvisioningTemplateFromGallery.cs @@ -14,8 +14,9 @@ using SharePointPnP.PowerShell.Commands.Utilities; using Resources = SharePointPnP.PowerShell.Commands.Properties.Resources; -namespace SharePointPnP.PowerShell.Commands.Provisioning +namespace SharePointPnP.PowerShell.Commands.Provisioning.Site { + [Obsolete("The PnP Template Gallery has been shut down.")] [Cmdlet(VerbsCommon.Get, "PnPProvisioningTemplateFromGallery", DefaultParameterSetName = "Search")] [CmdletHelp("Retrieves or searches provisioning templates from the PnP Template Gallery", Category = CmdletHelpCategory.Lists)] [CmdletExample( diff --git a/Commands/Provisioning/NewProvisioningTemplate.cs b/Commands/Provisioning/Site/NewProvisioningTemplate.cs similarity index 90% rename from Commands/Provisioning/NewProvisioningTemplate.cs rename to Commands/Provisioning/Site/NewProvisioningTemplate.cs index a9d0ae020..37b713e08 100644 --- a/Commands/Provisioning/NewProvisioningTemplate.cs +++ b/Commands/Provisioning/Site/NewProvisioningTemplate.cs @@ -9,7 +9,7 @@ namespace SharePointPnP.PowerShell.Commands.Provisioning Category = CmdletHelpCategory.Provisioning)] [CmdletExample( Code = @"PS:> $template = New-PnPProvisioningTemplate", - Remarks = "Creates a new instance of a provisioning template object.", + Remarks = "Creates a new instance of a site template object.", SortOrder = 1)] public class NewProvisioningTemplate : PSCmdlet { diff --git a/Commands/Provisioning/NewProvisioningTemplateFromFolder.cs b/Commands/Provisioning/Site/NewProvisioningTemplateFromFolder.cs similarity index 100% rename from Commands/Provisioning/NewProvisioningTemplateFromFolder.cs rename to Commands/Provisioning/Site/NewProvisioningTemplateFromFolder.cs diff --git a/Commands/Provisioning/ReadProvisioningTemplate.cs b/Commands/Provisioning/Site/ReadProvisioningTemplate.cs similarity index 100% rename from Commands/Provisioning/ReadProvisioningTemplate.cs rename to Commands/Provisioning/Site/ReadProvisioningTemplate.cs diff --git a/Commands/Provisioning/RemoveFileFromProvisioningTemplate.cs b/Commands/Provisioning/Site/RemoveFileFromProvisioningTemplate.cs similarity index 96% rename from Commands/Provisioning/RemoveFileFromProvisioningTemplate.cs rename to Commands/Provisioning/Site/RemoveFileFromProvisioningTemplate.cs index 00e480bc3..d007b450d 100644 --- a/Commands/Provisioning/RemoveFileFromProvisioningTemplate.cs +++ b/Commands/Provisioning/Site/RemoveFileFromProvisioningTemplate.cs @@ -4,14 +4,11 @@ using OfficeDevPnP.Core.Framework.Provisioning.Providers.Xml; using SharePointPnP.PowerShell.CmdletHelpAttributes; using System; -using System.Collections.Generic; using System.IO; using System.Linq; using System.Management.Automation; -using System.Text; -using System.Threading.Tasks; -namespace SharePointPnP.PowerShell.Commands.Provisioning +namespace SharePointPnP.PowerShell.Commands.Provisioning.Site { [Cmdlet(VerbsCommon.Remove, "PnPFileFromProvisioningTemplate")] [CmdletHelp("Removes a file from a PnP Provisioning Template", diff --git a/Commands/Provisioning/SaveProvisioningTemplate.cs b/Commands/Provisioning/Site/SaveProvisioningTemplate.cs similarity index 93% rename from Commands/Provisioning/SaveProvisioningTemplate.cs rename to Commands/Provisioning/Site/SaveProvisioningTemplate.cs index 035941840..5238dfab2 100644 --- a/Commands/Provisioning/SaveProvisioningTemplate.cs +++ b/Commands/Provisioning/Site/SaveProvisioningTemplate.cs @@ -14,11 +14,11 @@ namespace SharePointPnP.PowerShell.Commands.Provisioning { [Cmdlet(VerbsData.Save, "PnPProvisioningTemplate")] - [CmdletHelp("Saves a PnP provisioning tempalte to the file system", + [CmdletHelp("Saves a PnP site template to the file system", Category = CmdletHelpCategory.Provisioning)] [CmdletExample( - Code = @"PS:> Save-PnPProvisioningTemplate -InputInstance $template -Out .\template.pnp", - Remarks = "Saves a PnP provisioning template to the file system as a PnP file.", + Code = @"PS:> Save-PnPSiteTemplate -InputInstance $template -Out .\template.pnp", + Remarks = "Saves a PnP site template to the file system as a PnP file.", SortOrder = 1)] public class SaveProvisioningTemplate : PSCmdlet { diff --git a/Commands/Provisioning/SetProvisioningTemplateMetadata.cs b/Commands/Provisioning/Site/SetProvisioningTemplateMetadata.cs similarity index 89% rename from Commands/Provisioning/SetProvisioningTemplateMetadata.cs rename to Commands/Provisioning/Site/SetProvisioningTemplateMetadata.cs index 5e4508e9e..307e3e435 100644 --- a/Commands/Provisioning/SetProvisioningTemplateMetadata.cs +++ b/Commands/Provisioning/Site/SetProvisioningTemplateMetadata.cs @@ -10,40 +10,40 @@ using OfficeDevPnP.Core.Framework.Provisioning.Providers; using SharePointPnP.PowerShell.Commands.Utilities; -namespace SharePointPnP.PowerShell.Commands.Provisioning +namespace SharePointPnP.PowerShell.Commands.Provisioning.Site { [Cmdlet(VerbsCommon.Set, "PnPProvisioningTemplateMetadata")] [CmdletHelp("Sets metadata of a provisioning template", Category = CmdletHelpCategory.Provisioning)] [CmdletExample( Code = @"PS:> Set-PnPProvisioningTemplateMetadata -Path template.xml -TemplateDisplayName ""DisplayNameValue""", - Remarks = @"Sets the DisplayName property of a provisioning template in XML format.", + Remarks = @"Sets the DisplayName property of a site template in XML format.", SortOrder = 1)] [CmdletExample( Code = @"PS:> Set-PnPProvisioningTemplateMetadata -Path template.pnp -TemplateDisplayName ""DisplayNameValue""", - Remarks = @"Sets the DisplayName property of a provisioning template in Office Open XML format.", + Remarks = @"Sets the DisplayName property of a site template in Office Open XML format.", SortOrder = 2)] [CmdletExample( Code = @"PS:> Set-PnPProvisioningTemplateMetadata -Path template.xml -TemplateImagePreviewUrl ""Full URL of the Image Preview""", - Remarks = @"Sets the Url to the preview image of a provisioning template in XML format.", + Remarks = @"Sets the Url to the preview image of a site template in XML format.", SortOrder = 3)] [CmdletExample( Code = @"PS:> Set-PnPProvisioningTemplateMetadata -Path template.pnp -TemplateImagePreviewUrl ""Full URL of the Image Preview""", - Remarks = @"Sets the to the preview image of a provisioning template in Office Open XML format.", + Remarks = @"Sets the to the preview image of a site template in Office Open XML format.", SortOrder = 4)] [CmdletExample( Code = @"PS:> Set-PnPProvisioningTemplateMetadata -Path template.xml -TemplateProperties @{""Property1"" = ""Test Value 1""; ""Property2""=""Test Value 2""}", - Remarks = @"Sets the property 'Property1' to the value 'Test Value 1' of a provisioning template in XML format.", + Remarks = @"Sets the property 'Property1' to the value 'Test Value 1' of a site template in XML format.", SortOrder = 5)] [CmdletExample( Code = @"PS:> Set-PnPProvisioningTemplateMetadata -Path template.pnp -TemplateProperties @{""Property1"" = ""Test Value 1""; ""Property2""=""Test Value 2""}", - Remarks = @"Sets the property 'Property1' to the value 'Test Value 1' of a provisioning template in Office Open XML format.", + Remarks = @"Sets the property 'Property1' to the value 'Test Value 1' of a site template in Office Open XML format.", SortOrder = 6)] public class SetProvisioningTemplateMetadata : PnPWebCmdlet { - [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true, ValueFromPipeline = true, HelpMessage = "Path to the xml or pnp file containing the provisioning template.")] + [Parameter(Mandatory = true, Position = 0, ValueFromPipelineByPropertyName = true, ValueFromPipeline = true, HelpMessage = "Path to the xml or pnp file containing the site template.")] public string Path; [Parameter(Mandatory = false, HelpMessage = "It can be used to specify the DisplayName of the template file that will be updated.")] diff --git a/Commands/Provisioning/Tenant/AddProvisioningTemplate.cs b/Commands/Provisioning/Tenant/AddProvisioningTemplate.cs new file mode 100644 index 000000000..fef54f1a0 --- /dev/null +++ b/Commands/Provisioning/Tenant/AddProvisioningTemplate.cs @@ -0,0 +1,39 @@ +#if !ONPREMISES +using OfficeDevPnP.Core.Framework.Provisioning.Model; +using SharePointPnP.PowerShell.CmdletHelpAttributes; +using SharePointPnP.PowerShell.Commands.Base.PipeBinds; +using System; +using System.Linq; +using System.Management.Automation; + +namespace SharePointPnP.PowerShell.Commands.Provisioning.Tenant +{ + [Cmdlet(VerbsCommon.Add, "PnPProvisioningTemplate", SupportsShouldProcess = true)] + [CmdletHelp("Adds a PnP Provisioning Template object to a tenant template", + Category = CmdletHelpCategory.Provisioning, SupportedPlatform = CmdletSupportedPlatform.Online)] + [CmdletExample( + Code = @"PS:> Add-PnpProvisioningTemplate -TenantTemplate $tenanttemplate -SiteTemplate $sitetemplate", + Remarks = "Adds an existing site template to an existing tenant template object", + SortOrder = 1)] + public class AddProvisioningTemplate : PSCmdlet + { + [Parameter(Mandatory = true, HelpMessage = "The template to add to the tenant template")] + [Alias("Template")] + public ProvisioningTemplate SiteTemplate; + + [Parameter(Mandatory = true, HelpMessage = "The tenant template to add the template to", ValueFromPipeline = true)] + [Alias("Hierarchy")] + public ProvisioningHierarchy TenantTemplate; + + protected override void ProcessRecord() + { + if(TenantTemplate.Templates.FirstOrDefault(t => t.Id == SiteTemplate.Id) == null) + { + TenantTemplate.Templates.Add(SiteTemplate); + } else { + WriteError(new ErrorRecord(new Exception($"Template with ID {SiteTemplate.Id} already exists in hierarchy"), "DUPLICATETEMPLATE", ErrorCategory.InvalidData, SiteTemplate)); + } + } + } +} +#endif \ No newline at end of file diff --git a/Commands/Provisioning/Tenant/AddTenantSequence.cs b/Commands/Provisioning/Tenant/AddTenantSequence.cs new file mode 100644 index 000000000..482b0b0ec --- /dev/null +++ b/Commands/Provisioning/Tenant/AddTenantSequence.cs @@ -0,0 +1,49 @@ +#if !ONPREMISES +using OfficeDevPnP.Core.Framework.Provisioning.Model; +using SharePointPnP.PowerShell.CmdletHelpAttributes; +using System; +using System.Linq; +using System.Management.Automation; + +namespace SharePointPnP.PowerShell.Commands.Provisioning.Tenant +{ + [Cmdlet(VerbsCommon.Add, "PnPTenantSequence", SupportsShouldProcess = true)] + [Alias("Add-PnPProvisioningSequence")] + [CmdletHelp("Adds a tenant sequence object to a tenant template", + Category = CmdletHelpCategory.Provisioning, SupportedPlatform = CmdletSupportedPlatform.Online)] + [CmdletExample( + Code = @"PS:> Add-PnPTenantSequence -Template $mytemplate -Sequence $mysequence", + Remarks = "Adds an existing sequence object to an existing hierarchy object", + SortOrder = 1)] + [CmdletExample( + Code = @"PS:> New-PnPTenantSequence -Id ""MySequence"" | Add-PnPTenantSequence -Template $template", + Remarks = "Creates a new instance of a provisioning sequence object and sets the Id to the value specified, then the sequence is added to an existing hierarchy object", + SortOrder = 2)] + public class AddTenantSequence : PSCmdlet + { + [Parameter(Mandatory = true, HelpMessage = "The template to add the sequence to", ParameterSetName = ParameterAttribute.AllParameterSets)] + [Alias("Hierarchy")] + public ProvisioningHierarchy Template; + + [Parameter(Mandatory = true, HelpMessage = "Optional Id of the sequence", ParameterSetName = ParameterAttribute.AllParameterSets, ValueFromPipeline = true)] + public ProvisioningSequence Sequence; + + protected override void ProcessRecord() + { + if (MyInvocation.InvocationName.ToLower() == "add-pnpprovisioningsequence") + { + WriteWarning("Add-PnPProvisioningSequence has been deprecated. Use Add-PnPTenantSequence instead."); + } + if (Template.Sequences.FirstOrDefault(s => s.ID == Sequence.ID) == null) + { + Template.Sequences.Add(Sequence); + WriteObject(Template); + } + else + { + WriteError(new ErrorRecord(new Exception($"Sequence with ID {Sequence.ID} already exists in template"), "DUPLICATESEQUENCEID", ErrorCategory.InvalidData, Sequence)); + } + } + } +} +#endif \ No newline at end of file diff --git a/Commands/Provisioning/AddProvisioningSite.cs b/Commands/Provisioning/Tenant/AddTenantSequenceSite.cs similarity index 58% rename from Commands/Provisioning/AddProvisioningSite.cs rename to Commands/Provisioning/Tenant/AddTenantSequenceSite.cs index e98888827..17bf559d0 100644 --- a/Commands/Provisioning/AddProvisioningSite.cs +++ b/Commands/Provisioning/Tenant/AddTenantSequenceSite.cs @@ -4,16 +4,17 @@ using SharePointPnP.PowerShell.Commands.Base.PipeBinds; using System.Management.Automation; -namespace SharePointPnP.PowerShell.Commands.Provisioning +namespace SharePointPnP.PowerShell.Commands.Provisioning.Tenant { - [Cmdlet(VerbsCommon.Add, "PnPProvisioningSite", SupportsShouldProcess = true)] - [CmdletHelp("Adds a provisioning sequence object to a provisioning hierarchy", + [Cmdlet(VerbsCommon.Add, "PnPTenantSequenceSite", SupportsShouldProcess = true)] + [Alias("Add-PnPProvisioningSite")] + [CmdletHelp("Adds a existing tenant sequence site object to a tenant template", Category = CmdletHelpCategory.Provisioning, SupportedPlatform = CmdletSupportedPlatform.Online)] [CmdletExample( - Code = @"PS:> Add-PnPProvisioningSite -Site $myteamsite -Sequence $mysequence", + Code = @"PS:> Add-PnPTenantSequenceSite -Site $myteamsite -Sequence $mysequence", Remarks = "Adds an existing site object to an existing hierarchy sequence", SortOrder = 1)] - public class AddProvisioningSite : PSCmdlet + public class AddTenantSequenceSite : PSCmdlet { [Parameter(Mandatory = true, ValueFromPipeline = true)] public ProvisioningSitePipeBind Site; @@ -23,6 +24,10 @@ public class AddProvisioningSite : PSCmdlet protected override void ProcessRecord() { + if (MyInvocation.InvocationName.ToLower() == "add-pnpprovisioningsite") + { + WriteWarning("Add-PnPProvisioningSite has been deprecated. Use Add-PnPTenantSequenceSite instead."); + } Sequence.SiteCollections.Add(Site.Site); WriteObject(Sequence); } diff --git a/Commands/Provisioning/AddProvisioningSubSite.cs b/Commands/Provisioning/Tenant/AddTenantSequenceSubSite.cs similarity index 62% rename from Commands/Provisioning/AddProvisioningSubSite.cs rename to Commands/Provisioning/Tenant/AddTenantSequenceSubSite.cs index 89669e8db..4b7201cfa 100644 --- a/Commands/Provisioning/AddProvisioningSubSite.cs +++ b/Commands/Provisioning/Tenant/AddTenantSequenceSubSite.cs @@ -5,16 +5,17 @@ using System.Linq; using System.Management.Automation; -namespace SharePointPnP.PowerShell.Commands.Provisioning +namespace SharePointPnP.PowerShell.Commands.Provisioning.Tenant { - [Cmdlet(VerbsCommon.Add, "PnPProvisioningSubSite", SupportsShouldProcess = true)] - [CmdletHelp("Adds a provisioning sequence object to a provisioning site object", + [Cmdlet(VerbsCommon.Add, "PnPTenantSequenceSubSite", SupportsShouldProcess = true)] + [Alias("Add-PnPPnPProvisioningSubSite")] + [CmdletHelp("Adds a tenant sequence sub site object to a tenant sequence site object", Category = CmdletHelpCategory.Provisioning, SupportedPlatform = CmdletSupportedPlatform.Online)] [CmdletExample( - Code = @"PS:> Add-PnPProvisioningSubSite -Site $mysite -SubSite $mysubsite", - Remarks = "Adds an existing subsite object to an existing hierarchy sequence site object", + Code = @"PS:> Add-PnPTenantSequenceSubSite -Site $mysite -SubSite $mysubsite", + Remarks = "Adds an existing subsite object to an existing sequence site object", SortOrder = 1)] - public class AddProvisioningSubSite : PSCmdlet + public class AddTenantSequenceSubSite : PSCmdlet { [Parameter(Mandatory = true, HelpMessage = "The subsite to add")] public TeamNoGroupSubSite SubSite; @@ -24,6 +25,11 @@ public class AddProvisioningSubSite : PSCmdlet protected override void ProcessRecord() { + if (MyInvocation.InvocationName.ToLower() == "add-pnpprovisioningsubsite") + { + WriteWarning("Add-PnPProvisioningSubSite has been deprecated. Use Add-PnPTenantSequenceSubSite instead."); + } + if (Site.Sites.Cast().FirstOrDefault(s => s.Url == SubSite.Url) == null) { Site.Sites.Add(SubSite); diff --git a/Commands/Provisioning/ApplyProvisioningHierarchy.cs b/Commands/Provisioning/Tenant/ApplyTenantTemplate.cs similarity index 88% rename from Commands/Provisioning/ApplyProvisioningHierarchy.cs rename to Commands/Provisioning/Tenant/ApplyTenantTemplate.cs index 41be05e31..c1ef23888 100644 --- a/Commands/Provisioning/ApplyProvisioningHierarchy.cs +++ b/Commands/Provisioning/Tenant/ApplyTenantTemplate.cs @@ -13,26 +13,27 @@ using System.Linq; using System.Management.Automation; -namespace SharePointPnP.PowerShell.Commands.Provisioning +namespace SharePointPnP.PowerShell.Commands.Provisioning.Tenant { - [Cmdlet("Apply", "PnPProvisioningHierarchy", SupportsShouldProcess = true)] - [CmdletHelp("Adds a provisioning sequence object to a provisioning site object", + [Cmdlet("Apply", "PnPTenantTemplate", SupportsShouldProcess = true)] + [Alias("Apply-PnPProvisioningHierarchy")] + [CmdletHelp("Applies a tenant template to the current tenant.", Category = CmdletHelpCategory.Provisioning, SupportedPlatform = CmdletSupportedPlatform.Online)] [CmdletExample( - Code = @"PS:> Apply-PnPProvisioningHierarchy -Path myfile.pnp", - Remarks = "Will read the provisioning hierarchy from the filesystem and will apply the sequences in the hierarchy", + Code = @"PS:> Apply-PnPTenantTemplate -Path myfile.pnp", + Remarks = "Will read the tenant template from the filesystem and will apply the sequences in the template", SortOrder = 1)] [CmdletExample( - Code = @"PS:> Apply-PnPProvisioningHierarchy -Path myfile.pnp -SequenceId ""mysequence""", - Remarks = "Will read the provisioning hierarchy from the filesystem and will apply the specified sequence in the hierarchy", + Code = @"PS:> Apply-PnPTenantTemplate -Path myfile.pnp -SequenceId ""mysequence""", + Remarks = "Will read the tenant template from the filesystem and will apply the specified sequence in the template", SortOrder = 1)] [CmdletExample( - Code = @"PS:> Apply-PnPProvisioningHierarchy -Path myfile.pnp -Parameters @{""ListTitle""=""Projects"";""parameter2""=""a second value""}", - Remarks = @"Applies a provisioning hierarchy template to the current tenant. It will populate the parameter in the template the values as specified and in the template you can refer to those values with the {parameter:} token. + Code = @"PS:> Apply-PnPTenantTemplate -Path myfile.pnp -Parameters @{""ListTitle""=""Projects"";""parameter2""=""a second value""}", + Remarks = @"Applies a tenant template to the current tenant. It will populate the parameter in the template the values as specified and in the template you can refer to those values with the {parameter:} token. For instance with the example above, specifying {parameter:ListTitle} in your template will translate to 'Projects' when applying the template. These tokens can be used in most string values in a template.", SortOrder = 3)] - public class ApplyProvisioningHierarchy : PnPAdminCmdlet + public class ApplyTenantTemplate : PnPAdminCmdlet { private const string ParameterSet_PATH = "By Path"; private const string ParameterSet_OBJECT = "By Object"; @@ -44,12 +45,13 @@ public class ApplyProvisioningHierarchy : PnPAdminCmdlet public string Path; [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ParameterSetName = ParameterSet_OBJECT)] - public ProvisioningHierarchy Hierarchy; + [Alias("Hierarchy")] + public ProvisioningHierarchy Template; [Parameter(Mandatory = false)] public string SequenceId; - [Parameter(Mandatory = false, HelpMessage = "Root folder where resources/files that are being referenced in the template are located. If not specified the same folder as where the provisioning template is located will be used.", ParameterSetName = ParameterAttribute.AllParameterSets)] + [Parameter(Mandatory = false, HelpMessage = "Root folder where resources/files that are being referenced in the template are located. If not specified the same folder as where the tenant template is located will be used.", ParameterSetName = ParameterAttribute.AllParameterSets)] public string ResourceFolder; [Parameter(Mandatory = false, HelpMessage = "Allows you to only process a specific part of the template. Notice that this might fail, as some of the handlers require other artifacts in place if they are not part of what your applying.", ParameterSetName = ParameterAttribute.AllParameterSets)] @@ -84,6 +86,11 @@ public class ApplyProvisioningHierarchy : PnPAdminCmdlet protected override void ExecuteCmdlet() { + if (MyInvocation.InvocationName.ToLower() == "apply-pnpprovisioninghierarchy") + { + WriteWarning("Apply-PnPProvisioningHierarchy has been deprecated. Use Apply-PnPTenantTemplate instead."); + } + var applyingInformation = new ProvisioningTemplateApplyingInformation(); if (MyInvocation.BoundParameters.ContainsKey("Handlers")) @@ -199,7 +206,7 @@ protected override void ExecuteCmdlet() } case ParameterSet_OBJECT: { - hierarchyToApply = Hierarchy; + hierarchyToApply = Template; if (ResourceFolder != null) { var fileSystemConnector = new FileSystemConnector(ResourceFolder, ""); @@ -259,7 +266,7 @@ private ProvisioningHierarchy GetHierarchy() { Path = System.IO.Path.Combine(SessionState.Path.CurrentFileSystemLocation.Path, Path); } - return ReadProvisioningHierarchy.LoadProvisioningHierarchyFromFile(Path, TemplateProviderExtensions); + return ReadTenantTemplate.LoadProvisioningHierarchyFromFile(Path, TemplateProviderExtensions); } } } diff --git a/Commands/Provisioning/GetProvisioningSequence.cs b/Commands/Provisioning/Tenant/GetTenantSequence.cs similarity index 53% rename from Commands/Provisioning/GetProvisioningSequence.cs rename to Commands/Provisioning/Tenant/GetTenantSequence.cs index f59079421..2c5e16080 100644 --- a/Commands/Provisioning/GetProvisioningSequence.cs +++ b/Commands/Provisioning/Tenant/GetTenantSequence.cs @@ -4,35 +4,41 @@ using System; using System.Management.Automation; -namespace SharePointPnP.PowerShell.Commands.Provisioning +namespace SharePointPnP.PowerShell.Commands.Provisioning.Tenant { - [Cmdlet(VerbsCommon.Get, "PnPProvisioningSequence", SupportsShouldProcess = true)] - [CmdletHelp("Returns one ore more provisioning sequence object(s) from a provisioning hierarchy", + [Cmdlet(VerbsCommon.Get, "PnPTenantSequence", SupportsShouldProcess = true)] + [Alias("Get-PnPProvisioningSequence")] + [CmdletHelp("Returns one ore more provisioning sequence object(s) from a tenant template", Category = CmdletHelpCategory.Provisioning)] [CmdletExample( - Code = @"PS:> Get-PnPProvisioningSequence -Hierarchy $myhierarchy", - Remarks = "Returns all sequences from the specified hierarchy", + Code = @"PS:> Get-PnPTenantSequence -Template $myhierarchy", + Remarks = "Returns all sequences from the specified tenant template", SortOrder = 1)] [CmdletExample( - Code = @"PS:> Get-PnPProvisioningSequence -Hierarchy $myhierarchy -Identity ""mysequence""", - Remarks = "Returns the specified sequence from the specified hierarchy", + Code = @"PS:> Get-PnPTenantSequence -Template $myhierarchy -Identity ""mysequence""", + Remarks = "Returns the specified sequence from the specified tenant template", SortOrder = 2)] - public class GetProvisioningSequence : PSCmdlet + public class GetTenantSequence : PSCmdlet { [Parameter(Mandatory = true, HelpMessage = "The hierarchy to retrieve the sequence from", ParameterSetName = ParameterAttribute.AllParameterSets)] - public ProvisioningHierarchy Hierarchy; + public ProvisioningHierarchy Template; [Parameter(Mandatory = false, HelpMessage = "Optional Id of the sequence", ParameterSetName = ParameterAttribute.AllParameterSets, ValueFromPipeline = true)] public ProvisioningSequencePipeBind Identity; protected override void ProcessRecord() { + + if (MyInvocation.InvocationName.ToLower() == "get-pnpprovisioningsequence") + { + WriteWarning("Get-PnPProvisioningSequence has been deprecated. Use Get-PnPTenantSequence instead."); + } if (!MyInvocation.BoundParameters.ContainsKey("Identity")) { - WriteObject(Hierarchy.Sequences, true); + WriteObject(Template.Sequences, true); } else { - WriteObject(Identity.GetSequenceFromHierarchy(Hierarchy)); + WriteObject(Identity.GetSequenceFromHierarchy(Template)); } } } diff --git a/Commands/Provisioning/GetProvisioningSite.cs b/Commands/Provisioning/Tenant/GetTenantSequenceSite.cs similarity index 63% rename from Commands/Provisioning/GetProvisioningSite.cs rename to Commands/Provisioning/Tenant/GetTenantSequenceSite.cs index d736ac23f..3dacb1758 100644 --- a/Commands/Provisioning/GetProvisioningSite.cs +++ b/Commands/Provisioning/Tenant/GetTenantSequenceSite.cs @@ -4,20 +4,21 @@ using System; using System.Management.Automation; -namespace SharePointPnP.PowerShell.Commands.Provisioning +namespace SharePointPnP.PowerShell.Commands.Provisioning.Tenant { - [Cmdlet(VerbsCommon.Get, "PnPProvisioningSite", SupportsShouldProcess = true)] - [CmdletHelp("Returns one ore more provisioning sequence object(s) from a provisioning hierarchy", + [Cmdlet(VerbsCommon.Get, "PnPTenantSequenceSite", SupportsShouldProcess = true)] + [Alias("Get-PnPProvisioningSite")] + [CmdletHelp("Returns one ore more sites from a tenant template", Category = CmdletHelpCategory.Provisioning)] [CmdletExample( - Code = @"PS:> Get-PnPProvisioningSite -Sequence $mysequence", + Code = @"PS:> Get-PnPTenantSequenceSite -Sequence $mysequence", Remarks = "Returns all sites from the specified sequence", SortOrder = 1)] [CmdletExample( - Code = @"PS:> Get-PnPProvisioningSite -Sequence $mysequence -Identity 8058ea99-af7b-4bb7-b12a-78f93398041e", + Code = @"PS:> Get-PnPTenantSequenceSite -Sequence $mysequence -Identity 8058ea99-af7b-4bb7-b12a-78f93398041e", Remarks = "Returns the specified site from the specified sequence", SortOrder = 2)] - public class GetProvisioningSite : PSCmdlet + public class GetTenantSequenceSite : PSCmdlet { [Parameter(Mandatory = true, HelpMessage = "The sequence to retrieve the site from", ParameterSetName = ParameterAttribute.AllParameterSets)] public ProvisioningSequence Sequence; @@ -26,6 +27,11 @@ public class GetProvisioningSite : PSCmdlet public ProvisioningSitePipeBind Identity; protected override void ProcessRecord() { + if (MyInvocation.InvocationName.ToLower() == "get-pnpprovisioningsite") + { + WriteWarning("Get-PnPProvisioningSite has been deprecated. Use Get-PnPTenantSequenceSite instead."); + } + if (!MyInvocation.BoundParameters.ContainsKey("Identity")) { WriteObject(Sequence.SiteCollections, true); diff --git a/Commands/Provisioning/NewProvisioningSequence.cs b/Commands/Provisioning/Tenant/NewTenantSequence.cs similarity index 52% rename from Commands/Provisioning/NewProvisioningSequence.cs rename to Commands/Provisioning/Tenant/NewTenantSequence.cs index 649aa803a..637872131 100644 --- a/Commands/Provisioning/NewProvisioningSequence.cs +++ b/Commands/Provisioning/Tenant/NewTenantSequence.cs @@ -4,25 +4,31 @@ using System; using System.Management.Automation; -namespace SharePointPnP.PowerShell.Commands.Provisioning +namespace SharePointPnP.PowerShell.Commands.Provisioning.Tenant { - [Cmdlet(VerbsCommon.New, "PnPProvisioningSequence", SupportsShouldProcess = true)] - [CmdletHelp("Creates a new provisioning sequence object", + [Cmdlet(VerbsCommon.New, "PnPTenantSequence", SupportsShouldProcess = true)] + [Alias("New-PnPProvisioningSequence")] + [CmdletHelp("Creates a new tenant sequence object", Category = CmdletHelpCategory.Provisioning, SupportedPlatform = CmdletSupportedPlatform.Online)] [CmdletExample( - Code = @"PS:> $sequence = New-PnPProvisioningSequence", - Remarks = "Creates a new instance of a provisioning sequence object.", + Code = @"PS:> $sequence = New-PnPTenantSequence", + Remarks = "Creates a new instance of a tenant sequence object.", SortOrder = 1)] [CmdletExample( - Code = @"PS:> $sequence = New-PnPProvisioningSequence -Id ""MySequence""", - Remarks = "Creates a new instance of a provisioning sequence object and sets the Id to the value specified.", + Code = @"PS:> $sequence = New-PnPTenantSequence -Id ""MySequence""", + Remarks = "Creates a new instance of a tenant sequence object and sets the Id to the value specified.", SortOrder = 2)] - public class NewProvisioningSequence : PSCmdlet + public class NewTenantSequence : PSCmdlet { [Parameter(Mandatory = false, HelpMessage = "Optional Id of the sequence", ParameterSetName = ParameterAttribute.AllParameterSets)] public string Id; protected override void ProcessRecord() { + if (MyInvocation.InvocationName.ToLower() == "new-pnpprovisioningsequence") + { + WriteWarning("New-PnPProvisioningSequence has been deprecated. Use New-PnPTenantSequence instead."); + } + var result = new ProvisioningSequence(); if (this.MyInvocation.BoundParameters.ContainsKey("Id")) { diff --git a/Commands/Provisioning/NewProvisioningCommunicationSite.cs b/Commands/Provisioning/Tenant/NewTenantSequenceCommunicationSite.cs similarity index 75% rename from Commands/Provisioning/NewProvisioningCommunicationSite.cs rename to Commands/Provisioning/Tenant/NewTenantSequenceCommunicationSite.cs index 26d811288..88ff3691e 100644 --- a/Commands/Provisioning/NewProvisioningCommunicationSite.cs +++ b/Commands/Provisioning/Tenant/NewTenantSequenceCommunicationSite.cs @@ -4,16 +4,17 @@ using System.Linq; using System.Management.Automation; -namespace SharePointPnP.PowerShell.Commands.Provisioning +namespace SharePointPnP.PowerShell.Commands.Provisioning.Tenant { - [Cmdlet(VerbsCommon.New, "PnPProvisioningCommunicationSite", SupportsShouldProcess = true)] + [Cmdlet(VerbsCommon.New, "PnPTenantSequenceCommunicationSite", SupportsShouldProcess = true)] + [Alias("New-PnPProvisioningCommunicationSite")] [CmdletHelp("Creates a communication site object", Category = CmdletHelpCategory.Provisioning, SupportedPlatform = CmdletSupportedPlatform.Online)] [CmdletExample( - Code = @"PS:> $site = New-PnPProvisioningCommunicationSite -Url ""/sites/mycommunicationsite"" -Title ""My Team Site""", + Code = @"PS:> $site = New-PnPTenantSequenceCommunicationSite -Url ""/sites/mycommunicationsite"" -Title ""My Team Site""", Remarks = "Creates a new communication site object with the specified variables", SortOrder = 1)] - public class NewProvisioningCommunicationSite : PSCmdlet + public class NewTenantSequenceCommunicationSite : PSCmdlet { [Parameter(Mandatory = true)] public string Url; @@ -47,6 +48,11 @@ public class NewProvisioningCommunicationSite : PSCmdlet protected override void ProcessRecord() { + if (MyInvocation.InvocationName.ToLower() == "new-pnpprovisioningcommunicationsite") + { + WriteWarning("New-PnPProvisioningCommunicationSite has been deprecated. Use New-PnPTenantSequenceCommunicationSite instead."); + } + var site = new CommunicationSiteCollection { Url = Url, diff --git a/Commands/Provisioning/NewProvisioningTeamNoGroupSite.cs b/Commands/Provisioning/Tenant/NewTenantSequenceTeamNoGroupSite.cs similarity index 68% rename from Commands/Provisioning/NewProvisioningTeamNoGroupSite.cs rename to Commands/Provisioning/Tenant/NewTenantSequenceTeamNoGroupSite.cs index 759873a4b..3e61f9dc6 100644 --- a/Commands/Provisioning/NewProvisioningTeamNoGroupSite.cs +++ b/Commands/Provisioning/Tenant/NewTenantSequenceTeamNoGroupSite.cs @@ -4,16 +4,17 @@ using System.Linq; using System.Management.Automation; -namespace SharePointPnP.PowerShell.Commands.Provisioning +namespace SharePointPnP.PowerShell.Commands.Provisioning.Tenant { - [Cmdlet(VerbsCommon.New, "PnPProvisioningTeamNoGroupSite", SupportsShouldProcess = true)] - [CmdletHelp("Creates a team site without an Office 365 group object", + [Cmdlet(VerbsCommon.New, "PnPTenantSequenceTeamNoGroupSite", SupportsShouldProcess = true)] + [Alias("New-PnPProvisioningTeamNoGroupSite")] + [CmdletHelp("Creates a new team site without an Office 365 group in-memory object", Category = CmdletHelpCategory.Provisioning, SupportedPlatform = CmdletSupportedPlatform.Online)] [CmdletExample( - Code = @"PS:> $site = New-PnPProvisioningTeamNoGroupSite -Alias ""MyTeamSite"" -Title ""My Team Site""", + Code = @"PS:> $site = New-PnPTenantSequenceTeamNoGroupSite -Alias ""MyTeamSite"" -Title ""My Team Site""", Remarks = "Creates a new team site object with the specified variables", SortOrder = 1)] - public class NewProvisioningTeamNoGroupSite : PSCmdlet + public class NewTenantSequenceTeamNoGroupSite : PSCmdlet { [Parameter(Mandatory = true)] public string Url; @@ -41,6 +42,11 @@ public class NewProvisioningTeamNoGroupSite : PSCmdlet protected override void ProcessRecord() { + if (MyInvocation.InvocationName.ToLower() == "new-pnpprovisioningteamnogroupsite") + { + WriteWarning("New-PnPProvisioningTeamNoGroupSite has been deprecated. Use New-PnPTenantSequenceTeamNoGroupSite instead."); + } + var site = new TeamNoGroupSiteCollection { Url = Url, diff --git a/Commands/Provisioning/NewProvisioningTeamNoGroupSubSite.cs b/Commands/Provisioning/Tenant/NewTenantSequenceTeamNoGroupSubSite.cs similarity index 72% rename from Commands/Provisioning/NewProvisioningTeamNoGroupSubSite.cs rename to Commands/Provisioning/Tenant/NewTenantSequenceTeamNoGroupSubSite.cs index 9918c1469..19b65c1dc 100644 --- a/Commands/Provisioning/NewProvisioningTeamNoGroupSubSite.cs +++ b/Commands/Provisioning/Tenant/NewTenantSequenceTeamNoGroupSubSite.cs @@ -4,16 +4,17 @@ using System.Linq; using System.Management.Automation; -namespace SharePointPnP.PowerShell.Commands.Provisioning +namespace SharePointPnP.PowerShell.Commands.Provisioning.Tenant { - [Cmdlet(VerbsCommon.New, "PnPProvisioningTeamNoGroupSubSite", SupportsShouldProcess = true)] + [Cmdlet(VerbsCommon.New, "PnPTenantSequenceTeamNoGroupSubSite", SupportsShouldProcess = true)] + [Alias("New-PnPProvisioningTeamNoGroupSubSite")] [CmdletHelp("Creates a team site subsite with no Office 365 group object", Category = CmdletHelpCategory.Provisioning, SupportedPlatform = CmdletSupportedPlatform.Online)] [CmdletExample( - Code = @"PS:> $site = New-PnPProvisioningTeamNoGroupSubSite -Url ""MyTeamSubsite"" -Title ""My Team Site"" -TimeZoneId 4", + Code = @"PS:> $site = New-PnPTenantSequenceTeamNoGroupSubSite -Url ""MyTeamSubsite"" -Title ""My Team Site"" -TimeZoneId 4", Remarks = "Creates a new team site subsite object with the specified variables", SortOrder = 1)] - public class NewProvisioningTeamNoGroupSubSite : PSCmdlet + public class NewTenantSequenceTeamNoGroupSubSite : PSCmdlet { [Parameter(Mandatory = true)] @@ -42,7 +43,11 @@ public class NewProvisioningTeamNoGroupSubSite : PSCmdlet protected override void ProcessRecord() { - SiteCollection c; + if (MyInvocation.InvocationName.ToLower() == "new-pnpprovisioningteamnogroupsubsite") + { + WriteWarning("New-PnPProvisioningTeamNoGroupSubSite has been deprecated. Use New-PnPTenantSequenceTeamNoGroupSubSite instead."); + } + var site = new TeamNoGroupSubSite() { Url = Url, diff --git a/Commands/Provisioning/NewProvisioningTeamSite.cs b/Commands/Provisioning/Tenant/NewTenantSequenceTeamSite.cs similarity index 72% rename from Commands/Provisioning/NewProvisioningTeamSite.cs rename to Commands/Provisioning/Tenant/NewTenantSequenceTeamSite.cs index 467e56ff6..b889aa8cc 100644 --- a/Commands/Provisioning/NewProvisioningTeamSite.cs +++ b/Commands/Provisioning/Tenant/NewTenantSequenceTeamSite.cs @@ -4,16 +4,17 @@ using System.Linq; using System.Management.Automation; -namespace SharePointPnP.PowerShell.Commands.Provisioning +namespace SharePointPnP.PowerShell.Commands.Provisioning.Tenant { - [Cmdlet(VerbsCommon.New, "PnPProvisioningTeamSite", SupportsShouldProcess = true)] + [Cmdlet(VerbsCommon.New, "PnPTenantSequenceTeamSite", SupportsShouldProcess = true)] + [Alias("New-PnPProvisioningTeamSite")] [CmdletHelp("Creates a team site object", Category = CmdletHelpCategory.Provisioning, SupportedPlatform = CmdletSupportedPlatform.Online)] [CmdletExample( - Code = @"PS:> $site = New-PnPProvisioningTeamSite -Alias ""MyTeamSite"" -Title ""My Team Site""", + Code = @"PS:> $site = New-PnPTenantSequenceTeamSite -Alias ""MyTeamSite"" -Title ""My Team Site""", Remarks = "Creates a new team site object with the specified variables", SortOrder = 1)] - public class NewProvisioningTeamSite : PSCmdlet + public class NewTenantSequenceTeamSite : PSCmdlet { [Parameter(Mandatory = true)] @@ -42,6 +43,11 @@ public class NewProvisioningTeamSite : PSCmdlet protected override void ProcessRecord() { + if (MyInvocation.InvocationName.ToLower() == "new-pnpprovisioningcommunicationsite") + { + WriteWarning("New-PnPProvisioningCommunicationSite has been deprecated. Use New-PnPTenantSequenceCommunicationSite instead."); + } + var site = new TeamSiteCollection { Alias = Alias, diff --git a/Commands/Provisioning/NewProvisioningHierarchy.cs b/Commands/Provisioning/Tenant/NewTenantTemplate.cs similarity index 59% rename from Commands/Provisioning/NewProvisioningHierarchy.cs rename to Commands/Provisioning/Tenant/NewTenantTemplate.cs index 5094b4e04..43c557dcb 100644 --- a/Commands/Provisioning/NewProvisioningHierarchy.cs +++ b/Commands/Provisioning/Tenant/NewTenantTemplate.cs @@ -3,16 +3,17 @@ using SharePointPnP.PowerShell.CmdletHelpAttributes; using System.Management.Automation; -namespace SharePointPnP.PowerShell.Commands.Provisioning +namespace SharePointPnP.PowerShell.Commands.Provisioning.Tenant { - [Cmdlet(VerbsCommon.New, "PnPProvisioningHierarchy", SupportsShouldProcess = true)] - [CmdletHelp("Creates a new provisioning hierarchy object", + [Cmdlet(VerbsCommon.New, "PnPTenantTemplate", SupportsShouldProcess = true)] + [Alias("New-PnPProvisioningHierarchy")] + [CmdletHelp("Creates a new tenant template object", Category = CmdletHelpCategory.Provisioning, SupportedPlatform = CmdletSupportedPlatform.Online)] [CmdletExample( - Code = @"PS:> $hierarchy = New-PnPProvisioningHierarchy", - Remarks = "Creates a new instance of a provisioning hierarchy object.", + Code = @"PS:> $template = New-PnPTenantTemplate", + Remarks = "Creates a new instance of a tenant template object.", SortOrder = 1)] - public class NewProvisioningHierarchy : PSCmdlet + public class NewTenantTemplate : PSCmdlet { [Parameter(Mandatory = false)] public string Author; @@ -28,6 +29,10 @@ public class NewProvisioningHierarchy : PSCmdlet protected override void ProcessRecord() { + if (MyInvocation.InvocationName.ToLower() == "new-pnpprovisioninghierarchy") + { + WriteWarning("New-PnPProvisioningHierarchy has been deprecated. Use New-PnPTenantTemplate instead."); + } var result = new ProvisioningHierarchy(); result.Author = Author; result.Description = Description; diff --git a/Commands/Provisioning/ReadProvisioningHierarchy.cs b/Commands/Provisioning/Tenant/ReadTenantTemplate.cs similarity index 80% rename from Commands/Provisioning/ReadProvisioningHierarchy.cs rename to Commands/Provisioning/Tenant/ReadTenantTemplate.cs index 7c9fb7bd1..25e0c5cb8 100644 --- a/Commands/Provisioning/ReadProvisioningHierarchy.cs +++ b/Commands/Provisioning/Tenant/ReadTenantTemplate.cs @@ -9,16 +9,17 @@ using System.IO; using System.Management.Automation; -namespace SharePointPnP.PowerShell.Commands.Provisioning +namespace SharePointPnP.PowerShell.Commands.Provisioning.Tenant { - [Cmdlet(VerbsCommunications.Read, "PnPProvisioningHierarchy")] - [CmdletHelp("Loads/Reads a PnP provisioning hierarchy from the file system and returns an in-memory instance of this template.", + [Cmdlet(VerbsCommunications.Read, "PnPTenantTemplate")] + [Alias("Read-PnPProvisioningHierarchy")] + [CmdletHelp("Loads/Reads a PnP tenant template from the file system and returns an in-memory instance of this template.", Category = CmdletHelpCategory.Provisioning, SupportedPlatform = CmdletSupportedPlatform.Online)] [CmdletExample( - Code = @"PS:> Read-PnPProvisioningHierarchy -Path hierarchy.pnp", - Remarks = "Reads a PnP provisioning hierarchy file from the file system and returns an in-memory instance", + Code = @"PS:> Read-PnPTenantTemplate -Path template.pnp", + Remarks = "Reads a PnP tenant templatey file from the file system and returns an in-memory instance", SortOrder = 1)] - public class ReadProvisioningHierarchy : PSCmdlet + public class ReadTenantTemplate : PSCmdlet { [Parameter(Mandatory = true, Position = 0, HelpMessage = "Filename to read from, optionally including full path.")] public string Path; @@ -28,6 +29,11 @@ public class ReadProvisioningHierarchy : PSCmdlet protected override void ProcessRecord() { + if (MyInvocation.InvocationName.ToLower() == "read-pnpprovisioninghierarchy") + { + WriteWarning("Read-PnPProvisioningHierarchy has been deprecated. Use Read-PnPTenantTemplate instead."); + } + if (!System.IO.Path.IsPathRooted(Path)) { Path = System.IO.Path.Combine(SessionState.Path.CurrentFileSystemLocation.Path, Path); diff --git a/Commands/Provisioning/SaveProvisioningHierarchy.cs b/Commands/Provisioning/Tenant/SaveTenantTemplate.cs similarity index 79% rename from Commands/Provisioning/SaveProvisioningHierarchy.cs rename to Commands/Provisioning/Tenant/SaveTenantTemplate.cs index 2672f45b3..e22ef83ca 100644 --- a/Commands/Provisioning/SaveProvisioningHierarchy.cs +++ b/Commands/Provisioning/Tenant/SaveTenantTemplate.cs @@ -9,19 +9,21 @@ using System.Linq; using System.Management.Automation; -namespace SharePointPnP.PowerShell.Commands.Provisioning +namespace SharePointPnP.PowerShell.Commands.Provisioning.Tenant { - [Cmdlet(VerbsData.Save, "PnPProvisioningHierarchy")] + [Cmdlet(VerbsData.Save, "PnPTenantTemplate")] + [Alias("Save-PnPProvisioningHierarchy")] [CmdletHelp("Saves a PnP provisioning hierarchy to the file system", Category = CmdletHelpCategory.Provisioning, SupportedPlatform = CmdletSupportedPlatform.Online)] [CmdletExample( - Code = @"PS:> Save-PnPProvisioningHierarchy -Hierarchy $hierarchy -Out .\hierarchy.pnp", - Remarks = "Saves a PnP provisioning hiearchy to the file system", + Code = @"PS:> Save-PnPTenantTemplate -Template $template -Out .\hierarchy.pnp", + Remarks = "Saves a PnP tenant template to the file system", SortOrder = 1)] - public class SaveProvisioningHierarchy : PSCmdlet + public class SaveTenantTemplate : PSCmdlet { - [Parameter(Mandatory = true, HelpMessage = "Allows you to provide an in-memory instance of the ProvisioningHierarchy type of the PnP Core Component. When using this parameter, the -Out parameter refers to the path for saving the template and storing any supporting file for the template.")] - public ProvisioningHierarchy Hierarchy; + [Parameter(Mandatory = true, HelpMessage = "Allows you to provide an in-memory instance of a Tenant Template. When using this parameter, the -Out parameter refers to the path for saving the template and storing any supporting file for the template.")] + [Alias("Hierarchy")] + public ProvisioningHierarchy Template; [Parameter(Mandatory = true, Position = 0, HelpMessage = "Filename to write to, optionally including full path.")] public string Out; @@ -29,11 +31,12 @@ public class SaveProvisioningHierarchy : PSCmdlet [Parameter(Mandatory = false, HelpMessage = "Specifying the Force parameter will skip the confirmation question.")] public SwitchParameter Force; - //[Parameter(Mandatory = false, HelpMessage = "Allows you to specify the ITemplateProviderExtension to execute while saving a template.")] - //public ITemplateProviderExtension[] TemplateProviderExtensions; - protected override void ProcessRecord() { + if (MyInvocation.InvocationName.ToLower() == "save-pnpprovisioninghierarchy") + { + WriteWarning("Save-PnPProvisioningHierarchy has been deprecated. Use Save-PnPTenantTemplate instead."); + } // Determine the output file name and path string outFileName = Path.GetFileName(Out); @@ -86,7 +89,7 @@ protected override void ProcessRecord() XMLTemplateProvider provider = new XMLOpenXMLTemplateProvider( Out, fileSystemConnector, templateFileName: templateFileName); WriteObject("Processing template"); - provider.SaveAs(Hierarchy, templateFileName); + provider.SaveAs(Template, templateFileName); ProcessFiles(Out, fileSystemConnector, provider.Connector); //provider.SaveAs(Hierarchy, templateFileName); @@ -95,38 +98,38 @@ protected override void ProcessRecord() else { XMLTemplateProvider provider = new XMLFileSystemTemplateProvider(outPath, ""); - provider.SaveAs(Hierarchy, Out); + provider.SaveAs(Template, Out); } } private void ProcessFiles(string templateFileName, FileConnectorBase fileSystemConnector, FileConnectorBase connector) { - var hierarchy = ReadProvisioningHierarchy.LoadProvisioningHierarchyFromFile(templateFileName, null); - if (Hierarchy.Tenant?.AppCatalog != null) + var hierarchy = ReadTenantTemplate.LoadProvisioningHierarchyFromFile(templateFileName, null); + if (Template.Tenant?.AppCatalog != null) { - foreach (var app in Hierarchy.Tenant.AppCatalog.Packages) + foreach (var app in Template.Tenant.AppCatalog.Packages) { WriteObject($"Processing {app.Src}"); AddFile(app.Src, hierarchy, fileSystemConnector, connector); } } - if (Hierarchy.Tenant?.SiteScripts != null) + if (Template.Tenant?.SiteScripts != null) { - foreach (var siteScript in Hierarchy.Tenant.SiteScripts) + foreach (var siteScript in Template.Tenant.SiteScripts) { WriteObject($"Processing {siteScript.JsonFilePath}"); AddFile(siteScript.JsonFilePath, hierarchy, fileSystemConnector, connector); } } - if (Hierarchy.Localizations != null && Hierarchy.Localizations.Any()) + if (Template.Localizations != null && Template.Localizations.Any()) { - foreach (var location in Hierarchy.Localizations) + foreach (var location in Template.Localizations) { WriteObject($"Processing {location.ResourceFile}"); AddFile(location.ResourceFile, hierarchy, fileSystemConnector, connector); } } - foreach (var template in Hierarchy.Templates) + foreach (var template in Template.Templates) { if(template.WebSettings != null && template.WebSettings.SiteLogo != null) { diff --git a/Commands/Provisioning/TestProvisioningHierarchy.cs b/Commands/Provisioning/Tenant/TestTenantTemplate.cs similarity index 68% rename from Commands/Provisioning/TestProvisioningHierarchy.cs rename to Commands/Provisioning/Tenant/TestTenantTemplate.cs index b339ff341..3ace7cb30 100644 --- a/Commands/Provisioning/TestProvisioningHierarchy.cs +++ b/Commands/Provisioning/Tenant/TestTenantTemplate.cs @@ -5,50 +5,56 @@ using System.Linq; using System.Management.Automation; -namespace SharePointPnP.PowerShell.Commands.Provisioning +namespace SharePointPnP.PowerShell.Commands.Provisioning.Tenant { - [Cmdlet(VerbsDiagnostic.Test, "PnPProvisioningHierarchy", SupportsShouldProcess = true)] + [Cmdlet(VerbsDiagnostic.Test, "PnPTenantTemplate", SupportsShouldProcess = true)] + [Alias("Test-PnPProvisioningHierarchy")] [CmdletHelp("Tests a provisioning hierarchy for invalid references", Category = CmdletHelpCategory.Provisioning)] [CmdletExample( Code = @"PS:> Test-PnPProvisioningHierarchy -Hierarchy $myhierarchy", Remarks = "Checks for valid template references", SortOrder = 1)] - public class TestProvisioningHierarchy : PnPCmdlet + public class TestTenantTemplate : PnPCmdlet { - [Parameter(Mandatory = true, HelpMessage = "The hierarchy to add the sequence to", ParameterSetName = ParameterAttribute.AllParameterSets)] - public ProvisioningHierarchy Hierarchy; + [Parameter(Mandatory = true, HelpMessage = "The in-memory template to test", ParameterSetName = ParameterAttribute.AllParameterSets)] + [Alias("Hierarchy")] + public ProvisioningHierarchy Template; protected override void ExecuteCmdlet() { + if (MyInvocation.InvocationName.ToLower() == "test-pnpprovisioninghierarchy") + { + WriteWarning("Test-PnPProvisioningHierarchy has been deprecated. Use Test-PnPTenantTemplate instead."); + } List issues = new List(); - foreach(var sequence in Hierarchy.Sequences) + foreach(var sequence in Template.Sequences) { foreach (var site in sequence.SiteCollections) { foreach (var template in site.Templates) { - if(Hierarchy.Templates.FirstOrDefault(t => t.Id == template) == null) + if(Template.Templates.FirstOrDefault(t => t.Id == template) == null) { - issues.Add($"Template {template} referenced in site {site.Id} is not present in hierarchy."); + issues.Add($"Template {template} referenced in site {site.Id} is not present in tenant template."); } } foreach(var subsite in site.Sites.Cast()) { foreach (var template in subsite.Templates) { - if (Hierarchy.Templates.FirstOrDefault(t => t.Id == template) == null) + if (Template.Templates.FirstOrDefault(t => t.Id == template) == null) { - issues.Add($"Template {template} referenced in subsite with url {subsite.Url} in site {site.Id} is not present in hierarchy"); + issues.Add($"Template {template} referenced in subsite with url {subsite.Url} in site {site.Id} is not present in tenant template."); } } } } } - foreach(var template in Hierarchy.Templates) + foreach(var template in Template.Templates) { var used = false; - foreach(var sequence in Hierarchy.Sequences) + foreach(var sequence in Template.Sequences) { foreach(var site in sequence.SiteCollections) { @@ -78,7 +84,7 @@ protected override void ExecuteCmdlet() } if(!used) { - issues.Add($"Template {template.Id} is not used by any site in the hierarchy."); + issues.Add($"Template {template.Id} is not used by any site in the tenant template sequence."); } } if(issues.Any()) diff --git a/Commands/RecycleBin/GetTenantRecycleBinItem.cs b/Commands/RecycleBin/GetTenantRecycleBinItem.cs index 1d0134162..4c80c7c34 100644 --- a/Commands/RecycleBin/GetTenantRecycleBinItem.cs +++ b/Commands/RecycleBin/GetTenantRecycleBinItem.cs @@ -8,7 +8,7 @@ namespace SharePointPnP.PowerShell.Commands.RecycleBin { [Cmdlet(VerbsCommon.Get, "PnPTenantRecycleBinItem", DefaultParameterSetName = "All")] - [CmdletHelp("Returns the items in the tenant scoped recycle bin", + [CmdletHelp("Returns all modern and classic site collections in the tenant scoped recycle bin", DetailedDescription = "This command will return all the items in the tenant recycle bin for the Office 365 tenant you are connected to. Be sure to connect to the SharePoint Online Admin endpoint (https://yourtenantname-admin.sharepoint.com) in order for this command to work.", Category = CmdletHelpCategory.RecycleBin, SupportedPlatform = CmdletSupportedPlatform.Online, @@ -16,13 +16,13 @@ namespace SharePointPnP.PowerShell.Commands.RecycleBin OutputTypeLink = "https://msdn.microsoft.com/en-us/library/microsoft.online.sharepoint.tenantadministration.deletedsiteproperties.aspx")] [CmdletExample( Code = @"PS:> Get-PnPTenantRecycleBinItem", - Remarks = "Returns all site collections in the tenant scoped recycle bin", + Remarks = "Returns all modern and classic site collections in the tenant scoped recycle bin", SortOrder = 1)] public class GetTenantRecycleBinItems : PnPAdminCmdlet { protected override void ExecuteCmdlet() { - var deletedSites = Tenant.GetDeletedSiteProperties(0); + var deletedSites = Tenant.GetDeletedSitePropertiesFromSharePoint("0"); ClientContext.Load(deletedSites, c => c.IncludeWithDefaultProperties(s => s.Url, s => s.SiteId, s => s.DaysRemaining, s => s.Status)); ClientContext.ExecuteQueryRetry(); if (deletedSites.AreItemsAvailable) diff --git a/Commands/SharePointPnP.PowerShell.Commands.csproj b/Commands/SharePointPnP.PowerShell.Commands.csproj index fb50e70a3..a66dc5503 100644 --- a/Commands/SharePointPnP.PowerShell.Commands.csproj +++ b/Commands/SharePointPnP.PowerShell.Commands.csproj @@ -303,14 +303,14 @@ ..\packages\Microsoft.ApplicationInsights.2.5.1\lib\net45\Microsoft.ApplicationInsights.dll - - ..\packages\Microsoft.Data.Edm.5.6.2\lib\net40\Microsoft.Data.Edm.dll + + ..\packages\Microsoft.Data.Edm.5.8.4\lib\net40\Microsoft.Data.Edm.dll - - ..\packages\Microsoft.Data.OData.5.6.2\lib\net40\Microsoft.Data.OData.dll + + ..\packages\Microsoft.Data.OData.5.8.4\lib\net40\Microsoft.Data.OData.dll - - ..\packages\Microsoft.Data.Services.Client.5.6.2\lib\net40\Microsoft.Data.Services.Client.dll + + ..\packages\Microsoft.Data.Services.Client.5.8.4\lib\net40\Microsoft.Data.Services.Client.dll ..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.1.0.0\lib\netstandard1.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll @@ -401,8 +401,8 @@ - - ..\packages\System.Spatial.5.6.2\lib\net40\System.Spatial.dll + + ..\packages\System.Spatial.5.8.4\lib\net40\System.Spatial.dll ..\packages\System.Text.Encodings.Web.4.0.0\lib\netstandard1.0\System.Text.Encodings.Web.dll @@ -501,22 +501,22 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + @@ -686,28 +686,28 @@ - - + + - - - + + + - - - - - + + + + + - + - - - + + + diff --git a/Commands/Site/SetSite.cs b/Commands/Site/SetSite.cs index 68fdbbe5f..603fa1207 100644 --- a/Commands/Site/SetSite.cs +++ b/Commands/Site/SetSite.cs @@ -1,6 +1,13 @@ #if !ONPREMISES +using Microsoft.Online.SharePoint.TenantAdministration; +using Microsoft.Online.SharePoint.TenantManagement; using Microsoft.SharePoint.Client; +using OfficeDevPnP.Core; +using OfficeDevPnP.Core.Entities; using SharePointPnP.PowerShell.CmdletHelpAttributes; +using SharePointPnP.PowerShell.Commands.Utilities; +using System; +using System.Collections.Generic; using System.Management.Automation; namespace SharePointPnP.PowerShell.Commands.Site @@ -31,27 +38,107 @@ namespace SharePointPnP.PowerShell.Commands.Site SortOrder = 4)] public class SetSite : PnPCmdlet { - [Parameter(Mandatory = false, HelpMessage = "The classification to set")] + +#if !ONPREMISES + private const string ParameterSet_LOCKSTATE = "Set Lock State"; + private const string ParameterSet_PROPERTIES = "Set Properties"; +#endif + + [Parameter(Mandatory = false)] + [Alias("Url")] + public string Identity; + + [Parameter(Mandatory = false, HelpMessage = "The classification to set", ParameterSetName = ParameterSet_PROPERTIES)] public string Classification; - [Parameter(Mandatory = false, HelpMessage = "Disables flows for this site")] + [Parameter(Mandatory = false, HelpMessage = "Disables flows for this site", ParameterSetName = ParameterSet_PROPERTIES)] public SwitchParameter DisableFlows; - [Parameter(Mandatory = false, HelpMessage = "Sets the logo if the site is modern team site. If you want to set the logo for a classic site, use Set-PnPWeb -SiteLogoUrl")] + [Parameter(Mandatory = false, HelpMessage = "Sets the logo if the site is modern team site. If you want to set the logo for a classic site, use Set-PnPWeb -SiteLogoUrl", ParameterSetName = ParameterSet_PROPERTIES)] public string LogoFilePath; + [Parameter(Mandatory = false, HelpMessage = "Specifies what the sharing capablilites are for the site. Possible values: Disabled, ExternalUserSharingOnly, ExternalUserAndGuestSharing, ExistingExternalUserSharingOnly", ParameterSetName = ParameterSet_PROPERTIES)] + public SharingCapabilities? Sharing = null; + + [Parameter(Mandatory = false, HelpMessage = "Specifies the storage quota for this site collection in megabytes. This value must not exceed the company's available quota.", ParameterSetName = ParameterSet_PROPERTIES)] + public long? StorageMaximumLevel = null; + + [Parameter(Mandatory = false, HelpMessage = "Specifies the warning level for the storage quota in megabytes. This value must not exceed the values set for the StorageMaximumLevel parameter", ParameterSetName = ParameterSet_PROPERTIES)] + public long? StorageWarningLevel = null; + + [Parameter(Mandatory = false, HelpMessage = "Specifies the quota for this site collection in Sandboxed Solutions units. This value must not exceed the company's aggregate available Sandboxed Solutions quota. The default value is 0. For more information, see Resource Usage Limits on Sandboxed Solutions in SharePoint 2010 : http://msdn.microsoft.com/en-us/library/gg615462.aspx.", ParameterSetName = ParameterSet_PROPERTIES)] + [Obsolete("Sandboxed solution code has been deprecated")] + public double? UserCodeMaximumLevel = null; + + [Parameter(Mandatory = false, HelpMessage = "Specifies the warning level for the resource quota. This value must not exceed the value set for the UserCodeMaximumLevel parameter", ParameterSetName = ParameterSet_PROPERTIES)] + [Obsolete("Sandboxed solution code has been deprecated")] + public double? UserCodeWarningLevel = null; + + [Parameter(Mandatory = false, HelpMessage = "Sets the lockstate of a site", ParameterSetName = ParameterSet_LOCKSTATE)] + public SiteLockState? LockState; + + [Parameter(Mandatory = false, HelpMessage = "Specifies if the site administrator can upgrade the site collection", ParameterSetName = ParameterSet_PROPERTIES)] + public SwitchParameter? AllowSelfServiceUpgrade = null; + + [Parameter(Mandatory = false, HelpMessage = "Specifies if a site allows custom script or not. See https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f for more information.", ParameterSetName = ParameterSet_PROPERTIES)] + [Alias("DenyAndAddCustomizePages")] + public SwitchParameter NoScriptSite; + + [Parameter(Mandatory = false, HelpMessage = "Specifies owner(s) to add as site collection adminstrators. They will be added as additional site collection administrators. Existing administrators will stay. Can be both users and groups.", ParameterSetName = ParameterSet_PROPERTIES)] + public List Owners; + + [Parameter(Mandatory = false, HelpMessage = "Specifies if comments on site pages are enabled or disabled", ParameterSetName = ParameterSet_PROPERTIES)] + public SwitchParameter CommentsOnSitePagesDisabled; + + [Parameter(Mandatory = false, HelpMessage = @"Specifies the default link permission for the site collection. None - Respect the organization default link permission. View - Sets the default link permission for the site to ""view"" permissions. Edit - Sets the default link permission for the site to ""edit"" permissions", ParameterSetName = ParameterSet_PROPERTIES)] + public SharingPermissionType? DefaultLinkPermission; + + [Parameter(Mandatory = false, HelpMessage = @"Specifies the default link type for the site collection. None - Respect the organization default sharing link type. AnonymousAccess - Sets the default sharing link for this site to an Anonymous Access or Anyone link. Internal - Sets the default sharing link for this site to the ""organization"" link or company shareable link. Direct - Sets the default sharing link for this site to the ""Specific people"" link", ParameterSetName = ParameterSet_PROPERTIES)] + public SharingLinkType? DefaultSharingLinkType; + + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_PROPERTIES)] + public AppViewsPolicy? DisableAppViews; + + [Parameter(Mandatory = false, ParameterSetName = ParameterSet_PROPERTIES)] + public CompanyWideSharingLinksPolicy? DisableCompanyWideSharingLinks; + + [Parameter(Mandatory = false, HelpMessage = @"Specifies to prevent non-owners from inviting new users to the site", ParameterSetName = ParameterSet_PROPERTIES)] + public SwitchParameter DisableSharingForNonOwners; + + [Parameter(Mandatory = false, HelpMessage = @"Specifies the language of this site collection.", ParameterSetName = ParameterSet_PROPERTIES)] + public uint? LocaleId; + + [Parameter(Mandatory = false, HelpMessage = @"Specifies the language of this site collection.", ParameterSetName = ParameterSet_PROPERTIES)] + public string NewUrl; + + [Parameter(Mandatory = false, HelpMessage = @"Specifies the Geo/Region restrictions of this site.", ParameterSetName = ParameterSet_PROPERTIES)] + public RestrictedToRegion? RestrictedToGeo; + + [Parameter(Mandatory = false, HelpMessage = @"Disables or enables the Social Bar for Site Collection.", ParameterSetName = ParameterSet_PROPERTIES)] + public SwitchParameter SocialBarOnSitePagesDisabled; + + [Parameter(Mandatory = false, HelpMessage = "Wait for the operation to complete", ParameterSetName = ParameterSet_LOCKSTATE)] + public SwitchParameter Wait; + protected override void ExecuteCmdlet() { - var executeQueryRequired = false; + var context = ClientContext; var site = ClientContext.Site; - if (MyInvocation.BoundParameters.ContainsKey("Classification")) + var siteUrl = ClientContext.Url; + + var executeQueryRequired = false; + + if (!string.IsNullOrEmpty(Identity)) { - site.Classification = Classification; - executeQueryRequired = true; + context = ClientContext.Clone(Identity); + site = context.Site; + siteUrl = context.Url; } - if (MyInvocation.BoundParameters.ContainsKey("DisableFlows")) + + + if (MyInvocation.BoundParameters.ContainsKey("Classification")) { - site.DisableFlows = DisableFlows; + site.Classification = Classification; executeQueryRequired = true; } if (MyInvocation.BoundParameters.ContainsKey("LogoFilePath")) @@ -67,22 +154,183 @@ protected override void ExecuteCmdlet() { var bytes = System.IO.File.ReadAllBytes(LogoFilePath); var mimeType = System.Web.MimeMapping.GetMimeMapping(LogoFilePath); - var result = OfficeDevPnP.Core.Sites.SiteCollection.SetGroupImage(ClientContext, bytes, mimeType).GetAwaiter().GetResult(); + var result = OfficeDevPnP.Core.Sites.SiteCollection.SetGroupImage(context, bytes, mimeType).GetAwaiter().GetResult(); } else { throw new System.Exception("Logo file does not exist"); } - } else + } + else { throw new System.Exception("Not an Office365 group enabled site."); } } if (executeQueryRequired) { - ClientContext.ExecuteQueryRetry(); + context.ExecuteQueryRetry(); + } + + if (IsTenantProperty()) + { + var tenantAdminUrl = UrlUtilities.GetTenantAdministrationUrl(context.Url); + context = context.Clone(tenantAdminUrl); + + executeQueryRequired = false; + Func timeoutFunction = TimeoutFunction; + Tenant tenant = new Tenant(context); + var siteProperties = tenant.GetSitePropertiesByUrl(siteUrl, false); + if (LockState.HasValue) + { + tenant.SetSiteLockState(siteUrl, LockState.Value, Wait, Wait ? timeoutFunction : null); + WriteWarning("You changed the lockstate of this site. This change is not guaranteed to be effective immediately. Please wait a few minutes for this to take effect."); + } + + if (Owners != null && Owners.Count > 0) + { + var admins = new List(); + foreach (var owner in Owners) + { + var userEntity = new UserEntity { LoginName = owner }; + admins.Add(userEntity); + } + tenant.AddAdministrators(admins, new Uri(siteUrl)); + } + if (Sharing.HasValue) + { + siteProperties.SharingCapability = Sharing.Value; + executeQueryRequired = true; + } + if (StorageMaximumLevel.HasValue) + { + siteProperties.StorageMaximumLevel = StorageMaximumLevel.Value; + executeQueryRequired = true; + } + if (StorageWarningLevel.HasValue) + { + siteProperties.StorageWarningLevel = StorageWarningLevel.Value; + executeQueryRequired = true; + } +#pragma warning disable CS0618 // Type or member is obsolete + if (UserCodeWarningLevel.HasValue) + { + siteProperties.UserCodeWarningLevel = UserCodeWarningLevel.Value; + executeQueryRequired = true; + } + if (UserCodeMaximumLevel.HasValue) + { + siteProperties.UserCodeMaximumLevel = UserCodeMaximumLevel.Value; + executeQueryRequired = true; + } +#pragma warning restore CS0618 // Type or member is obsolete + + if (AllowSelfServiceUpgrade.HasValue) + { + siteProperties.AllowSelfServiceUpgrade = AllowSelfServiceUpgrade.Value; + executeQueryRequired = true; + } + if (NoScriptSite.IsPresent) + { + siteProperties.DenyAddAndCustomizePages = (NoScriptSite == true ? DenyAddAndCustomizePagesStatus.Enabled : DenyAddAndCustomizePagesStatus.Disabled); + executeQueryRequired = true; + } + if (CommentsOnSitePagesDisabled.IsPresent) + { + siteProperties.CommentsOnSitePagesDisabled = CommentsOnSitePagesDisabled; + executeQueryRequired = true; + } + if (DefaultLinkPermission.HasValue) + { + siteProperties.DefaultLinkPermission = DefaultLinkPermission.Value; + executeQueryRequired = true; + } + if (DefaultSharingLinkType.HasValue) + { + siteProperties.DefaultSharingLinkType = DefaultSharingLinkType.Value; + executeQueryRequired = true; + } + if (DisableAppViews.HasValue) + { + siteProperties.DisableAppViews = DisableAppViews.Value; + executeQueryRequired = true; + } + if (DisableCompanyWideSharingLinks.HasValue) + { + siteProperties.DisableCompanyWideSharingLinks = DisableCompanyWideSharingLinks.Value; + executeQueryRequired = true; + } + if (DisableFlows.IsPresent) + { + siteProperties.DisableFlows = DisableFlows ? FlowsPolicy.Disabled : FlowsPolicy.NotDisabled; + executeQueryRequired = true; + } + if (LocaleId.HasValue) + { + siteProperties.Lcid = LocaleId.Value; + executeQueryRequired = true; + } + if (!string.IsNullOrEmpty(NewUrl)) + { + siteProperties.NewUrl = NewUrl; + executeQueryRequired = true; + } + if (RestrictedToGeo.HasValue) + { + siteProperties.RestrictedToRegion = RestrictedToGeo.Value; + executeQueryRequired = true; + } + if (SocialBarOnSitePagesDisabled.IsPresent) + { + siteProperties.SocialBarOnSitePagesDisabled = SocialBarOnSitePagesDisabled; + executeQueryRequired = true; + } + if (executeQueryRequired) + { + siteProperties.Update(); + tenant.Context.ExecuteQueryRetry(); + } + + if (DisableSharingForNonOwners.IsPresent) + { + Office365Tenant office365Tenant = new Office365Tenant(context); + context.Load(office365Tenant); + context.ExecuteQueryRetry(); + office365Tenant.DisableSharingForNonOwnersOfSite(siteUrl); + context.ExecuteQuery(); + } + } + } + + private bool TimeoutFunction(TenantOperationMessage message) + { + if (message == TenantOperationMessage.SettingSiteProperties || message == TenantOperationMessage.SettingSiteLockState) + { + Host.UI.Write("."); } + return Stopping; } + + private bool IsTenantProperty() => LockState.HasValue || + (Owners != null && Owners.Count > 0) || + Sharing.HasValue || + StorageMaximumLevel.HasValue || + StorageWarningLevel.HasValue || +#pragma warning disable CS0618 // Type or member is obsolete + UserCodeMaximumLevel.HasValue || + UserCodeWarningLevel.HasValue || +#pragma warning restore CS0618 // Type or member is obsolete + AllowSelfServiceUpgrade.HasValue || + NoScriptSite.IsPresent || + CommentsOnSitePagesDisabled.IsPresent || + DefaultLinkPermission.HasValue || + DefaultSharingLinkType.HasValue || + DisableAppViews.HasValue || + DisableFlows.IsPresent || + DisableSharingForNonOwners.IsPresent || + LocaleId.HasValue || + !string.IsNullOrEmpty(NewUrl) || + RestrictedToGeo.HasValue || + SocialBarOnSitePagesDisabled.IsPresent; } } #endif \ No newline at end of file diff --git a/Commands/app.config b/Commands/app.config index 286872ee0..752055dfe 100644 --- a/Commands/app.config +++ b/Commands/app.config @@ -54,6 +54,18 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/Commands/packages.config b/Commands/packages.config index 19f91682b..5294fe07f 100644 --- a/Commands/packages.config +++ b/Commands/packages.config @@ -5,9 +5,9 @@ - - - + + + @@ -36,7 +36,7 @@ - + diff --git a/README.md b/README.md index 5e7c52809..053645a8e 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,12 @@ To use the library you first need to connect to your tenant: Connect-PnPOnline –Url https://yoursite.sharepoint.com –Credentials (Get-Credential) ``` +Or if you have Multi Factor Authentication enabled or if you are using a federated identity provider like AD FS, instead use: + +```powershell +Connect-PnPOnline –Url https://yoursite.sharepoint.com –UseWebLogin +``` + To view all cmdlets, enter: ```powershell @@ -105,4 +111,4 @@ To debug the cmdlets: launch PowerShell and attach Visual Studio to the powershe This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. - \ No newline at end of file + diff --git a/Samples/Modules.Install/Install-PowerShellPackageMangement.ps1 b/Samples/Modules.Install/Install-PowerShellPackageMangement.ps1 index 1934b4b67..5be565cf2 100644 --- a/Samples/Modules.Install/Install-PowerShellPackageMangement.ps1 +++ b/Samples/Modules.Install/Install-PowerShellPackageMangement.ps1 @@ -29,7 +29,7 @@ if (!(Get-command -Module PowerShellGet).count -gt 0) $URL = $Request.GetResponse() $Filename = $URL.ResponseUri.OriginalString.Split("/")[-1] $url.close() - $WC = New-Object System.Net.WebClient + $WC = New-Object -TypeName System.Net.WebClient $WC.DownloadFile($version,"$env:TEMP\$Filename") $WC.Dispose() diff --git a/Samples/Modules.Install/Install-SharePointPnPPowerShell.ps1 b/Samples/Modules.Install/Install-SharePointPnPPowerShell.ps1 index 17adfedca..682d23063 100644 --- a/Samples/Modules.Install/Install-SharePointPnPPowerShell.ps1 +++ b/Samples/Modules.Install/Install-SharePointPnPPowerShell.ps1 @@ -1,2 +1,2 @@ -Invoke-Expression (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/officedev/PnP-PowerShell/master/Samples/Modules.Install/Install-PowerShellPackageMangement.ps1') # We use this to install the PowerShell Package Manager for the PowerShell Gallery -Invoke-Expression (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/officedev/PnP-PowerShell/master/Samples/Modules.Install/Install-SharePointPnPPowerShellHelperModule.ps1') \ No newline at end of file +Invoke-Expression (New-Object -TypeName Net.WebClient).DownloadString('https://raw.githubusercontent.com/officedev/PnP-PowerShell/master/Samples/Modules.Install/Install-PowerShellPackageMangement.ps1') # We use this to install the PowerShell Package Manager for the PowerShell Gallery +Invoke-Expression (New-Object -TypeName Net.WebClient).DownloadString('https://raw.githubusercontent.com/officedev/PnP-PowerShell/master/Samples/Modules.Install/Install-SharePointPnPPowerShellHelperModule.ps1') \ No newline at end of file diff --git a/Samples/Modules.Install/Install-SharePointPnPPowerShellHelperModule.ps1 b/Samples/Modules.Install/Install-SharePointPnPPowerShellHelperModule.ps1 index cde094f52..de4b68c45 100644 --- a/Samples/Modules.Install/Install-SharePointPnPPowerShellHelperModule.ps1 +++ b/Samples/Modules.Install/Install-SharePointPnPPowerShellHelperModule.ps1 @@ -39,11 +39,11 @@ param ( if (!(Get-command -Module $moduleName).count -gt 0) { - Install-Module $moduleName -Force -SkipPublisherCheck + Install-Module -Name $moduleName -Force -SkipPublisherCheck } - Write-Output "The modules for $moduleVersion have been installed and can now be used" - Write-Output 'On the next release you can just run Update-Module -force to update this and other installed modules' + Write-Output -InputObject "The modules for $moduleVersion have been installed and can now be used" + Write-Output -InputObject 'On the next release you can just run Update-Module -force to update this and other installed modules' } function Request-SPOOrOnPremises @@ -51,9 +51,9 @@ function Request-SPOOrOnPremises [string]$title="Confirm" [string]$message="Which version of the Modules do you want to install?" - $SPO = New-Object System.Management.Automation.Host.ChoiceDescription "SharePoint &Online", "SharePoint Online" - $SP2016 = New-Object System.Management.Automation.Host.ChoiceDescription "SharePoint 201&6", "SharePoint 2016" - $SP2013 = New-Object System.Management.Automation.Host.ChoiceDescription "SharePoint 201&3", "SharePoint 2013" + $SPO = New-Object -TypeName System.Management.Automation.Host.ChoiceDescription -ArgumentList "SharePoint &Online", "SharePoint Online" + $SP2016 = New-Object -TypeName System.Management.Automation.Host.ChoiceDescription -ArgumentList "SharePoint 201&6", "SharePoint 2016" + $SP2013 = New-Object -TypeName System.Management.Automation.Host.ChoiceDescription -ArgumentList "SharePoint 201&3", "SharePoint 2013" $options = [System.Management.Automation.Host.ChoiceDescription[]]($SPO, $SP2016, $SP2013) $result = $host.ui.PromptForChoice($title, $message, $options, 0) @@ -69,12 +69,12 @@ function Request-SPOOrOnPremises if ((Get-command -Module PowerShellGet).count -gt 0) { - Write-Output 'PowerShellPackageManagement now installed we will now run the next command in 10 Seconds' + Write-Output -InputObject 'PowerShellPackageManagement now installed we will now run the next command in 10 Seconds' Start-Sleep -Seconds 10 Install-SharePointPnPPowerShellModule -ModuleToInstall (Request-SPOOrOnPremises) } else { - Write-Output "PowerShellPackageManagement is not installed on this Machine - Please run the below to install - you will need to Copy and Paste it as i'm not doing everything for you ;-)" - Write-Output "Invoke-Expression (New-Object Net.WebClient).DownloadString('http://bit.ly/PSPackManInstall')" + Write-Output -InputObject "PowerShellPackageManagement is not installed on this Machine - Please run the below to install - you will need to Copy and Paste it as i'm not doing everything for you ;-)" + Write-Output -InputObject "Invoke-Expression (New-Object -TypeName Net.WebClient).DownloadString('http://bit.ly/PSPackManInstall')" } diff --git a/Samples/Provisioning.CreateSitesFromCsv/CreateSites.ps1 b/Samples/Provisioning.CreateSitesFromCsv/CreateSites.ps1 index c8b915bb9..03c567de7 100644 --- a/Samples/Provisioning.CreateSitesFromCsv/CreateSites.ps1 +++ b/Samples/Provisioning.CreateSitesFromCsv/CreateSites.ps1 @@ -46,7 +46,7 @@ else # Prompts for credentials, if not found in the Windows Credential Manager. $email = Read-Host -Prompt "Please enter tenant admin email" $pass = Read-host -AsSecureString "Please enter tenant admin password" - $credentials = New-Object –TypeName "System.Management.Automation.PSCredential" –ArgumentList $email, $pass + $credentials = New-Object -TypeName "System.Management.Automation.PSCredential" –ArgumentList $email, $pass } if($credentials -eq $null -or $csvConfig -eq $null) @@ -67,7 +67,7 @@ foreach ($item in $csvConfig) Write-Host "Provisioning site collection $siteUrl" -ForegroundColor Yellow - if(Get-PnPTenantSite | where {$_.Url -eq $siteUrl}) + if(Get-PnPTenantSite | where-Object -FilterScript {$_.Url -eq $siteUrl}) { Write-Host "Site collection $siteUrl exists. Moving to the next one." -ForegroundColor Yellow continue @@ -87,7 +87,7 @@ foreach ($item in $csvConfig) Write-Host "Provisioning sub web $siteUrl." -ForegroundColor Yellow - if(Get-PnPSubWebs | where {$_.Url -eq $siteUrl}) + if(Get-PnPSubWebs | where-Object -FilterScript {$_.Url -eq $siteUrl}) { Write-Host "Sub web $siteUrl exists. Moving to the next one." -ForegroundColor Yellow continue diff --git a/Samples/Provisioning.CreateWithEngine/DevRampUp-Demo-PnP-ProvisioningEngine.ps1 b/Samples/Provisioning.CreateWithEngine/DevRampUp-Demo-PnP-ProvisioningEngine.ps1 index 9a4ab6fa8..5a7c825f7 100644 Binary files a/Samples/Provisioning.CreateWithEngine/DevRampUp-Demo-PnP-ProvisioningEngine.ps1 and b/Samples/Provisioning.CreateWithEngine/DevRampUp-Demo-PnP-ProvisioningEngine.ps1 differ diff --git a/Samples/Provisioning.CreateWithPowerShell/DevRampUp-Demo-PnP-PSProvisioning.ps1 b/Samples/Provisioning.CreateWithPowerShell/DevRampUp-Demo-PnP-PSProvisioning.ps1 index b2cfb4d8d..986ca121b 100644 Binary files a/Samples/Provisioning.CreateWithPowerShell/DevRampUp-Demo-PnP-PSProvisioning.ps1 and b/Samples/Provisioning.CreateWithPowerShell/DevRampUp-Demo-PnP-PSProvisioning.ps1 differ diff --git a/Samples/Provisioning.ModernListLibraryWebPartsFromXlsx/ProvisionModernPagesAndWebParts.ps1 b/Samples/Provisioning.ModernListLibraryWebPartsFromXlsx/ProvisionModernPagesAndWebParts.ps1 index 914dbb2b8..f9a674495 100644 --- a/Samples/Provisioning.ModernListLibraryWebPartsFromXlsx/ProvisionModernPagesAndWebParts.ps1 +++ b/Samples/Provisioning.ModernListLibraryWebPartsFromXlsx/ProvisionModernPagesAndWebParts.ps1 @@ -106,12 +106,12 @@ function Add-PnPModernListWebPart() { } If (($Section -eq 0) -and ($Column -eq 0)) { - Write-Warning "The Section and Column fields for the [$WebPartTitle] web part have been left blank or have zero values" + Write-Warning -Message "The Section and Column fields for the [$WebPartTitle] web part have been left blank or have zero values" try { Add-PnPClientSideWebPart -Page $PageName -DefaultWebPartType List -WebPartProperties $webPartProperties } catch { - Write-Error "Unable to add [$WebPartTitle] web part to the [$PageName] page. Check that that there is a section [$Section] with [$Column] columns" + Write-Error -Message "Unable to add [$WebPartTitle] web part to the [$PageName] page. Check that that there is a section [$Section] with [$Column] columns" } } Else { @@ -119,45 +119,45 @@ function Add-PnPModernListWebPart() { Add-PnPClientSideWebPart -Page $PageName -DefaultWebPartType List -WebPartProperties $webPartProperties -Section $Section -Column $Column -ErrorAction Stop #-Order $Order } catch { - Write-Error "Unable to add [$WebPartTitle] web part to the [$PageName] page. Check that that there is a section [$Section] with [$Column] columns" + Write-Error -Message "Unable to add [$WebPartTitle] web part to the [$PageName] page. Check that that there is a section [$Section] with [$Column] columns" } } } #Import 'Site' worksheet from the excel configuration spreadsheet try { - Write-Verbose "Importing site worksheet from the excel configuration file: [$configFilePath]" + Write-Verbose -Message "Importing site worksheet from the excel configuration file: [$configFilePath]" $xlSiteSheet = Import-Excel -Path $configFilePath -WorkSheetname Site #Opens the excel file and imports the Site worksheet } catch { - Write-Error "Unable to open spreadsheet from [$configFilePath] or 'Site' worksheet does not exist" + Write-Error -Message "Unable to open spreadsheet from [$configFilePath] or 'Site' worksheet does not exist" EXIT } #Save site url to a variable and connect to the site try { - Write-Verbose "Importing site url from the site worksheet." + Write-Verbose -Message "Importing site url from the site worksheet." $site = $xlSiteSheet[0].'TargetSiteUrl' #gets the first site url value from the TargetSiteUrl column - Write-Verbose "Connecting to site: $site" + Write-Verbose -Message "Connecting to site: $site" Connect-PnPOnline -Url $site } catch { - Write-Error "Unable to open site at [$site]" + Write-Error -Message "Unable to open site at [$site]" EXIT } #Import 'ModernPages' worksheet from the excel configuration spreadsheet try { - Write-Verbose "Importing ModernPages worksheet from the excel configuration file." + Write-Verbose -Message "Importing ModernPages worksheet from the excel configuration file." $xlPagesSheet = Import-Excel -Path $configFilePath -WorkSheetname ModernPages #Imports the Libraries worksheet } catch { - Write-Error "Unable to open spreadsheet from [$configFilePath] or 'ModernPages' worksheet does not exist." + Write-Error -Message "Unable to open spreadsheet from [$configFilePath] or 'ModernPages' worksheet does not exist." EXIT } -Write-Verbose "Begin adding ModernPages to the site." +Write-Verbose -Message "Begin adding ModernPages to the site." #Import each worksheet row and add modern site pages and relevant sections to the site ForEach ($row in $xlPagesSheet) { @@ -167,11 +167,11 @@ ForEach ($row in $xlPagesSheet) { #Add new modern site page try { - Write-Verbose "Adding the $page page with $layout layout." + Write-Verbose -Message "Adding the $page page with $layout layout." Add-PnPClientSidePage -Name $page -LayoutType $layout } catch { - Write-Warning "Unable to add [$page] page." + Write-Warning -Message "Unable to add [$page] page." } #Add sections to the new page (in the order specified in the worksheet) @@ -181,12 +181,12 @@ ForEach ($row in $xlPagesSheet) { $sectionOrder = 1 ForEach ($section in $arraySections) { - Write-Verbose "Adding the $section section to the $page page. Section order is $sectionOrder." + Write-Verbose -Message "Adding the $section section to the $page page. Section order is $sectionOrder." try { Add-PnPClientSidePageSection -Page $page -SectionTemplate $section -Order $sectionOrder } catch { - Write-Warning "Unable to add [$section] section to [$page] page. Ensure [$section] is a valid Section Template value (e.g. OneColumn, TwoColumn, ThreeColumn etc)" + Write-Warning -Message "Unable to add [$section] section to [$page] page. Ensure [$section] is a valid Section Template value (e.g. OneColumn, TwoColumn, ThreeColumn etc)" } $sectionOrder++ } @@ -194,15 +194,15 @@ ForEach ($row in $xlPagesSheet) { } try { - Write-Verbose "Importing ModernListLibraryWebParts worksheet from the excel configuration file." + Write-Verbose -Message "Importing ModernListLibraryWebParts worksheet from the excel configuration file." $xlWebPartsSheet = Import-Excel -Path $configFilePath -WorkSheetname ModernListLibraryWebParts #Imports the Libraries worksheet } catch { - Write-Error "Unable to open spreadsheet from [$configFilePath] or 'ModernListLibraryWebParts' worksheet does not exist." + Write-Error -Message "Unable to open spreadsheet from [$configFilePath] or 'ModernListLibraryWebParts' worksheet does not exist." EXIT } -Write-Verbose "Begin adding Modern List / Library web parts to pages:" +Write-Verbose -Message "Begin adding Modern List / Library web parts to pages:" #iterate through the worksheet rows and add web parts to the pages ForEach ($row in $xlWebPartsSheet) { @@ -216,9 +216,9 @@ ForEach ($row in $xlWebPartsSheet) { $wpTitle = $row.'WebPartTitle'; #saves value in WebPartTitle column to a variable $wpHeight = $row.'WebPartHeight'; #saves value in WebPartHeight column to a variable - Write-Verbose "Adding web part to the '$page' page with title [$wpTitle]" - Write-Verbose "web part will be added with '$viewName' view for the '$listLibraryName' $wpType" - Write-Verbose "web part will be added to column $column in section $section height is set to $wpHeight" #order is: $order + Write-Verbose -Message "Adding web part to the '$page' page with title [$wpTitle]" + Write-Verbose -Message "web part will be added with '$viewName' view for the '$listLibraryName' $wpType" + Write-Verbose -Message "web part will be added to column $column in section $section height is set to $wpHeight" #order is: $order Add-PnPModernListWebPart -PageName $page -WebPartType $wpType -ListName $listLibraryName -ViewName $viewName -WebPartHeight $wpHeight -WebPartTitle $wpTitle -Section $section -Column $column #-Order $order } diff --git a/Samples/Provisioning.SelfHostedWithAzureWebJob/Engine/mrgovernance.ps1 b/Samples/Provisioning.SelfHostedWithAzureWebJob/Engine/mrgovernance.ps1 index ef187f2c8..0353ccb20 100644 --- a/Samples/Provisioning.SelfHostedWithAzureWebJob/Engine/mrgovernance.ps1 +++ b/Samples/Provisioning.SelfHostedWithAzureWebJob/Engine/mrgovernance.ps1 @@ -4,7 +4,7 @@ param( . $PSScriptRoot/shared.ps1 -Write-Output @" +Write-Output -InputObject @" ___ ___ _____ | \/ | | __ \ | . . |_ __ | | \/ _____ _____ _ __ _ __ __ _ _ __ ___ ___ @@ -18,7 +18,7 @@ Write-Output @" $variablesSet = CheckEnvironmentalVariables if ($variablesSet -eq $false) { - Write-Output "Missing one of the following environmental variables: TenantURL, PrimarySiteCollectionOwnerEmail, SiteDirectoryUrl, AppId, AppSecret" + Write-Output -InputObject "Missing one of the following environmental variables: TenantURL, PrimarySiteCollectionOwnerEmail, SiteDirectoryUrl, AppId, AppSecret" exit } Connect -Url "$tenantURL$siteDirectorySiteUrl" @@ -32,7 +32,7 @@ foreach ($site in $res.ResultRows) { Connect -Url "$tenantURL$siteDirectorySiteUrl" $siteItem = Get-PnPListItem -List $siteDirectoryList -Id $itemId - Write-Output "Processing $url - $itemId" + Write-Output -InputObject "Processing $url - $itemId" if ($syncPermissions) { SyncPermissions -siteUrl $url -item $siteItem } diff --git a/Samples/Provisioning.SelfHostedWithAzureWebJob/Engine/mrprovision.ps1 b/Samples/Provisioning.SelfHostedWithAzureWebJob/Engine/mrprovision.ps1 index 1d8e8537f..8e9a4ef9e 100644 --- a/Samples/Provisioning.SelfHostedWithAzureWebJob/Engine/mrprovision.ps1 +++ b/Samples/Provisioning.SelfHostedWithAzureWebJob/Engine/mrprovision.ps1 @@ -46,27 +46,27 @@ function EnsureSite { Connect -Url $tenantAdminUrl $site = Get-PnPTenantSite -Url $siteUrl -ErrorAction SilentlyContinue if ( $? -eq $false) { - Write-Output "Site at $siteUrl does not exist - let's create it" + Write-Output -InputObject "Site at $siteUrl does not exist - let's create it" $site = New-PnPTenantSite -Title $title -Url $siteUrl -Owner $siteCollectionAdmin -TimeZone 3 -Description $description -Lcid 1033 -Template "STS#0" -RemoveDeletedSite:$true -Wait if ($? -eq $false) { # send e-mail $mailHeadBody = GetMailContent -email $owner.Email -mailFile "fail" - Write-Output "Sending fail mail to $ownerAddresses" + Write-Output -InputObject "Sending fail mail to $ownerAddresses" Send-PnPMail -To $ownerAddresses -Subject $mailHeadBody[0] -Body ($mailHeadBody[1] -f $siteUrl) - Write-Error "Something happened" + Write-Error -Message "Something happened" UpdateStatus -id $siteEntryId -status 'Failed' return; } } elseif ($site.Status -ne "Active") { - Write-Output "Site at $siteUrl already exist" + Write-Output -InputObject "Site at $siteUrl already exist" while ($true) { # Wait for site to be ready $site = Get-PnPTenantSite -Url $siteUrl if ( $site.Status -eq "Active" ) { break; } - Write-Output "Site not ready" + Write-Output -InputObject "Site not ready" Start-Sleep -s 20 } } @@ -77,50 +77,50 @@ function EnsureSecurityGroups([string]$siteUrl, [string]$title, [string[]]$owner $visitorsGroup = Get-PnPGroup -AssociatedVisitorGroup -ErrorAction SilentlyContinue if ( $? -eq $false) { - Write-Output "Creating visitors group" + Write-Output -InputObject "Creating visitors group" $visitorsGroup = New-PnPGroup -Title "$title Visitors" -Owner $siteCollectionAdmin Set-PnPGroup -Identity $visitorsGroup -SetAssociatedGroup Visitors } $membersGroup = Get-PnPGroup -AssociatedMemberGroup -ErrorAction SilentlyContinue if ( $? -eq $false) { - Write-Output "Creating members group" + Write-Output -InputObject "Creating members group" $membersGroup = New-PnPGroup -Title "$title Members" -Owner $siteCollectionAdmin Set-PnPGroup -Identity $membersGroup -SetAssociatedGroup Members } $ownersGroup = Get-PnPGroup -AssociatedOwnerGroup -ErrorAction SilentlyContinue if ( $? -eq $false) { - Write-Output "Creating owners group" + Write-Output -InputObject "Creating owners group" $ownersGroup = New-PnPGroup -Title "$title Owners" -Owner $siteCollectionAdmin Set-PnPGroup -Identity $ownersGroup -SetAssociatedGroup Owners } if ($owners -ne $null) { - $existingOwners = @($ownersGroup.Users | select -ExpandProperty LoginName) + $existingOwners = @($ownersGroup.Users | Select-Object -ExpandProperty LoginName) foreach ($login in $owners) { if (-not $existingOwners.Contains($login)) { - Write-Output "`tAdding owner: $login" + Write-Output -InputObject "`tAdding owner: $login" Add-PnPUserToGroup -Identity $ownersGroup -LoginName $login } } } if ($members -ne $null) { - $existingMembers = @($membersGroup.Users | select -ExpandProperty LoginName) + $existingMembers = @($membersGroup.Users | Select-Object -ExpandProperty LoginName) foreach ($login in $members) { if (-not $existingOwners.Contains($login)) { - Write-Output "`tAdding member: $login" + Write-Output -InputObject "`tAdding member: $login" Add-PnPUserToGroup -Identity $membersGroup -LoginName $login } } } if ($visitors -ne $null) { - $existingVisitors = @($visitorsGroup.Users | select -ExpandProperty LoginName) + $existingVisitors = @($visitorsGroup.Users | Select-Object -ExpandProperty LoginName) foreach ($login in $visitors) { if (-not $existingOwners.Contains($login)) { - Write-Output "`tAdding visitor: $login" + Write-Output -InputObject "`tAdding visitor: $login" Add-PnPUserToGroup -Identity $visitorsGroup -LoginName $login } } @@ -132,7 +132,7 @@ function ApplyTemplate([string]$siteUrl, [string]$templateUrl, [string]$template $appliedTemplates = Get-PnPPropertyBag -Key $propBagTemplateInfoStampKey if ((-not $appliedTemplates.Contains("|$templateName|") -or $Force)) { - Write-Output "`tApplying template $templateName to $siteUrl" + Write-Output -InputObject "`tApplying template $templateName to $siteUrl" Apply-PnPProvisioningTemplate -Path $templateUrl if ($? -eq $true) { $appliedTemplates = "$appliedTemplates|$templateName|" @@ -140,13 +140,13 @@ function ApplyTemplate([string]$siteUrl, [string]$templateUrl, [string]$template } } else { - Write-Output "`tTemplate $templateName already applied to $siteUrl" + Write-Output -InputObject "`tTemplate $templateName already applied to $siteUrl" } } function SetSiteUrl($siteItem, $siteUrl, $title) { Connect -Url "$tenantURL$siteDirectorySiteUrl" - Write-Output "`tSetting site URL to $siteUrl" + Write-Output -InputObject "`tSetting site URL to $siteUrl" Set-PnPListItem -List $siteDirectoryList -Identity $siteItem["ID"] -Values @{"$($columnPrefix)SiteURL" = "$siteUrl, $title"} -ErrorAction SilentlyContinue >$null 2>&1 } @@ -166,7 +166,7 @@ function SendReadyEmail() { if ( -not [string]::IsNullOrWhiteSpace($toEmail) ) { $mailHeadBody = GetMailContent -email $toEmail -mailFile "welcome" - Write-Output "Sending ready mail to $toEmail and $ccEmails" + Write-Output -InputObject "Sending ready mail to $toEmail and $ccEmails" Send-PnPMail -To $toEmail -Cc $ccEmails -Subject ($mailHeadBody[0] -f $title) -Body ($mailHeadBody[1] -f $title, $siteUrl) } } @@ -179,7 +179,7 @@ function Apply-TemplateConfigurations($siteUrl, $siteItem, $templateConfiguratio $subModules = $siteItem["$($columnPrefix)SubModules"] if ($templateConfig -ne $null) { - $chosenTemplateConfig = $templateConfigurationItems |? Id -eq $templateConfig.LookupId + $chosenTemplateConfig = $templateConfigurationItems | Where-Object -Property Id -eq $templateConfig.LookupId $hasTemplate = Get-PnPPropertyBag -Key $propBagTemplateNameStampKey if (-not $hasTemplate) { @@ -190,7 +190,7 @@ function Apply-TemplateConfigurations($siteUrl, $siteItem, $templateConfiguratio $chosenSubModules = $chosenTemplateConfig["$($columnPrefix)SubModules"] if ($chosenBaseTemplate -ne $null) { - $pnpTemplate = $baseModuleItems |? Id -eq $chosenBaseTemplate.LookupId + $pnpTemplate = $baseModuleItems | Where-Object -Property Id -eq $chosenBaseTemplate.LookupId $pnpUrl = $tenantUrl + $pnpTemplate["FileRef"] $templateName = $pnpTemplate["FileLeafRef"] ApplyTemplate -siteUrl $siteUrl -templateUrl $pnpUrl -templateName $templateName @@ -202,7 +202,7 @@ function Apply-TemplateConfigurations($siteUrl, $siteItem, $templateConfiguratio } if ($chosenSubModules -ne $null) { foreach ($module in $chosenSubModules) { - $pnpTemplate = $subModuleItems |? Id -eq $module.LookupId + $pnpTemplate = $subModuleItems | Where-Object -Property Id -eq $module.LookupId $pnpUrl = $tenantUrl + $pnpTemplate["FileRef"] $templateName = $pnpTemplate["FileLeafRef"] ApplyTemplate -siteUrl $siteUrl -templateUrl $pnpUrl -templateName $templateName @@ -214,24 +214,24 @@ function Apply-TemplateConfigurations($siteUrl, $siteItem, $templateConfiguratio } } if ($allGood) { - Write-Output "`tTemplate $($chosenTemplateConfig["Title"]) applied" + Write-Output -InputObject "`tTemplate $($chosenTemplateConfig["Title"]) applied" Set-PnPPropertyBagValue -Key $propBagTemplateNameStampKey -Value $chosenTemplateConfig["Title"] } } } foreach ($module in $subModules) { - $pnpTemplate = $subModuleItems |? Id -eq $module.LookupId + $pnpTemplate = $subModuleItems | Where-Object -Property Id -eq $module.LookupId $pnpUrl = $tenantUrl + $pnpTemplate["FileRef"] ApplyTemplate -siteUrl $siteUrl -templateUrl $pnpUrl -templateName $pnpTemplate["FileLeafRef"] } # Ensure list is updated with all applied modules Connect -Url $siteUrl - $appliedTemplates = (Get-PnPPropertyBag -Key $propBagTemplateInfoStampKey).Split('|') |? {$_} #remove empty lines - $ids = $appliedTemplates | % { + $appliedTemplates = (Get-PnPPropertyBag -Key $propBagTemplateInfoStampKey).Split('|') | Where-Object -FilterScript {$_} #remove empty lines + $ids = $appliedTemplates | Foreach-Object -Process { $name = $_ - $subModuleItems |? {$_["FileLeafRef"] -eq $name} | select -ExpandProperty Id + $subModuleItems | Where-Object -FilterScript {$_["FileLeafRef"] -eq $name} | Select-Object -ExpandProperty Id } Connect -Url "$tenantURL$siteDirectorySiteUrl" Set-PnPListItem -List $siteDirectoryList -Identity $siteItem["ID"] -Values @{"$($columnPrefix)SubModules" = $ids} -ErrorAction SilentlyContinue >$null 2>&1 @@ -242,7 +242,7 @@ function SyncMetadata($siteUrl, $title, $description) { Connect -Url $siteUrl $web = Get-PnPWeb -Includes Description if ($web.Title -ne $title -or $web.Description -ne $description) { - Write-Output "`tSync title/description to $siteUrl" + Write-Output -InputObject "`tSync title/description to $siteUrl" Set-PnPWeb -Title $title -Description $description } } @@ -276,7 +276,7 @@ function GetRecentlyUpdatedItems($IntervalMinutes) { } } -Write-Output @" +Write-Output -InputObject @" ___ ___ ______ _ _ | \/ | | ___ \ (_) (_) | . . |_ __ | |_/ / __ _____ ___ ___ _ ___ _ __ @@ -290,7 +290,7 @@ Write-Output @" $variablesSet = CheckEnvironmentalVariables if ($variablesSet -eq $false) { - Write-Output "Missing one of the following environmental variables: TenantURL, PrimarySiteCollectionOwnerEmail, SiteDirectoryUrl, AppId, AppSecret" + Write-Output -InputObject "Missing one of the following environmental variables: TenantURL, PrimarySiteCollectionOwnerEmail, SiteDirectoryUrl, AppId, AppSecret" exit } @@ -301,7 +301,7 @@ $subModuleItems = @(Get-PnPListItem -List $subModulesLibrary) $siteDirectoryItems = GetRecentlyUpdatedItems -Interval $timerIntervalMinutes if (!$siteDirectoryItems -or ($siteDirectoryItems -ne $null -and (0 -eq $siteDirectoryItems.Count))) { - Write-Output "No site requests detected last $timerIntervalMinutes minutes" + Write-Output -InputObject "No site requests detected last $timerIntervalMinutes minutes" } foreach ($siteItem in $siteDirectoryItems) { @@ -313,19 +313,19 @@ foreach ($siteItem in $siteDirectoryItems) { $title = $siteItem["Title"] $description = $siteItem["$($columnPrefix)ProjectDescription"] - $ownerEmailAddresses = @(@($siteItem["$($columnPrefix)SiteOwners"]) |? {-not [String]::IsNullOrEmpty($_.Email)} | select -ExpandProperty Email) + $ownerEmailAddresses = @(@($siteItem["$($columnPrefix)SiteOwners"]) | Where-Object -FilterScript {-not [String]::IsNullOrEmpty($_.Email)} | Select-Object -ExpandProperty Email) $siteStatus = $siteItem["$($columnPrefix)SiteStatus"] - $ownerEmailAddresses = $ownerEmailAddresses | select -uniq | sort + $ownerEmailAddresses = $ownerEmailAddresses | Select-Object -Unique | Sort-Object - $businessOwnerEmailAddress = @($siteItem["$($columnPrefix)BusinessOwner"] |? {-not [String]::IsNullOrEmpty($_.Email)} | select -ExpandProperty Email) + $businessOwnerEmailAddress = @($siteItem["$($columnPrefix)BusinessOwner"] | Where-Object -FilterScript {-not [String]::IsNullOrEmpty($_.Email)} | Select-Object -ExpandProperty Email) - $owners = @($siteItem["$($columnPrefix)SiteOwners"]) | select -ExpandProperty LookupId - $owners = @($owners | % { GetLoginName -lookupId $_ }) - $members = @($siteItem["$($columnPrefix)SiteMembers"]) | select -ExpandProperty LookupId - $members = @($members | % { GetLoginName -lookupId $_ }) - $visitors = @($siteItem["$($columnPrefix)SiteVisitors"]) | select -ExpandProperty LookupId - $visitors = @($visitors | % { GetLoginName -lookupId $_ }) + $owners = @($siteItem["$($columnPrefix)SiteOwners"]) | Select-Object -ExpandProperty LookupId + $owners = @($owners | Foreach-Object -Process { GetLoginName -lookupId $_ }) + $members = @($siteItem["$($columnPrefix)SiteMembers"]) | Select-Object -ExpandProperty LookupId + $members = @($members | Foreach-Object -Process { GetLoginName -lookupId $_ }) + $visitors = @($siteItem["$($columnPrefix)SiteVisitors"]) | Select-Object -ExpandProperty LookupId + $visitors = @($visitors | Foreach-Object -Process { GetLoginName -lookupId $_ }) $ownerAccount = GetLoginName -lookupId $siteItem["$($columnPrefix)BusinessOwner"].LookupId $ownerAccount = New-PnPUser -LoginName $ownerAccount @@ -337,7 +337,7 @@ foreach ($siteItem in $siteDirectoryItems) { $siteUrl = $siteItem["$($columnPrefix)SiteURL"].Url } - Write-Output "`nProcessing $siteUrl" + Write-Output -InputObject "`nProcessing $siteUrl" Connect -Url "$tenantURL$siteDirectorySiteUrl" $urlToSiteDirectory = "$tenantURL$siteDirectorySiteUrl$siteDirectoryList" diff --git a/Samples/Provisioning.SelfHostedWithAzureWebJob/Engine/shared.ps1 b/Samples/Provisioning.SelfHostedWithAzureWebJob/Engine/shared.ps1 index ae6796a40..8c5349c6a 100644 --- a/Samples/Provisioning.SelfHostedWithAzureWebJob/Engine/shared.ps1 +++ b/Samples/Provisioning.SelfHostedWithAzureWebJob/Engine/shared.ps1 @@ -74,7 +74,7 @@ function SetRequestAccessEmail([string]$siteUrl, [string]$ownersEmail) { Connect -Url $siteUrl $emails = Get-PnPRequestAccessEmails if ($emails -ne $ownersEmail) { - Write-Output "`tSetting site request e-mail to $ownersEmail" + Write-Output -InputObject "`tSetting site request e-mail to $ownersEmail" Set-PnPRequestAccessEmails -Emails $ownersEmail } } @@ -85,32 +85,32 @@ function SyncPermissions { [Microsoft.SharePoint.Client.ListItem]$item ) - Write-Output "`tSyncing owners/members/visitors from site to directory list" + Write-Output -InputObject "`tSyncing owners/members/visitors from site to directory list" Connect -Url $siteUrl $visitorsGroup = Get-PnPGroup -AssociatedVisitorGroup -ErrorAction SilentlyContinue $membersGroup = Get-PnPGroup -AssociatedMemberGroup -ErrorAction SilentlyContinue $ownersGroup = Get-PnPGroup -AssociatedOwnerGroup -ErrorAction SilentlyContinue - $visitors = @($visitorsGroup.Users | select -ExpandProperty LoginName) - $members = @($membersGroup.Users | select -ExpandProperty LoginName) - $owners = @($ownersGroup.Users | select -ExpandProperty LoginName) + $visitors = @($visitorsGroup.Users | Select-Object -ExpandProperty LoginName) + $members = @($membersGroup.Users | Select-Object -ExpandProperty LoginName) + $owners = @($ownersGroup.Users | Select-Object -ExpandProperty LoginName) Connect -Url "$tenantURL$siteDirectorySiteUrl" - $owners = @($owners -notlike 'SHAREPOINT\system' | % {New-PnPUser -LoginName $_ | select -ExpandProperty ID} | sort) - $members = @($members -notlike 'SHAREPOINT\system' | % {New-PnPUser -LoginName $_ | select -ExpandProperty ID} | sort) - $visitors = @($visitors -notlike 'SHAREPOINT\system' | % {New-PnPUser -LoginName $_ | select -ExpandProperty ID} | sort) + $owners = @($owners -notlike 'SHAREPOINT\system' | Foreach-Object -Process {New-PnPUser -LoginName $_ | Select-Object -ExpandProperty ID} | Sort-Object) + $members = @($members -notlike 'SHAREPOINT\system' | Foreach-Object -Process {New-PnPUser -LoginName $_ | Select-Object -ExpandProperty ID} | Sort-Object) + $visitors = @($visitors -notlike 'SHAREPOINT\system' | Foreach-Object -Process {New-PnPUser -LoginName $_ | Select-Object -ExpandProperty ID} | Sort-Object) - $existingOwners = @($item["$($columnPrefix)SiteOwners"] | select -ExpandProperty LookupId | sort) - $existingMembers = @($item["$($columnPrefix)SiteMembers"] | select -ExpandProperty LookupId | sort) - $existingVisitors = @($item["$($columnPrefix)SiteVisitors"] | select -ExpandProperty LookupId | sort) + $existingOwners = @($item["$($columnPrefix)SiteOwners"] | Select-Object -ExpandProperty LookupId | Sort-Object) + $existingMembers = @($item["$($columnPrefix)SiteMembers"] | Select-Object -ExpandProperty LookupId | Sort-Object) + $existingVisitors = @($item["$($columnPrefix)SiteVisitors"] | Select-Object -ExpandProperty LookupId | Sort-Object) $diffOwner = Compare-Object -ReferenceObject $owners -DifferenceObject $existingOwners -PassThru $diffMember = Compare-Object -ReferenceObject $members -DifferenceObject $existingMembers -PassThru $diffVisitor = Compare-Object -ReferenceObject $visitors -DifferenceObject $existingVisitors -PassThru if ($diffOwner -or $diffMember -or $diffVisitor) { - Write-Output "`tUpdating changed owners/members/visitors" + Write-Output -InputObject "`tUpdating changed owners/members/visitors" $siteItem = Set-PnPListItem -List $siteDirectoryList -Identity $itemId -Values @{"$($columnPrefix)SiteOwners" = $owners; "$($columnPrefix)SiteMembers" = $members; "$($columnPrefix)SiteVisitors" = $visitors} } } diff --git a/Tests/FilesTest.cs b/Tests/FilesTest.cs new file mode 100644 index 000000000..2bf24a234 --- /dev/null +++ b/Tests/FilesTest.cs @@ -0,0 +1,232 @@ +#if !ONPREMISES +using Microsoft.Online.SharePoint.TenantAdministration; +using Microsoft.SharePoint.Client; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Collections; +using System.Linq; +using System.Management.Automation.Runspaces; + +namespace SharePointPnP.PowerShell.Tests +{ + [TestClass] + public class FilesTests + { + private string site1Id; + private string site2Id; + private string site1Url; + private string site2Url; + + private const string targetLibraryRelativeUrl = "/sites/dev/Shared%20Documents"; + private const string targetLibraryName = "Documents"; + private const string targetLibraryDesc = "Documents library for Files testing"; + private const string targetFileName = "Testfile.txt"; + private const string targetFileContents = "Some random file contents"; + private const string targetCopyFolderName = "CopyDestination"; + private const string targetFileNameWithAmpersand = "Test & file.txt"; + private const string targetSite2LibraryRelativeUrl = "/sites/dev2/Shared%20Documents"; + + [TestInitialize] + public void Initialize() + { + using (var ctx = TestCommon.CreateClientContext()) + { + site1Id = Guid.NewGuid().ToString(); + site2Id = Guid.NewGuid().ToString(); + + site1Url = $"{TestCommon.GetTenantRootUrl(ctx)}/sites/PNPPS_Test_{site1Id}"; + site2Url = $"{TestCommon.GetTenantRootUrl(ctx)}/sites/PNPPS_Test_{site2Id}"; + + using (var site1Ctx = OfficeDevPnP.Core.Sites.SiteCollection.CreateAsync(ctx, new OfficeDevPnP.Core.Sites.CommunicationSiteCollectionCreationInformation() + { + Url = site1Url, + Lcid = 1033, + Title = "PnP PowerShell File Copy Test Site 1" + }).GetAwaiter().GetResult()) + { + site1Ctx.Web.EnsureProperty(w => w.ServerRelativeUrl); + Folder folder = site1Ctx.Web.GetFolderByServerRelativeUrl($"{site1Ctx.Web.ServerRelativeUrl}/Shared%20Documents"); + FileCreationInformation fci = new FileCreationInformation + { + Content = System.Text.Encoding.ASCII.GetBytes(targetFileContents), + Url = targetFileName, + Overwrite = true + }; + File fileToUpload = folder.Files.Add(fci); + site1Ctx.Load(fileToUpload); + fci.Url = targetFileNameWithAmpersand; + fci.Overwrite = true; + fileToUpload = folder.Files.Add(fci); + site1Ctx.Load(fileToUpload); + site1Ctx.ExecuteQueryRetry(); + + folder.EnsureFolder(targetCopyFolderName); + + } + OfficeDevPnP.Core.Sites.SiteCollection.CreateAsync(ctx, new OfficeDevPnP.Core.Sites.CommunicationSiteCollectionCreationInformation() + { + Url = site2Url, + Lcid = 1033, + Title = "PnP PowerShell File Copy Test Site 2" + }).GetAwaiter().GetResult(); + } + } + + + [TestCleanup] + public void Cleanup() + { + + using (var ctx = TestCommon.CreateTenantClientContext()) + { + Tenant tenant = new Tenant(ctx); + tenant.DeleteSiteCollection(site1Url, false); + tenant.DeleteSiteCollection(site2Url, false); + } + } + + [TestMethod] + public void GetFile_AsListItem_Test() + { + using (var scope = new PSTestScope(site1Url, true)) + { + var siteRelativeFolderUrl = $"/sites/PNPPS_Test_{site1Id}/Shared%20Documents"; + + var values = new Hashtable(); + values.Add("Title", "Test"); + //Get-PnPFile -Url /sites/project/_catalogs/themes/15/company.spcolor -AsFile", + var results = scope.ExecuteCommand("Get-PnPFile", + new CommandParameter("Url", $"{siteRelativeFolderUrl}/{targetFileName}"), + new CommandParameter("AsListItem")); + + Assert.IsTrue(results.Any()); + + Assert.IsTrue(results[0].BaseObject.GetType() == typeof(Microsoft.SharePoint.Client.ListItem)); + } + } + + [TestMethod] + public void GetFile_AsFile_Test() + { + using (var scope = new PSTestScope(site1Url, true)) + { + var siteRelativeFolderUrl = $"/sites/PNPPS_Test_{site1Id}/Shared%20Documents"; + + var results = scope.ExecuteCommand("Get-PnPFile", + new CommandParameter("Url", $"{siteRelativeFolderUrl}/{targetFileName}"), + new CommandParameter("AsFile")); + + Assert.IsTrue(results.Any()); + + Assert.IsTrue(results[0].BaseObject.GetType() == typeof(Microsoft.SharePoint.Client.File)); + } + } + + [TestMethod] + public void CopyFileTest() + { + using (var scope = new PSTestScope(site1Url, true)) + { + var sourceUrl = $"/sites/PNPPS_Test_{site1Id}/Shared%20Documents/{targetFileName}"; + + var destinationUrl = $"/sites/PNPPS_Test_{site1Id}/Shared%20Documents/{targetCopyFolderName}"; + + var results = scope.ExecuteCommand("Copy-PnPFile", + new CommandParameter("SourceUrl", sourceUrl), + new CommandParameter("TargetUrl", destinationUrl), + new CommandParameter("Force")); + + + using (var ctx = TestCommon.CreateClientContext(site1Url)) + { + File initialFile = ctx.Web.GetFileByServerRelativeUrl(destinationUrl); + ctx.Load(initialFile); + ctx.ExecuteQueryRetry(); + if (!initialFile.Exists) + { + Assert.Fail("Copied file cannot be found"); + } + } + } + } + + [TestMethod] + public void CopyFile_WithAmpersand_Test() + { + using (var scope = new PSTestScope(site1Url, true)) + { + var sourceUrl = $"/sites/PNPPS_Test_{site1Id}/Shared%20Documents/{targetFileNameWithAmpersand}"; + var destinationUrl = $"/sites/PNPPS_Test_{site1Id}/Shared%20Documents/{targetCopyFolderName}"; + + var results = scope.ExecuteCommand("Copy-PnPFile", + new CommandParameter("SourceUrl", sourceUrl), + new CommandParameter("TargetUrl", destinationUrl), + new CommandParameter("Force")); + + using (var ctx = TestCommon.CreateClientContext(site1Url)) + { + File initialFile = ctx.Web.GetFileByServerRelativeUrl(destinationUrl); + ctx.Load(initialFile); + ctx.ExecuteQueryRetry(); + if (!initialFile.Exists) + { + Assert.Fail("Copied file cannot be found"); + } + } + } + } + + [TestMethod] + public void CopyFile_BetweenSiteCollections_Test() + { + using (var scope = new PSTestScope(site1Url, true)) + { + var sourceUrl = $"/sites/PNPPS_Test_{site1Id}/Shared%20Documents/{targetFileName}"; + var destinationFolderUrl = $"/sites/PNPPS_Test_{site2Id}/Shared%20Documents"; + string destinationFileUrl = $"/sites/PNPPS_Test_{site2Id}/Shared%20Documents/{targetFileName}"; + var results = scope.ExecuteCommand("Copy-PnPFile", + new CommandParameter("SourceUrl", sourceUrl), + new CommandParameter("TargetUrl", destinationFolderUrl), + new CommandParameter("Force")); + + using (var ctx = TestCommon.CreateClientContext(site2Url)) + { + File initialFile = ctx.Web.GetFileByServerRelativeUrl(destinationFileUrl); + ctx.Load(initialFile); + ctx.ExecuteQuery(); + if (!initialFile.Exists) + { + Assert.Fail("Copied file cannot be found"); + } + } + } + } + + [TestMethod] + public void CopyFile_BetweenSiteCollectionsWithAmpersand_Test() + { + using (var scope = new PSTestScope(site1Url, true)) + { + var sourceUrl = $"/sites/PNPPS_Test_{site1Id}/Shared%20Documents/{targetFileNameWithAmpersand}"; + var destinationFolderUrl = $"/sites/PNPPS_Test_{site2Id}/Shared%20Documents"; + string destinationFileUrl = $"/sites/PNPPS_Test_{site2Id}/Shared%20Documents/{targetFileNameWithAmpersand}"; + var results = scope.ExecuteCommand("Copy-PnPFile", + new CommandParameter("SourceUrl", sourceUrl), + new CommandParameter("TargetUrl", destinationFolderUrl), + new CommandParameter("Force")); + + using (var ctx = TestCommon.CreateClientContext(site2Url)) + { + File initialFile = ctx.Web.GetFileByServerRelativeUrl(destinationFileUrl); + ctx.Load(initialFile); + ctx.ExecuteQuery(); + if (!initialFile.Exists) + { + Assert.Fail("Copied file cannot be found"); + } + } + } + } + } +} +#endif \ No newline at end of file diff --git a/Tests/PSTestScope.cs b/Tests/PSTestScope.cs index 6390cadb9..437e60d6c 100644 --- a/Tests/PSTestScope.cs +++ b/Tests/PSTestScope.cs @@ -57,7 +57,62 @@ public PSTestScope(bool connect = true) } else { - if (!string.IsNullOrEmpty("AppId") && !string.IsNullOrEmpty("AppSecret")) + if (!string.IsNullOrEmpty(AppId) && !string.IsNullOrEmpty(AppSecret)) + { + // Use oAuth Token to authenticate + if (!string.IsNullOrEmpty(Realm)) + { + cmd.Parameters.Add("Realm", Realm); + } + cmd.Parameters.Add("AppId", AppId); + cmd.Parameters.Add("AppSecret", AppSecret); + } + } + pipeLine.Commands.Add(cmd); + pipeLine.Invoke(); + } + } + + public PSTestScope(string siteUrl, bool connect = true) + { + SiteUrl = siteUrl; + CredentialManagerEntry = ConfigurationManager.AppSettings["SPOCredentialManagerLabel"]; + Realm = ConfigurationManager.AppSettings["Realm"]; + AppId = ConfigurationManager.AppSettings["AppId"]; + AppSecret = ConfigurationManager.AppSettings["AppSecret"]; + + var iss = InitialSessionState.CreateDefault(); + if (connect) + { + SessionStateCmdletEntry ssce = new SessionStateCmdletEntry("Connect-PnPOnline", typeof(ConnectOnline), null); + + iss.Commands.Add(ssce); + } + _runSpace = RunspaceFactory.CreateRunspace(iss); + + _runSpace.Open(); + + // Sets the execution policy to unrestricted. Requires Visual Studio to run in elevated mode. + var pipeLine = _runSpace.CreatePipeline(); + Command cmd = new Command("Set-ExecutionPolicy"); + cmd.Parameters.Add("ExecutionPolicy", "Unrestricted"); + cmd.Parameters.Add("Scope", "Process"); + pipeLine.Commands.Add(cmd); + pipeLine.Invoke(); + + if (connect) + { + pipeLine = _runSpace.CreatePipeline(); + cmd = new Command("connect-pnponline"); + cmd.Parameters.Add("Url", SiteUrl); + if (!string.IsNullOrEmpty(CredentialManagerEntry)) + { + // Use Windows Credential Manager to authenticate + cmd.Parameters.Add("Credentials", CredentialManagerEntry); + } + else + { + if (!string.IsNullOrEmpty(AppId) && !string.IsNullOrEmpty(AppSecret)) { // Use oAuth Token to authenticate if (!string.IsNullOrEmpty(Realm)) diff --git a/Tests/SharePointPnP.PowerShell.Tests.csproj b/Tests/SharePointPnP.PowerShell.Tests.csproj index a02992dba..36bdeff35 100644 --- a/Tests/SharePointPnP.PowerShell.Tests.csproj +++ b/Tests/SharePointPnP.PowerShell.Tests.csproj @@ -272,6 +272,7 @@ + diff --git a/Tests/TestCommon.cs b/Tests/TestCommon.cs index 98fc4cc87..87eae2a25 100644 --- a/Tests/TestCommon.cs +++ b/Tests/TestCommon.cs @@ -77,6 +77,7 @@ static TestCommon() #region Properties public static string TenantUrl { get; set; } public static string DevSiteUrl { get; set; } + public static string Dev2SiteUrl { get; set; } static string UserName { get; set; } static SecureString Password { get; set; } static ICredentials Credentials { get; set; } @@ -107,6 +108,11 @@ public static ClientContext CreateClientContext() return CreateContext(DevSiteUrl, Credentials); } + public static ClientContext CreateClientContext(string siteUrl) + { + return CreateContext(siteUrl, Credentials); + } + public static ClientContext CreateTenantClientContext() { return CreateContext(TenantUrl, Credentials); @@ -138,18 +144,18 @@ private static ClientContext CreateContext(string contextUrl, ICredentials crede { OfficeDevPnP.Core.AuthenticationManager am = new OfficeDevPnP.Core.AuthenticationManager(); - if (new Uri(DevSiteUrl).DnsSafeHost.Contains("spoppe.com")) + if (new Uri(contextUrl).DnsSafeHost.Contains("spoppe.com")) { - context = am.GetAppOnlyAuthenticatedContext(DevSiteUrl, SPOnlineConnectionHelper.GetRealmFromTargetUrl(new Uri(DevSiteUrl)), AppId, AppSecret, acsHostUrl: "windows-ppe.net", globalEndPointPrefix: "login"); + context = am.GetAppOnlyAuthenticatedContext(contextUrl, SPOnlineConnectionHelper.GetRealmFromTargetUrl(new Uri(contextUrl)), AppId, AppSecret, acsHostUrl: "windows-ppe.net", globalEndPointPrefix: "login"); } else { - context = am.GetAppOnlyAuthenticatedContext(DevSiteUrl, AppId, AppSecret); + context = am.GetAppOnlyAuthenticatedContext(contextUrl, AppId, AppSecret); } } else { - context = new ClientContext(DevSiteUrl); + context = new ClientContext(contextUrl); context.Credentials = Credentials; } @@ -168,6 +174,12 @@ private static SecureString GetSecureString(string input) return secureString; } + + public static string GetTenantRootUrl(ClientContext ctx) + { + var uri = new Uri(ctx.Url); + return $"https://{uri.DnsSafeHost}"; + } #endregion } }