Automating Sensitivity Label and Encryption Removal in SharePoint Online with PowerShell

Encryption Removal in SharePoint Online with PowerShell

In modern enterprise environments, sensitivity labels and encryption policies are critical for protecting data. However, there are scenarios—such as data migration, restructuring, or administrative overrides—where these protections need to be temporarily removed. This blog post walks through a PowerShell script designed to automate the removal of Microsoft Purview sensitivity labels and encryption from files stored in SharePoint Online document libraries.

This script is particularly useful for IT administrators managing large-scale SharePoint environments where manual intervention would be inefficient and error-prone. It leverages the PnP PowerShell module and Microsoft Entra ID app registrations to authenticate and perform operations across multiple sites.

Requirements

To run this script, you will need PowerShell 7 installed along with the PnP.PowerShell module. You will also need four app registrations within Entra ID that are generated by PnP.Powershell. For more information on creating these app registrations, see https://pnp.github.io/powershell/articles/registerapplication.html.

Script

Here is the full script. You can copy and paste this to VS Code for modification. See below the script for an explanation of what the script does and what you might need to change.

# RUN FIRST BY ITSELF, NOT AS PART OF WHOLE SCRIPT EXECUTION
if ($cred -eq $null) {$cred = get-credential}

$temp_owner = "admin@domain.onmicrosoft.com" # temporary site collection administrator (should be account running script)
$justification_text = "Administrator Change." # justification to provide when label is removed
$pnp_clientID_1 = "<app id 1>" # application ID of Pnp.Powershell Entra ID app
$pnp_clientID_2 = "<app id 2>" # application ID of Pnp.Powershell Entra ID app
$pnp_clientID_3 = "<app id 3>" # application ID of Pnp.Powershell Entra ID app
$pnp_clientID_4 = "<app id 4>" # application ID of Pnp.Powershell Entra ID app
$SP_domain = "<sp domain>" # part between https:// and .sharepoint.com
$log_file = 'C:\Users\admin\Downloads\remove-label-SP.txt'
$completed_log = 'C:\Users\admin\Downloads\remove-label-completed-SP.txt'

$sites = import-csv 'C:\Users\admin\Downloads\Data explorer _ Microsoft Purview-SP.csv' # sites to process. exported from Purview reports.

# create log files
$date = get-date -format "MM-dd-yyyyTHH:mm:ss"
$f_log_file = ($log_file.replace(".txt","_$date.txt")).replace(":","_")
$f_log_file = $f_log_file.replace("C_","C:")
if ((test-path $f_log_file) -eq $false) {new-item -type file $f_log_file | out-null}
add-content $f_log_file "$date SCRIPT_START"

if ((test-path $completed_log) -eq $false) {new-item -type file $completed_log | out-null}
add-content $completed_log "$date SCRIPT_START"
$date = ""

# connect to SharePoint
$pnp_url = "https://" + $SP_domain + ".sharepoint.com/"
$pnp_clientID = $pnp_clientID_1
connect-pnponline -url $pnp_url -clientid $pnp_clientID -credential $cred
add-content -path $f_log_file -value "$(Get-Date -format "MM-dd-yyyyTHH:mm:ss") CONNECTED USING APP REG 1"

# set up progress bar
$count = 0
$total = $sites.count

