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 diff --git a/documentation/Add-PnPFileSensitivityLabel.md b/documentation/Add-PnPFileSensitivityLabel.md new file mode 100644 index 000000000..2381b435f --- /dev/null +++ b/documentation/Add-PnPFileSensitivityLabel.md @@ -0,0 +1,105 @@ +--- +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 -Identity -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 -Identity "/sites/Marketing/Shared Documents/Report.pptx" -SensitivityLabelId "b5b11b04-05b3-4fe4-baa9-b7f5f65b8b64" -JustificationText "Previous label no longer applies" -AssignmentMethod Privileged +``` + +### 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 + +### -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: FilePipeBind +Parameter Sets: (All) + +Required: True +Position: 0 +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..af54b859a --- /dev/null +++ b/src/Commands/Files/AddFileSensitivityLabel.cs @@ -0,0 +1,51 @@ +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.Management.Automation; +using System.Net.Http.Headers; + +namespace PnP.PowerShell.Commands.Files +{ + [Cmdlet(VerbsCommon.Add, "PnPFileSensitivityLabel")] + [RequiredApiDelegatedOrApplicationPermissions("graph/Files.ReadWrite.All")] + [RequiredApiDelegatedOrApplicationPermissions("graph/Sites.ReadWrite.All")] + + public class AddFileSensitivityLabel : PnPGraphCmdlet + { + [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true)] + public FilePipeBind Identity; + + [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; + + 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"; + + var payload = new + { + sensitivityLabelId = SensitivityLabelId, + assignmentMethod = AssignmentMethod.ToString(), + justificationText = JustificationText + }; + + HttpResponseHeaders responseHeader = RestHelper.PostGetResponseHeader(Connection.HttpClient, requestUrl, AccessToken, payload: payload); + + WriteVerbose($"File sensitivity label assigned to {file.Name}"); + 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); } }