We did migrate from ADFS to Password Hash Synchronization (PHS). The password sync time interval…
Delete folder in Exchange Online from all mailboxes
Do you want to delete a folder from all mailboxes in Exchange Online with PowerShell? To make it more interesting, what if you want to delete specific folders and target specific mailboxes. Impressive on how to achieve that, right? This article will teach you how to delete folders in Exchange Online from all mailboxes.
Table of contents
- Before you start to delete folders in Exchange Online
- Add impersonation rights in Exchange Online
- Microsoft Exchange Web Services Managed API 2.2
- Create text files for the script
- Register application in Azure AD
- Prepare the Delete Folders Exchange Online PowerShell script
- Edit the Delete Folders Exchange Online PowerShell script
- Install MSAL.PS PowerShell module
- Run the Delete Folders Exchange Online PowerShell script
- Conclusion
Before you start to delete folders in Exchange Online
Follow the steps carefully, as shown in the article to:
- Delete specific folder/folders from specific mailboxes in Exchange Online
- Delete specific folder/folders from all mailboxes in Exchange Online
Add impersonation rights in Exchange Online
Use impersonation when you have a service application that needs to access multiple mailboxes and “act as” the mailbox owner. Read more about impersonation and EWS in Exchange.
Create and add impersonation rights to the account that will run the script. It can be a global admin account or a service account. In our example, the global admin account is added.
Sign in to Exchange Admin Center (Exchange Online). Click on Roles > Admin roles. Click on Add role group.
Give the new role group a name — for example, Application-Impersonation.
Assign the role ApplicationImpersonation.
Add yourself, the global admin, or a service account that you created as a member.
Review the role group and click on Add role group.
The role group Application-Impersonation is created successfully.
Note: It can take up to an hour before the changes are applied.
The next step is to install Microsoft Exchange Web Services Managed API 2.2.
Microsoft Exchange Web Services Managed API 2.2
Download Microsoft Exchange Web Services Managed API 2.2. Save the file to the system.
Run the setup as administrator and install Microsoft Exchange Web Services Managed API 2.2.
After installing, verify in the installation path that you can see the files.
The next step is to create the text files.
Create text files for the script
Create three text files in the C:\Temp folder.
- Folders.txt
- Log.txt
- Users.txt
Open Folders.txt and add FolderName at the top. Add the folder names on each line. In our example, we like to delete four folders in the mailboxes.
The script will generate logs and place them in the Log.txt file. Keep it empty.
Open Users.txt and add EmailAddress at the top. Add the email addresses on each line. The script will delete the folders from these mailboxes.
Read more: Export a list of mailboxes to CSV file »
The next step is to register an application in Azure AD.
Register application in Azure AD
To register an application in Azure AD, follow the below steps:
1. Sign in to the Microsoft Azure portal.
2. Navigate to Azure Active Directory > App registrations.
3. Click on New registration.
4. Fill in the name DeleteFolders.
5. Select Accounts in this organizational directory only.
6. Choose Public client/native (mobile & desktop) and fill in the URL:
https://login.microsoftonline.com/common/oauth2/nativeclient
7. Click on Register.
8. Copy the Application (client) ID and Directory (tenant) ID and paste it into Notepad (you will need it later).
The next step is to download the PowerShell script.
Prepare the Delete Folders Exchange Online PowerShell script
Download the Delete-Folders-EXO.ps1 PowerShell script and save it to the C:\Scripts folder.
<#
.SYNOPSIS
Delete-Folders-EXO.ps1
.DESCRIPTION
Delete specific folder/folders from specific mailboxes in Exchange Online.
.LINK
www.alitajran.com/delete-folder-in-exchange-online-from-all-mailboxes
.NOTES
Written by: Catalin Streang
Edited by: ALI TAJRAN
Website: www.alitajran.com
LinkedIn: linkedin.com/in/alitajran
.LICENSE
The MIT License (MIT)
Copyright (c) 2020 ALI TAJRAN
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
.CHANGELOG
V1.00, 10/09/2020 - Initial version
V2.00, 01/31/2023 - Support Modern Authentication
.REQUIRED
The script requires EWS Managed API 2.2.
Make sure the Import-Module command matches the Microsoft.Exchange.WebServices.dll location of EWS Managed API, chosen during the installation.
#>
# Provide Directory (tenant) ID or Tenant domain name
$TenantId = "2d845888-c017-4121-abe5-02f619863965"
# Provide Application (client) ID
$AppClientId = "fccc7ed0-6218-41f9-a89b-d43b29bf7681"
$MsalParams = @{
ClientId = $AppClientId
TenantId = $TenantId
Scopes = "https://outlook.office.com/EWS.AccessAsUser.All"
}
$MsalResponse = Get-MsalToken @MsalParams
$EWSAccessToken = $MsalResponse.AccessToken
# Variables
[string]$info = "White" # Color for informational messages
[string]$warning = "Yellow" # Color for warning messages
[string]$error = "Red" # Color for error messages
[string]$success = "Green" # Color for success messages
[string]$LogFile = "C:\Temp\Log.txt" # Path of the Log File
[string]$FoldersCSV = "C:\Temp\Folders.txt" # Path of the Folders File
[string]$UsersCSV = "C:\Temp\Users.txt" # Path of the Users File
function DeleteFolder($MailboxName) {
Write-Host "Searching for folder in Mailbox Name:" $MailboxName -ForegroundColor $info
Add-Content $LogFile ("Searching for folder in Mailbox Name:" + $MailboxName)
# Change the user to impersonate
$service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $MailboxName)
do {
$oFolderView = New-Object Microsoft.Exchange.WebServices.Data.FolderView(1)
$oFolderView.Traversal = [Microsoft.Exchange.Webservices.Data.FolderTraversal]::Deep
$oSearchFilter = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName, $FolderName)
$oFindFolderResults = $service.FindFolders([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot, $oSearchFilter, $oFolderView)
if ($oFindFolderResults.TotalCount -eq 0) {
Write-Host "Folder $FolderName does not exist in Mailbox:" $MailboxName -ForegroundColor $warning
Add-Content $LogFile ("Folder does not exist in Mailbox:" + $MailboxName)
}
else {
Write-Host "Folder $FolderName EXISTS in Mailbox:" $MailboxName -ForegroundColor $success
Add-Content $LogFile ("Folder EXISTS in Mailbox:" + $MailboxName)
$oFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service, $oFindFolderResults.Folders[0].Id)
Write-Host "Deleting Folder:" $FolderName -ForegroundColor $success
Add-Content $LogFile ("Deleting Folder:" + $FolderName)
# You can choose from a few delete types, just choose one:
$oFolder.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
#$oFolder.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::SoftDelete)
}
} while ($oFindFolderResults.TotalCount -ne 0)
$service.ImpersonatedUserId = $null
}
Import-Module -Name "C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll"
$service = [Microsoft.Exchange.WebServices.Data.ExchangeService]::new()
# Connect with Modern Authentication
$service.Credentials = [Microsoft.Exchange.WebServices.Data.OAuthCredentials]$EWSAccessToken
# Exchange Online URL
$service.Url = New-Object Uri("https://outlook.office365.com/EWS/Exchange.asmx")
# Read the data
Import-Csv $FoldersCSV -Encoding UTF8 | Foreach-Object {
$FolderName = $_.FolderName.ToString()
Import-Csv $UsersCSV -Encoding UTF8 | Foreach-Object {
$EmailAddress = $_.EmailAddress.ToString()
# Catch the errors
trap [System.Exception] {
Write-Host ("Error: " + $_.Exception.Message) -ForegroundColor $error
Add-Content $LogFile ("Error: " + $_.Exception.Message)
continue
}
DeleteFolder($EmailAddress)
}
}
The next step is to edit the script.
Edit the Delete Folders Exchange Online PowerShell script
Change the TenantId (line 46) and AppClientId (line 49) with the values you copied from the registered application in Azure AD.
The script will delete the folders and the messages in the folders completely, and you can’t recover them from the Recoverable items folder.
Do you want to delete the folders and move the messages to the mailbox Recoverable Items folder? Change it to SoftDelete.
Check lines 100 and 101 for the available options.
$oFolder.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
#$oFolder.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::SoftDelete)
The next step is to install the MSAL.PS PowerShell module.
Install MSAL.PS PowerShell module
We will use the MSAL.PS PowerShell module to get the tokens from Microsoft.
Start Windows PowerShell or Windows PowerShell ISE as administrator. Install the MSAL.PS PowerShell module.
Install-Module -Name MSAL.PS
The next and last step is to run the script.
Run the Delete Folders Exchange Online PowerShell script
In our example, we know that user James got all the folders in his mailbox.
Before running the script
- Subfolder Folder Audio
- Subfolder Folder Pictures
- Folder Folder Music
- Folder Folder Videos
Change the directory to the scripts folder and run the script.
PS C:\> cd C:\scripts
PS C:\scripts> .\Delete-Folders-EXO.ps1
A login window will show up. Sign in with the account that you added as a member to the impersonation role, and check the checkbox Consent on behalf of your organization. Next, click Accept.
It starts searching for the folders in the mailboxes. The output will write to the Log.txt file.
Searching for folder in Mailbox Name: James.Paterson@exoip.com
Folder EXISTS in Mailbox: James.Paterson@exoip.com
Deleting Folder: Folder Audio
Folder does not exist in Mailbox: James.Paterson@exoip.com
Searching for folder in Mailbox Name: Dylan.Piper@exoip.com
Folder does not exist in Mailbox: Dylan.Piper@exoip.com
Searching for folder in Mailbox Name: James.Paterson@exoip.com
Folder EXISTS in Mailbox: James.Paterson@exoip.com
Deleting Folder: Folder Pictures
Folder does not exist in Mailbox: James.Paterson@exoip.com
Searching for folder in Mailbox Name: Dylan.Piper@exoip.com
Folder does not exist in Mailbox: Dylan.Piper@exoip.com
Searching for folder in Mailbox Name: James.Paterson@exoip.com
Folder EXISTS in Mailbox: James.Paterson@exoip.com
Deleting Folder: Folder Music
Folder does not exist in Mailbox: James.Paterson@exoip.com
Searching for folder in Mailbox Name: Dylan.Piper@exoip.com
Folder does not exist in Mailbox: Dylan.Piper@exoip.com
Searching for folder in Mailbox Name: James.Paterson@exoip.com
Folder EXISTS in Mailbox: James.Paterson@exoip.com
Deleting Folder: Folder Videos
Folder does not exist in Mailbox: James.Paterson@exoip.com
Searching for folder in Mailbox Name: Dylan.Piper@exoip.com
Folder does not exist in Mailbox: Dylan.Piper@exoip.com
Rerun the script. It will show that there is nothing to delete.
PS C:\scripts> .\Delete-Folders-EXO.ps1
Searching for folder in Mailbox Name: James.Paterson@exoip.com
Folder does not exist in Mailbox: James.Paterson@exoip.com
Searching for folder in Mailbox Name: Dylan.Piper@exoip.com
Folder does not exist in Mailbox: Dylan.Piper@exoip.com
Searching for folder in Mailbox Name: James.Paterson@exoip.com
Folder does not exist in Mailbox: James.Paterson@exoip.com
Searching for folder in Mailbox Name: Dylan.Piper@exoip.com
Folder does not exist in Mailbox: Dylan.Piper@exoip.com
Searching for folder in Mailbox Name: James.Paterson@exoip.com
Folder does not exist in Mailbox: James.Paterson@exoip.com
Searching for folder in Mailbox Name: Dylan.Piper@exoip.com
Folder does not exist in Mailbox: Dylan.Piper@exoip.com
Searching for folder in Mailbox Name: James.Paterson@exoip.com
Folder does not exist in Mailbox: James.Paterson@exoip.com
Searching for folder in Mailbox Name: Dylan.Piper@exoip.com
Folder does not exist in Mailbox: Dylan.Piper@exoip.com
After running the script
The folders are deleted from the Office 365 mailbox.
Check the Log.txt file if you want to know which folders are deleted from which mailboxes.
Did this article help you to delete a folder in Exchange Online with PowerShell?
Keep reading: Move mailbox to Exchange Online with PowerShell »
Conclusion
You learned how to delete a folder from all mailboxes in Exchange Online. Not only one folder that you can delete but specific folders that you can give up in a text file. Follow the steps shown in the article before you immediately run the script. The Delete-Folders-EXO.ps1 PowerShell script is excellent for achieving the results.
Did you enjoy this article? You may also like How to get mailbox size greater than in Microsoft 365. Don’t forget to follow us and share this article.
Hey there,
it is a very nice script. Thanks for that!
I have a question. Is there a simple way to extend the script so that it also searches for folders in the in-place archive?
Best regards!
I receive following error for some users but for rest, function works as charm!.
Exchange Web Services are not currently available for this request because none of the Client Access Servers in the destination site could process the request.
Any advise on this?
Hello Dear Ali and All readers.
I have continue searching for the issue I faced and mentioned above. I found some advices and added 2 new line to ps1 script.
In order to sort out the error “Exchange Web Services are not currently available for this request because none of the Client Access Servers in the destination site could process the request.” which given for some specific users in our organization, I added “$service.HttpHeaders.add(“X-AnchorMailbox”, $MailboxName);” in Line 73 top of ” # Change the user to impersonate” sentence. Adding this line only and run the script, helps to clear folder for only 1 user of 170 and I needed to run script by giving only 1 user address in Users.txt in order to get script remove folder. However adding extra line to clear “$service.HttpHeaders” after delection fuction, also helped to work more then 1 users in users.txt
The second script line “$service.HttpHeaders.clear()” wa sadded to line 114 after ” $service.ImpersonatedUserId = $null” line.
Reason: Some users in organization wasn’t found with only “::SmtpAddress, $MailboxName” selection in below line
$service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $MailboxName)
Hi!
Thank you for the description and for keeping it up to dated. It is very clear, and still working. I did read your about page. So nice to have this kind of knowledge and enthusiastic.
If I would like to write a same sript like this, from zero, what kind of knowledge should I have?
I do work with Exchange online and M365 technologies for years, and have some scripting experience. I could write some powershell script on my own, but this is next-next level what you are doing here. Can you recommend some reading/courses/skills?
Thanks again,
Have a nice day
Huge save!!! Migration went south. Users mailboxes got all dumped into eachother… Yes, literally each mailbox has hundreds of folders in the name of their email…
Anyways, looks like this is working out. You just saved me from having to piss off a lot of users.
script finish with this error after few minutes.
Error: The request failed. The operation has timed out.
Secondly, we can only use folder name instead of the folder path, so if there will be two Inbox folders in the mailbox both will be removed. How can we use folder path in the script?
Any command for delete all items specific folder, single user mailbox through exchange Powrshell.
Exchange server 2019
Example:- delete all e-mail in delete folder.
Thanks a lot for this script.
Can you add an option to delete the content of the folder without deleting the folder?
Hi Ali,
Thanks for that great post!
Unfortunately, it is not working anymore because Microsoft blocked basic authentication few weeks ago. Could you update your script for using OAuth authentication?
I updated the script to support Modern Authentication.
This article just saved me days of manual work with an Office 365 migration that had default folders altered due to a language mismatch with the tenant. I can now automate what would have been a painstakingly manual fix. Thank you, you legend!
Quick question.. Does anyone know if there is something along these lines available for Exchange On-Premise? Thank you in advance.
Thanks for the clarification it is truly an informative clarification, thanks for sending it.
Great script.
Thanks!
Hi Ali,
thanks for this nice script, works very well with the regular outlook folders, however I cannot delete a contacts folder, I get an Error: Object cannot be deleted.
I have an old contact list which is shared with almost 1200 users and I want to have this removed by your script, do you have a suggestion or solution?
Thanks alot
Arash Pourwafa
I created a folder in “Contact items”, and it successfully deletes it.
Great post. Really helped me out.
Can this be modified to also target subfolders as well? In our environment, users may have subfolders named the same for multiple folders. E.g. Inbox/Job1/Phase1 and Inbox/Job2/Phase1. If I wanted to remove Phase1 from ONLY the Job1 folder, could this be done using this script?
Yes, it will search for the folder name in the subfolders too.
I guess what he meant is: can you define a specific path to search in instead of searching in through whole mailbox? Eg. only search in Inbox\Job1\*