New Graph SDK Cmdlet to Assign Sensitivity Labels

In July 2024, I covered how to use the assignSensitivityLabel Graph API to assign sensitivity labels to files stored in SharePoint Online. The example script provided with the article runs an API request to assign labels. At that time, a cmdlet wasn’t available because it takes Microsoft some time to generate cmdlets for the Microsoft Graph PowerShell SDK after new APIs appear. The Set-MgDriveItemSensitivityLabel cmdlet is now available and can be used to assign a sensitivity label to a file with PowerShell code like this:

If ($FileType -in $ValidFileTypes) { 
   Try {
     Set-MgDriveItemSensitivityLabel -DriveId $DriveId -DriveItemId $File.Id -SensitivityLabelId $SensitivityLabelId -ErrorAction Stop
     $Status = $true
   } Catch {
     Write-Host ("Error applying label {0} to {1} ({2})" -f $SensitivityLabelName, $File.Name, $_.Exception.Message) -ForegroundColor Red
   }
}

In the example, the check against the $ValidFileTypes array ensures that the file is of a type that supports sensitivity labels (Office .DOCX, PPTX, XLSX files, and PDF files).

The Files.ReadWrite.All permission is required to assign sensitivity labels to files.

The Danger of Overwriting

The assignSensitivityLabel API (and cmdlet) overwrites any previously assigned sensitivity label, including labels set by auto-label policies and manually assigned by users. This is not the way that Purview auto-label policies work. Auto-label policies won’t replace a manually assigned label for a file or replace a sensitivity label with a lower-priority label. No guiderails come with the API. If an app uses the API to assign sensitivity labels, it’s assumed that the app code contains any safeguards required by the tenant.

It’s a good idea to check files for the assigned label before deciding to proceed with the assignment of a new sensitivity label. Unfortunately, there isn’t an SDK cmdlet for the extractSensitivityLabels API, so the check for existing labels must be implemented in code. Here’s an example:

$FileType = $File.Name.Split(".")[1]
  If ($FileType -in $ValidFileTypes) { 
    $Uri = ("https://graph.microsoft.com/V1.0/sites/{0}/drive/items/{1}/extractSensitivityLabels" -f $Site.Id, $File.id)
    Try {
       [array]$SensitivityLabelInfo = Invoke-MgGraphRequest -Uri $Uri -Method POST 
    } Catch {
       Write-Host ("Error reading sensitivity label data from file {0}" -f $File.Name) -ForegroundColor Yellow
      # PDFs often return errors when reading sensitivity label info, so I ignore them and only accept the error for Office documents
      If ($FileType.ToUpper() -ne "PDF") {
          $SensitivityLabelName = "Error"
       }
     }
}

The code retrieves the existing sensitivity labels present for the file. It doesn’t check whether assigning a new label is an upgrade or downgrade in sensitivity. If you want to prevent overwriting of existing labels or downgrading of protection, code must be included to check for these conditions.

Files can accumulate sensitivity labels from different tenants when they are shared directly or as attachments. The recipient of an email attachment with a sensitivity label can download the file (which always retains its original label) and assign a new sensitivity label to the file. The exception is where a user applies a label with rights-management-based encryption. In this case, that label becomes the only sensitivity label present for a file because the rights defined in the label govern access to file content.

Payment Required

Use of a metered API means that Microsoft must be paid for each API transaction (the current charge is $0.00185 to assign a sensitivity label to a file). To pay the charges, the Entra ID app running the API must be associated with an Azure subscription with a valid credit card. To avoid excessive demands on the service, Microsoft restricts tenants to a limit of 100,000 API calls to apply sensitivity labels over a 24-hour period.

Apps that use the assignSensitivityLabel API or Set-MgDriveItemSensitivityLabel cmdlet must be registered as Azure resources and associated with an Azure subscription. Each app that uses the API or cmdlet must be registered separately.

Creating an Azure Resource for an App

The code shown below is an Azure CLI command to create a resource called AssignLabelsApp in the SensitivityLabels resource group (the resource group must already exist). The resource type is a Graph service account, which points to the application identifier of the app used to run the API. To link the new resources with an Azure subscription, include the identifier for the subscription in the subscription parameter:

az resource create --resource-group SensitivityLabels --name AssignLabelsApp--resource-type Microsoft.GraphServices/accounts --properties "{""appId"": ""212eb7dc-9c47-4f13-9620-d8471178b8ad""}" --location Global --subscription 31429342-a1a5-4427-9e2d-551840f2ad25

The simplest way to create the new resource is to prepare the command in Notepad or a similar editor, making sure that the values used for the application identifier, subscription identifier, and the resource group are correct, and that you use a unique resource name. Then open the Azure portal and create a cloud shell session, and paste the command you prepared into the shell.

After creating the Azure resource, you can run Connect-MgGraph to create an app-only session (using the application identifier specified for the Azure resource) and run the API requests or cmdlet. Failure to register the app and link it to a valid subscription that can accept charges results in a “payment required” error:

Error applying label to Agenda - Launch.docx ([paymentRequired] : Payment Required. Ensure that your application is able to call this premium API. For details see https://aka.ms/graph-metered-overview)

No Delegated Mode

The requirement to enable charging by registering an app as an Azure resource in a tenant means that you cannot use the Set-MgDriveItemSensitivityLabel in delegated mode, even if you have full access to the site storing the target files.

The issue here is that when you create an interactive session with the Connect-MgGraph cmdlet to run in delegated mode, the enterprise Microsoft Graph Command Line Tools app is used. A tenant can’t make an enterprise app (owned by Microsoft) into an Azure resource to pay for API calls. Any attempt to do so fails because the Microsoft Graph Command Line Tools app is not owned by the tenant.

Cmdlets Don’t Work Around Graph Restrictions

The new Set-MgDriveItemSensitivityLabel cmdlet makes it slightly easier to assign a sensitivity label through PowerShell (the older process using Invoke-MgGraphRequest is not difficult). However, it’s important to emphasize that Microsoft Graph PowerShell SDK cmdlets are not workarounds for restrictions applied to the underlying Graph APIs. This could never work because the cmdlets essentially pass API requests to the Graph. The Set-MgDriveItemSensitivityLabel cmdlet is an excellent example of this principle in action. Make sure that you have your Azure resources lined up before attempting to run the cmdlet!

About the Author

Tony Redmond

Tony Redmond has written thousands of articles about Microsoft technology since 1996. He is the lead author for the Office 365 for IT Pros eBook, the only book covering Office 365 that is updated monthly to keep pace with change in the cloud. Apart from contributing to Practical365.com, Tony also writes at Office365itpros.com to support the development of the eBook. He has been a Microsoft MVP since 2004.

Leave a Reply