ForEach ($site in $sites) {

# set counts for progress bar
$count = $count + 1
$percent = $count/$total
$percent_readable = $percent.tostring("P")
$percent_bar = $percent * 100
# display progress bar
write-progress "processing $count of $total - $percent_readable complete." -PercentComplete $percent_bar

$site_url = $site.URL

add-content -path $f_log_file -value "$(Get-Date -format "MM-dd-yyyyTHH:mm:ss") START $site_url"

# connect to site
set-pnptenantsite $site_url -owners $temp_owner
connect-pnponline -url $site_url -clientid $pnp_clientID -credential $cred

# Get All Files from the document library - In batches of 500
$lists = get-pnplist | where-object -filterscript {$_.BaseTemplate -eq "101" -AND $_.ItemCount -ne "0" -AND $_.Title -ne "_catalogs/hubsite" -AND $_.Title -ne "Style Library" -AND $_.Title -notlike "PersistedManagedNavigationList*"}

$list_count = $lists.count
add-content -path $f_log_file -value "$(Get-Date -format "MM-dd-yyyyTHH:mm:ss") FOUND $list_count List(s)"

ForEach ($list in $lists) {
$list_title = $list.Title

add-content -path $f_log_file -value "$(Get-Date -format "MM-dd-yyyyTHH:mm:ss") PROCESSING $list_title"

$list_items = Get-PnPListItem -List $list_title -pagesize 4000 | where-object -filterscript {$_.FieldValues['_DisplayName'] -like "L2*"}

# set up progress bar
$count = 0
$total = $list_items.count

$list_items_count = $list_items.count
add-content -path $f_log_file -value "$(Get-Date -format "MM-dd-yyyyTHH:mm:ss") FOUND $list_items_count Files with L2 Label"

$list_processing_count = 0

do {
ForEach ($item in $list_items) {
# set counts for progress bar
$count = $count + 1
$percent = $count/$total
$percent_readable = $percent.tostring("P")
$percent_bar = $percent * 100
# display progress bar
write-progress "processing $count of $total - $percent_readable complete." -PercentComplete $percent_bar

$file_url = $Item.FieldValues['FileRef']
$url = ($pnp_url + $file_url).replace(".com//",".com/")

try {
Unlock-PnPSensitivityLabelEncryptedFile -Url $url -JustificationText $justification_text -erroraction stop

add-content -path $f_log_file -value "$(Get-Date -format "MM-dd-yyyyTHH:mm:ss") RELABELED $file_url"
}
catch {
add-content -path $f_log_file -value "$(Get-Date -format "MM-dd-yyyyTHH:mm:ss") ERR_RELAB $file_url $($_.Exception.Message)"

if ($($_.Exception.Message) -eq "ResourceBudgetExceeded") {
$id_rotated = 0
write-host "ResourceBudgetExceeded. Changing App Reg." -foregroundcolor red
if ($pnp_clientID -eq $pnp_clientID_1 -AND $id_rotated -eq 0) {
$pnp_clientID = $pnp_clientID_2
connect-pnponline -url $site_url -clientid $pnp_clientID -credential $cred
write-host "changed from client id 1 to client ID 2" -foregroundcolor yellow
add-content -path $f_log_file -value "$(Get-Date -format "MM-dd-yyyyTHH:mm:ss") CHANGED TO APP REG 2"
$id_rotated = 1
start-sleep -s 120
}
if ($pnp_clientID -eq $pnp_clientID_2 -AND $id_rotated -eq 0) {
$pnp_clientID = $pnp_clientID_3
connect-pnponline -url $site_url -clientid $pnp_clientID -credential $cred
write-host "changed from client id 2 to client ID 3" -foregroundcolor yellow
add-content -path $f_log_file -value "$(Get-Date -format "MM-dd-yyyyTHH:mm:ss") CHANGED TO APP REG 3"
$id_rotated = 1
start-sleep -s 120
}
if ($pnp_clientID -eq $pnp_clientID_3 -AND $id_rotated -eq 0) {
$pnp_clientID = $pnp_clientID_4
connect-pnponline -url $site_url -clientid $pnp_clientID -credential $cred
write-host "changed from client id 3 to client ID 4" -foregroundcolor yellow
add-content -path $f_log_file -value "$(Get-Date -format "MM-dd-yyyyTHH:mm:ss") CHANGED TO APP REG 4"
$id_rotated = 1
start-sleep -s 120
}
if ($pnp_clientID -eq $pnp_clientID_4 -AND $id_rotated -eq 0) {
$pnp_clientID = $pnp_clientID_1
connect-pnponline -url $site_url -clientid $pnp_clientID -credential $cred
write-host "changed from client id 4 to client ID 1" -foregroundcolor yellow
add-content -path $f_log_file -value "$(Get-Date -format "MM-dd-yyyyTHH:mm:ss") CHANGED TO APP REG 1"
$id_rotated = 1
start-sleep -s 120
}
}
}

$list_processing_count++

$percent = 0
$percent_readable = ""
$percent_bar = 0
$file_url = ""
$url = ""

start-sleep -seconds 1
}
}
until ($list_processing_count -eq $list_items_count)

add-content -path $f_log_file -value "$(Get-Date -format "MM-dd-yyyyTHH:mm:ss") COMPLETED $list_title"

$list_title = ""
$list_items = ""
$list_items_count = 0
}

remove-pnpsitecollectionadmin -owners $temp_owner

$date = get-date -format "MM-dd-yyyyTHH:mm:ss"
add-content -path $f_log_file -value "$date COMPLETED $site_url"
add-content -path $completed_log -value "$date COMPLETED $site_url"
write-host "$date COMPLETED $site_url" -foregroundcolor green
$date = ""

$site_url = ""
$lists = ""
$list_count = ""
}

$date = get-date -format "MM-dd-yyyyTHH:mm:ss"
add-content -path $f_log_file -value "$date SCRIPT_END"
add-content -path $completed_log -value "$date SCRIPT_END"
$date = ""

Script Overview and Breakdown

1. Credential Handling

