From 534e6f796c2e37d677fc6c9c52f4b34a89e281a9 Mon Sep 17 00:00:00 2001 From: Gautam Sheth Date: Sun, 10 Nov 2024 22:56:37 +0200 Subject: [PATCH 1/3] Add Add-PnPFileSensitivityLabel cmdlet for assigning sensitivity labels to SharePoint files --- documentation/Add-PnPFileSensitivityLabel.md | 100 ++++++++++++++++++ .../SensitivityLabelAssignmentMethod .cs | 9 ++ src/Commands/Files/AddFileSensitivityLabel.cs | 72 +++++++++++++ src/Commands/Utilities/REST/RestHelper.cs | 34 +++--- 4 files changed, 198 insertions(+), 17 deletions(-) create mode 100644 documentation/Add-PnPFileSensitivityLabel.md create mode 100644 src/Commands/Enums/SensitivityLabelAssignmentMethod .cs create mode 100644 src/Commands/Files/AddFileSensitivityLabel.cs diff --git a/documentation/Add-PnPFileSensitivityLabel.md b/documentation/Add-PnPFileSensitivityLabel.md new file mode 100644 index 000000000..5b7281585 --- /dev/null +++ b/documentation/Add-PnPFileSensitivityLabel.md @@ -0,0 +1,100 @@ +--- +Module Name: PnP.PowerShell +schema: 2.0.0 +applicable: SharePoint Online +online version: https://pnp.github.io/powershell/cmdlets/Add-PnPFileSensitivityLabel.html +external help file: PnP.PowerShell.dll-Help.xml +title: Add-PnPFileSensitivityLabel +--- + +# Add-PnPFileSensitivityLabel + +## SYNOPSIS + +**Required Permissions** + + * Microsoft Graph API : One of Files.ReadWrite.All, Sites.ReadWrite.All + +Add the sensitivity label information for a file in SharePoint. + +## SYNTAX +```powershell +Add-PnPFileSensitivityLabel -Url -SensitivityLabelId -AssignmentMethod -JustificationText +``` + +## DESCRIPTION + +The Add-PnPFileSensitivityLabel cmdlet adds the sensitivity label information for a file in SharePoint using Microsoft Graph. It takes a URL as input, decodes it, and specifically encodes the '+' character if it is part of the filename. It also takes the sensitivity label Id , assignment method and justification text values as input. + +## EXAMPLES + +### Example 1 +This example adds the sensitivity label information for the file at the specified URL. + +```powershell +Add-PnPFileSensitivityLabel -Url "/sites/Marketing/Shared Documents/Report.pptx" -SensitivityLabelId b5b11b04-05b3-4fe4-baa9-b7f5f65b8b64 -JustificationText "Previous label no longer applies" -AssignmentMethod Privileged +``` + +This example adds the sensitivity label information for the file at the specified URL. + +## PARAMETERS + +### -Url +Specifies the URL of the file on which we add the sensitivity label information. + +```yaml +Type: String +Parameter Sets: (All) + +Required: True +Position: Named +Default value: None +Accept pipeline input: True +Accept wildcard characters: False +``` + +### -SensitivityLabelId +ID of the sensitivity label to be assigned, or empty string to remove the sensitivity label. + +```yaml +Type: string +Parameter Sets: (All) + +Required: True +Position: Named +Default value: None +Accept pipeline input: True +Accept wildcard characters: False +``` + +### -AssignmentMethod +The assignment method of the label on the document. Indicates whether the assignment of the label was done automatically, standard, or as a privileged operation (the equivalent of an administrator operation). + +```yaml +Type: Guid +Parameter Sets: (All) +Accepted values: Standard, Privileged, Auto +Required: False +Position: Named +Default value: None +Accept pipeline input: True +Accept wildcard characters: False +``` + +### -JustificationText +Justification text for audit purposes, and is required when downgrading/removing a label. + +```yaml +Type: Guid +Parameter Sets: (All) + +Required: False +Position: Named +Default value: None +Accept pipeline input: True +Accept wildcard characters: False +``` + +## RELATED LINKS + +[Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp) diff --git a/src/Commands/Enums/SensitivityLabelAssignmentMethod .cs b/src/Commands/Enums/SensitivityLabelAssignmentMethod .cs new file mode 100644 index 000000000..7eda7161c --- /dev/null +++ b/src/Commands/Enums/SensitivityLabelAssignmentMethod .cs @@ -0,0 +1,9 @@ +namespace PnP.PowerShell.Commands.Enums +{ + public enum SensitivityLabelAssignmentMethod + { + Standard, + Privileged, + Auto + } +} diff --git a/src/Commands/Files/AddFileSensitivityLabel.cs b/src/Commands/Files/AddFileSensitivityLabel.cs new file mode 100644 index 000000000..b37c454b1 --- /dev/null +++ b/src/Commands/Files/AddFileSensitivityLabel.cs @@ -0,0 +1,72 @@ +using PnP.Framework.Utilities; +using PnP.PowerShell.Commands.Attributes; +using PnP.PowerShell.Commands.Base; +using PnP.PowerShell.Commands.Utilities.REST; +using System; +using System.Management.Automation; + +namespace PnP.PowerShell.Commands.Files +{ + [Cmdlet(VerbsCommon.Add, "PnPFileSensitivityLabel")] + [RequiredApiDelegatedOrApplicationPermissions("graph/Files.ReadWrite.All")] + [RequiredApiDelegatedOrApplicationPermissions("graph/Sites.ReadWrite.All")] + + public class AddFileSensitivityLabel : PnPGraphCmdlet + { + [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true)] + public string Url = string.Empty; + + [Parameter(Mandatory = true)] + public string SensitivityLabelId; + + [Parameter(Mandatory = false)] + public Enums.SensitivityLabelAssignmentMethod AssignmentMethod = Enums.SensitivityLabelAssignmentMethod.Privileged; + + [Parameter(Mandatory = false)] + public string JustificationText = string.Empty; + + protected override void ExecuteCmdlet() + { + var serverRelativeUrl = string.Empty; + + if (Uri.IsWellFormedUriString(Url, UriKind.Absolute)) + { + // We can't deal with absolute URLs + Url = UrlUtility.MakeRelativeUrl(Url); + } + + // Remove URL decoding from the Url as that will not work. We will encode the + character specifically, because if that is part of the filename, it needs to stay and not be decoded. + Url = Utilities.UrlUtilities.UrlDecode(Url.Replace("+", "%2B")); + + Connection.PnPContext.Web.EnsureProperties(w => w.ServerRelativeUrl); + + var webUrl = Connection.PnPContext.Web.ServerRelativeUrl; + + if (!Url.ToLower().StartsWith(webUrl.ToLower())) + { + serverRelativeUrl = UrlUtility.Combine(webUrl, Url); + } + else + { + serverRelativeUrl = Url; + } + + var file = Connection.PnPContext.Web.GetFileByServerRelativeUrl(Url); + file.EnsureProperties(f => f.VroomDriveID, f => f.VroomItemID); + + var requestUrl = $"https://{Connection.GraphEndPoint}/v1.0/drives/{file.VroomDriveID}/items/{file.VroomItemID}/assignSensitivityLabel"; + + var payload = new + { + sensitivityLabelId = SensitivityLabelId, + assignmentMethod = AssignmentMethod.ToString(), + justificationText = JustificationText + }; + + var responseHeader = RestHelper.PostGetResponseHeader(Connection.HttpClient, requestUrl, AccessToken, payload: payload); + + WriteVerbose($"File sensitivity label assigned to {Url}"); + WriteObject(responseHeader.Location); + } + } +} diff --git a/src/Commands/Utilities/REST/RestHelper.cs b/src/Commands/Utilities/REST/RestHelper.cs index e338d0bde..8f5ada496 100644 --- a/src/Commands/Utilities/REST/RestHelper.cs +++ b/src/Commands/Utilities/REST/RestHelper.cs @@ -1,3 +1,4 @@ +using Microsoft.SharePoint.Client; using System; using System.Collections.Generic; using System.Linq; @@ -7,16 +8,15 @@ using System.Text.Json; using System.Text.Json.Serialization; using System.Threading; -using Microsoft.SharePoint.Client; namespace PnP.PowerShell.Commands.Utilities.REST { internal static class RestHelper - { + { #region GET public static T ExecuteGetRequest(ClientContext context, string url, string select = null, string filter = null, string expand = null, uint? top = null) { - var returnValue = ExecuteGetRequest(context, url, select, filter, expand, top); + var returnValue = ExecuteGetRequest(context, url, select, filter, expand, top); var returnObject = JsonSerializer.Deserialize(returnValue, new JsonSerializerOptions() { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); return returnObject; @@ -208,9 +208,9 @@ public static T Get(HttpClient httpClient, string url, ClientContext clientCo return default(T); } -#endregion + #endregion -#region POST + #region POST public static string Post(HttpClient httpClient, string url, string accessToken, string accept = "application/json") { @@ -270,7 +270,7 @@ public static string Post(HttpClient httpClient, string url, ClientContext clien message = GetMessage(url, HttpMethod.Post, clientContext, accept); } return SendMessage(httpClient, message); - } + } public static T Post(HttpClient httpClient, string url, string accessToken, object payload, bool camlCasePolicy = true) { @@ -333,9 +333,9 @@ public static T Post(HttpClient httpClient, string url, ClientContext clientC } -#endregion + #endregion -#region PATCH + #region PATCH public static T Patch(HttpClient httpClient, string url, string accessToken, object payload, bool camlCasePolicy = true) { var stringContent = Patch(httpClient, url, accessToken, payload); @@ -360,7 +360,7 @@ public static T Patch(HttpClient httpClient, string url, string accessToken, public static string Patch(HttpClient httpClient, string url, string accessToken, object payload, string accept = "application/json") { - HttpRequestMessage message = null; + HttpRequestMessage message = null; if (payload != null) { var content = new StringContent(JsonSerializer.Serialize(payload, new JsonSerializerOptions() { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull })); @@ -373,9 +373,9 @@ public static string Patch(HttpClient httpClient, string url, string accessToken } return SendMessage(httpClient, message); } -#endregion + #endregion -#region PUT + #region PUT public static T ExecutePutRequest(ClientContext context, string url, string content, string select = null, string filter = null, string expand = null, string contentType = null) { HttpContent stringContent = new StringContent(content); @@ -439,9 +439,9 @@ private static HttpResponseMessage ExecutePutRequestInternal(ClientContext conte var returnValue = client.PutAsync(url, content).GetAwaiter().GetResult(); return returnValue; } -#endregion + #endregion -#region MERGE + #region MERGE public static T ExecuteMergeRequest(ClientContext context, string url, string content, string select = null, string filter = null, string expand = null, string contentType = null) { HttpContent stringContent = new StringContent(content); @@ -506,9 +506,9 @@ private static HttpResponseMessage ExecuteMergeRequestInternal(ClientContext con var returnValue = client.PostAsync(url, content).GetAwaiter().GetResult(); return returnValue; } -#endregion + #endregion -#region DELETE + #region DELETE public static string Delete(HttpClient httpClient, string url, string accessToken, string accept = "application/json") { @@ -584,7 +584,7 @@ private static HttpResponseMessage ExecuteDeleteRequestInternal(ClientContext co var returnValue = client.DeleteAsync(url).GetAwaiter().GetResult(); return returnValue; } -#endregion + #endregion private static HttpRequestMessage GetMessage(string url, HttpMethod method, string accessToken, string accept = "application/json", HttpContent content = null) { @@ -693,7 +693,7 @@ private static System.Net.Http.Headers.HttpResponseHeaders SendMessageGetRespons } else { - var errorContent = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); ; + var errorContent = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); throw new HttpRequestException(errorContent); } } From a23f63b4656867ca4d63d3bf9ef7c196e4c5dd89 Mon Sep 17 00:00:00 2001 From: Gautam Sheth Date: Mon, 11 Nov 2024 21:00:31 +0200 Subject: [PATCH 2/3] Updated as per review comments --- documentation/Add-PnPFileSensitivityLabel.md | 19 ++++++---- src/Commands/Files/AddFileSensitivityLabel.cs | 37 ++++--------------- 2 files changed, 20 insertions(+), 36 deletions(-) diff --git a/documentation/Add-PnPFileSensitivityLabel.md b/documentation/Add-PnPFileSensitivityLabel.md index 5b7281585..2381b435f 100644 --- a/documentation/Add-PnPFileSensitivityLabel.md +++ b/documentation/Add-PnPFileSensitivityLabel.md @@ -19,7 +19,7 @@ Add the sensitivity label information for a file in SharePoint. ## SYNTAX ```powershell -Add-PnPFileSensitivityLabel -Url -SensitivityLabelId -AssignmentMethod -JustificationText +Add-PnPFileSensitivityLabel -Identity -SensitivityLabelId -AssignmentMethod -JustificationText ``` ## DESCRIPTION @@ -32,22 +32,27 @@ The Add-PnPFileSensitivityLabel cmdlet adds the sensitivity label information fo This example adds the sensitivity label information for the file at the specified URL. ```powershell -Add-PnPFileSensitivityLabel -Url "/sites/Marketing/Shared Documents/Report.pptx" -SensitivityLabelId b5b11b04-05b3-4fe4-baa9-b7f5f65b8b64 -JustificationText "Previous label no longer applies" -AssignmentMethod Privileged +Add-PnPFileSensitivityLabel -Identity "/sites/Marketing/Shared Documents/Report.pptx" -SensitivityLabelId "b5b11b04-05b3-4fe4-baa9-b7f5f65b8b64" -JustificationText "Previous label no longer applies" -AssignmentMethod Privileged ``` -This example adds the sensitivity label information for the file at the specified URL. +### Example 2 +This example removes the sensitivity label information for the file at the specified URL. + +```powershell +Add-PnPFileSensitivityLabel -Identity "/sites/Marketing/Shared Documents/Report.pptx" -SensitivityLabelId "" -JustificationText "Previous label no longer applies" -AssignmentMethod Privileged +``` ## PARAMETERS -### -Url -Specifies the URL of the file on which we add the sensitivity label information. +### -Identity +The server relative path to the file, the unique identifier of the file, the listitem representing the file, or the file object itself on which we are adding the sensitivity label. ```yaml -Type: String +Type: FilePipeBind Parameter Sets: (All) Required: True -Position: Named +Position: 0 Default value: None Accept pipeline input: True Accept wildcard characters: False diff --git a/src/Commands/Files/AddFileSensitivityLabel.cs b/src/Commands/Files/AddFileSensitivityLabel.cs index b37c454b1..af54b859a 100644 --- a/src/Commands/Files/AddFileSensitivityLabel.cs +++ b/src/Commands/Files/AddFileSensitivityLabel.cs @@ -1,9 +1,10 @@ -using PnP.Framework.Utilities; +using PnP.Core.Model.SharePoint; using PnP.PowerShell.Commands.Attributes; using PnP.PowerShell.Commands.Base; +using PnP.PowerShell.Commands.Base.PipeBinds; using PnP.PowerShell.Commands.Utilities.REST; -using System; using System.Management.Automation; +using System.Net.Http.Headers; namespace PnP.PowerShell.Commands.Files { @@ -13,8 +14,8 @@ namespace PnP.PowerShell.Commands.Files public class AddFileSensitivityLabel : PnPGraphCmdlet { - [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true)] - public string Url = string.Empty; + [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true)] + public FilePipeBind Identity; [Parameter(Mandatory = true)] public string SensitivityLabelId; @@ -29,29 +30,7 @@ protected override void ExecuteCmdlet() { var serverRelativeUrl = string.Empty; - if (Uri.IsWellFormedUriString(Url, UriKind.Absolute)) - { - // We can't deal with absolute URLs - Url = UrlUtility.MakeRelativeUrl(Url); - } - - // Remove URL decoding from the Url as that will not work. We will encode the + character specifically, because if that is part of the filename, it needs to stay and not be decoded. - Url = Utilities.UrlUtilities.UrlDecode(Url.Replace("+", "%2B")); - - Connection.PnPContext.Web.EnsureProperties(w => w.ServerRelativeUrl); - - var webUrl = Connection.PnPContext.Web.ServerRelativeUrl; - - if (!Url.ToLower().StartsWith(webUrl.ToLower())) - { - serverRelativeUrl = UrlUtility.Combine(webUrl, Url); - } - else - { - serverRelativeUrl = Url; - } - - var file = Connection.PnPContext.Web.GetFileByServerRelativeUrl(Url); + IFile file = Identity.GetCoreFile(Connection.PnPContext, this); file.EnsureProperties(f => f.VroomDriveID, f => f.VroomItemID); var requestUrl = $"https://{Connection.GraphEndPoint}/v1.0/drives/{file.VroomDriveID}/items/{file.VroomItemID}/assignSensitivityLabel"; @@ -63,9 +42,9 @@ protected override void ExecuteCmdlet() justificationText = JustificationText }; - var responseHeader = RestHelper.PostGetResponseHeader(Connection.HttpClient, requestUrl, AccessToken, payload: payload); + HttpResponseHeaders responseHeader = RestHelper.PostGetResponseHeader(Connection.HttpClient, requestUrl, AccessToken, payload: payload); - WriteVerbose($"File sensitivity label assigned to {Url}"); + WriteVerbose($"File sensitivity label assigned to {file.Name}"); WriteObject(responseHeader.Location); } } From 5b3c9e2644393981069e74dd20e2f8e9fc5eded9 Mon Sep 17 00:00:00 2001 From: KoenZomers Date: Thu, 14 Nov 2024 12:42:18 +0100 Subject: [PATCH 3/3] Added changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8817919a6..94986cdcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). - Added `-HidePeoplePreviewingFiles` to `Set-PnPSite` which allows for hiding the people previewing files feature on a site [#4416](https://github.com/pnp/powershell/pull/4416) - Added `-AllowWebPropertyBagUpdateWhenDenyAddAndCustomizePagesIsEnabled` to `Set-PnPTenant` which allows for updating of web property bag when DenyAddAndCustomizePages is enabled [#4508](https://github.com/pnp/powershell/pull/4508) - Added `SiteId` to the output of `Get-PnPTenantSite` [#4527](https://github.com/pnp/powershell/pull/4527) +- Added `Add-PnPFileSensitivityLabel` which allows for assigning sensitivity labels to SharePoint files [#4538](https://github.com/pnp/powershell/pull/4538) ### Changed