Skip to main content

Key Rollover and Labeling Guide

Security add-in for Microsoft 365

Using DKE introduces a specific challenge:
Automatic labeling in SharePoint does not work with DKE-protected labels.

This means files must be labeled manually or via alternative methods before migration, to ensure Microsoft 365 cannot read the contents.

Potential Solutions

Here are several ways to apply the required labels to files:

  1. Manual Labeling via the Purview Label Client
  2. Azure Information Protection (AIP) Scanner
  3. Powershell labeling files

1. Manual Labeling

Involves selecting individual files or folders in File Explorer and applying the appropriate label.

Downside:
Limited logging in case of errors, and files must be checked one-by-one — very time-consuming and unsuitable for large migrations.

2. AIP Scanner

A tool installed on-premises to apply labels automatically to files on file shares or SharePoint On-Premises, based on defined policies.

Advantages:
Great for larger environments or where labeling needs to be extended to on-premises setups.

Disadvantage:
In my case, with only a small local drive involved in the migration, the implementation overhead was too high.

3. PowerShell-Based Labeling

Due to the limitations above, I chose to label files using PowerShell.

Requirements:

  • A client with PowerShell and the Purview Label Client installed
  • An app registration in Entra ID (formerly Azure Active Directory)

Limitations:

  • MSG files (Outlook messages) cannot be labeled via PowerShell
  • Password-protected or certificate-signed PDFs can't be labeled either (Limitation of the label system itself, not PowerShell)

The PowerShell Challenge

Using standard PowerShell commands as per Microsoft documentation led to PowerShell freezing or running indefinitely.
Here is an example of a command that failed::

Get-FileStatus -Path \\Finance\Projects\ | Where-Object {$_.IsLabeled -eq $False} | Set-FileLabel -LabelId d9f23ae3-4321-4321-4321-f515f824c57b

Microsoft recommends adding the following for garbage collection:

[GC]::Collect()
[GC]::WaitForPendingFinalizers()

Our testing has proven that the above is not sufficient and additional work is required to reliably label files using a retry mechanism and job-based processing

Label File with Powershell

Get-ChildItem -Path \\Finance\Projects\ -Recurse -File | ForEach-Object {
try {
$maxRetries = 3
$retryCount = 0
$setSuccess = $false

while (-not $setSuccess -and $retryCount -lt $maxRetries) {
$retryCount++
$jobsetlabel = Start-Job -ScriptBlock {
param ($fileName, $DKELabelId)
Set-FileLabel -FileName $fileName -LabelId $DKELabelId
[GC]::Collect()
[GC]::WaitForPendingFinalizers()
return $true
} -ArgumentList $_.FullName, "d9f23ae3-4321-4321-4321-f515f824c57b"

$finishedsetlabel = $jobsetlabel | Wait-Job -Timeout 10 | Receive-Job

if ($finishedsetlabel) {
$setSuccess = $true
Write-Host "Label set successfully for $($_.FullName) on attempt $retryCount." -ForegroundColor Green
}
}
}
catch {
Write-Host "Failed to set label after $maxRetries attempts for $($_.FullName)." -ForegroundColor Red
}
}

Script Highlights:

  • Retry mechanism: Tries up to 3 times per file
  • Job-based execution: Each file is labeled in a separate job to avoid resource issues
  • Memory cleanup: Uses [GC]::Collect() and [GC]::WaitForPendingFinalizers() after each job
  • Timeout control: Prevents hanging by using Wait-Job -Timeout 10

With this approach, I successfully labeled all relevant files without PowerShell freezing or running indefinitely.

Additional Script for Pre-Migration Audit

To ensure all files were correctly labeled before migration, I also wrote a script that read the label of each file and logged the results to a CSV. This allowed for manual review and adjustments where needed.

Need help?