The script begins by checking if credentials are already stored. If not, it prompts the user to enter them:

if ($cred -eq $null) {$cred = get-credential}

Note that this needs to be run independently of the script. This will also need to be an account that is in Entra ID with at least SharePoint Administrator access. This account also either needs to be either temporarily excluded from MFA or have a policy in Entra ID Conditional Access temporarily applied to it so that it is not prompted to MFA. Setting up either of these options is out of scope for this blog post.

2. Variable Initialization

Next, variables are configured to assist with script execution. Follow the notes next to the variables for an explanation of the variable. Note that the site collection administrator should be the same account used above.

3. Logging

Two log files are created: one for general logging and another to track completed sites.

4. CSV Input

The script also imports a CSV file containing the list of SharePoint sites to process—typically exported from Microsoft Purview reports.

5. Connect to SharePoint

The script connects to SharePoint Online using the first app registration ID.

6. Identifying and Processing Labeled Files

Within each library, the script identifies files with the label specified in the variable.

7. Throttling and App Registration Rotation

Microsoft 365 APIs enforce throttling limits. If the script encounters a ResourceBudgetExceeded error, it automatically rotates to the next app registration ID and reconnects. This built-in resilience allows the script to continue processing without manual intervention.

8. Cleanup and Final Logging

After processing each site, the script removes the temporary admin and logs the completion. This ensures that permissions are not left elevated and that the process is fully auditable.

Conclusion

This PowerShell script is a powerful tool for SharePoint Online administrators needing to remove sensitivity labels and encryption at scale. It automates a complex, multi-step process while incorporating robust error handling, logging, and authentication management.

By leveraging Microsoft Purview reports, PnP PowerShell, and app registration rotation, the script ensures compliance and efficiency in sensitive data operations. Whether you’re preparing for a migration, restructuring your information architecture, or responding to an urgent business need, this script can save hours of manual work and reduce the risk of human error.

Disclaimer

All content provided on this blog is for information purposes only. Windows Management Experts, Inc. makes no representation as to the accuracy or completeness of any information on this site. Windows Management Experts, Inc. will not be liable for any errors or omissions in this information nor for the availability of this information. It is highly recommended that you consult one of our technical consultants, should you need any further assistance.

Windows Management Experts

Now a Microsoft Solutions Partner for:

✓ Data & AI

✓ Digital and App Innovation

✓ Infrastructure

✓ Security

The Solutions Partner badge highlights WME’s excellence and commitment. Microsoft’s thorough evaluation ensures we’re skilled, deliver successful projects, and prioritize security over everything. This positions WME in a global tech community, ready to innovate on the cloud for your evolving business needs.

Contact us: sales@winmgmtexperts.com

Share:

Facebook
Twitter
LinkedIn
Picture of Andrew

Andrew

Contact Us

