Entra / Microsoft 365 · Compliance & audit
Apply exclude-all holds to inactive mailboxes
Removes inactive mailboxes from compliance holds so they can be permanently deleted during cleanup.
Connect & set up
Run these once per session. All scopes are read-only unless the script makes changes.
Connect-ExchangeOnline -ShowBanner:$false
Run it
The main script. Copy it, or download the .ps1 and run it from your console.
[array]$Modules = Get-Module | Select-Object -ExpandProperty NameIf ("ExchangeOnlineManagement" -notin $Modules) {Write-Host "Connecting to Exchange Online..."Connect-ExchangeOnline -ShowBanner:$false}[array]$InactiveMailboxes = Get-Mailbox -InactiveMailboxOnly -ResultSize Unlimited | Sort-Object WhenCreated -DescendingIf ($InactiveMailboxes) {[int]$ComplianceTagged = $InactiveMailboxes | Where-Object { $_.ComplianceTagHoldApplied -ne $null } | Measure-Object | Select-Object -ExpandProperty Count[int]$InPlaceHolds = $InactiveMailboxes | Where-Object { $_.InPlaceHolds.Count -gt 0 } | Measure-Object | Select-Object -ExpandProperty Count[int]$DelayHoldApplied = $InactiveMailboxes | Where-Object { $_.$DelayHoldApplied -eq $true } | Measure-Object | Select-Object -ExpandProperty Count[int]$DelayReleaseHoldApplied = $InactiveMailboxes | Where-Object { $_.$DelayReleaseHoldApplied -eq $true } | Measure-Object | Select-Object -ExpandProperty Count} Else {Write-Host "No inactive mailboxes found"Break}Write-Host ""Write-Host ("Found {0} inactive mailboxes" -f $InactiveMailboxes.Count)Write-Host "Of these:"Write-Host (" - {0} have compliance tags applied" -f $ComplianceTagged)Write-Host (" - {0} have in-place holds noted" -f $InPlaceHolds)Write-Host (" - {0} have delay hold applied" -f $DelayHoldApplied)Write-Host (" - {0} have delay release hold applied" -f $DelayReleaseHoldApplied)Write-HostWrite-Host "Processing inactive mailboxes to exclude from all holds..."$Report = [System.Collections.Generic.List[Object]]::new()ForEach ($Mailbox in $InactiveMailboxes) {Write-Host ("Processing inactive mailbox {0} ({1}) created on {2}" -f $Mailbox.DisplayName, $Mailbox.PrimarySmtpAddress, $WhenCreated)$ReportLine = [PSCustomObject][Ordered]@{Timestamp = Get-Date -Format 'dd-MMM-yyyy HH:mm:ss'DisplayName = $Mailbox.DisplayNamePrimarySmtpAddress = $Mailbox.PrimarySmtpAddressWhenCreated = Get-Date $Mailbox.WhenCreated -Format 'dd-MMM-yyyy HH:mm'WhenSoftDeleted = If ($Mailbox.WhenSoftDeleted) { Get-Date $Mailbox.WhenSoftDeleted -Format 'dd-MMM-yyyy HH:mm' } Else { 'N/A' }ComplianceTagHoldApplied = $Mailbox.ComplianceTagHoldAppliedInPlaceHoldsCount = $Mailbox.InPlaceHolds.CountDelayHoldApplied = $Mailbox.DelayHoldAppliedDelayReleaseHoldApplied = $Mailbox.DelayReleaseHoldAppliedIsInactiveMailbox = $Mailbox.IsInactiveMailboxIsSoftDeletedByRemoveMailbox = $Mailbox.IsSoftDeletedByRemove}Try {Set-Mailbox -Identity $Mailbox.DistinguishedName -ExcludeFromAllHolds -InactiveMailbox -ErrorAction Stop$ReportLine | Add-Member -NotePropertyName 'ExcludedFromAllHolds' -NotePropertyValue 'Succeeded'} Catch {Write-Host ("Failed to exclude mailbox {0} from all holds: {1}" -f $Mailbox.DisplayName, $_.Exception.Message) -ForegroundColor Red$ReportLine | Add-Member -NotePropertyName 'ExcludedFromAllHolds' -NotePropertyValue 'Failed'}$Report.Add($ReportLine)}$Report | Out-GridView# Export the report as an Excel worksheet or CSV fileIf (Get-Module ImportExcel -ListAvailable) {$ExcelGenerated = $trueImport-Module ImportExcel -ErrorAction SilentlyContinue$ExcelOutputFile = ((New-Object -ComObject Shell.Application).Namespace('shell:Downloads').Self.Path) + "\ExcludeAllHolds.xlsx"If (Test-Path $ExcelOutputFile) {Remove-Item $ExcelOutputFile -ErrorAction SilentlyContinue}$Report | Export-Excel -Path $ExcelOutputFile -WorksheetName "Exclude All Holds" -Title ("Exclude All Holds Report {0}" -f (Get-Date -format 'dd-MMM-yyyy')) -TitleBold -TableName "ExcludeAllHolds"} Else {$CSVOutputFile = ((New-Object -ComObject Shell.Application).Namespace('shell:Downloads').Self.Path) + "\ExcludeAllHolds.CSV"$Report | Export-Csv -Path $CSVOutputFile -NoTypeInformation -Encoding Utf8}If ($ExcelGenerated) {Write-Output ("Excel worksheet output written to {0}" -f $ExcelOutputFile)} Else {Write-Output ("CSV output file written to {0}" -f $CSVOutputFile)}Write-Output "All done - enjoy the information about inactive mailboxes that have been excluded from all holds!"
Attribution
Author
Office365itpros