HomeAbout Me
Microsoft 365
Default Sensitivity Labels - Programatically
Simon Ågren
Simon Ågren
May 13, 2024
1 min

Table Of Contents

01
Introduction
02
Setting Default Sensitivity Labels in SharePoint via UI
03
Setting Default Sensitivity Labels in programmatically
04
Looping Through OneDrive Libraries
05
Tracking Delta Changes
06
Azure Function Example
07
Conclusion
Default Sensitivity Labels - Programatically

Introduction

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.


Setting Default Sensitivity Labels in SharePoint via UI

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.

Library settings - default label
Library settings - default label


Setting Default Sensitivity Labels in programmatically

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.

Example: Setting Default Sensitivity Label for a SharePoint Library

# Connect to SharePoint Online
Connect-PnPOnline -Url https://yourtenant.sharepoint.com -Interactive
# Set default sensitivity label for a document library
Set-PnPList -Identity "Demo List" -DefaultSensitivityLabelForLibrary "Confidential"

Example: Setting Default Sensitivity Label for a OneDrive Library

# Connect to SharePoint Online
Connect-PnPOnline -Url https://yourtenant-admin.sharepoint.com -Interactive
# Connect to the OneDrive site for a specific user
Connect-PnPOnline -Url https://yourtenant-my.sharepoint.com/personal/jane_doe_contoso_com -Interactive
# Set default sensitivity label for the "Documents" library
Set-PnPList -Identity "Documents" -DefaultSensitivityLabelForLibrary "Confidential"

Looping Through OneDrive Libraries

To apply labels across all OneDrive libraries in your organization:

# Connect to SharePoint Online
Connect-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" library
foreach ($site in $oneDriveSites) {
Connect-PnPOnline -Url $site.Url -Interactive
Set-PnPList -Identity "Documents" -DefaultSensitivityLabelForLibrary "Confidential"
}

Tracking Delta Changes

Delta queries can help detect changes in OneDrive libraries to ensure all new or modified libraries are labeled correctly.

# Connect to SharePoint Online
Connect-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 sites
foreach ($site in $oneDriveSites) {
# Check if the site is new or has changed
if ($site.LastModified -gt (Get-Date).AddDays(-1)) {
Connect-PnPOnline -Url $site.Url -Interactive
Set-PnPList -Identity "Documents" -DefaultSensitivityLabelForLibrary "Confidential"
}
}

Azure Function Example

Context and Explanation

Azure Function Setup:

  • The function is HTTP-triggered and supports both GET and POST requests.
  • It interacts with Microsoft Graph API using GraphServiceClient.

Key Concepts

  1. Authentication: Managed identities and client secrets ensure secure API access.
  2. Delta Query: Detect new or modified users and track changes over time.
  3. Retry Logic: Handle throttling with exponential backoff for API requests.
  4. Assign Sensitivity Labels: Use REST API calls to apply labels programmatically.
  5. Persist Delta Link: Store the delta link in Azure Table Storage for continued tracking.

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.

Complete Code

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 milliseconds
while (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; }
}

Conclusion

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


Tags

purviewm365sam
Previous Article
Default Sensitivity Labels in SharePoint and OneDrive

Simon Ågren

CTA & Microsoft MVP

Solving business problems with tech

Expertise

Microsoft 365
Azure

Social Media

githubtwitterwebsite

Related Posts

Post-Deployment Strategies for Copilot
Post-Deployment Strategies for Copilot
December 14, 2024
3 min

Quick Links

About

Social Media