Sensitivity labels are essential for classifying and protecting sensitive information in your organization. By configuring default sensitivity labels for document libraries in SharePoint and OneDrive, you can ensure all files automatically inherit an appropriate label. While SharePoint provides a user interface for this, OneDrive requires programmatic methods.
In this blog post, we will explore how to configure default sensitivity labels using PnP PowerShell, track delta changes to identify newly created or modified libraries, and leverage an Azure Function for automation at scale.
You can set default sensitivity labels for SharePoint document libraries via the user interface. Navigate to the library settings, select Default sensitivity label, and choose a label from the dropdown.
For detailed instructions, see my blog post Understanding Default Sensitivity Labels in Document Libraries.
You can use this concept for both SharePoint and OneDrive libraries. But unlike SharePoint, OneDrive does not offer a user interface to configure default sensitivity labels. Instead, you must use APIs.
# Connect to SharePoint OnlineConnect-PnPOnline -Url https://yourtenant.sharepoint.com -Interactive# Set default sensitivity label for a document librarySet-PnPList -Identity "Demo List" -DefaultSensitivityLabelForLibrary "Confidential"
# Connect to SharePoint OnlineConnect-PnPOnline -Url https://yourtenant-admin.sharepoint.com -Interactive# Connect to the OneDrive site for a specific userConnect-PnPOnline -Url https://yourtenant-my.sharepoint.com/personal/jane_doe_contoso_com -Interactive# Set default sensitivity label for the "Documents" librarySet-PnPList -Identity "Documents" -DefaultSensitivityLabelForLibrary "Confidential"
To apply labels across all OneDrive libraries in your organization:
# Connect to SharePoint OnlineConnect-PnPOnline -Url https://yourtenant-admin.sharepoint.com -Interactive# Get all OneDrive sites$oneDriveSites = Get-PnPTenantSite -IncludeOneDriveSites# Loop through each OneDrive site and set the default sensitivity label for the "Documents" libraryforeach ($site in $oneDriveSites) {Connect-PnPOnline -Url $site.Url -InteractiveSet-PnPList -Identity "Documents" -DefaultSensitivityLabelForLibrary "Confidential"}
Delta queries can help detect changes in OneDrive libraries to ensure all new or modified libraries are labeled correctly.
# Connect to SharePoint OnlineConnect-PnPOnline -Url https://yourtenant-admin.sharepoint.com -Interactive# Get all OneDrive sites$oneDriveSites = Get-PnPTenantSite -IncludeOneDriveSites# Loop through each OneDrive site and check for new or changed sitesforeach ($site in $oneDriveSites) {# Check if the site is new or has changedif ($site.LastModified -gt (Get-Date).AddDays(-1)) {Connect-PnPOnline -Url $site.Url -InteractiveSet-PnPList -Identity "Documents" -DefaultSensitivityLabelForLibrary "Confidential"}}
Azure Function Setup:
GraphServiceClient
.Disclaimer:
This code is conceptual and based on Sanjoyan’s example. It has not been tested in a production environment and may require adjustments and thorough testing.
using System.Net.Http;using Microsoft.Azure.WebJobs;using Microsoft.Azure.WebJobs.Extensions.Http;using Microsoft.Extensions.Logging;using Microsoft.Graph;using Azure.Identity;using Microsoft.Azure.Cosmos.Table;public static async Task Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequestMessage req,ILogger log){var managedIdentityCredential = new ManagedIdentityCredential();var clientSecretCredential = new ClientSecretCredential(tenantId, clientId, clientSecret);var credential = new ChainedTokenCredential(managedIdentityCredential, clientSecretCredential);var client = new GraphServiceClient(credential);try{string deltaLink = await GetDeltaLinkAsync();var deltaQuery = string.IsNullOrEmpty(deltaLink)? await client.Users.Delta().Request().GetAsync(): await client.Users.Delta().Request().GetAsync(deltaLink);log.LogInformation("Delta query completed.");foreach (var user in deltaQuery.CurrentPage){await AssignDefaultSensitivityLabel(user.Id, credential, log);}deltaLink = deltaQuery.AdditionalData["@odata.deltaLink"].ToString();await SaveDeltaLinkAsync(deltaLink);return req.CreateResponse(HttpStatusCode.OK);}catch (Exception ex){log.LogError($"An error occurred: {ex.Message}");return req.CreateResponse(HttpStatusCode.InternalServerError, "An error occurred while processing the request.");}}private static async Task AssignDefaultSensitivityLabel(string userId, TokenCredential credential, ILogger log){var client = new HttpClient();var tokenRequestContext = new TokenRequestContext(new[] { "https://graph.microsoft.com/.default" });var accessToken = await credential.GetTokenAsync(tokenRequestContext);var request = new HttpRequestMessage(HttpMethod.Post, $"https://{tenantName}-my.sharepoint.com/personal/{userId}_{tenantName}_onmicrosoft_com/_api/web/lists/GetByTitle('Documents')"){Headers ={{ "Accept", "application/json;odata=verbose" },{ "Content-Type", "application/json;odata=verbose" },{ "X-HTTP-Method", "MERGE" },{ "If-Match", "*" },{ "Authorization", $"Bearer {accessToken.Token}" }},Content = new StringContent($@"{{""__metadata"": {{""type"": ""SP.List""}},""DefaultSensitivityLabelForLibrary"": """"}}")};HttpResponseMessage response = null;int retryCount = 0;int maxRetries = 5;int delay = 2000; // Delay in millisecondswhile (retryCount < maxRetries){try{response = await client.SendAsync(request);if (response.StatusCode == HttpStatusCode.TooManyRequests){retryCount++;log.LogWarning($"Throttling detected. Retrying in {delay} milliseconds. Attempt {retryCount} of {maxRetries}.");await Task.Delay(delay);delay *= 2; // Exponential backoff}else{response.EnsureSuccessStatusCode();log.LogInformation("Sensitivity label assigned successfully.");break;}}catch (HttpRequestException httpEx){log.LogError($"HTTP request error: {httpEx.Message}");throw;}catch (Exception ex){log.LogError($"An error occurred: {ex.Message}");throw;}}if (response.StatusCode == HttpStatusCode.TooManyRequests){log.LogError("Max retries exceeded due to throttling.");throw new Exception("Max retries exceeded due to throttling.");}}public static async Task SaveDeltaLinkAsync(string deltaLink){var storageAccount = CloudStorageAccount.Parse(storageConnectionString);var tableClient = storageAccount.CreateCloudTableClient(new TableClientConfiguration());var table = tableClient.GetTableReference("DeltaLinks");await table.CreateIfNotExistsAsync();var deltaEntity = new DeltaLinkEntity("DeltaLinkPartition", "DeltaLinkRow"){DeltaLink = deltaLink};var insertOrReplaceOperation = TableOperation.InsertOrReplace(deltaEntity);await table.ExecuteAsync(insertOrReplaceOperation);}public static async Task GetDeltaLinkAsync(){var storageAccount = CloudStorageAccount.Parse(storageConnectionString);var tableClient = storageAccount.CreateCloudTableClient(new TableClientConfiguration());var table = tableClient.GetTableReference("DeltaLinks");var retrieveOperation = TableOperation.Retrieve("DeltaLinkPartition", "DeltaLinkRow");var result = await table.ExecuteAsync(retrieveOperation);var deltaEntity = result.Result as DeltaLinkEntity;return deltaEntity?.DeltaLink;}public class DeltaLinkEntity : TableEntity{public DeltaLinkEntity() { }public DeltaLinkEntity(string partitionKey, string rowKey){PartitionKey = partitionKey;RowKey = rowKey;}public string DeltaLink { get; set; }}
By programmatically setting default sensitivity labels, you enhance security and compliance across your organization’s document libraries. Whether through PowerShell scripts or scalable solutions like Azure Functions, this approach ensures sensitive data is protected at all times.
Thank you for reading!
/Simon