Skip to main content

Securosys365 - Key Rollover

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.

Possible Solutions

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

  1. Manual Labeling via the Purview Label Client
  2. Using the Azure Information Protection (AIP) Scanner
  3. Labeling files using PowerShell

I've explored all these options in depth and would like to share my experiences:


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 also can't be labeled
    (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’s the example 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()

However, this didn't solve the issue in my case.


My Working PowerShell Solution

After testing, I developed a script that reliably labels files using a retry mechanism and job-based processing:

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 jobs from hanging with Wait-Job -Timeout 10

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


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 into a CSV. This allowed for manual review and adjustments where needed.