Entra / Microsoft 365 · Exchange Online
Search and remove mailbox calendar items
Uses Search-Mailbox to find and remove calendar items from user mailboxes within a defined date range.
Connect & set up
Run these once per session. All scopes are read-only unless the script makes changes.
Connect-ExchangeOnline
Run it
The main script. Copy it, or download the .ps1 and run it from your console.
param([string] $StartDate = "1-Jan-2019",[string] $EndDate = "1-Dec-2019")Clear-Host$ModulesLoaded = Get-Module | Select-Object NameIf (!($ModulesLoaded -match "ExchangeOnlineManagement")) {Write-Host "Please connect to the Exchange Online Management module and then restart the script" ; break}# Set up the search query - change these parameters to whatever you want to use to search for items to be removed$Query = "Received:$($StartDate)..$($EndDate) kind:meetings" + ' AND (-subject:"Thread Id")'# Find the mailboxes to process - this example uses a check against the custom attribute 12. You could also read in user details from a CSV file# or a different filter to find users. The point is that you end up with an array of mailboxes for Search-Mailbox to process[array]$Users = Get-ExoMailbox -Filter {CustomAttribute12 -eq "Search"} -Properties CustomAttribute12 -RecipientTypeDetails UserMailbox -ResultSize UnlimitedIf (!$Users) {Write-Host "No matching users found - exiting" ; break}$UserReport = [System.Collections.Generic.List[Object]]::new() # Create output fileForEach ($User in $Users) {$Status = (Search-Mailbox -Identity $User.UserPrincipalName-SearchQuery $Query -EstimateResultOnly -DoNotIncludeArchive -SearchDumpster:$False)If ($Status) {$ReportLine = [PSCustomObject] @{UserPrincipalName = $User.UserPrincipalNameDisplayName = $User.DisplayNameItemsFound = $Status.ResultItemsCountItemsSize = $Status.ResultItemsSizeSearchType = "Estimate"SearchTime = Get-Date }$UserReport.Add($ReportLine) } #End if} # End For# Filter the users where we have found some items$ProcessUsers = $UserReport | Where-Object {$_.ItemsFound -ne "0"}Clear-Host$ProcessUsers | Format-Table DisplayName, UserPrincipalName, ItemsFound, ItemsSize -AutoSize$PromptTitle = 'Remove items from mailboxes'$PromptMessage = 'Please confirm whether to proceed to remove found items from mailboxes'$yes = New-Object System.Management.Automation.Host.ChoiceDescription "&yes", 'yes?'$no = New-Object System.Management.Automation.Host.ChoiceDescription "&no", 'no?'$cancel = New-Object System.Management.Automation.Host.ChoiceDescription "&cancel", 'Exit'$PromptOptions = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no, $cancel)$PromptDecision = $host.ui.PromptForChoice($PromptTitle, $PromptMessage, $PromptOptions, 0)$i = 0Switch ($PromptDecision) {"0" {ForEach ($User in $ProcessUsers) {Write-Host "Removing items from the mailbox of" $User.DisplayName$Status = (Search-Mailbox -Identity $User.UserPrincipalName -SearchQuery $Query -DeleteContent -DoNotIncludeArchive -SearchDumpster:$False -Confirm:$False -Force)If ($Status) { # Add record to capture what we didWrite-Host "Mailbox for" $User.DisplayName "processed to remove" $Status.ResultItemsCount "items"$ReportLine = [PSCustomObject] @{UserPrincipalName = $User.UserPrincipalNameDisplayName = $User.DisplayNameItemsFound = $Status.ResultItemsCountItemsSize = $Status.ResultItemsSizeSearchType = "Removal"SearchTime = Get-Date }$ProcessUsers.Add($ReportLine)$i++}} #End ForEachWrite-Host "All done." $i "mailboxes processed and cleaned up. Details stored in c:\temp\SearchMailboxRemovals.csv"$ProcessUsers | Export-CSV -NoTypeInformation c:\temp\SearchMailboxRemovals.csv}"1" {Write-Host "OK. Maybe later? Messages not removed from mailboxes"}"2" {Write-Host "Cancelled. Messages not removed from mailboxes"}} #End Switch
Parameters
ParameterDefaultNotes
-StartDate1-Jan-2019Start of the reporting window.-EndDate1-Dec-2019End of the reporting window.Attribution
Author
Office365itpros