Entra / Microsoft 365 · Compliance & audit
Switch litigation holds to retention
Moves mailboxes on litigation hold onto a Microsoft 365 retention policy and clears the litigation holds afterward.
Connect & set up
Run these once per session. All scopes are read-only unless the script makes changes.
Connect-MgGraph -NoWelcome -Scopes Sites.Read.All, User.ReadBasic.All, Reports.Read.All, ReportSettings.ReadWrite.AllConnect-ExchangeOnline -ShowBanner:$false
Run it
The main script. Copy it, or download the .ps1 and run it from your console.
[string[]]$RequiredScopes = @("Sites.Read.All","User.ReadBasic.All", "Reports.Read.All", "ReportSettings.ReadWrite.All")Connect-MgGraph -NoWelcome -Scopes $RequiredScopes[string[]]$CurrentScopes = (Get-MgContext).Scopes$CheckScopes =[object[]][Linq.Enumerable]::Intersect($RequiredScopes,$CurrentScopes)If ($CheckScopes.Count -ne 4) { # Must have all 4 required scopesWrite-Host ("To run this script, you need to connect to Microsoft Graph with the following scopes: {0}" -f ($RequiredScopes -join ", ")) -ForegroundColor RedDisconnect-GraphBreak}[array]$Modules = Get-Module | Select-Object -ExpandProperty NameIf ("ExchangeOnlineManagement" -Notin $Modules) {Write-Host "Connecting to Exchange Online..." -ForegroundColor YellowConnect-ExchangeOnline -showBanner:$false -UserPrincipalName (Get-MgContext).Account}Connect-IPPSSession -ShowBanner:$false -UserPrincipalName (Get-MgContext).Account# Find mailboxes with litigation hold enabled[array]$Mbx = Get-ExoMailbox -RecipientTypeDetails UserMailbox -Properties LitigationHoldEnabled, LitigationHoldDuration `-Filter {LitigationHoldEnabled -eq $True} -ResultSize UnlimitedIf ($Mbx) {# Only take mailboxes with unlimited hold duration$Mbx = $Mbx | Where-Object { $_.LitigationHoldDuration -eq "Unlimited" }Write-Host ("Litigation hold is enabled for {0} mailboxes" -f $Mbx.Count) -ForegroundColor Green} Else {Write-Host "No mailboxes with litigation hold enabled" -ForegroundColor GreenBreak}# Handle data obfuscation setting for the tenant because we need real rather than obfuscated names for the OneDrive accounts$ObfuscationChanged = $falseIf ((Get-MgAdminReportSetting).DisplayConcealedNames -eq $True) {$Parameters = @{ displayConcealedNames = $False }Update-MgAdminReportSetting -BodyParameter $Parameters$ObfuscationChanged = $true}Write-Host "Finding OneDrive usage information..." -ForegroundColor Yellow$Uri = "https://graph.microsoft.com/v1.0/reports/getOneDriveUsageAccountDetail(period='D90')"Invoke-MgGraphRequest -uri $Uri -method Get -OutputFilePath data.csv[array]$OneDriveData = Import-CSV data.csv | Select-Object 'Site Id', 'Owner Principal Name'$OneDriveHash = @{}ForEach ($OneDrive in $OneDriveData) {$OneDriveHash.Add($OneDrive.'Owner Principal Name'.toLower(), [string]$OneDrive.'Site Id')}# Create file containing mailbox and OneDrive data for the holds$MbxReport = [System.Collections.Generic.List[Object]]::new()ForEach ($M in $Mbx) {$OneDriveURL = $null# Get OneDrive URL for the mailbox$SiteId = $OneDriveHash[$M.UserPrincipalName.ToLower()]If ($SiteId) {$OneDrive = Get-MgSite -SiteId $SiteId -ErrorAction SilentlyContinueIf ($OneDrive) {$OneDriveURL = $OneDrive.WebUrl + "/"}} Else {$OneDriveURL = "No OneDrive URL found"}$ReportLine = [PSCustomObject][Ordered]@{UserPrincipalName = $M.UserPrincipalNameDisplayName = $M.DisplayNameLitigationHoldEnabled = $M.LitigationHoldEnabledOneDriveUrl = $OneDriveURL}$MbxReport.Add($ReportLine)}# Create arrays of the mailbioxes and OneDrive accounts to place on hold[string[]]$MailboxesToHold = $MbxReport.UserPrincipalName# Can't have more than 1,000 mailboxes as locations for a retention policy: https://learn.microsoft.com/en-us/microsoft-365/compliance/retention-limits?view=o365-worldwide#locations-for-retention-policiesIf ($MailboxesToHold.Count -gt 1000) {Write-Host ("There are {0} shared mailboxes to place on hold. Retention policy locations are limited to 1000 mailboxes. Please split the mailboxes into smaller groups and run the script again." -f $MailboxesToHold.Count) -ForegroundColor RedBreak}[string[]]$OneDriveToHold = $MbxReport.OneDriveUrl | Sort-Object -Unique# Reset tenant obfuscation settings to TrueIf ($ObfuscationChanged) {If ((Get-MgAdminReportSetting).DisplayConcealedNames -eq $False) {$Parameters = @{ displayConcealedNames = $True }Update-MgAdminReportSetting -BodyParameter $Parameters}}Write-Host "Creating Microsoft 365 retention policy to replace litigation holds..." -ForegroundColor Yellow$NewPolicy = New-RetentionCompliancePolicy -Name "Litigation Hold Retention Policy" -ExchangeLocation $MailboxesToHold -OneDriveLocation $OneDriveToHold `-Comment ("Retention policy to replace litigation holds created by Switch-LitigationHoldsforRetentionPolicies.PS1 script on {0}" -f (Get-Date).ToString("dd-MMM-yyyy"))If ($NewPolicy) {Write-Host ("Retention policy {0} created" -f $NewPolicy.Name) -ForegroundColor Green$NewPolicyRule = New-RetentionComplianceRule -Name LitigationHoldRule -Policy "Litigation Hold Retention Policy" -RetentionDuration unlimited `-Comment "Created by Switch-LitigationHoldsforRetentionPolicies.PS1 script"If ($NewPolicyRule) {Write-Host ("Retention rule {0} created" -f $NewPolicyRule.Name) -ForegroundColor Green} Else {Write-Host "Failed to create retention rule" -ForegroundColor RedBreak}} Else {Write-Host "Failed to create retention policy" -ForegroundColor RedBreak}
Attribution
Author
Office365itpros