From b2b9aa0969ac6fd29b464985b8f8eb68c56eb9a8 Mon Sep 17 00:00:00 2001 From: Nishkalank Bezawada <47456098+NishkalankBezawada@users.noreply.github.com> Date: Fri, 22 Sep 2023 11:12:40 +0200 Subject: [PATCH 1/4] Feature 3422- New Commandlet- Convert-PnPFileToPdf --- documentation/Convert-PnPFileToPdf.md | 257 ++++++++++++++++++++++ src/Commands/Files/ConvertFile.cs | 185 ++++++++++++++++ src/Commands/Utilities/REST/RestHelper.cs | 27 +++ 3 files changed, 469 insertions(+) create mode 100644 documentation/Convert-PnPFileToPdf.md create mode 100644 src/Commands/Files/ConvertFile.cs diff --git a/documentation/Convert-PnPFileToPdf.md b/documentation/Convert-PnPFileToPdf.md new file mode 100644 index 000000000..2defdf104 --- /dev/null +++ b/documentation/Convert-PnPFileToPdf.md @@ -0,0 +1,257 @@ +--- +Module Name: PnP.PowerShell +schema: 2.0.0 +applicable: SharePoint Online +online version: https://pnp.github.io/powershell/cmdlets/Convert-PnPFileToPdf.html +external help file: PnP.PowerShell.dll-Help.xml +title: Convert-PnPFileToPdf +--- + +# Convert-PnPFileToPdf + +## SYNOPSIS +Converts a file to Pdf + +## SYNTAX + + +### Save to local path +```powershell +Convert-PnPFileToPdf -Url -Path [-Force] +``` + +### Return as memorystream +```powershell +Convert-PnPFileToPdf -Url -AsMemoryStream +``` + +### Save to SharePoint Online (Same SiteCollection) +```powershell +Convert-PnPFileToPdf -Url -DocumentLibrary [-Checkout] [-CheckInComment ] [-CheckinType ] + [-Approve] [-ApproveComment ] [-Publish] [-PublishComment ] +``` + +## DESCRIPTION +Allows converting of a file from SharePoint Online. The file contents can either be directly saved to local disk, or stored in memory for further processing, or Can be uploaded back to SharePoint Online SiteCollection + +## EXAMPLES + +### EXAMPLE 1 +```powershell +Convert-PnPFileToPdf -Url "/sites/project/Shared Documents/Document.docx" -AsMemoryStream +``` + +Retrieves the file and converts to PDF, and outputs its content to the console as a Memory Stream + +### EXAMPLE 2 +```powershell +Convert-PnPFileToPdf -Url "/sites/project/Shared Documents/Document.docx" +``` + +Retrieves the file and converts to PDF, and outputs its content to the console as a Memory Stream + +### EXAMPLE 3 +```powershell +Convert-PnPFileToPdf -Url "/sites/project/Shared Documents/Document.docx" -Path "C:\Temp" +``` + +Retrieves the file and converts to PDF, and save it to the given local path + +### EXAMPLE 4 +```powershell +Convert-PnPFileToPdf -Url "/sites/project/Shared Documents/Document.docx" -Path "C:\Temp" -Force +``` + +Retrieves the file and converts to PDF, and save it to the given local path. Force parameter will override the existing file in the location where the document gets saved. + +### EXAMPLE 5 +```powershell +Convert-PnPFileToPdf -Url "/sites/SampleTeamSite/Shared Documents/Nishkalank's/Book.xlsx.docx" -DocumentLibrary "Archive" +``` + +Retrieves the file and converts to PDF, and save it to the given Document library (Folder) in SharePoint Online (Same SiteCollection). Returns the saved file information in the console. + +### EXAMPLE 6 +```powershell +Convert-PnPFileToPdf -Url "/sites/SampleTeamSite/Shared Documents/Nishkalank's/Presentation.pptx" -DocumentLibrary "Shared Documents" -CheckOut -CheckInType 1 -CheckInComment "Check-in via PowerShell" -Publish -PublishComment "Published via PowerShell" -Approve -ApproveComment "Approved via PowerShell" +``` + +Retrieves the file and converts to PDF, and save it to the given Document library in SharePoint Online (Same SiteCollection). Returns the saved file information in the console. +Note : CheckOut, CheckInType, CheckInComment, Publish, PublishComment, Approve and ApproveComment only works with the document libraries where Versioning is enabled. + + +## PARAMETERS + +### -Url +The URL (server or site relative) to the file + +```yaml +Type: String +Parameter Sets: (All) +Aliases: ServerRelativeUrl, SiteRelativeUrl + +Required: True +Position: 0 +Default value: None +Accept pipeline input: True (ByValue) +Accept wildcard characters: False +``` + + +### -AsMemoryStream + +```yaml +Type: SwitchParameter +Parameter Sets: Return as memorystream + +Required: True +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Path +Local path where the file should be saved + +```yaml +Type: String +Parameter Sets: Save to local path + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + + +### -Force +Overwrites the file if it exists. + +```yaml +Type: SwitchParameter +Parameter Sets: Save to local path + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -DocumentLibrary +The destination library in the site + +```yaml +Type: FolderPipeBind +Parameter Sets: (UPLOADTOSHAREPOINT) + +Required: True +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -CheckInComment +The comment added to the checkin + +```yaml +Type: String +Parameter Sets: (UPLOADTOSHAREPOINT) + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -CheckinType +Specifies the type of check-in for a file. + +```yaml +Type: Enum (Microsoft.SharePoint.Client.CheckinType) +Parameter Sets: (UPLOADTOSHAREPOINT) + +Required: False +Position: Named +Default value: MinorCheckIn +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Checkout +If versioning is enabled, this will check out the file first if it exists, upload the file, then check it in again + +```yaml +Type: SwitchParameter +Parameter Sets: (UPLOADTOSHAREPOINT) + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Publish +Will auto publish the file + +```yaml +Type: SwitchParameter +Parameter Sets: (UPLOADTOSHAREPOINT) + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -PublishComment +The comment added to the publish action + +```yaml +Type: String +Parameter Sets: (UPLOADTOSHAREPOINT) + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Approve +Will auto approve the uploaded file + +```yaml +Type: SwitchParameter +Parameter Sets: (UPLOADTOSHAREPOINT) + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -ApproveComment +The comment added to the approval + +```yaml +Type: String +Parameter Sets: (UPLOADTOSHAREPOINT) + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +## RELATED LINKS + +[Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp) diff --git a/src/Commands/Files/ConvertFile.cs b/src/Commands/Files/ConvertFile.cs new file mode 100644 index 000000000..9eae84771 --- /dev/null +++ b/src/Commands/Files/ConvertFile.cs @@ -0,0 +1,185 @@ +using Microsoft.SharePoint.Client; +using PnP.Framework.Utilities; +using System.Management.Automation; +using PnP.PowerShell.Commands.Base; +using PnP.PowerShell.Commands.Utilities.REST; +using System.IO; +using PnP.PowerShell.Commands.Base.PipeBinds; + +namespace PnP.PowerShell.Commands.Files +{ + [Cmdlet(VerbsData.Convert, "PnPFileToPdf")] + public class ConvertFile : PnPWebCmdlet + { + private const string URLTOPATH = "Save to local path"; + private const string URLASMEMORYSTREAM = "Return as memorystream"; + private const string UPLOADTOSHAREPOINT = "Upload to SharePoint"; + + [Parameter(Mandatory = true, ParameterSetName = URLTOPATH, Position = 0, ValueFromPipeline = true)] + [Parameter(Mandatory = true, ParameterSetName = URLASMEMORYSTREAM, Position = 0, ValueFromPipeline = true)] + [Parameter(Mandatory = true, ParameterSetName = UPLOADTOSHAREPOINT, Position = 0, ValueFromPipeline = true)] + [Alias("ServerRelativeUrl", "SiteRelativeUrl")] + public string Url; + + [Parameter(Mandatory = true, ParameterSetName = URLTOPATH)] + [Alias("Local path")] + public string Path = string.Empty; + + [Parameter(Mandatory = false, ParameterSetName = URLTOPATH)] + public SwitchParameter Force; + + [Parameter(Mandatory = true, ParameterSetName = UPLOADTOSHAREPOINT)] + [ValidateNotNullOrEmpty] + public FolderPipeBind DocumentLibrary; + + [Parameter(Mandatory = false, ParameterSetName = UPLOADTOSHAREPOINT)] + public SwitchParameter Checkout; + + [Parameter(Mandatory = false, ParameterSetName = UPLOADTOSHAREPOINT)] + public string CheckInComment = string.Empty; + + [Parameter(Mandatory = false, ParameterSetName = UPLOADTOSHAREPOINT)] + public CheckinType CheckinType = CheckinType.MinorCheckIn; + + [Parameter(Mandatory = false, ParameterSetName = UPLOADTOSHAREPOINT)] + public SwitchParameter Approve; + + [Parameter(Mandatory = false, ParameterSetName = UPLOADTOSHAREPOINT)] + public string ApproveComment = string.Empty; + + [Parameter(Mandatory = false, ParameterSetName = UPLOADTOSHAREPOINT)] + public SwitchParameter Publish; + + [Parameter(Mandatory = false)] + public string PublishComment = string.Empty; + + [Parameter(Mandatory = false, ParameterSetName = URLASMEMORYSTREAM)] + public SwitchParameter AsMemoryStream; + + + + protected override void ExecuteCmdlet() + { + if (string.IsNullOrEmpty(Path)) + { + Path = SessionState.Path.CurrentFileSystemLocation.Path; + } + else if (!System.IO.Path.IsPathRooted(Path)) + { + Path = System.IO.Path.Combine(SessionState.Path.CurrentFileSystemLocation.Path, Path); + } + + var graphAccessToken = TokenHandler.GetAccessToken(this, $"https://{Connection.GraphEndPoint}/.default", Connection); + Url = Utilities.UrlUtilities.UrlDecode(Url.Replace("+", "%2B")); + var serverRelativeUrl = GetServerRelativeUrl(Url); + var fileObj = GetFileByServerRelativePath(serverRelativeUrl); + var siteId = PnPContext.Site.Id.ToString(); + var listId = fileObj.ListId.ToString(); + var itemId = fileObj.ListItemAllFields.Id.ToString(); + var sourceFileName = fileObj.Name.ToString().Substring(0, fileObj.Name.ToString().LastIndexOf(".")); + var apiUrl = $"https://{Connection.GraphEndPoint}/v1.0/sites/{siteId}/lists/{listId}/items/{itemId}/driveItem/content?format=pdf"; + byte[] response = RestHelper.GetByteArrayAsync(Connection.HttpClient, apiUrl, graphAccessToken).GetAwaiter().GetResult(); + var fileToDownloadName = !string.IsNullOrEmpty(sourceFileName) ? sourceFileName : "Download"; + + switch (ParameterSetName) + { + case URLTOPATH: + var fileOut = System.IO.Path.Combine(Path, $"{fileToDownloadName}.pdf"); + if (!Directory.Exists(Path)) + { + Directory.CreateDirectory(Path); + } + if (!Force && System.IO.File.Exists(fileOut)) + { + WriteWarning($"File '{fileToDownloadName}' exists already. Use the -Force parameter to overwrite the file."); + } + else + { + System.IO.File.WriteAllBytes(fileOut, response); + WriteObject($"File saved as {fileOut}"); + } + break; + + case URLASMEMORYSTREAM: + var stream = new MemoryStream(response); + WriteObject(stream); + break; + + case UPLOADTOSHAREPOINT: + var targetLibrary = EnsureFolder(); + Stream fileStream = new MemoryStream(response); + var targetFileName = $"{fileToDownloadName}.pdf"; + var uploadedFile = targetLibrary.UploadFileAsync(targetFileName, fileStream, true).GetAwaiter().GetResult(); + if (Checkout || ParameterSpecified(nameof(CheckinType))) + { + CurrentWeb.CheckInFile(uploadedFile.ServerRelativeUrl, CheckinType, CheckInComment); + } + if (Publish) + { + CurrentWeb.PublishFile(uploadedFile.ServerRelativeUrl, PublishComment); + } + if (Approve) + { + CurrentWeb.ApproveFile(uploadedFile.ServerRelativeUrl, ApproveComment); + } + ClientContext.Load(uploadedFile); + try + { + ClientContext.ExecuteQueryRetry(); + } + catch (ServerException) + { + ClientContext.Load(uploadedFile, f => f.Length, f => f.Name, f => f.TimeCreated, f => f.TimeLastModified, f => f.Title); + ClientContext.ExecuteQueryRetry(); + } + WriteObject(uploadedFile); + break; + } + } + + private string GetServerRelativeUrl(string url) + { + var webUrl = CurrentWeb.EnsureProperty(w => w.ServerRelativeUrl); + return url.ToLower().StartsWith(webUrl.ToLower()) ? url : UrlUtility.Combine(webUrl, Url); + } + + private Microsoft.SharePoint.Client.File GetFileByServerRelativePath(string serverRelativeUrl) + { + var fileListItem = CurrentWeb.GetFileByServerRelativePath(ResourcePath.FromDecodedUrl(serverRelativeUrl)); + ClientContext.Load(fileListItem, f => f.Exists, f => f.ListItemAllFields, f => f.ListId, f => f.Name); + ClientContext.ExecuteQueryRetry(); + if (fileListItem.Exists) + { + return fileListItem; + } + else + { + throw new PSArgumentException($"No file found with the provided Url {serverRelativeUrl}", "Url"); + } + } + + + private Folder EnsureFolder() + { + // First try to get the folder if it exists already. This avoids an Access Denied exception if the current user doesn't have Full Control access at Web level + CurrentWeb.EnsureProperty(w => w.ServerRelativeUrl); + + Folder library = null; + try + { + library = DocumentLibrary.GetFolder(CurrentWeb); + library.EnsureProperties(f => f.ServerRelativeUrl); + return library; + } + // Exception will be thrown if the library does not exist yet on SharePoint + catch (ServerException serverEx) when (serverEx.ServerErrorCode == -2147024894) + { + // create the library + CurrentWeb.CreateList(ListTemplateType.DocumentLibrary, DocumentLibrary.ServerRelativeUrl, false, true, "", false, false); + library = DocumentLibrary.GetFolder(CurrentWeb); + library.EnsureProperties(f => f.ServerRelativeUrl); + return library; + } + } + } +} diff --git a/src/Commands/Utilities/REST/RestHelper.cs b/src/Commands/Utilities/REST/RestHelper.cs index b159e78df..c340be8ee 100644 --- a/src/Commands/Utilities/REST/RestHelper.cs +++ b/src/Commands/Utilities/REST/RestHelper.cs @@ -153,6 +153,12 @@ public static async Task GetAsync(HttpClient httpClient, string url, str return await SendMessageAsync(httpClient, message); } + public static async Task GetByteArrayAsync(HttpClient httpClient, string url, string accessToken, string accept = "application/json") + { + var message = GetMessage(url, HttpMethod.Get, accessToken, accept); + return await SendMessageByteArrayAsync(httpClient, message); + } + public static async Task GetAsync(HttpClient httpClient, string url, ClientContext clientContext, string accept = "application/json") { var message = GetMessage(url, HttpMethod.Get, clientContext, accept); @@ -649,6 +655,27 @@ private static async Task SendMessageAsync(HttpClient httpClient, HttpRe } } + private static async Task SendMessageByteArrayAsync(HttpClient httpClient, HttpRequestMessage message) + { + var response = await httpClient.SendAsync(message); + while (response.StatusCode == (HttpStatusCode)429) + { + // throttled + var retryAfter = response.Headers.RetryAfter; + await Task.Delay(retryAfter.Delta.Value.Seconds * 1000); + response = await httpClient.SendAsync(CloneMessage(message)); + } + if (response.IsSuccessStatusCode) + { + return await response.Content.ReadAsByteArrayAsync(); + } + else + { + var errorContent = await response.Content.ReadAsStringAsync(); + throw new HttpRequestException($"HTTP Error {response.StatusCode}: {errorContent}"); + } + } + private static async Task SendMessageAsyncGetResponseHeader(HttpClient httpClient, HttpRequestMessage message) { var response = await httpClient.SendAsync(message); From b8a5c7634bf11cd088a2feac5991a2c411878f6a Mon Sep 17 00:00:00 2001 From: Koen Zomers Date: Tue, 26 Sep 2023 15:14:05 +0200 Subject: [PATCH 2/4] Rename to have filename match the cmdlet name and some minor cleanup --- src/Commands/Files/{ConvertFile.cs => ConvertFileToPdf.cs} | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) rename src/Commands/Files/{ConvertFile.cs => ConvertFileToPdf.cs} (99%) diff --git a/src/Commands/Files/ConvertFile.cs b/src/Commands/Files/ConvertFileToPdf.cs similarity index 99% rename from src/Commands/Files/ConvertFile.cs rename to src/Commands/Files/ConvertFileToPdf.cs index 9eae84771..9d085b043 100644 --- a/src/Commands/Files/ConvertFile.cs +++ b/src/Commands/Files/ConvertFileToPdf.cs @@ -9,7 +9,7 @@ namespace PnP.PowerShell.Commands.Files { [Cmdlet(VerbsData.Convert, "PnPFileToPdf")] - public class ConvertFile : PnPWebCmdlet + public class ConvertFileToPdf : PnPWebCmdlet { private const string URLTOPATH = "Save to local path"; private const string URLASMEMORYSTREAM = "Return as memorystream"; @@ -22,7 +22,6 @@ public class ConvertFile : PnPWebCmdlet public string Url; [Parameter(Mandatory = true, ParameterSetName = URLTOPATH)] - [Alias("Local path")] public string Path = string.Empty; [Parameter(Mandatory = false, ParameterSetName = URLTOPATH)] @@ -56,8 +55,6 @@ public class ConvertFile : PnPWebCmdlet [Parameter(Mandatory = false, ParameterSetName = URLASMEMORYSTREAM)] public SwitchParameter AsMemoryStream; - - protected override void ExecuteCmdlet() { if (string.IsNullOrEmpty(Path)) @@ -158,7 +155,6 @@ private Microsoft.SharePoint.Client.File GetFileByServerRelativePath(string serv } } - private Folder EnsureFolder() { // First try to get the folder if it exists already. This avoids an Access Denied exception if the current user doesn't have Full Control access at Web level From e067775811a51dc9500d77cae1f4d26a4e1d10be Mon Sep 17 00:00:00 2001 From: Koen Zomers Date: Tue, 26 Sep 2023 15:19:21 +0200 Subject: [PATCH 3/4] Added changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c70d7262b..ebf4ce3e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). - Added `Get-PnPFlowOwner` cmdlet which allows retrieving the owners of a Power Automate flow [#3314](https://github.com/pnp/powershell/pull/3314) - Added `-AvailableForTagging` to `Set-PnPTerm` which allows the available for tagging property on a Term to be set [#3321](https://github.com/pnp/powershell/pull/3321) - Added `Get-PnPPowerPlatformConnector` cmdlet which allows for all custom connectors to be retrieved [#3309](https://github.com/pnp/powershell/pull/3309) +- Added `Convert-PnPFileToPdf` cmdlet which allows for a file to be converted to PDF [#3435](https://github.com/pnp/powershell/pull/3435) ### Fixed From 2fa5b158e7e58fedfb0593f04545c0bc79eda2c0 Mon Sep 17 00:00:00 2001 From: Nishkalank Bezawada <47456098+NishkalankBezawada@users.noreply.github.com> Date: Thu, 19 Oct 2023 18:39:46 +0200 Subject: [PATCH 4/4] Resolving comments by Gautam Sheth --- documentation/Convert-PnPFileToPdf.md | 130 +++---------------------- src/Commands/Files/ConvertFileToPdf.cs | 64 ++++-------- 2 files changed, 30 insertions(+), 164 deletions(-) diff --git a/documentation/Convert-PnPFileToPdf.md b/documentation/Convert-PnPFileToPdf.md index 2defdf104..658e50ee1 100644 --- a/documentation/Convert-PnPFileToPdf.md +++ b/documentation/Convert-PnPFileToPdf.md @@ -2,12 +2,12 @@ Module Name: PnP.PowerShell schema: 2.0.0 applicable: SharePoint Online -online version: https://pnp.github.io/powershell/cmdlets/Convert-PnPFileToPdf.html +online version: https://pnp.github.io/powershell/cmdlets/Convert-PnPFileToPDF.html external help file: PnP.PowerShell.dll-Help.xml -title: Convert-PnPFileToPdf +title: Convert-PnPFileToPDF --- -# Convert-PnPFileToPdf +# Convert-PnPFileToPDF ## SYNOPSIS Converts a file to Pdf @@ -17,18 +17,17 @@ Converts a file to Pdf ### Save to local path ```powershell -Convert-PnPFileToPdf -Url -Path [-Force] +Convert-PnPFileToPDF -Url -Path [-Force] ``` ### Return as memorystream ```powershell -Convert-PnPFileToPdf -Url -AsMemoryStream +Convert-PnPFileToPDF -Url -AsMemoryStream ``` ### Save to SharePoint Online (Same SiteCollection) ```powershell -Convert-PnPFileToPdf -Url -DocumentLibrary [-Checkout] [-CheckInComment ] [-CheckinType ] - [-Approve] [-ApproveComment ] [-Publish] [-PublishComment ] +Convert-PnPFileToPDF -Url -Folder ``` ## DESCRIPTION @@ -38,46 +37,39 @@ Allows converting of a file from SharePoint Online. The file contents can either ### EXAMPLE 1 ```powershell -Convert-PnPFileToPdf -Url "/sites/project/Shared Documents/Document.docx" -AsMemoryStream +Convert-PnPFileToPDF -Url "/sites/project/Shared Documents/Document.docx" -AsMemoryStream ``` Retrieves the file and converts to PDF, and outputs its content to the console as a Memory Stream ### EXAMPLE 2 ```powershell -Convert-PnPFileToPdf -Url "/sites/project/Shared Documents/Document.docx" +Convert-PnPFileToPDF -Url "/sites/project/Shared Documents/Document.docx" ``` Retrieves the file and converts to PDF, and outputs its content to the console as a Memory Stream ### EXAMPLE 3 ```powershell -Convert-PnPFileToPdf -Url "/sites/project/Shared Documents/Document.docx" -Path "C:\Temp" +Convert-PnPFileToPDF -Url "/sites/project/Shared Documents/Document.docx" -Path "C:\Temp" ``` Retrieves the file and converts to PDF, and save it to the given local path ### EXAMPLE 4 ```powershell -Convert-PnPFileToPdf -Url "/sites/project/Shared Documents/Document.docx" -Path "C:\Temp" -Force +Convert-PnPFileToPDF -Url "/sites/project/Shared Documents/Document.docx" -Path "C:\Temp" -Force ``` Retrieves the file and converts to PDF, and save it to the given local path. Force parameter will override the existing file in the location where the document gets saved. ### EXAMPLE 5 ```powershell -Convert-PnPFileToPdf -Url "/sites/SampleTeamSite/Shared Documents/Nishkalank's/Book.xlsx.docx" -DocumentLibrary "Archive" +Convert-PnPFileToPDF -Url "/sites/SampleTeamSite/Shared Documents/Nishkalank's/Book.xlsx.docx" -Folder "Archive" ``` Retrieves the file and converts to PDF, and save it to the given Document library (Folder) in SharePoint Online (Same SiteCollection). Returns the saved file information in the console. -### EXAMPLE 6 -```powershell -Convert-PnPFileToPdf -Url "/sites/SampleTeamSite/Shared Documents/Nishkalank's/Presentation.pptx" -DocumentLibrary "Shared Documents" -CheckOut -CheckInType 1 -CheckInComment "Check-in via PowerShell" -Publish -PublishComment "Published via PowerShell" -Approve -ApproveComment "Approved via PowerShell" -``` - -Retrieves the file and converts to PDF, and save it to the given Document library in SharePoint Online (Same SiteCollection). Returns the saved file information in the console. -Note : CheckOut, CheckInType, CheckInComment, Publish, PublishComment, Approve and ApproveComment only works with the document libraries where Versioning is enabled. ## PARAMETERS @@ -140,7 +132,7 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -DocumentLibrary +### -Folder The destination library in the site ```yaml @@ -154,104 +146,6 @@ Accept pipeline input: False Accept wildcard characters: False ``` -### -CheckInComment -The comment added to the checkin - -```yaml -Type: String -Parameter Sets: (UPLOADTOSHAREPOINT) - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -CheckinType -Specifies the type of check-in for a file. - -```yaml -Type: Enum (Microsoft.SharePoint.Client.CheckinType) -Parameter Sets: (UPLOADTOSHAREPOINT) - -Required: False -Position: Named -Default value: MinorCheckIn -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Checkout -If versioning is enabled, this will check out the file first if it exists, upload the file, then check it in again - -```yaml -Type: SwitchParameter -Parameter Sets: (UPLOADTOSHAREPOINT) - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Publish -Will auto publish the file - -```yaml -Type: SwitchParameter -Parameter Sets: (UPLOADTOSHAREPOINT) - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -PublishComment -The comment added to the publish action - -```yaml -Type: String -Parameter Sets: (UPLOADTOSHAREPOINT) - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -Approve -Will auto approve the uploaded file - -```yaml -Type: SwitchParameter -Parameter Sets: (UPLOADTOSHAREPOINT) - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -ApproveComment -The comment added to the approval - -```yaml -Type: String -Parameter Sets: (UPLOADTOSHAREPOINT) - -Required: False -Position: Named -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - ## RELATED LINKS [Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp) diff --git a/src/Commands/Files/ConvertFileToPdf.cs b/src/Commands/Files/ConvertFileToPdf.cs index 9d085b043..5bd29e31f 100644 --- a/src/Commands/Files/ConvertFileToPdf.cs +++ b/src/Commands/Files/ConvertFileToPdf.cs @@ -8,8 +8,8 @@ namespace PnP.PowerShell.Commands.Files { - [Cmdlet(VerbsData.Convert, "PnPFileToPdf")] - public class ConvertFileToPdf : PnPWebCmdlet + [Cmdlet(VerbsData.Convert, "PnPFileToPDF")] + public class ConvertFileToPDF : PnPWebCmdlet { private const string URLTOPATH = "Save to local path"; private const string URLASMEMORYSTREAM = "Return as memorystream"; @@ -29,28 +29,7 @@ public class ConvertFileToPdf : PnPWebCmdlet [Parameter(Mandatory = true, ParameterSetName = UPLOADTOSHAREPOINT)] [ValidateNotNullOrEmpty] - public FolderPipeBind DocumentLibrary; - - [Parameter(Mandatory = false, ParameterSetName = UPLOADTOSHAREPOINT)] - public SwitchParameter Checkout; - - [Parameter(Mandatory = false, ParameterSetName = UPLOADTOSHAREPOINT)] - public string CheckInComment = string.Empty; - - [Parameter(Mandatory = false, ParameterSetName = UPLOADTOSHAREPOINT)] - public CheckinType CheckinType = CheckinType.MinorCheckIn; - - [Parameter(Mandatory = false, ParameterSetName = UPLOADTOSHAREPOINT)] - public SwitchParameter Approve; - - [Parameter(Mandatory = false, ParameterSetName = UPLOADTOSHAREPOINT)] - public string ApproveComment = string.Empty; - - [Parameter(Mandatory = false, ParameterSetName = UPLOADTOSHAREPOINT)] - public SwitchParameter Publish; - - [Parameter(Mandatory = false)] - public string PublishComment = string.Empty; + public FolderPipeBind Folder; [Parameter(Mandatory = false, ParameterSetName = URLASMEMORYSTREAM)] public SwitchParameter AsMemoryStream; @@ -66,16 +45,12 @@ protected override void ExecuteCmdlet() Path = System.IO.Path.Combine(SessionState.Path.CurrentFileSystemLocation.Path, Path); } - var graphAccessToken = TokenHandler.GetAccessToken(this, $"https://{Connection.GraphEndPoint}/.default", Connection); Url = Utilities.UrlUtilities.UrlDecode(Url.Replace("+", "%2B")); var serverRelativeUrl = GetServerRelativeUrl(Url); var fileObj = GetFileByServerRelativePath(serverRelativeUrl); - var siteId = PnPContext.Site.Id.ToString(); - var listId = fileObj.ListId.ToString(); - var itemId = fileObj.ListItemAllFields.Id.ToString(); var sourceFileName = fileObj.Name.ToString().Substring(0, fileObj.Name.ToString().LastIndexOf(".")); - var apiUrl = $"https://{Connection.GraphEndPoint}/v1.0/sites/{siteId}/lists/{listId}/items/{itemId}/driveItem/content?format=pdf"; - byte[] response = RestHelper.GetByteArrayAsync(Connection.HttpClient, apiUrl, graphAccessToken).GetAwaiter().GetResult(); + var apiUrl = GeneratePdfApiUrl(Url, sourceFileName, fileObj); + byte[] response = RestHelper.GetByteArrayAsync(Connection.HttpClient, apiUrl, GraphAccessToken).GetAwaiter().GetResult(); var fileToDownloadName = !string.IsNullOrEmpty(sourceFileName) ? sourceFileName : "Download"; switch (ParameterSetName) @@ -84,7 +59,7 @@ protected override void ExecuteCmdlet() var fileOut = System.IO.Path.Combine(Path, $"{fileToDownloadName}.pdf"); if (!Directory.Exists(Path)) { - Directory.CreateDirectory(Path); + throw new PSArgumentException("Path does not exists"); } if (!Force && System.IO.File.Exists(fileOut)) { @@ -107,18 +82,6 @@ protected override void ExecuteCmdlet() Stream fileStream = new MemoryStream(response); var targetFileName = $"{fileToDownloadName}.pdf"; var uploadedFile = targetLibrary.UploadFileAsync(targetFileName, fileStream, true).GetAwaiter().GetResult(); - if (Checkout || ParameterSpecified(nameof(CheckinType))) - { - CurrentWeb.CheckInFile(uploadedFile.ServerRelativeUrl, CheckinType, CheckInComment); - } - if (Publish) - { - CurrentWeb.PublishFile(uploadedFile.ServerRelativeUrl, PublishComment); - } - if (Approve) - { - CurrentWeb.ApproveFile(uploadedFile.ServerRelativeUrl, ApproveComment); - } ClientContext.Load(uploadedFile); try { @@ -155,6 +118,15 @@ private Microsoft.SharePoint.Client.File GetFileByServerRelativePath(string serv } } + private string GeneratePdfApiUrl(string url, string sourceFileName, Microsoft.SharePoint.Client.File fileObj) + { + var siteId = PnPContext.Site.Id.ToString(); + var listId = fileObj.ListId.ToString(); + var itemId = fileObj.ListItemAllFields.Id.ToString(); + return $"https://{Connection.GraphEndPoint}/v1.0/sites/{siteId}/lists/{listId}/items/{itemId}/driveItem/content?format=pdf"; + } + + private Folder EnsureFolder() { // First try to get the folder if it exists already. This avoids an Access Denied exception if the current user doesn't have Full Control access at Web level @@ -163,7 +135,7 @@ private Folder EnsureFolder() Folder library = null; try { - library = DocumentLibrary.GetFolder(CurrentWeb); + library = Folder.GetFolder(CurrentWeb); library.EnsureProperties(f => f.ServerRelativeUrl); return library; } @@ -171,8 +143,8 @@ private Folder EnsureFolder() catch (ServerException serverEx) when (serverEx.ServerErrorCode == -2147024894) { // create the library - CurrentWeb.CreateList(ListTemplateType.DocumentLibrary, DocumentLibrary.ServerRelativeUrl, false, true, "", false, false); - library = DocumentLibrary.GetFolder(CurrentWeb); + CurrentWeb.CreateList(ListTemplateType.DocumentLibrary, Folder.ServerRelativeUrl, false, true, "", false, false); + library = Folder.GetFolder(CurrentWeb); library.EnsureProperties(f => f.ServerRelativeUrl); return library; }