Entra / Microsoft 365 · SharePoint & OneDrive
Apply sensitivity labels to SharePoint files
Applies sensitivity labels to unlabeled files in a SharePoint Online document library using Microsoft Graph.
Connect & set up
Run these once per session. All scopes are read-only unless the script makes changes.
Connect-MgGraph -NoWelcome -AppId $AppId -TenantId $TenantId -CertificateThumbprint $CertThumbprint
Run it
The main script. Copy it, or download the .ps1 and run it from your console.
param([string] $SiteName = "",[string] $TenantId = "",[string] $AppId = "",[string] $CertThumbPrint = "")function Get-DriveItems {[CmdletBinding()]param ([Parameter()]$DriveId,[Parameter()]$FolderId)# Get data for a folder and its children[array]$Data = Get-MgDriveItemChild -DriveId $DriveId -DriveItemId $FolderId -All# Split the data into files and folders[array]$Folders = $Data | Where-Object {$_.folder.childcount -gt 0} | Sort-Object Name$Global:TotalFolders = $TotalFolders + $Folders.Count[array]$Files = $Data | Where-Object {$null -ne $_.file.mimetype}# Process the files to find each has a sensitivity label. If not, label itForEach ($File in $Files) {$SensitivityLabelName = $null; $SensitivityLabelInfo = $Null; $Status = $false$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 documentsIf ($FileType.ToUpper() -ne "PDF") {$SensitivityLabelName = "Error"}}}If (($null -eq $SensitivityLabelInfo.labels.sensitivityLabelId) -and ($FileType -in $ValidFileTypes) -and $SensitivityLabelName -ne "Error") {Write-Host ("Assigning sensitivity label to {0}" -f $File.Name)$Uri = ("https://graph.microsoft.com/v1.0/drives/{0}/items/{1}/assignSensitivityLabel" -f $DriveId, $File.Id)Try {Invoke-MgGraphRequest -Method "POST" -Uri $Uri -Body $AssignmentPayload -OutputType PSObject$Status = $true # set so that we report the update} Catch {$Error[0].Exception.MessageWrite-Host ("Failed to assign sensitivity label to file {0}" -f $File.Name ) -ForegroundColor Red}}If ($File.LastModifiedDateTime) {$LastModifiedDateTime = Get-Date $File.LastModifiedDateTime -format 'dd-MMM-yyyy HH:mm'} Else {$LastModifiedDateTime = $null}If ($File.CreatedDateTime) {$FileCreatedDateTime = Get-Date $File.CreatedDateTime -format 'dd-MMM-yyyy HH:mm'}If ($Status -eq $true) {$ReportLine = [PSCustomObject]@{FileName = $File.NameFolder = $File.parentreference.nameSize = (FormatFileSize $File.Size)Created = $FileCreatedDateTimeAuthor = $File.CreatedBy.User.DisplayNameLastModified = $LastModifiedDateTime'Last modified by' = $File.LastModifiedBy.User.DisplayName'Sensitivity label' = $AssignedSensitivityLabelName}$ReportData.Add($ReportLine)}}# Process the foldersForEach ($Folder in $Folders) {Write-Host ("Processing folder {0} ({1} files/size {2})" -f $Folder.Name, $Folder.folder.childcount, (FormatFileSize $Folder.Size))Get-DriveItems -Drive $DriveId -FolderId $Folder.Id}}function FormatFileSize {# Format File Size nicelyparam ([parameter(Mandatory = $true)]$InFileSize)If ($InFileSize -lt 1KB) { # Format the size of a document$FileSize = $InFileSize.ToString() + " B"}ElseIf ($InFileSize -lt 1MB) {$FileSize = $InFileSize / 1KB$FileSize = ("{0:n2}" -f $FileSize) + " KB"}Elseif ($InFileSize -lt 1GB) {$FileSize = $InFileSize / 1MB$FileSize = ("{0:n2}" -f $FileSize) + " MB"}Elseif ($InFileSize -ge 1GB) {$FileSize = $InFileSize / 1GB$FileSize = ("{0:n2}" -f $FileSize) + " GB"}Return $FileSize}# Disconnect from any previous Graph SDK sessionDisconnect-MgGraph -ErrorAction SilentlyContinue# Insert values for your tenant and app here$CertThumbprint = "F79286DB88C21491110109A0222348FACF694CBD"# Guid for sensitivity label to apply - againm from your tenant$Global:SensitivityLabelId = "27451a5b-5823-4853-bcd4-2204d03ab477"$Global:AssignedSensitivityLabelName = "Internal"# Parameters to assign a sensitivity label$Global:AssignmentPayload = @{}$AssignmentPayload.Add("AssignmentMethod", "Auto")$AssignmentPayload.Add("Justification", "API application of label")$AssignmentPayload.Add("SensitivityLabelId", $SensitivityLabelId)# Connect to the Microsoft GraphConnect-MgGraph -NoWelcome -AppId $AppId -TenantId $TenantId -CertificateThumbprint $CertThumbprintWrite-Host "Setting up to assign Sensitivity labels to unlabelled files..."$Global:SensitivityLabelsAvailable = $true[array]$Global:ValidfileTypes = "docx", "pptx", "xlsx", "pdf"# Find the siteWrite-Host "Looking for matching sites..."[array]$Sites = Get-MgSite -Search ($SiteName)If (!($Sites)) { # Nothing foundWrite-Host "No matching sites found - exiting"break}If ($Sites.Count -eq 1) { # Only one site found - go ahead$Global:Site = $Sites[0]$SiteName = $Site.DisplayNameWrite-Host "Found site to process:" $SiteName} ElseIf ($Sites.Count -gt 1) {# More than one site found. Ask which to useClear-Host[int]$i = 1Write-Host "More than one matching site was found. We need you to select a site to report."Write-Host " "ForEach ($SiteOption in $Sites) {Write-Host ("{0}: {1} ({2})" -f $i, $SiteOption.DisplayName, $SiteOption.Name); $i++}Write-Host ""[Int]$Answer = Read-Host "Enter the number of the site to use"If (($Answer -gt 0) -and ($Answer -le $i)) {[int]$Si = ($Answer-1)$SiteName = $Sites[$Si].DisplayNameWrite-Host ("OK. Selected site is {0}" -f $Sites[$Si].DisplayName)$Global:Site = $Sites[$Si]}}If (!($Site)) {Write-Host ("Can't find the {0} site - script exiting" -f $Uri)break}# Find the document libraries in the site[array]$Drives = Get-MgSiteDrive -SiteId $Site.IdIf (!($Drives)) {Write-Host "No document libraries found in the site" -ForegroundColor RedBreak}If ($Drives.Count -eq 1) { # Only one drive found - go ahead$Drive = $Drives$DriveName = $Drive.NameWrite-Host "Found drive to process:" $DriveName} Elseif ($Drives.Count -gt 1) { # More than one drive found. Ask which to useClear-Host; Write-Host "More than one drive found in site. We need you to select a drive to report."; [int]$i=1Write-Host " "ForEach ($DriveOption in $Drives) {Write-Host ("{0}: {1}" -f $i, $DriveOption.Name); $i++}Write-Host ""[Int]$Answer = Read-Host "Enter the number of the drive to use"If (($Answer -gt 0) -and ($Answer -le $i)) {[int]$Si = ($Answer-1)$DriveName = $Drives[$Si].NameWrite-Host "OK. Selected drive is" $Drives[$Si].Name$Drive = $Drives[$Si]}}If (!($Drive)) {Write-Host ("Can't find the {0} drive - script exiting" -f $Uri) ; break}[datetime]$StartProcessing = Get-Date$Global:TotalFolders = 1# Create output list and CSV file$Global:ReportData = [System.Collections.Generic.List[Object]]::new()$CSVOutputFile = ((New-Object -ComObject Shell.Application).Namespace('shell:Downloads').Self.Path) + ("\Files {0}-{1} library.csv" -f $Site.displayName, $DriveName)# Get the items in the root, including child foldersWrite-Host "Fetching file information..."Get-DriveItems -Drive $Drive.Id -FolderId "root"[datetime]$EndProcessing = Get-Date$ElapsedTime = ($EndProcessing - $StartProcessing)$FilesPerMinute = [math]::Round(($ReportData.Count / ($ElapsedTime.TotalSeconds / 60)), 2)Write-Host ""Write-Host ("Processed {0} files in {1} folders in {2}:{3} minutes ({4} files/minute)" -f `$ReportData.Count, $TotalFolders, $ElapsedTime.Minutes, $ElapsedTime.Seconds, $FilesPerMinute)$ReportData | Out-GridView -Title ("Files in {0} document library for the {1} site" -f $DriveName, $SiteName)$ReportData | Export-Csv -Path $CSVOutputFile -NoTypeInformation -Encoding UTF8Write-Host ("Report data saved to {0}" -f $CSVOutputFile)
Parameters
ParameterDefaultNotes
-SiteName""Name of the SharePoint site whose document library should be processed.-TenantId""Microsoft Entra tenant ID for app-only Graph authentication.-AppId""Application (client) ID for the app registration used to connect.-CertThumbPrint""Certificate thumbprint for app-only Graph authentication.Attribution
Author
Office365itpros