Entra / Microsoft 365 · Compliance & audit
Switch litigation holds to eDiscovery
Moves mailboxes on litigation hold into an eDiscovery case hold, then removes the original litigation holds once the case hold is active.
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 on hold for a single case: https://learn.microsoft.com/en-us/purview/ediscovery-create-holds?WT.mc_id=M365-MVP-9501#ediscovery-hold-limitsIf ($MailboxesToHold.Count -gt 1000) {Write-Host ("There are {0} mailboxes to place on hold. eDiscovery standard cases are limited to 1000 mailboxes. Please split the mailboxes into smaller groups and run the script again." -f $MailboxesToHold.Count) -ForegroundColor Red}# Reset tenant obfuscation settings to TrueIf ($ObfuscationChanged) {If ((Get-MgAdminReportSetting).DisplayConcealedNames -eq $False) {$Parameters = @{ displayConcealedNames = $True }Update-MgAdminReportSetting -BodyParameter $Parameters}}[string[]]$OneDriveToHold = $MbxReport.OneDriveUrl | Sort-Object -UniqueWrite-Host "Creating standard eDiscovery case to replace litigation holds..." -ForegroundColor Yellow$Case = New-ComplianceCase -Description "eDiscovery Case for Mailbox Litigation Holds" -Name "eDiscovery Case to Replace Mailbox Litigation Holds"If ($Case) {Write-Host ("eDiscovery case created {0} - now applying holds to {1} mailboxes and {2} OneDrive accounts" -f $Case.Name, $MailboxesToHold.Count, $OneDriveToHold.Count) -ForegroundColor Green$HoldPolicy = New-CaseHoldPolicy -Name "Hold Policy for Mailboxes on Litigation Hold" -Case $Case.Name -ExchangeLocation $MailboxesToHold `-SharePointLocation $OneDriveToHold -Comment "Hold policy for mailboxes and OneDrive accounts to replace litigation holds"$HoldRule = New-CaseHoldRule -Name "Hold Policy Litigation Rule 1" -Policy $HoldPolicy.Name -ContentMatchQuery ""# Set-CaseHoldPolicy -Identity "eDiscovery Replace Litigtion Hold Policy" -AddSharePointLocation $OneDriveToHold} Else {Write-Host "An error occurred creating the eDiscovery case" -ForegroundColor RedBreak}If ($HoldRule) {Write-Host ("Hold policy {0} created with rule {1}" -f $HoldPolicy.Name, $HoldRule.Name) -ForegroundColor GreenWrite-Host "The litigation hold replacement eDiscovery case is now active. After 3 hours it should be safe to remove the litigation holds from the mailboxes." -ForegroundColor Green} Else {Write-Host "An error occurred creating the eDiscovery hold policy and rule" -ForegroundColor Red}
Attribution
Author
Office365itpros