Please enable JavaScript in your browser to complete this form.
Name
  • United States+1
  • United Kingdom+44
  • Afghanistan+93
  • Åland Islands+358
  • Albania+355
  • Algeria+213
  • American Samoa+1
  • Andorra+376
  • Angola+244
  • Anguilla+1
  • Antigua & Barbuda+1
  • Argentina+54
  • Armenia+374
  • Aruba+297
  • Ascension Island+247
  • Australia+61
  • Austria+43
  • Azerbaijan+994
  • Bahamas+1
  • Bahrain+973
  • Bangladesh+880
  • Barbados+1
  • Belarus+375
  • Belgium+32
  • Belize+501
  • Benin+229
  • Bermuda+1
  • Bhutan+975
  • Bolivia+591
  • Bosnia & Herzegovina+387
  • Botswana+267
  • Brazil+55
  • British Indian Ocean Territory+246
  • British Virgin Islands+1
  • Brunei+673
  • Bulgaria+359
  • Burkina Faso+226
  • Burundi+257
  • Cambodia+855
  • Cameroon+237
  • Canada+1
  • Cape Verde+238
  • Caribbean Netherlands+599
  • Cayman Islands+1
  • Central African Republic+236
  • Chad+235
  • Chile+56
  • China+86
  • Christmas Island+61
  • Cocos (Keeling) Islands+61
  • Colombia+57
  • Comoros+269
  • Congo - Brazzaville+242
  • Congo - Kinshasa+243
  • Cook Islands+682
  • Costa Rica+506
  • Côte d’Ivoire+225
  • Croatia+385
  • Cuba+53
  • Curaçao+599
  • Cyprus+357
  • Czechia+420
  • Denmark+45
  • Djibouti+253
  • Dominica+1
  • Dominican Republic+1
  • Ecuador+593
  • Egypt+20
  • El Salvador+503
  • Equatorial Guinea+240
  • Eritrea+291
  • Estonia+372
  • Eswatini+268
  • Ethiopia+251
  • Falkland Islands+500
  • Faroe Islands+298
  • Fiji+679
  • Finland+358
  • France+33
  • French Guiana+594
  • French Polynesia+689
  • Gabon+241
  • Gambia+220
  • Georgia+995
  • Germany+49
  • Ghana+233
  • Gibraltar+350
  • Greece+30
  • Greenland+299
  • Grenada+1
  • Guadeloupe+590
  • Guam+1
  • Guatemala+502
  • Guernsey+44
  • Guinea+224
  • Guinea-Bissau+245
  • Guyana+592
  • Haiti+509
  • Honduras+504
  • Hong Kong SAR China+852
  • Hungary+36
  • Iceland+354
  • India+91
  • Indonesia+62
  • Iran+98
  • Iraq+964
  • Ireland+353
  • Isle of Man+44
  • Israel+972
  • Italy+39
  • Jamaica+1
  • Japan+81
  • Jersey+44
  • Jordan+962
  • Kazakhstan+7
  • Kenya+254
  • Kiribati+686
  • Kosovo+383
  • Kuwait+965
  • Kyrgyzstan+996
  • Laos+856
  • Latvia+371
  • Lebanon+961
  • Lesotho+266
  • Liberia+231
  • Libya+218
  • Liechtenstein+423
  • Lithuania+370
  • Luxembourg+352
  • Macao SAR China+853
  • Madagascar+261
  • Malawi+265
  • Malaysia+60
  • Maldives+960
  • Mali+223
  • Malta+356
  • Marshall Islands+692
  • Martinique+596
  • Mauritania+222
  • Mauritius+230
  • Mayotte+262
  • Mexico+52
  • Micronesia+691
  • Moldova+373
  • Monaco+377
  • Mongolia+976
  • Montenegro+382
  • Montserrat+1
  • Morocco+212
  • Mozambique+258
  • Myanmar (Burma)+95
  • Namibia+264
  • Nauru+674
  • Nepal+977
  • Netherlands+31
  • New Caledonia+687
  • New Zealand+64
  • Nicaragua+505
  • Niger+227
  • Nigeria+234
  • Niue+683
  • Norfolk Island+672
  • North Korea+850
  • North Macedonia+389
  • Northern Mariana Islands+1
  • Norway+47
  • Oman+968
  • Pakistan+92
  • Palau+680
  • Palestinian Territories+970
  • Panama+507
  • Papua New Guinea+675
  • Paraguay+595
  • Peru+51
  • Philippines+63
  • Poland+48
  • Portugal+351
  • Puerto Rico+1
  • Qatar+974
  • Réunion+262
  • Romania+40
  • Russia+7
  • Rwanda+250
  • Samoa+685
  • San Marino+378
  • São Tomé & Príncipe+239
  • Saudi Arabia+966
  • Senegal+221
  • Serbia+381
  • Seychelles+248
  • Sierra Leone+232
  • Singapore+65
  • Sint Maarten+1
  • Slovakia+421
  • Slovenia+386
  • Solomon Islands+677
  • Somalia+252
  • South Africa+27
  • South Korea+82
  • South Sudan+211
  • Spain+34
  • Sri Lanka+94
  • St. Barthélemy+590
  • St. Helena+290
  • St. Kitts & Nevis+1
  • St. Lucia+1
  • St. Martin+590
  • St. Pierre & Miquelon+508
  • St. Vincent & Grenadines+1
  • Sudan+249
  • Suriname+597
  • Svalbard & Jan Mayen+47
  • Sweden+46
  • Switzerland+41
  • Syria+963
  • Taiwan+886
  • Tajikistan+992
  • Tanzania+255
  • Thailand+66
  • Timor-Leste+670
  • Togo+228
  • Tokelau+690
  • Tonga+676
  • Trinidad & Tobago+1
  • Tunisia+216
  • Turkey+90
  • Turkmenistan+993
  • Turks & Caicos Islands+1
  • Tuvalu+688
  • U.S. Virgin Islands+1
  • Uganda+256
  • Ukraine+380
  • United Arab Emirates+971
  • Uruguay+598
  • Uzbekistan+998
  • Vanuatu+678
  • Vatican City+39
  • Venezuela+58
  • Vietnam+84
  • Wallis & Futuna+681
  • Western Sahara+212
  • Yemen+967
  • Zambia+260
  • Zimbabwe+263
10 * 14 =
On Key

More Posts

Be assured of everything

Get WME Services

Stay ahead of the competition with our Professional IT offerings.

Please enable JavaScript in your browser to complete this form.
3 * 12 =