diff --git a/Binaries/SharePointPnP.Modernization.Framework.dll b/Binaries/SharePointPnP.Modernization.Framework.dll index 9e72a5383..dcf7148f4 100644 Binary files a/Binaries/SharePointPnP.Modernization.Framework.dll and b/Binaries/SharePointPnP.Modernization.Framework.dll differ diff --git a/Binaries/SharePointPnP.Modernization.Framework.xml b/Binaries/SharePointPnP.Modernization.Framework.xml index 654e8e2c9..1cbe10919 100644 --- a/Binaries/SharePointPnP.Modernization.Framework.xml +++ b/Binaries/SharePointPnP.Modernization.Framework.xml @@ -2490,7 +2490,7 @@ Information about the page to transform The path to the created modern page - + Performs the logic needed to swap a genered Migrated_Page.aspx to Page.aspx and then Page.aspx to Old_Page.aspx @@ -4265,6 +4265,13 @@ Page list item Last modified by user/account + + + Get's the blog last published date time + + Page list item + DateTime of the last modification + Get's the page page layout file diff --git a/Binaries/release/SharePointPnP.Modernization.Framework.dll b/Binaries/release/SharePointPnP.Modernization.Framework.dll index eb16ea7f7..f1721a993 100644 Binary files a/Binaries/release/SharePointPnP.Modernization.Framework.dll and b/Binaries/release/SharePointPnP.Modernization.Framework.dll differ diff --git a/Binaries/release/SharePointPnP.Modernization.Framework.xml b/Binaries/release/SharePointPnP.Modernization.Framework.xml index 654e8e2c9..1cbe10919 100644 --- a/Binaries/release/SharePointPnP.Modernization.Framework.xml +++ b/Binaries/release/SharePointPnP.Modernization.Framework.xml @@ -2490,7 +2490,7 @@ Information about the page to transform The path to the created modern page - + Performs the logic needed to swap a genered Migrated_Page.aspx to Page.aspx and then Page.aspx to Old_Page.aspx @@ -4265,6 +4265,13 @@ Page list item Last modified by user/account + + + Get's the blog last published date time + + Page list item + DateTime of the last modification + Get's the page page layout file diff --git a/CHANGELOG.md b/CHANGELOG.md index 50cc4d2c5..5ccee2439 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,26 @@ 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/). +## [Unreleased] + +### Added + +### Changed + +### Contributors + +## [3.14.1910.1] + +### Added + +- ConvertTo-PnPClientSidePage: Added support for logging to console via `-LogType Console` +- Copy-PnPFile: Fixes (#2300) +- ConvertTo-PnPClientSidePage: Added support for controlling the target page name is any cross site transformation (so wiki, web part, blog in addition the already existing option for publishing pages) via the `-TargetPageName` parameter + +### Changed + +### Contributors + ## [3.14.1910.0] ### Added @@ -18,6 +38,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). ### Changed +- Several documentation fixes - Add-PnPClientSideWebPart now also works for SP2019 - Added -List parameter to Get-PnPFolder to retrieve all folders in a list - Added owner paramter to New-PnPSite when create Communications site @@ -28,11 +49,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). ### Contributors +- Aleksandr SaPozhkov [shurick81] - Garry Trinder [garrytrinder] - Koen Zomers [KoenZomers] - Gautam Sheth [gautamdsheth] - Giacomo Pozzoni [jackpoz] - Paul Bullock [pkbullock] +- Andres Mariano Gorzelany [get-itips] ## [3.13.1909.0] diff --git a/Commands/ClientSidePages/ClientSidePageTransformatorLogType.cs b/Commands/ClientSidePages/ClientSidePageTransformatorLogType.cs index b8ba1e7f0..7a41a20c5 100644 --- a/Commands/ClientSidePages/ClientSidePageTransformatorLogType.cs +++ b/Commands/ClientSidePages/ClientSidePageTransformatorLogType.cs @@ -6,6 +6,7 @@ public enum ClientSidePageTransformatorLogType None = 0, File = 1, SharePoint = 2, + Console = 3, } } #endif \ No newline at end of file diff --git a/Commands/ClientSidePages/ConvertToClientSidePage.cs b/Commands/ClientSidePages/ConvertToClientSidePage.cs index cc6e5790b..6670fb82a 100644 --- a/Commands/ClientSidePages/ConvertToClientSidePage.cs +++ b/Commands/ClientSidePages/ConvertToClientSidePage.cs @@ -23,19 +23,19 @@ namespace SharePointPnP.PowerShell.Commands.ClientSidePages Category = CmdletHelpCategory.ClientSidePages, SupportedPlatform = CmdletSupportedPlatform.Online)] [CmdletExample( Code = @"PS:> ConvertTo-PnPClientSidePage -Identity ""somepage.aspx"" -Overwrite", - Remarks = "Converts a wiki page named 'somepage' to a client side page", + Remarks = "Converts a wiki/web part page named 'somepage' to a client side page", SortOrder = 1)] [CmdletExample( Code = @"PS:> ConvertTo-PnPClientSidePage -Identity ""somepage.aspx"" -Overwrite -WebPartMappingFile c:\contoso\webpartmapping.xml", - Remarks = "Converts a wiki page named 'somepage' to a client side page using a custom provided mapping file", + Remarks = "Converts a wiki/web part page named 'somepage' to a client side page using a custom provided mapping file", SortOrder = 2)] [CmdletExample( Code = @"PS:> ConvertTo-PnPClientSidePage -Identity ""somepage.aspx"" -Overwrite -AddPageAcceptBanner", - Remarks = "Converts a wiki page named 'somepage' to a client side page and adds the page accept banner web part on top of the page. This requires that the SPFX solution holding the web part (https://github.com/SharePoint/sp-dev-modernization/blob/master/Solutions/PageTransformationUI/assets/sharepointpnp-pagetransformation-client.sppkg?raw=true) has been installed to the tenant app catalog", + Remarks = "Converts a wiki/web part page named 'somepage' to a client side page and adds the page accept banner web part on top of the page. This requires that the SPFX solution holding the web part (https://github.com/SharePoint/sp-dev-modernization/blob/master/Solutions/PageTransformationUI/assets/sharepointpnp-pagetransformation-client.sppkg?raw=true) has been installed to the tenant app catalog", SortOrder = 3)] [CmdletExample( Code = @"PS:> ConvertTo-PnPClientSidePage -Identity ""somepage.aspx"" -Overwrite -CopyPageMetadata", - Remarks = "Converts a wiki page named 'somepage' to a client side page, including the copying of the page metadata (if any)", + Remarks = "Converts a wiki/web part page named 'somepage' to a client side page, including the copying of the page metadata (if any)", SortOrder = 4)] [CmdletExample( Code = @"PS:> ConvertTo-PnPClientSidePage -Identity ""somepage.aspx"" -PublishingPage -Overwrite -TargetWebUrl https://contoso.sharepoint.com/sites/targetmodernsite", @@ -55,16 +55,20 @@ namespace SharePointPnP.PowerShell.Commands.ClientSidePages SortOrder = 8)] [CmdletExample( Code = @"PS:> ConvertTo-PnPClientSidePage -Identity ""somepage.aspx"" -Overwrite -TargetWebUrl https://contoso.sharepoint.com/sites/targetmodernsite", - Remarks = "Converts a wiki page named 'somepage' to a client side page in the https://contoso.sharepoint.com/sites/targetmodernsite site", + Remarks = "Converts a wiki/web part page named 'somepage' to a client side page in the https://contoso.sharepoint.com/sites/targetmodernsite site", SortOrder = 9)] [CmdletExample( Code = @"PS:> ConvertTo-PnPClientSidePage -Identity ""somepage.aspx"" -LogType File -LogFolder c:\temp -LogVerbose -Overwrite", - Remarks = "Converts a web part page named 'somepage' and creates a log file in c:\\temp using verbose logging", + Remarks = "Converts a wiki/web part page named 'somepage' and creates a log file in c:\\temp using verbose logging", SortOrder = 10)] [CmdletExample( Code = @"PS:> ConvertTo-PnPClientSidePage -Identity ""somepage.aspx"" -LogType SharePoint -LogSkipFlush", - Remarks = "Converts a web part page named 'somepage' and creates a log file in SharePoint but skip the actual write. Use this option to make multiple ConvertTo-PnPClientSidePage invocations create a single log", + Remarks = "Converts a wiki/web part page named 'somepage' and creates a log file in SharePoint but skip the actual write. Use this option to make multiple ConvertTo-PnPClientSidePage invocations create a single log", SortOrder = 11)] + [CmdletExample( + Code = @"PS:> ConvertTo-PnPClientSidePage -Identity ""My post title"" -BlogPage -LogType Console -Overwrite -TargetWebUrl https://contoso.sharepoint.com/sites/targetmodernsite", + Remarks = "Converts a blog page with a title starting with 'my post title' to a client side page in the https://contoso.sharepoint.com/sites/targetmodernsite site", + SortOrder = 12)] public class ConvertToClientSidePage : PnPWebCmdlet { private static string rootFolder = ""; @@ -165,6 +169,9 @@ public class ConvertToClientSidePage : PnPWebCmdlet [Parameter(Mandatory = false, HelpMessage = "Name for the target page (only applies to publishing page transformation)")] public string PublishingTargetPageName = ""; + [Parameter(Mandatory = false, HelpMessage = "Name for the target page (only applies when doing cross site page transformation)")] + public string TargetPageName = ""; + [Parameter(Mandatory = false, HelpMessage = "Optional connection to be used by the cmdlet. Retrieve the value for this parameter by either specifying -ReturnConnection on Connect-PnPOnline or by executing Get-PnPConnection.")] // do not remove '#!#99' public SPOnlineConnection TargetConnection = null; @@ -246,6 +253,8 @@ protected override void ExecuteCmdlet() throw new Exception($"Provided pagelayout mapping file {this.PageLayoutMapping} does not exist"); } + bool crossSiteTransformation = TargetConnection != null || !string.IsNullOrEmpty(TargetWebUrl); + // Create target client context (when needed) ClientContext targetContext = null; if (TargetConnection == null) @@ -337,6 +346,17 @@ protected override void ExecuteCmdlet() pageTransformator.RegisterObserver(new MarkdownToSharePointObserver(targetContext ?? this.ClientContext, includeVerbose: this.LogVerbose, includeDebugEntries: this.LogVerbose)); } } + else if (this.LogType == ClientSidePageTransformatorLogType.Console) + { + if (this.PublishingPage) + { + publishingPageTransformator.RegisterObserver(new ConsoleObserver(includeDebugEntries: this.LogVerbose)); + } + else + { + pageTransformator.RegisterObserver(new ConsoleObserver(includeDebugEntries: this.LogVerbose)); + } + } // Clear the client side component cache if (this.ClearCache) @@ -356,7 +376,7 @@ protected override void ExecuteCmdlet() KeepPageCreationModificationInformation = this.KeepPageCreationModificationInformation, PostAsNews = this.PostAsNews, DisablePageComments = this.DisablePageComments, - TargetPageName = this.PublishingTargetPageName, + TargetPageName = !string.IsNullOrEmpty(this.PublishingTargetPageName) ? this.PublishingTargetPageName : this.TargetPageName, SkipUrlRewrite = this.SkipUrlRewriting, SkipDefaultUrlRewrite = this.SkipDefaultUrlRewriting, UrlMappingFile = this.UrlMappingFile, @@ -374,7 +394,7 @@ protected override void ExecuteCmdlet() finally { // Flush log - if (this.LogType != ClientSidePageTransformatorLogType.None && !this.LogSkipFlush) + if (this.LogType != ClientSidePageTransformatorLogType.None && this.LogType != ClientSidePageTransformatorLogType.Console && !this.LogSkipFlush) { publishingPageTransformator.FlushObservers(); } @@ -406,6 +426,7 @@ protected override void ExecuteCmdlet() SetAuthorInPageHeader = this.SetAuthorInPageHeader, PostAsNews = this.PostAsNews, DisablePageComments = this.DisablePageComments, + TargetPageName = crossSiteTransformation ? this.TargetPageName : "", SkipUrlRewrite = this.SkipUrlRewriting, SkipDefaultUrlRewrite = this.SkipDefaultUrlRewriting, UrlMappingFile = this.UrlMappingFile, @@ -427,7 +448,7 @@ protected override void ExecuteCmdlet() finally { // Flush log - if (this.LogType != ClientSidePageTransformatorLogType.None && !this.LogSkipFlush) + if (this.LogType != ClientSidePageTransformatorLogType.None && this.LogType != ClientSidePageTransformatorLogType.Console && !this.LogSkipFlush) { pageTransformator.FlushObservers(); } diff --git a/Commands/ClientSidePages/ExportClientSidePage.cs b/Commands/ClientSidePages/ExportClientSidePage.cs index 4a52d9928..45af92961 100644 --- a/Commands/ClientSidePages/ExportClientSidePage.cs +++ b/Commands/ClientSidePages/ExportClientSidePage.cs @@ -72,7 +72,7 @@ protected override void ProcessRecord() private void ExtractTemplate(string dirName, string fileName, ExtractConfiguration configuration) { var outputTemplate = new ProvisioningTemplate(); - outputTemplate.Id = Guid.NewGuid().ToString("N"); + outputTemplate.Id = $"TEMPLATE-{Guid.NewGuid():N}".ToUpper(); var helper = new OfficeDevPnP.Core.Framework.Provisioning.ObjectHandlers.Utilities.ClientSidePageContentsHelper(); ProvisioningTemplateCreationInformation ci = null; if (configuration != null) diff --git a/Commands/Files/CopyFile.cs b/Commands/Files/CopyFile.cs index c12afb5fd..062ad6980 100644 --- a/Commands/Files/CopyFile.cs +++ b/Commands/Files/CopyFile.cs @@ -128,6 +128,7 @@ protected override void ExecuteCmdlet() file = _sourceContext.Web.GetFileByServerRelativePath(ResourcePath.FromDecodedUrl(SourceUrl)); #endif file.EnsureProperties(f => f.Name, f => f.Exists); + isFile = file.Exists; } catch { @@ -168,17 +169,17 @@ protected override void ExecuteCmdlet() _targetContext = ClientContext.Clone(targetWebUri.AbsoluteUri); var dstWeb = _targetContext.Web; - dstWeb.EnsureProperty(s => s.Url); + dstWeb.EnsureProperties(s => s.Url, s => s.ServerRelativeUrl); if (srcWeb.Url == dstWeb.Url) { try { - var targetFile = UrlUtility.Combine(TargetUrl, file.Name); + var targetFile = UrlUtility.Combine(TargetUrl, file?.Name); // If src/dst are on the same Web, then try using CopyTo - backwards compability #if ONPREMISES - file.CopyTo(targetFile, OverwriteIfAlreadyExists); + file?.CopyTo(targetFile, OverwriteIfAlreadyExists); #else - file.CopyToUsingPath(ResourcePath.FromDecodedUrl(targetFile), OverwriteIfAlreadyExists); + file?.CopyToUsingPath(ResourcePath.FromDecodedUrl(targetFile), OverwriteIfAlreadyExists); #endif _sourceContext.ExecuteQueryRetry(); return; @@ -196,11 +197,15 @@ protected override void ExecuteCmdlet() bool targetFolderExists = false; try { +#if ONPREMISES targetFolder = _targetContext.Web.GetFolderByServerRelativeUrl(TargetUrl); +#else + targetFolder = _targetContext.Web.GetFolderByServerRelativePath(ResourcePath.FromDecodedUrl(TargetUrl)); +#endif #if !SP2013 targetFolder.EnsureProperties(f => f.Name, f => f.Exists); if (!targetFolder.Exists) throw new Exception("TargetUrl is an existing file, not folder"); - targetFolderExists = true; + targetFolderExists = true; #else targetFolder.EnsureProperties(f => f.Name); try @@ -226,8 +231,12 @@ protected override void ExecuteCmdlet() foreach (List targetList in lists) { if (!TargetUrl.StartsWith(targetList.RootFolder.ServerRelativeUrl, StringComparison.InvariantCultureIgnoreCase)) continue; - fileOrFolderName = Regex.Replace(TargetUrl, targetList.RootFolder.ServerRelativeUrl, "", RegexOptions.IgnoreCase).Trim('/'); - targetFolder = srcIsFolder ? targetList.RootFolder.EnsureFolder(fileOrFolderName) : targetList.RootFolder; + fileOrFolderName = Regex.Replace(TargetUrl, _targetContext.Web.ServerRelativeUrl, "", RegexOptions.IgnoreCase).Trim('/'); + targetFolder = srcIsFolder + ? _targetContext.Web.EnsureFolderPath(fileOrFolderName) + : targetList.RootFolder; + //fileOrFolderName = Regex.Replace(TargetUrl, targetList.RootFolder.ServerRelativeUrl, "", RegexOptions.IgnoreCase).Trim('/'); + //targetFolder = srcIsFolder ? targetList.RootFolder.EnsureFolder(fileOrFolderName) : targetList.RootFolder; break; } } @@ -310,7 +319,7 @@ private File UploadFileWithSpecialCharacters(Folder folder, string fileName, Sys { throw new ArgumentException("Filename is required"); } - + // Create the file var newFileInfo = new FileCreationInformation() { diff --git a/Commands/Properties/AssemblyInfo.cs b/Commands/Properties/AssemblyInfo.cs index 541ef6e55..28c9c4b1c 100644 --- a/Commands/Properties/AssemblyInfo.cs +++ b/Commands/Properties/AssemblyInfo.cs @@ -48,6 +48,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.14.1910.0")] -[assembly: AssemblyFileVersion("3.14.1910.0")] +[assembly: AssemblyVersion("3.14.1910.1")] +[assembly: AssemblyFileVersion("3.14.1910.1")] [assembly: InternalsVisibleTo("SharePointPnP.PowerShell.Tests")] \ No newline at end of file diff --git a/Commands/Provisioning/Site/GetProvisioningTemplate.cs b/Commands/Provisioning/Site/GetProvisioningTemplate.cs index 11d3eac74..a84fa35dd 100644 --- a/Commands/Provisioning/Site/GetProvisioningTemplate.cs +++ b/Commands/Provisioning/Site/GetProvisioningTemplate.cs @@ -358,6 +358,7 @@ private void ExtractTemplate(XMLPnPSchemaVersion schema, string path, string pac var percentage = Convert.ToInt32((100 / Convert.ToDouble(total)) * Convert.ToDouble(step)); WriteProgress(new ProgressRecord(0, $"Extracting Template from {SelectedWeb.Url}", message) { PercentComplete = percentage }); + WriteProgress(new ProgressRecord(1, " ", " ") { RecordType = ProgressRecordType.Completed }); }; creationInformation.MessagesDelegate = (message, type) => { diff --git a/Tests/FilesTest.cs b/Tests/FilesTest.cs index 085a85c80..d1c1d5e06 100644 --- a/Tests/FilesTest.cs +++ b/Tests/FilesTest.cs @@ -44,10 +44,14 @@ private string Site2RelativeFolderUrl } } + private const string SourceFolderWithFolders = "SourceFolderWithFoldersAndFilesAndEmptyFolder"; + private const string SourceFolderName = "SourceFolder"; private const string TargetFileName = "Testfile.txt"; private const string TargetFileContents = "Some random file contents"; private const string TargetCopyFolderName = "CopyDestination"; + private const string EmptyFolderName = "EmptyFolder"; private const string TargetFileNameWithAmpersand = "Test & file.txt"; + private const string TargetFileNameWithHashtag = "Test & file.txt"; [TestInitialize] public void Initialize() @@ -87,10 +91,34 @@ public void Initialize() fileToUpload = folder.Files.Add(fci); site1Ctx.Load(fileToUpload); - site1Ctx.ExecuteQueryRetry(); + fci.Url = TargetFileNameWithHashtag; + fci.Overwrite = true; + fileToUpload = folder.Files.Add(fci); + site1Ctx.Load(fileToUpload); folder.EnsureFolder(TargetCopyFolderName); + // Prereq for CopyFile_EmptyFolderBetweenSiteCollections_Test + folder.EnsureFolder(EmptyFolderName); + + // Prereq for CopyFile_FolderWithSkipSourceFolderNameBetweenSiteCollections_Test + var sourceFolder = folder.EnsureFolder(SourceFolderName); + fileToUpload = sourceFolder.Files.Add(fci); + site1Ctx.Load(fileToUpload); + + + // Prereq for CopyFile_FolderWithFoldersAndEmptyFolderBetweenSiteCollections_Test + var folderHirachyFolder0 = folder.EnsureFolder(SourceFolderWithFolders); + var folderHirachyFolder1 = folderHirachyFolder0.EnsureFolder(TargetCopyFolderName); + + var folderHirachyFile0 = folderHirachyFolder0.Files.Add(fci); + var folderHirachyFile1 = folderHirachyFolder1.Files.Add(fci); + site1Ctx.Load(folderHirachyFile0); + site1Ctx.Load(folderHirachyFile1); + + folderHirachyFolder1.EnsureFolder(EmptyFolderName); + + site1Ctx.ExecuteQueryRetry(); } OfficeDevPnP.Core.Sites.SiteCollection.CreateAsync(ctx, new OfficeDevPnP.Core.Sites.CommunicationSiteCollectionCreationInformation() { @@ -144,7 +172,7 @@ public void GetFile_AsFile_Test() var results = scope.ExecuteCommand("Get-PnPFile", new CommandParameter("Url", siteRelativeFileUrl), new CommandParameter("AsFile")); - + Assert.IsFalse(results.Any()); } } @@ -158,7 +186,7 @@ public void GetFile_AsObject_Test() var results = scope.ExecuteCommand("Get-PnPFile", new CommandParameter("Url", siteRelativeFileUrl)); - + Assert.IsTrue(results.Any()); Assert.IsTrue(results[0].BaseObject.GetType() == typeof(Microsoft.SharePoint.Client.File)); } @@ -235,6 +263,33 @@ public void CopyFile_WithAmpersand_Test() } } + [TestMethod] + public void CopyFile_WithHashtag_Test() + { + using (var scope = new PSTestScope(_site1Url, true)) + { + var sourceUrl = $"{Site1RelativeFolderUrl}/{TargetFileNameWithHashtag}"; + var destinationUrl = $"{Site1RelativeFolderUrl}/{TargetCopyFolderName}"; + var destinationFileUrl = $"{destinationUrl}/{TargetFileNameWithHashtag}"; + + 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(destinationFileUrl); + ctx.Load(initialFile); + ctx.ExecuteQueryRetry(); + if (!initialFile.Exists) + { + Assert.Fail("Copied file cannot be found"); + } + } + } + } + [TestMethod] public void CopyFile_BetweenSiteCollections_Test() { @@ -288,6 +343,135 @@ public void CopyFile_BetweenSiteCollectionsWithAmpersand_Test() } } } + + [TestMethod] + public void CopyFile_BetweenSiteCollectionsWithHashtag_Test() + { + using (var scope = new PSTestScope(_site1Url, true)) + { + var sourceUrl = $"{Site1RelativeFolderUrl}/{TargetFileNameWithHashtag}"; + var destinationFolderUrl = $"{Site2RelativeFolderUrl}"; + string destinationFileUrl = $"{destinationFolderUrl}/{TargetFileNameWithHashtag}"; + + 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_EmptyFolder_Test() + { + using (var scope = new PSTestScope(_site1Url, true)) + { + var sourceUrl = $"{Site1RelativeFolderUrl}/{EmptyFolderName}"; + var destinationUrl = $"{Site1RelativeFolderUrl}/{TargetCopyFolderName}/{EmptyFolderName}"; + + var results = scope.ExecuteCommand("Copy-PnPFile", + new CommandParameter("SourceUrl", sourceUrl), + new CommandParameter("TargetUrl", destinationUrl), + new CommandParameter("Force")); + + using (var ctx = TestCommon.CreateClientContext(_site1Url)) + { + Folder initialFolder = ctx.Web.GetFolderByServerRelativePath(ResourcePath.FromDecodedUrl(destinationUrl)); + initialFolder.EnsureProperties(f => f.Name, f => f.Exists); + ctx.Load(initialFolder); + ctx.ExecuteQuery(); + if (!initialFolder.Exists) + { + Assert.Fail("Copied folder cannot be found"); + } + } + } + } + + [TestMethod] + public void CopyFile_EmptyFolderBetweenSiteCollections_Test() + { + using (var scope = new PSTestScope(_site1Url, true)) + { + var sourceUrl = $"{Site1RelativeFolderUrl}/{EmptyFolderName}"; + var destinationUrl = $"{Site2RelativeFolderUrl}/{EmptyFolderName}"; + + var results = scope.ExecuteCommand("Copy-PnPFile", + new CommandParameter("SourceUrl", sourceUrl), + new CommandParameter("TargetUrl", destinationUrl), + new CommandParameter("Force")); + + using (var ctx = TestCommon.CreateClientContext(_site2Url)) + { + Folder initialFolder = ctx.Web.GetFolderByServerRelativePath(ResourcePath.FromDecodedUrl(destinationUrl)); + initialFolder.EnsureProperties(f => f.Name, f => f.Exists); + ctx.Load(initialFolder); + ctx.ExecuteQuery(); + if (!initialFolder.Exists) + { + Assert.Fail("Copied folder cannot be found"); + } + } + } + } + + [TestMethod] + public void CopyFile_FolderWithSkipSourceFolderNameBetweenSiteCollections_Test() + { + using (var scope = new PSTestScope(_site1Url, true)) + { + var sourceUrl = $"{Site1RelativeFolderUrl}/{SourceFolderName}"; + var destinationUrl = $"{Site2RelativeFolderUrl}"; + + var results = scope.ExecuteCommand("Copy-PnPFile", + new CommandParameter("SourceUrl", sourceUrl), + new CommandParameter("TargetUrl", destinationUrl), + new CommandParameter(name: "SkipSourceFolderName"), + new CommandParameter("Force")); + + using (var ctx = TestCommon.CreateClientContext(_site2Url)) + { + Folder initialFolder = ctx.Web.GetFolderByServerRelativePath(ResourcePath.FromDecodedUrl(destinationUrl)); + initialFolder.EnsureProperties(f => f.Name, f => f.Exists, f => f.Files); + ctx.Load(initialFolder); + ctx.ExecuteQuery(); + Assert.AreEqual(1, initialFolder.Files.Count); + } + } + } + + [TestMethod] + public void CopyFile_FolderWithFoldersAndEmptyFolderBetweenSiteCollections_Test() + { + using (var scope = new PSTestScope(_site1Url, true)) + { + var sourceUrl = $"{Site1RelativeFolderUrl}/{SourceFolderWithFolders}"; + var destinationUrl = $"{Site2RelativeFolderUrl}"; + + var results = scope.ExecuteCommand("Copy-PnPFile", + new CommandParameter("SourceUrl", sourceUrl), + new CommandParameter("TargetUrl", destinationUrl), + new CommandParameter("Force")); + + using (var ctx = TestCommon.CreateClientContext(_site2Url)) + { + List list = ctx.Web.GetListUsingPath(ResourcePath.FromDecodedUrl(destinationUrl)); + ctx.Load(list); + ctx.ExecuteQuery(); + Assert.AreEqual(5, list.ItemCount); + } + } + } } } #endif \ No newline at end of file diff --git a/version.txt b/version.txt index 8f80374bc..764245439 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -3.14.1910.0 \ No newline at end of file +3.14.1910.1 \ No newline at end of file