Last version: 2.00, February 27th, 2021
Recently, I was asked if it is possible to remove stub items. The reason was they were going to transition to a newer version of Exchange and they wouldn’t be using the archiving solution in the new environment. When required, vendor tooling would be used to search through the existing archives.
In such cases it makes sense to remove the stubs from the mailbox, which are shortcut messages that points to a copy of the original message in the archive solution. The new environment won’t contain the required Outlook plugins or extensions to retrieve the original message from the archive using the stub, making the stub lead to a partial or empty message.
To identify stubs, one can filter on an attribute of each item, MessageClass. This attribute defines which kind of item it is (in fact, determines what form Outlook should use in order to present or process the information). Examples of MessageClass definitions are IPM.Note (regular e-mail messages), IPM.Note.EnterpriseVault.Shortcut (message archived by Enterprise Vault) or IPM.ixos-archive (message archived by Opentext/IXOS LiveLink E-Mail Archive).
To identify stubs from Outlook, add the Message Class field to your Outlook view, e.g.:
When you want to remove the stubs using Outlook, you can utilize the Advanced Find function of Outlook, but that is a very labor intensive, tedious and non-centralized per-mailbox procedure:
Requirements
Using the script requires Exchange Web Services (EWS) Managed API and for OAuth authentication the Microsoft Authentication Library (MSAL) libraries. You can install these packages from NuGet, or place their DLL’s in the same folder as the script. For an example of how to install EWS.Managed.Api from NuGet, see this article; for MSAL follow the same process but with the package titled ‘Microsoft.Identity.Client’.
Also take notice that since you’ll be processing user mailboxes, you’ll need to have full mailbox access or impersonation permissions when using Basic Authentication; the latter is preferred. For details on how to configure impersonation for Exchange On-Premises or Office 365, see this blog post. Using a registered app with OAuth is always through Impersonation.
Usage
The script Remove-MessagesClassItems.ps1 uses the following syntax:
Remove-MessageClassItems.ps1 [-Identity] [-MessageClass] [-Type] [-Server ] [-Impersonation] [-DeleteMode ] [-Type] [-Before ] [-MailboxOnly] [-ArchiveOnly] [-IncludeFolders] -ExcludeFolders [-NoProgressBar] [-Force] [-WhatIf] [-Confirm] [-Secret] [-CertificateThumbprint] [-CertificateFile] [-CertificatePassword] [-TenantId] [-ClientId] [-TrustAll]
A quick walk-through on the parameters and switches:
- Identity is the name or e-mail address of the mailbox.
- MessageClass specifies the Message Class to remove, for example IPM.Note.EnterpriseVault.Shortcut (EnterpriseVault). You can use wildcards around or at the end to include folders containing or starting with this string, e.g. ‘IPM.ixos*’ or ‘*EnterpriseVault*’. Matching is always case-insensitive.
- Server is the name of the Client Access Server to access for Exchange Web Services. When omitted, the script will attempt to use Autodiscover.
- Type determines what folder class to process. Options are Mail, Calendar, Contacts, Tasks, Notes or All (Default).
- Switch Impersonation specifies if impersonation will be used for mailbox access, otherwise the current user context will be used.
- DeleteMode specifies how to remove messages. Possible values are HardDelete (permanently deleted), SoftDelete (use dumpster, default) or MoveToDeletedItems (move to Deleted Items folder). Note that the Deleted Items folder will be processed, unless MoveToDeletedItems is used.
- Before can be used to only remove items received before specified date.
- MailboxOnly specifies you only want to process the primary mailbox of specified users. You als need to use this parameter when running against mailboxes on Exchange Server 2007.
- ArchiveOnly specifies you only want to process personal archives of specified users.
- IncludeFolders specifies one or more names of folder(s) to include, e.g. ‘Projects’. You can use wildcards around or at the end to include folders containing or starting with this string, e.g. ‘Projects*’ or ‘*Project*’. To match folders and subfolders, add a trailing \*, e.g. Projects\*. This will include folders named Projects and all subfolders. To match from the top of the structure, prepend using ‘\’. Matching is case-insensitive.
- ExcludeFolders specifies one or more folder(s) to exclude. Usage of wildcards and well-known folders identical to IncludeFolders.
Note that ExcludeFolders criteria overrule IncludeFolders when matching folders. - NoProgressBar prevents displaying a progress bar as folders and items are being processed.
-
ReplaceClass specifies that instead of removing the item, its PR_MESSAGE_CLASS class property will be modified to this value. For example, can be used in conjunction with MessageClass to modify any IPM.Note items pending Evault archival back to regular items, using: -MessageClass IPM.Note.EnterpriseVault.PendingArchive -ReplaceClass IPM.Note
- Report reports individual items detected as duplicate. Can be used together with WhatIf to perform pre-analysis.
- TrustAll can be used to accept all certificates, e.g. self-signed certificates or when accessing Exchange using endpoint with a different certificate.
For authentication, the following parameters are available:
- Credentials specifies credentials to use for Basic Authentication.
- TenantId specifies the identity of the Tenant (OAuth)
- ClientId specifies the Id of the registered application (OAuth).
- CertificateThumbprint specifies the thumbprint of the certificate from personal store to use for authentication (OAuth).
- CertificateFile specifies the external certificate file (pfx) to use for authentication (OAuth). This certificate needs to contain a private key; the registered application needs to contain the certificate’s public key.
- CertificatePassword optionally specifies the password to use with the certificate file (OAuth).
- Secret specifies the secret to use with the application (OAuth).
Well-Known Folders
For IncludeFolders, ExcludeFolders, you can also use well-known folders using this format: #WellKnownFolderName#, e.g. #Inbox#. Supported are #Calendar#, #Contacts#, #Inbox#, #Notes#, #SentItems#, #Tasks#, #JunkEmail# and #DeletedItems#. The script uses the currently configured Well-Known Folder of the mailbox to be processed.
Patterns
Here are some examples of using pattern matching in IncludeFolders or ExcludeFolders, based on the following tree structure:
+ TopFolderA + FolderA + SubFolderA + SubFolderB + FolderB + TopFolderB
The following filters will match folders from the above structure:
Filter | Matches |
FolderA | \TopFolderA\FolderA, \TopFolderB\FolderA |
Folder* | \TopFolderA\FolderA, \TopFolderA\FolderB, \TopFolderA\FolderA\SubFolderA, \TopFolderA\FolderA\SubFolderB |
FolderA\*Folder* | \TopFolderA\FolderA\SubFolderA, \TopFolderA\FolderA\SubFolderB |
\*FolderA\* | \TopFolderA, \TopFolderA\FolderA, \TopFolderA\FolderB, \TopFolderA\FolderA\SubFolderA, \TopFolderA\FolderA\SubFolderB, \TopFolderB\FolderA |
\*\FolderA | \TopFolderA\FolderA, \TopFolderB\FolderA |
Example
Suppose you want to remove IPM.Note.EnterpriseVault.Shortcut items from the mailbox of user1 and personal archive when enabled, moving the items to the DeletedItems by Impersonation. In such case, you could use the following cmdlet:
Remove-MessageClassItems.ps1 -Identity user1 -MessageClass IPM.Note.EnterpriseVault.Shortcut -DeleteMode MoveToDeletedItems -Impersonation –Verbose
Note: Screenshot shows Mailbox parameter, which is per 1.52 renamed to Identity
Note: By default, Remove-MessageClassItems will only search IPF.Note class folders (i.e. containing mail items), so you’ll only see those being processed. If you want all folders scanned (also classless), use the ScanAllFolders switch.
The script also supports Office 365. For example, to remove all items with ‘Enterprise’ in their message class text, received before 1/1/2014, only from the primary mailbox, excluding the folder Personal, using Basic Authentication, you can use:
$Credentials= Get-Credential Remove-MessageClassItems.ps1 -Identity olrik@office365tenant.com -DeleteMode MoveToDeletedItems -MessageClass *EnterpriseVault* -Before 1/1/2014 -MailboxOnly -ExcludeFolder Personal -Credentials $Credentials
In case you want to process multiple mailboxes, you can use a CSV file which needs to contain the Identity field. An example of how the CSV could look:
Identity francis philip
The cmdlet could then be something like:
Import-CSV users.csv1 | Remove-MessageClassItems.ps1 -MessageClass IPM.Note.EnterpriseVault.Shortcut -DeleteMode HardDelete
Feedback
You’re feedback is welcomed through the comments; if you got scripting suggestions, please use the contact form.
Download
You can download the script from the GitHub here.
Pingback: Removing Messages by Message Class (Updated) | EighTwOne (821) | JC's Blog-O-Gibberish
Michel, I would appreciate to learn more about the migration from EV to Exchange archiving. We are planning on moving from an Exchange 2007/EV 9.0.2 implementation to Exchange 2013 and the road block is the 34TB of data in EV and how best to get it back to exchange. On the plus side, we are not stubbing our emails.
LikeLike
Transvault 🙂
Nb : when you say 34TB is y compressed and duplicated DATA (singleinstanceless) ? Or just the DATA in disk ?
Regards,
Ben
LikeLike
Depends on scenario and setup. This customer cut off their archived data (ie isolated, available when required using vendor tools) and will move not (yet) archived mailbox data to the new e-mail environment, facilitating large mailboxes. Otherwise, they’d have to inject the original mail items using the stubs from the archive, but as that data is rarely consulted but has a significant storage footprint, they chose to cut it off.
LikeLike
Fantastic script! This is extremely useful in removing third-party voice mail messages from the Exchange environment. Not being very adept at EWS scripitng(but learning); I’d like to know how would the script be modified to find messages of a specific class older than, let’s say, 45-days?
(define in base property set and then filter?)
LikeLike
The line with “[Microsoft.Exchange.WebServices.Data.ItemSchema]::ItemClass, $MessageClass)” defines the item filter. It’s a single condition; if you want to combine multiple conditions, you need to utilize a SearchFilterCollection where you add all the individual conditions. Then, pass that collection instead of the single condition to FindItems, e.g.
..
$ItemSearchFilter1= New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo( [Microsoft.Exchange.WebServices.Data.ItemSchema]::ItemClass, $MessageClass)
$ItemSearchFilter2= New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsLessThanOrEqualTo( [Microsoft.Exchange.WebServices.Data.ItemSchema]::DateTimeReceived, (Get-Date).AddDays(-45))
$SearchFilterCollection= New Microsoft.Exchange.WebServices.Data.SearchFilter+SearchFilterCollection([Microsoft.Exchange.WebServices.Data.LogicalOperator]::And);
$SearchFilterCollection.add( $ItemSearchFilter1)
$SearchFilterCollection.add( $ItemSearchFilter2)
Do {
$ItemSearchResults= $SubFolder.FindItems( $ItemSearchFilterCollection, $ItemView)
..
Let me know if there’s more animo for this; I could make item age a parameter of course 🙂
LikeLike
Thank you for the prompt reply. When I replace the code to create the SearchFilterCollection..I get an error regarding “New”…seems to run, then remove all messages, not just message class specified. (Of course, working in a test environment)
[PS] E:\hold\msgclass>.\Remove-MessageClassItems45days.ps1 -Mailbox mbxrestore -MessageClass IPM.Note.Adomo.VM -DeleteMode MoveToDeletedItems -Impersonation -Verbose
Processing mailbox mbxrestore
VERBOSE: Loading Microsoft.Exchange.WebServices.dll
VERBOSE: Set to trust all certificates
VERBOSE: Using MBX.Restore@xxxxxx.xxxfor impersonation
VERBOSE: Looking up EWS URL using Autodiscover for MBX.Restore@xxxxxx.xxx
VERBOSE: Using EWS on CAS https://owa.xxxxxx.xxx/EWS/Exchange.asmx
VERBOSE: DeleteMode is MoveToDeletedItems
VERBOSE: Removing messages of class IPM.Note.Adomo.VM
VERBOSE: Processing folder Drafts
The term ‘New’ is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spellin
g of the name, or if a path was included, verify that the path is correct and try again.
At E:\hold\msgclass\Remove-MessageClassItems45days.ps1:166 char:38
+ $SearchFilterCollection= New <<<< Microsoft.Exchange.WebServices.Data.SearchFilter+SearchFilterCollec
tion([Microsoft.Exchange.WebServices.Data.LogicalOperator]::And);
+ CategoryInfo : ObjectNotFound: (New:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
You cannot call a method on a null-valued expression.
At E:\hold\msgclass\Remove-MessageClassItems45days.ps1:167 char:35
+ $SearchFilterCollection.add <<<< ( $ItemSearchFilter1)
+ CategoryInfo : InvalidOperation: (add:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
LikeLike
New should be New-Object. Additional code was provided as guidance (so you get the idea on the approach), not as working example. I’ll have a look at it later on.
LikeLike
Ok. Sounds good.Thanks again.
LikeLike
Change:
$ItemSearchFilter= New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo( [Microsoft.Exchange.WebServices.Data.ItemSchema]::ItemClass, $MessageClass)
Do {
$ItemSearchResults= $SubFolder.FindItems( $ItemSearchFilter, $ItemView)
to:
$ItemSearchFilter1= New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo( [Microsoft.Exchange.WebServices.Data.ItemSchema]::ItemClass, $MessageClass)
$ItemSearchFilter2= New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsLessThanOrEqualTo( [Microsoft.Exchange.WebServices.Data.ItemSchema]::DateTimeReceived, (Get-Date).AddDays(-45))
$ItemSearchFilterCollection= New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+SearchFilterCollection([Microsoft.Exchange.WebServices.Data.LogicalOperator]::And);
$ItemSearchFilterCollection.add( $ItemSearchFilter1)
$ItemSearchFilterCollection.add( $ItemSearchFilter2)
Do {
$ItemSearchResults= $SubFolder.FindItems( $ItemSearchFilterCollection, $ItemView)
LikeLike
Fantastic! Works perfectly! Thanks so much for your effort. I enjoy your blog and the UC Podcasts.
Regards.
LikeLike
Pingback: The UC Architects » Episode 22: A Game of Clouds
Fantastic !! Can’t thank you enough. Is it possible to make age as one of the parameters and also parameter to include a specific folder.
Regards.
LikeLike
Thanks for your suggestions; was already working on update, which has just been published. Might consider Exclude/Include options for future releases.
LikeLike
Can you give me some pointer as how to exclude messages in “Managed Folder” and its subfolders. We use Exchange Managed Folders for classifying important emails.
Regards
LikeLike
Took a while, but 1.5 contains what you’re looking for 🙂
LikeLike
Oops!! I meant exclude a specific folder.
Thanks
LikeLike
Added as option in 1.5
LikeLike
Thanks for the script. I am going to try to use it to see if my novice PS skills can change it from deleting items with a specified message class to changing them to a similiar but different message class. If you happen to catch this and have suggestions they would be appreciated.
Thanks again for your contributions to date.
J
LikeLike
I found a similar solution using the search-mailbox command. I chose this meathod because I’m not using Exchange Web Services.
Search-Mailbox -Identity $UserName -SearchQuery “IPM.NOTE.EnterpriseVault.Shortcut” -DeleteContent
You can test with the following commands.
This produces a report with the number of hits
Search-Mailbox -Identity $UserName -SearchQuery “IPM.NOTE.EnterpriseVault.Shortcut” –EstimateResultOnly
This will search a mailbox, and all hits will be copied to another mailbox. You can look at that mailbox and see exactly what would be deleted if you used the -DeleteContent command.
Search-Mailbox -Identity $UserName -SearchQuery “IPM.NOTE.EnterpriseVault.Shortcut” -TargetMailbox “TestMB” -TargetFolder “$UserName”
LikeLike
Mike,
sorry to latch on so late, but i’ve tried doing the search way (because i thought it would be faster), but the content detected doesn’t seem to catch everything. I’d like to use search because it’s faster.
Thoughts?
LikeLike
Just tried this script today but unfortunately it’s not working for me. In verbose mode I can see it’s processing all the folders, but it didn’t find any e-mails with the class “IPM.Note.EnterpriseVault.Shortcut”.
LikeLike
So, there aren’t any of those classes or the class specified is not matching. Can you elaborate a bit more on the situation?
LikeLike
After reading the comment below, I know why it’s not working for me. The stub mail items are all in the archive mailbox. Because the script did show all folders including the ones in the archive mailbox I thought it was also working for the archive. I will use the search-mailbox cmdlet for now. If you include the option to process the archive it will be a great script. Keep up the good work!
LikeLike
As you may have read below, I’ve put archive processing on the list 🙂
LikeLike
This is an awesome script. Thank you so much for taking the time to publish it.
What if the stub is already in the user’s Personal Archive? Can we use the script to remove stubs that have already been moved to the user’s archive?
LikeLike
Script currently only processes mailbox, but good suggestion,thank you. I’ll put it on the to do list.
LikeLike
This is gold! Thanks so much.
LikeLike
Hello Michel,
when I run the script I get the following. I’m running the script as a Exchange Administrator and I have full mailbox rights on this test account. I doesn’t remove any of the EAS messageClass items.
[PS] C:\>.\Remove-MessageClassItems.ps1 -Mailbox Training6 -DeleteMode SoftDelete -MessageClass IPM.Note.EAS -ScanAllFolders -verbose
Processing mailbox Training6
VERBOSE: Loading Microsoft.Exchange.WebServices.dll
VERBOSE: Set to trust all certificates
VERBOSE: Looking up EWS URL using Autodiscover for Training6@****.com
VERBOSE: Using EWS on CAS https://mail.****.com/EWS/Exchange.asmx
VERBOSE: DeleteMode is SoftDelete
VERBOSE: Removing messages of class IPM.Note.EAS
VERBOSE: Scanning all folders
VERBOSE: Processing folder Calendar
VERBOSE: Processing folder Contacts
VERBOSE: Processing folder Conversation Action Settings
VERBOSE: Processing folder Drafts
VERBOSE: Processing folder Inbox
VERBOSE: Processing folder Journal
VERBOSE: Processing folder Junk E-Mail
VERBOSE: Processing folder Notes
VERBOSE: Processing folder Outbox
VERBOSE: Processing folder Quick Step Settings
VERBOSE: Processing folder RSS Feeds
VERBOSE: Processing folder Sent Items
VERBOSE: Processing folder Suggested Contacts
VERBOSE: Processing folder Sync Issues
VERBOSE: Processing folder Conflicts
VERBOSE: Processing folder Local Failures
VERBOSE: Processing folder Server Failures
VERBOSE: Processing folder Tasks
LikeLike
Please check permissions or configure impersonation (see links in article for instructions) and try again.
LikeLike
Yup the impersonation rights worked! I guess the full mailbox isn’t good enough!
Thanks a lot you have no idea how much time this will save me lol 🙂
LikeLike
Great script. Thanks for it. I have a few suggestions that you can take or leave.
Enhancement Suggestions:
– Include a parameter to specify the EWS API location of not installed to the default location
– Include a parameter to run as a desired account to impersonate.
-Include a parameter to change the default EWS Exchange2007_SP1 config to other versions of Exchange
+ I did this as part of Troubleshooting my issues and it appeared to not be the root cause of the issue. Perhaps this is not required because of it.
– Provide a parameter to output verbose output to a log file (I know we can pipe it… but it would be nice to have on screen and off screen output)
Thanks again for the hard work and responsive assistance
LikeLike
Hi,
I’ve managed to get the script to run without error now (had various syntax issues), but it doesn’t seem to be doing anything. After hitting enter, I just get a line showing ‘>>’ and no further action happens.
I am trying to permanently remove EV stubs in Exchange 2010:
.\Remove-MessageClassItems.ps1″ -Mailbox TomU -MessageClass IPM.Note.EnterpriseVault.Shortcut -DeleteMode HardDelete -Impersonation –Verbose
Any ideas please?
Thanks
LikeLike
You shouldn’t have to edit the script. If you copied/pasted the exact cmdlet, there’s a quote mismatch (the >> means its waiting for more input since you didn’t enter a closing quote). Try this:
.\Remove-MessageClassItems.ps1 -Mailbox TomU -MessageClass IPM.Note.EnterpriseVault.Shortcut -DeleteMode HardDelete -Impersonation –Verbose
LikeLike
My bad, I didn’t edit the script, just the cmdlet. Your amendment now generates an error telling me it is not digitally signed? Appreciate your help.
File C:\2010\Remove-MessageClassItems.ps1 cannot be loaded. The file C:\2010\Remove-MessageClassItems.ps1 is not digitally signed. The script will not execute on the system. Please see “get-help about_signing” for more details..
At line:1 char:31
+ .\Remove-MessageClassItems.ps1 <<<< -Mailbox TomU -MessageClass IPM.Note.EnterpriseVault.Shortcut -DeleteMode HardDe
lete -Impersonation -Verbose
+ CategoryInfo : NotSpecified: (:) [], PSSecurityException
+ FullyQualifiedErrorId : RuntimeException
LikeLike
Run the script after executing
Set-ExecutionPolicy Unrestricted
LikeLike
Thanks, getting there…. A whole host of errors now though. Appreciate your time but understand if you have better things to be doing!
Processing mailbox TomU
VERBOSE: Loading Microsoft.Exchange.WebServices.dll
Exception calling “LoadFile” with “1” argument(s): “The system cannot find the file specified. (Exception from HRESULT:
0x80070002)”
At C:\2010\Remove-MessageClassItems.ps1:253 char:46
+ [void][Reflection.Assembly]::LoadFile <<<< ( $EwsDll)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
Unable to find type [Microsoft.Exchange.WebServices.Data.ExchangeVersion]: make sure that the assembly containing this
type is loaded.
At C:\2010\Remove-MessageClassItems.ps1:257 char:80
+ $ExchangeVersion= [Microsoft.Exchange.WebServices.Data.ExchangeVersion] <<<< ::Exchange2007_SP1
+ CategoryInfo : InvalidOperation: (Microsoft.Excha…ExchangeVersion:String) [], RuntimeException
+ FullyQualifiedErrorId : TypeNotFound
New-Object : Cannot find type [Microsoft.Exchange.WebServices.Data.ExchangeService]: make sure the assembly containing
this type is loaded.
At C:\2010\Remove-MessageClassItems.ps1:258 char:32
+ $EwsService= New-Object <<<< Microsoft.Exchange.WebServices.Data.ExchangeService( $ExchangeVersion)
+ CategoryInfo : InvalidType: (:) [New-Object], PSArgumentException
+ FullyQualifiedErrorId : TypeNotFound,Microsoft.PowerShell.Commands.NewObjectCommand
Property 'UseDefaultCredentials' cannot be found on this object; make sure it exists and is settable.
At C:\2010\Remove-MessageClassItems.ps1:259 char:21
+ $EwsService. <<<< UseDefaultCredentials= $true
+ CategoryInfo : InvalidOperation: (UseDefaultCredentials:String) [], RuntimeException
+ FullyQualifiedErrorId : PropertyNotFound
VERBOSE: Set to trust all certificates
VERBOSE: Using TomU@contoso.com for impersonation
Unable to find type [Microsoft.Exchange.WebServices.Data.ConnectingIdType]: make sure that the assembly containing this
type is loaded.
At C:\2010\Remove-MessageClassItems.ps1:270 char:165
+ $EwsService.ImpersonatedUserId= New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Micros
oft.Exchange.WebServices.Data.ConnectingIdType] <<<< ::SmtpAddress, $EmailAddress)
+ CategoryInfo : InvalidOperation: (Microsoft.Excha…onnectingIdType:String) [], RuntimeException
+ FullyQualifiedErrorId : TypeNotFound
VERBOSE: Looking up EWS URL using Autodiscover for TomU@contoso.com
Write-Error : A positional parameter cannot be found that accepts argument 'You cannot call a method on a null-valued e
xpression.'.
At C:\2010\Remove-MessageClassItems.ps1:286 char:28
+ Write-Error <<<< "Autodiscover failed: " $error[0]
+ CategoryInfo : InvalidArgument: (:) [Write-Error], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.WriteErrorCommand
LikeLike
@Tom: “Using this script requires Exchange 2007 or later and Exchange Web Services Managed API 1.2 (or later) which you can download here or you can copy the Microsoft.Exchange.WebServices.DLL locally and adjust the DLL path mentioned in the script when necessary. “
LikeLike
Ah ok thanks, we are using 2010 but I will need to discuss with our main admin about the web services DLLs ec.
Appreciate your time.
LikeLike
@No need to install; you can install it elsewhere, copy the Microsoft.Exchange.WebServices.DLL in the same location as the script and change the location (in the script) accordingly. Updated version of script will have additional logic to look for that DLL by the way.
LikeLike
Great, thanks!
LikeLike
Me again…. Now I’ve got this far… “Can’t access mailbox information store” ?
Cheers
Processing mailbox TomU
VERBOSE: Loading Microsoft.Exchange.WebServices.dll
VERBOSE: Set to trust all certificates
VERBOSE: Using TomU@square-enix.com for impersonation
VERBOSE: Looking up EWS URL using Autodiscover for TomU@xxx
VERBOSE: Using EWS on CAS https://xxx/EWS/Exchange.asmx
C:\2010\Remove-MessageClassItems.ps1 : Can’t access mailbox information store
At line:1 char:31
+ .\Remove-MessageClassItems.ps1 <<<< -Mailbox TomU -MessageClass IPM.Note.EnterpriseVault.Shortcut -DeleteMode HardDe
lete -Impersonation -Verbose
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Remove-MessageClassItems.ps1
LikeLike
Permissions; see instructions on usage (for links on) how to configure.
LikeLike
Ok , I did see that just thought I’d have permissions on my own mailbox already 8)
Thanks again! By the way, is there anyway to delete (or edit) this thread? I fear leaving a full email address showing from the scripts wasn’t ideal.
LikeLike
No, but changed them for you; you now work for Contoso 🙂
LikeLike
You’re too kind 🙂
LikeLike
I have tried on a couple of users who’s mailboxes I have full access permissions on, however I am still getting an error stating it can’t access the mailbox information store.
Do I have to use impersonation in 2010 or something?
Thanks
LikeLike
That would be the most elegant way. There are some pointers on how to set this up here
https://eightwone.com/2013/01/19/fixing-well-known-folders-troubles/
LikeLike
Is it possible to target only one folder? For instance I want to delete the
IPM.Note.Microsoft.Conversation files from the ConversationHistory folder on 139 mailboxes. I have my csv file ready but I was hoping to avoid running the script against all of the folders in each mailbox.
Thanks!
LikeLike
No, not yet. I’ll put it on the request list.
LikeLike
Thanks! One more thing – how can I export the results to a file? I need to run all my mailboxes with the whatif switch and analyse the results before I allow the actual deletions. Great script by thwe way.
LikeLike
whats wrong with just using:
Search-Mailbox -Identity jobloggs -SearchQuery “IPM.NOTE.EnterpriseVault” -DeleteContent
LikeLike
Hi,
I wanted to know whether this script will work on a 2013 exchange evironment? i have followed the directions posted in reference to impersonation, but still running into errors whether i excute the script from a CAS or MBX server. I am trying to delete stubs from a legacy email archive solution.
Thanks!
LikeLike
Have you waited for permissions to propagate? It can take up to 2 hrs due to caching etc.
LikeLike
Thanks for this script.. I’m trying to purge EV Shortcuts from a broken EV environment before a mail migration to O365. Script works fine for the most part but for a few users I get the “Can’t access mailbox information store” at line 1 char:31. These are users that are on the exact same mailbox database that users that the script works fine for. Impersonation is set on the account I’m using to run the script and again seems to work for the other users. Size issue? (these are fairly large Exchange 2010 mailboxes) I went so far as to specifically add Full right and send as to these problem mailboxes with no luck
LikeLike
Quick follow up.. I notice for some of my users that the script is working for I have to run it a few times to catch all the EV stubs. Not sure if that means anything.
LikeLike
Figured it out.. I did a
get-mailbox -identity “username” | export-csv user.csv -notype
On the users that were not working and discovered that despite showing as a regular User Mailbox in Exchange 2010 Management Console these mailboxes were apparently Linked Mailboxes. I discovered this by comparing all the properties of the mailboxes that did not work vs the ones that did and discovered that the failing mailboxes had a Linked Maser Account value (I have a very old Exchange environment that originally started as Exchange 5.5 so somewhere along the way during the migrations some mailboxes came across as Linked)
So I ran
Set-User -Identity user@fabrikam.com -LinkedMasterAccount $null
against the failing mailboxes and now the script is working.
LikeLike
Will this work against office 365. I have tried several times without luck. Getting the following error.
C:\Scripts\Remove-MessageClassItems.ps1 : Can’t access mailbox information store
LikeLike
No, not yet. o365 support is on the to-do list.
LikeLike
Pingback: Script Updates | EighTwOne (821)
Hi,
I’m running the script and it seems to be working great, (both against on prem and cloud users), however on certain users it just stalls out on various folders. They don’t seem to be that large but they just can’t process past them. I’ve run it in verbose but i don’t see anything specific being reported.
LikeLike
I dont think the “before” switch is working, or I am using the wrong format. What format does the -before switch need. Does it need the date that you want all items older than that to be deleted, or is it the number of days before. If it is date, what format do you need date? I tried MM/DD/YYYY and YYYY/MM/DD and it does not work properly with any of those. Or at least it’s not parsing it correctly. See the results below. Using the -before, it is still trying to remove ALL my stubs, not just the ones before the date I have specified. I am running it against an Exchange 2007 SP3 environment in preparation for moving to Exchange 2013 SP1
[PS] C:\Download>.\Remove-MessageClassItems.ps1 -Mailbox %USERNAME% -MessageClass IPM.Note.MimosaStubmimosa1 -Server cas2.MYDOMAIN.COM -DeleteMode har
ddelete -Before 2013/06/01 -Verbose
VERBOSE: Loading C:\Program Files\Microsoft\Exchange\Web Services\2.0\\Microsoft.Exchange.WebServices.dll
Processing mailbox USERNAME (%USERNAME%@MYDOMAIN.COM)
VERBOSE: Set to trust all certificates
VERBOSE: Using Exchange Web Services URL https://cas2.MYDOMAIN.COM/EWS/Exchange.asmx
VERBOSE: DeleteMode is harddelete
VERBOSE: PartialMatching is False
VERBOSE: Removing messages of class IPM.Note.MimosaStubmimosa1
VERBOSE: Removing messages older than 06/01/2013 00:00:00
VERBOSE: Scanning all IPF.Note (E-mail) folders
VERBOSE: Processing folder Deleted Items
VERBOSE: Processing folder Drafts
VERBOSE: Processing folder Inbox
Confirm
Are you sure you want to perform this action?
Performing operation “Remove-MessageClassItems.ps1” on Target “Remove 431 items from Inbox”.
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is “Y”):
LikeLike
The format provided should be in the current locale, e.g. mm/dd/yyyy (it’s of type datetime so you could fit in a time as well). This is evaluated against the item’s Received attribute. To see the expected format, use:
(Get-Culture).dateTimeFormat | Select *Pattern
(don’t have Ex2007 at hand, should this be a PoSH 1 quirk, you can run it from system running a more recent version of PoSH – it will run against your mailbox on Ex2007SP1+).
LikeLike
I ended up finding out it was an issue with impersonation. When I use impersonation it works fine. I also ran it from a 2012 server running Powershell 3 and the Exchange 2013 tools on it. One additional thing, when it goes to delete the items, it always prompts you to confirm. This is a good thing by and large. But it seems for whatever reason when it calculates the number of items in the inbox, it is more than double what the actual stubbed email count is. Every other folder it seems to be 100% accurate. Can you think of a reason for this, or perhaps it might be a quirk?
At any rate, I have to compliment you on this and a couple other powershell scripts I have found on your site (the delete duplicate items one), they have saved me a ton of hassle. I was planning on just using managed default folder policy to just delete all emails older than a certain thresshold just to purge the stubs, but this is much more palatable to the end user…
LikeLike
Michael, I found another thing I cannot explain. When running the script, it appears to not parse certain mail folders inside certain users mailboxes at all. Nothing special about these folders. I thought it might be a permissions thing, but looking at folder permissions, it seems that there would be nothing inhibiting it. Plus I thought with Impersonation, folder permission should be irrelavent. I could look at something in MFCMapi or PFDavAdmin if you want, but I am not sure what to look for. I did verify the messageclass is identical across all instances, (IPM.Note.MimosaStubMimosa1), so it’s not like some stubs have different message class than others. Every test user I have run this against has similar results. It’s just not hitting all folders.
LikeLike
Michael, I think I may have found my problem, let me know if you think. When looking at the script run, I found this text when running in verbose mode: “VERBOSE: Scanning all IPF.Note (E-mail) folders”. This led me to go into MFCMapi and look at the folders not being parsed. It appears none of these folders have the “PR_CONTAINER_CLASS” of IPF.Note. In fact, the folders do not have even have the “PR_CONTAINER_CLASS” field at all. Not just not poplulated, they do not have that attribute at all. For your information, about 80% of my users were migrated to Exchange from Groupwise many years ago, and it’s possible that when these folders were created in Exchange at that time by the (Quest) Migration tool, it created the folders as some odd type? Just throwing this out there. You may or may not have a way to fix this… thanks again.
LikeLike
The ScanAllFolders switch should allow the script to find (and remove) items in all folders (default is IPF.Note only). I’m not sure if Exchange would return “class-less folders”.
LikeLike
Thank you very much Michel, the -scanallfolders switch did absolutely work! this is great!
LikeLike
Message Classes can be exported and deleted with a simple command of which I blogged about here:
http://mrmapi.com/2014/01/08/migrating-from-symantec-enterprise-vault-to-exchange-archive-mailbox/
Thanks,
Jason
LikeLike
All roads lead to Rome. Yet, that requires Ex2010 or up, EMS or being member of the Discovery Management role group to name a few. There are lots of pre-Ex2010 customers that want to get rid of the stubs before moving data over (On-Prem or ExO). The script is not meant to be a replacement for Search-Mailbox (as indicated in another comment).
LikeLike
The search-mailbox command does not exist in Exchange 2007. Just a heads up that there are thousands of customers out there still using Exchange older than 2010. Sometimes Microsoft forgets that. We cant all be bleeding edge.
LikeLike
For those wanting to actually bring their Enterprise Vault archived data to their new environment (Exchange 2010, Exchange 2013, Office 364 or Google Apps for Business), our Archive Accelerator Restore product can do that. (link removed)
Dave
LikeLike
I have written it to remove message by using outlook script
http://msexchange.me/2014/11/15/remove-messages-based-on-message-class-outlook-powershell/
LikeLike
Pingback: Remove EnterPriseVault Shortcut Class Message after Office 365 Migration | Microsoft Technologies Blog
Hi Michel,
Thanks for the script!
I was using search-mailboxformessageclass.ps1 first, but this one seems easier to use. (especially that you can use the partial parameter)
I do have a problem however that no emails are found.
When I run it with the other powershell, it does find results.
I’m looking in the correct mailbox (not archive)
LikeLike
“the other zPowerShell” ? Script needs to be run (read: Tested) from regular PoSH
LikeLike
Hi Michel,
I previously used the script used here :
http://blogs.msdn.com/b/emeamsgdev/archive/2013/06/25/powershell-search-mailbox-for-items-of-a-particular-message-class-itemclass.aspx
I’ve managed to get your script working after configuring impersonation.
I can’t get it running without it.
The account I’m using is in another domain than the user mailboxes, so that might be the reason?
LikeLike
I am not aware of any resource-forest limitations. What is the issue?
LikeLike
I Love the script ! Its saved no end of time and effort, its very easy to use and does exactly what it says,
What it does do though, is if a read reciept had been archived and it removed the reciept stub, Exchange sends an email to sender of message stating that the item was deleted and not read.
Is there anyway to prevent this happening ?
This will no doubt generate quite a few bits of confusion on mass mailbox enviroments.
LikeLike
Thanks for the suggestion. That has already been put on the list to be implemented in a next version.
LikeLike
We resolved this by creating a transport rule which caught read-receipts from sender (mailboxes being processed ) this caught them whilst script ran.
LikeLike
Really helpful script, I am looking for option to get only the shortcut count not to delete them.
If you help me with this I will be really great
LikeLike
You can add output showing the number of items found, without performing the actual removal. For example:
If( $ItemSearchResults.Items.Count -gt 0) {
Write-Output “Found $($ItemSearchResults.Count items in $($SubFolder.DisplayName)”
}
LikeLike
I couldn’t get this working, if possible can you add in the script and post here please.
LikeLike
Any other options for processing against multiple mailboxes?
I’ve tried the imiport-csv option but I get an error that The term ‘Remove-MessageClassItems.ps1’ is not recognized as the name of a cmdlet. I would like to be able to run this on a per database level.
get-mailboxdatabase | get-mailbox | The term ‘Remove-MessageClassItems.ps1
LikeLike
pasted bad:
get-mailboxdatabase | get-mailbox | Remove-MessageClassItems.ps1
LikeLike
Try .\Remove-MessageClassItems.ps1
LikeLike
Getting issue as below…..
C:\Remove-MessageClassItems.ps1 : Can’t access mailbox information store
At line:1 char:1
+ .\MessageClass1.ps1 -Mailbox Test1 -MessageClass IPM.Note.Aftermail …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Remove-MessageClassItems.ps1
LikeLike
Check the other comments, attention areas are permissions, firewalls etc.
LikeLike
My comment on the get-mailboxdataBase | removemessageclass was a request. It would be nice to run this on a database level.
LikeLike
Hi Michel, We have 1200 mailboxes which need the archive stub removed, and the script runs fine, but fails on 10%, for whatever reason, is there a way to ID why and which mailboxes failed.
LikeLike
I’m using exchange 2007 and moving to 2010.
LikeLike
Does the script work against Office 365 mailboxes? I have ~200 mailboxes on Office 365 and I get below error when I run the script:
C:\Scripts\Remove-MessageClassItems.ps1 : A positional parameter cannot be found that accepts argument ‘Exception
calling “AutodiscoverUrl” with “2” argument(s): “The Autodiscover service couldn’t be located.”‘.
At line:1 char:1
+ .\Remove-MessageClassItems.ps1 -Mailbox rafatsum@genedemo.onmicrosoft.com -Messa …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Remove-MessageClassItems.ps1], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Remove-MessageClassItems.ps1
LikeLike
As already answered through e-mail, check your Autodiscover configuration, DNS entries, firewall settings etc.
You could bypass Autodiscover process directly specifying the EWS endpoint (using Server parameter), e.g. outlook.office365.com
Are you using Hybrid configuration?
LikeLike
Yes this is a Hybrid configuration. As a matter of fact, i have also tried a pure Office 365 tenant, from different location and got excat same error.
I have used the -server switch with Outlook.Office365.com and got “can’t access mailbox information store” error.
In both cases, i have given a user account that has tenant global admin, Exchange Org Managrnt and impersonation rights (I followed the instructions and assigned the right using the GUI)
??
Thanks for your help
Rafat
LikeLike
Thanks for the script. It ran successfully however as it ran, I received couple undelivered messages which I did not send and also don’t have on my sent items. I tested with another user got the same issue. Any idea, could it be read receipt of unread emails?
LikeLike
It’s the processing of read receipts or calendar invites. It’s on the list of enhancements.
LikeLike
the enhancements is still to come, or I must download again? Thanks for the quick response
LikeLike
Not in there yet – stay tuned
LikeLike
Can you provide me a resource as to make this script work. I have no knowledge of scripting with EWS. I have installed the API but all attempts to make it work have failed.
Thanks
Jamie
LikeLike
I think I have it now. Didn’t see the download for the script.
LikeLike
Script runs but doesn’t delete anything. I have tried exact message class name and partialmatching switch with general class name and neither will delete the items from my deleted items.
LikeLike
Account has (full access) permissions or impersonate permissions, and permissions on the folder containing duplicate items (per folder)?
LikeLike
Yes. Running on CAS with domain admin rights. Don’t understand your permissions on the folder containing duplicate items question.
LikeLike
Users can explicitly set folder permissions (right-click folder, Permissions). Domain admin rights may not suffice. More info on permissions at https://eightwone.com/2014/08/13/application-impersonation-to-be-or-pretend-to-be/
LikeLike
Folder permissions from Outlook are Default and Anon. – None. Shouldn’t I get an error if I don’t have rights? I will read more into the impersonation.
LikeLike
Hi Michael,
Thanks for the script. it is working fantastically for most of our mailboxes and folders within it. we are triggering the script from Exchange 2010 and we have exchange 2010 as well as exchange 2013 in our environment.
We have processed most of the mailboxes and folders within it but suddenly for one of the folder of anyone mailbox we faced following error as shown below. we tried accessing this folder and we could access it. the common thing is that we are facing issue only with mailboxes located in exchange 2013. we have verified personification permission and are good on that side for user credentials being used. also, it is working for all folders except few from exchange 2013. request you to kindly look into it.
PS>TerminatingError(): “Exception calling “FindItems” with “2” argument(s): “The request failed. The operation has timed out””
C:\do not delete\remove\Remove-MessageClassItems.ps1 : Can’t access mailbox
information store
LikeLike
Default timeout for EWS operations is 100 sec. Extend that period inserting the following line below “$EwsService.UseDefaultCredentials= $true”:
$EwsService.Timeout= X
where X is the timeout in milliseconds
A ‘timeout’ parameter is on the wishlist.
LikeLike
hi Michael,
Thanks for the suggestions. However, we are facing another issue with the same script. for some folders it prompts the previous error and for some the one that is displayed below.
I verified on permission side and also tried accessing those folders by logging to users profile by admin account, it is accessible in that way. Any kind of help or suggestions would be helpful. also, any link or blog with in depth information about EWS operations and flow and specifically in regards to this script would be of a great help to us.
C:\do not delete\remove\Remove-MessageClassItems.ps1 : Can’t access mailbox information store
At D:\Messaging_ShortcutReport\shrtct_rpt_ForTesting.ps1:9 char:26
+ Import-CSV .\users.csv | .\Remove-MessageClassItems.ps1 -MessageClass IPM.Note.E …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Remove-MessageClassItems.ps1
Transcript stopped, output file is C:\Do not delete\remove\ShrtctCounts-09-04-2015.txt
Regards,
Rohit M. Dhole
LikeLike
just to add that it processed most of the folders very well in this mailbox. However, failed for a specific folder which is different than the todays folder.
Regards,
Rohit M. Dhole
LikeLike
Permissions are in order?
LikeLike
Yes, permissions are very much in order and so it is working fine with other users and folder on the same server. However, if you want me to verify some permissions please let me know so that I could verify and get back with result.
LikeLike
Hi Michael,
At the beginning of the script I saw another error message, don’t know if it has anything to do with the error. I have given that error below which is related to EWSManagedAPI.
WARNING: Active Directory server settings remained unchanged.
Load-EWSManagedAPIDLL : The term ‘Load-EWSManagedAPIDLL’ is not recognized as the name of a cmdlet, function, script
file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct
and try again.
At C:\do not delete\remove\Remove-MessageClassItems.ps1:341 char:5
+ Load-EWSManagedAPIDLL
+ ~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Load-EWSManagedAPIDLL:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Regards,
Rohit M. Dhole
LikeLike
After making changes in EWS time out as suggested by you, here is the next error.
PS>TerminatingError(): “Exception calling “FindItems” with “2” argument(s): “An internal server error occurred. Try again later.””
C:\do not delete\remove\Remove-MessageClassItems.ps1 : Can’t access mailbox information store
Any help or any pointer would really be of great help !
Regards,
Rohit M. Dhole
LikeLike
Hi Michel,
Thanks a ton for your solution. I believe the first solution for Time Out value worked for me, I am able to complete the reports fluently. it gave above errors and I just increased the Time out value and it started working.
I am further looking for a script which could help me to remove older data which is older than specific date in a Mailbox.. it would be great if you could guide me to any script which could help me in this case.
Also, tough the reports are successful. I am getting this error at the beginning of all users information. do we have any workaround to overcome it ?
$EwsService.Timeout= X
where X is the timeout in milliseconds
A ‘timeout’ parameter is on the wishlist.
Regards,
Rohit M. Dhole
LikeLike
What error?
Older data .. why not apply a retention policy clearing out item older than X days, or is it a one-time task only?
LikeLike
Hi Michel,
Yes, it is the one time task and need to do on multiple users at a time. so just for one time activity we can’t go ahead and have retention tags and policies for multiple users.
Also, I pasted the error that I am getting in current script. Thanks for looking into it.
Regards,
Rohit M. Dhole
LikeLike
I believe I pasted wrong error,
Load-EWSManagedAPIDLL : The term ‘Load-EWSManagedAPIDLL’ is not recognized as
the name of a cmdlet, function, script file, or operable program. Check the
spelling of the name, or if a path was included, verify that the path is
correct and try again.
Regards,
Rohit M. Dhole
LikeLike
Hello Michael,
I am wondering when the messages are being deleted from the mailbox, if there is a way to suppress responses to and silently delete delivery receipts/read receipts. I am finding when we remove these messages for any archives messages that had any of these requests tagged a lot of auto responses get generated like “not read: re..” etc
Thanks,
J-
LikeLike
Yes, check the other comments. It’s on the shortlist of enhancements.
LikeLike
Great, thank you for the prompt response.
LikeLike
Hi Michel, great script! I am trying to use it to delete stubs from Enterprise Vault old than xx/xx/xxxx and it seems to be working as far as scanning the mailbox, etc. However, no items get deleted as it finds none. I notice that it is not scanning a folder that our PST migration process creates in the mailbox called _Personal Archive. This folder is created directly under the user mailbox such as:
>Joe.Smith@contoso.com
>Inbox
>_Personal Archive
I also tried -ScanAllFolders with no luck.
Am I missing something as to why it wont scan this particular folder? I read through entire blog and comments and didn’t see anything jump out.
Thanks for any guidance you can provide!!!
LikeLike
Hi Michel,
we are doing the same migration but i can’t delete anything for now… i need to create a search folder in everyone’s outlook with all the message Class IPM.NOTE.EnterpriseVault.Shortcut in it so the user can clean their own vault.
can you help me please?
LikeLike
This should do the trick:
New Search Folder > Create custom Search Folder, Choose > Name: Something, Criteria > Advanced tab > Add Field Mail Item, Message Class is IPM.NOTE.EnterpriseVault.Shortcut > Add to List > OK > OK > OK
LikeLike
oh sorry … i know how to do it manually but i want to script it to be able to push it to everyone the the company…
regards
LikeLike
This should get you started
http://gsexdev.blogspot.nl/2011/09/create-search-folder-using-ews-managed.html
LikeLike
Hi:
I’m trying to execute this command against a specific database and get an error. The command is
Get-MailboxDatabase DB_xxx | Get-Mailbox | .\Remove-MessageClassItems.ps1 -Impersonation -Verbose -DeleteMode SoftDelete -MessageClass EnterpriseV
ault -PartialMatching -ScanAllFolders -Before ((Get-Date).AddDays(-730))
The error is:
The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.At line:1 char:79
Any ideas?
Thanks
Patxi
LikeLike
The name of the mailbox parameter is mailbox, and you’re not passing that one via Get-Mailbox. Instead, try:
Get-MailboxDatabase DB_xxx | Get-Mailbox | ForEach { .\Remove-MessageClassItems.ps1 -Mailbox $_.Identity -Impersonation -Verbose -DeleteMode SoftDelete -MessageClass EnterpriseV
ault -PartialMatching -ScanAllFolders -Before ((Get-Date).AddDays(-730)) }
LikeLike
Hi Michel:
Thanks for your quick response. !!!!That worked¡¡¡¡
I only had to change $_.Identity for $_.Alias to make it work, as the Identity value has spaces, and Alias does not.
Thank you very much for your help. It saved me a lot of time
Best regards
Patxi
LikeLike
Hi Michel:
Another tricky question, at least for me…
Running your script to all mailboxes of a specific database, asks for deletion confirmation for every mailbox it encounters. Is there any way to automate this response (for example A to delete all ítems, etc.) to avoid typing this for every mailbox?
Thanks for your great Support.
Patxi
LikeLike
You can use -Confirm:$false
LikeLike
Perfect.
Thanks again Michel.
Have a nice day
Patxi
LikeLike
Hi Michel,
Awesome script. It’s weird that MS decided not to allow this in the “advanced” search applets of Exchange 2013.
I do have a feature request:
It is possible to move the items to the deleted items folder, but what I want to do is to export the items to a PST file and remove them. If it was possible to move the items to a random new empty folder, that would be great. If this folder could be located in a different mailbox, that would be even better. Is this something that would be hard to add on?
Thank you in advance!
Milan
LikeLike
Exporting to PST yes, as I’m interacting with the mailbox through EWS and have no ‘PST library’ at my disposal. I could create a ‘Duplicates’ folder and dump everything in there; noted on the wish list.
LikeLike
Ofcourse, I thought exporting to a PST would be difficult at the least. But moving items to a new seach folder should be straight forward …
Thank you for putting it on the wish list.
LikeLike
Could you give an indication on how much trouble this would be and when you could possibly come around to it, if ever? I apologise for sounding a bit snobby, i don’t mean to be, but we’re kind of in a jam with this being the only option and no EWS expertise or experience…
Bedankt voor het antwoord alvast!
LikeLike
As a work-around, could you not clear out the deleted items folder temporarily, and allow for a “Move to Deleted Items” execution? This would isolate your results into the Deleted Items Folder.
LikeLike
This is not an option, users often have good reasons for keeping messages in their Deleted Items Folder (I only have one, but hey …). Also using the Deleted items folder for live data, or actually anything else but junk, makes my techy-sences tingle inappropriately.
LikeLike
Yeah, my point was to use this as a potential temporary one-off process for one (or a small number of users) who may have a large number of items of a particular message class which were looking to export to PST.
That workflow would involve (per user) temporarily moving all items out of Deleted Items (into a subfolder), and using the script to “delete” the particular message class items into the Deleted items. Since the Deleted items would then contain nothing but the items with that particular message class, you could then export it to PST.
Once complete, you’d then place the original deleted items back into the Deleted Items folder, and leave the user alone.
I’m assuming you’d like to script this out for many users, in which case my idea wouldn’t work at all…
LikeLike
Yeah, it’s A LOT of mailboxes in this case. And doing it by hand, it would probably be easier running a search on messageclass in outlook and then dragging the results to a temp mailbox, folder or PST. Thaks though… workrounds are welcome too.
LikeLike
Oh, and yeah…Users that “file” stuff in Deleted Items, make me nervous…
LikeLike
Never mind. I figured it out.
A script from MSDN was easily adapted to do exactly what I needed it to do:
http://blogs.msdn.com/b/emeamsgdev/archive/2012/04/27/powershell-script-to-move-items-from-one-folder-to-another-in-a-user-s-mailbox.aspx?CommentPosted=true#commentmessage
All it needed was a check on ItemClaas before moving and a search iteration per folder to improve efficiency. It recreates teh folder structure at the target and it automatically skips the target folder when it a subfolder of the source folder, so you can just create target folder and move everything from “\” (=root) to it and it will all be just fine.
Available here:
https://sites.google.com/site/bikerbuva/software
LikeLike
Glad you figured it out
LikeLike
I’m no Powershell expert, but I can’t seem to be able output this to a log-file using redirection or piping to an “out-file.”
Am I missing something easy?
LikeLike
For the record, the following works to pipe the Get-Mailbox command to the script:
Get-Mailbox -database databasename | select samaccountname | Select-Object @{ expression={$_.samaccountname};label=’Mailbox’ } | .’C:scriptsRemove-MessageClassItems.ps1′ -MessageClass IPM.Note.EnterpriseVault.Shortcut -Confirm:$false -DeleteMode SoftDelete -Verbose -Impersonation -ScanAllFolders -Before ((Get-Date).AddDays(-30))
LikeLike
Only the parameter Mailbox accepts pipeline input, the the name of the attribute passed through the pipeline needs to match. The script doesn’t output objects, it outputs to the console (incl. warnings and errors), and additionaly the verbose or debug channel (if related common parameter is specified). You can redirect that console output the traditional way, see https://technet.microsoft.com/en-us/library/hh847746%28v=wps.620%29.aspx
LikeLike
Yeah, I’d figured that out, thanks…I’m using Select-Object @{ expression={$_.samaccountname};label=’Mailbox’ } for that…
LikeLike
I am getting this error while deleting the EV shortcuts from Office 365 mailbox:
Remove-MessageClassItems.ps1 : Can’t access mailbox information store
At line:1 char:1
I am running this command:
.\Remove-MessageClassItems.ps1 -Mailbox user@domain.com -Verbose -DeleteMode MoveToDeletedItems -MessageClass IPM.Note.EnterpriseVault.Shortcut -MailboxOnly -WhatIf -Server outlook.office365.com
The account used to run this command has got the Full Access and Impersonation rights on the mailbox. Any help with this will be appreciated a lot.
Thanks in advance.
LikeLike
What’s that ‘mailto…’ doing in there? Also, please relog before trying again.
LikeLike
I do not have mailto in the command which I am running, it’s just when you hover your mouse you get to see that, which is expected, I think. The same command worked on one of my colleague’s machine. I have installed the same version of EWS Managed API, still no go. Will try few more things and keep you updated.
LikeLike
Ah, I replied to the notification mail which showed the mailto HTML tag as plain text. Odd. Anyway, cmd looks ok – can’t access information store is usually something with access (permissions). You did specify Credentials, providing credentials with sufficient access?
LikeLike
Michel,
I tried to ensure due diligence in reading all the comments…
It appears this methodology deletes the emails of said message class before export… is there a method you could describe to export a pst that simply had a specific message class excluded or export a pst that is only of a specific message class (ipm.note e.g.)?
LikeLike
In modern Exchange, you can leverage the Search-Mailbox cmdlet to find messages based on certain conditions, and export the results a different mailbox with folder specification (and from there you can export it to PST). E.g., something like this should work: Get-Mailbox | Search-Mailbox -SearchQuery ‘MessageClass:IPM.Note’ -TargetMailbox ‘TargetMailbox’ -TargetFolder “Query1”
LikeLike
Hi Michiel, by ‘modern’ are you referring to Exch2016?
Search-Mailbox in Exch2013 does not support the “Message Class” property keyword. Right? Am I missing something?
LikeLike
My bad – you can use -MessageType but that is limited to predefined types (eg Email). Specifying -SearchQuery ‘IPM.NOTE.EnterpriseVault.Shortcut’ works though, but might match on too much items (not bound to message type).
LikeLike
Unfortunately (for us), we are still on Exchange 2013 (and will be for a while). Can you (or anyone) recommend a 3rd party tool that can accomplish this?
Many thanks, Michael
LikeLike
You need to use ews to move items to a separate folder and then export the mailbox while either selecting or excluding the particular folder you moved the items to.
LikeLike
I’m trying to run this against our Office 365 environment to try and clean out EnterpriseVault stubs and am getting all kinds of errors, I’m guessing because it’s running Exchange 2016?
.\Remove-MessageClassItems.ps1 -Mailbox me@company.com -Verbose -DeleteMode MoveToDeletedItems -MessageClass IPM.Notes.EnterpriseVault.Shortcut -ArchiveO
nly -WhatIf -Server outlook.office365.com
VERBOSE: Loading C:\Program Files\Microsoft\Exchange\Web Services\2.2\\Microsoft.Exchange.WebServices.dll
Processing mailbox me@company.com (me@company.com)
VERBOSE: Set to trust all certificates
New-Object : Multiple ambiguous overloads found for “ExchangeService” and the argument count: “1”.
At C:\PowerShell\Remove-MessageClassItems.ps1:399 char:22
+ $EwsService= New-Object Microsoft.Exchange.WebServices.Data.ExchangeServ …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [New-Object], MethodException
+ FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand
The property ‘UseDefaultCredentials’ cannot be found on this object. Verify that the property exists and can be set.
At C:\PowerShell\Remove-MessageClassItems.ps1:400 char:9
+ $EwsService.UseDefaultCredentials= $true
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : PropertyNotFound
The property ‘UseDefaultCredentials’ cannot be found on this object. Verify that the property exists and can be set.
At C:\PowerShell\Remove-MessageClassItems.ps1:413 char:13
+ $EwsService.UseDefaultCredentials= $true
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : PropertyNotFound
VERBOSE: Using Exchange Web Services URL https://outlook.office365.com/EWS/Exchange.asmx
The property ‘Url’ cannot be found on this object. Verify that the property exists and can be set.
At C:\PowerShell\Remove-MessageClassItems.ps1:424 char:13
+ $EwsService.Url= “$EwsUrl”
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : PropertyNotFound
VERBOSE: DeleteMode is MoveToDeletedItems
VERBOSE: PartialMatching is False
VERBOSE: Removing messages of class IPM.Notes.EnterpriseVault.Shortcut
LikeLike
Looks more like something with the EWS Managed API you’re using – which version you have installed?
LikeLike
Looks like I’m using 2.2
LikeLike
I have this same issue with EWS Managed API 1.2 and 2.2. Running Exchange 2013.
LikeLike
You are running this from a PowerShell session, not the Exchange Management Shell?
LikeLike
Great script and solved a lot of manual work.
However as a programmer i would recommend to use and handle try catch blocks whenever possible and accordingly. It’s a hassle to figure which line of code caused an error while each time an error message called “Can’t access mailbox information store” appears!
LikeLike
As a programmer, I would say the error is already thrown in a catch block, but nested ones don’t go well indeed.
Only thing is I could add $Error to the output, however it’s usually the same one (access denied). Cheers!
LikeLike
Hi Michael,
I’m getting this error now when i use your script
“Can’t access mailbox information store: cannot find an overload for “isequlto” and the argument count: “3′” at line:1 char:1
I’m not using any folder switch but even when i do, it throws that same error. I’m using ews 2.0 api
LikeLike
Which version are you running? 1.52 addresses an issue throwing such error.
LikeLike
hi there, trying to run this, great sript by the way
Import-CSV users.csv1 | Remove-MessageClassItems.ps1 -MessageClass IPM.Note.EnterpriseVault.Shortcut -DeleteMode HardDelete -Impersonation
and keep getting command failure about not able to take pipeline, what am i doing wrong please
LikeLike
What’s in the CSV? Should be something like:
Identity
MailAlias
Then:
Import-CSV users.csv | .\Remove-MessageClassItems.ps1 -MessageClass IPM.Note.EnterpriseVault.Shortcut -DeleteMode HardDelete -Impersonation
Also note that for Office 365 (use e-mail addresses as Identity) you need to specify/use Credential; for on-prem, your current credential will be used.
LikeLike
CSV file had
identity
user1
user2
here is output
[PS] C:\>Import-CSV c:\users.csv | Remove-MessageClassItems.ps1 -MessageClass IPM.Note.EAS -DeleteMode HardDelete -Imper
sonation
Security Warning
Run only scripts that you trust. While scripts from the Internet can be useful, this script can potentially harm your
computer. Do you want to run C:\Windows\system32\Remove-MessageClassItems.ps1?
[D] Do not run [R] Run once [S] Suspend [?] Help (default is “D”): r
C:\Windows\system32\Remove-MessageClassItems.ps1 : The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.
At line:1 char:55
+ Import-CSV c:\users.csv | Remove-MessageClassItems.ps1 <<<< -MessageClass IPM.Note.EAS -DeleteMode HardDelete -Imper
sonation
+ CategoryInfo : InvalidArgument: (@{Identity=AshruthB}:PSObject) [Remove-MessageClassItems.ps1], Paramet
erBindingException
+ FullyQualifiedErrorId : InputObjectNotBound,Remove-MessageClassItems.ps1
LikeLike
What version of the script are you using? Latest version is 1.52, and this should work:
[PS] C:\>Import-CSV c:\users.csv | .\Remove-MessageClassItems.ps1 -MessageClass IPM.Note.EAS -DeleteMode HardDelete -Impersonation
LikeLike
yes thats the version i am using and as you can see from my syntax i am using the same as you, yet i get that pipeline error
LikeLike
Not exactly – but this should throw a different error than the one you mentioned
[PS] C:\>Import-CSV c:\users.csv | Remove-MessageClassItems.ps1 -MessageClass IPM.Note.EAS -DeleteMode HardDelete -Impersonation
[PS] C:\>Import-CSV c:\users.csv | .\Remove-MessageClassItems.ps1 -MessageClass IPM.Note.EAS -DeleteMode HardDelete -Impersonation
LikeLike
i tried with .\ as well and gives me same error, very weird, must be something on our side i will need to investigate further
LikeLike
As a workaround, you can use the following to not use the pipeline:
Import-CSV c:\users.csv | % { .\Remove-MessageClassItems.ps1 -Identity $_.Identity -MessageClass IPM.Note.EAS -DeleteMode HardDelete -Impersonation }
LikeLike
thank you that seems to work 🙂
LikeLike
Hello Michel,
thank you for the great script! It is really useful. I would like to ask a question since my scripting skills are not up to par to make necessary adjustments.
So my case is as follows: I need to delete EV shortcuts older than 90 days in all the folders excluding one folder AND its subfolders.
I started with running the script with -ExcludeFolder specifying needed folder as its parameter. Script runs and excludes the folder that I specified, but still wants to process its subfolders and delete EV shortcuts from them.
I see there is a line of code $FolderView.Traversal= [Microsoft.Exchange.WebServices.Data.FolderTraversal]::Deep that may have something to do with this behavior.
However, from what I read and understood the logic of he Folder Traversal, this part should ensure that subfolders of the -ExcludeFolder will be excluded by the script too, which is not happening.
Can you please help to figure this out?
LikeLike
Currently the folder(s) specified only apply to that folder, not subfolders. Logic is coming to make this a lot more flexible (already implemented for the duplicate removal script). It’s more than traversal setting, which determines if search is depth first or breadth first. Stay tuned!
LikeLike
Thanks for the reply! By the way, the duplicate removal script is also awesome and much better than mentioned paid solutions.
LikeLike
Michael
Great script – does almost precisely what I need. But I’ve got a nervy client who would like to move the stubs into a new folder so they can be examined prior to deletion. I thought of using the MoveToDeletedItems, but then the stubs would be lumped in with the normal cruft.
If there any way to have an option to move all of the items found into a new folder – no need to recreate the folder structure?
LikeLike
Michael
Great script – does almost precisely what I need. But I’ve got a nervy client who would like to move the stubs into a new folder so they can be examined prior to deletion. I thought of using the MoveToDeletedItems, but then the stubs would be lumped in with the normal cruft.
If there any way to have an option to move all of the items found into a new folder – no need to recreate the folder structure?
LikeLike
The last version adds -Report, which you can use together with -WhatIf:$true to get a matching items found per folder. This may help in their analysis.
LikeLike
Thanks for the response. I’ll give that a go. Sounds like just the trick.
LikeLike
You could also temporarily clean out the Deleted Items folder (prior to execution), or simply sort by message class in Outlook (after using MoveToDeletedItems) and then move to a new folder at that point.
LikeLike
Just a note on the -Report option. When I used it, I received the following error when processing the Inbox
Processing folder \Inbox
WARNING: Error performing operation FindItems with Search options in Inbox. Error: Exception calling “FindItems” with “2” argument(s): “E
xchange Web Services are not currently available for this request because none of the Client Access Servers in the destination site could process the re
quest.”
There were 112,000 items in there, so that might have been the limiting factor.
LikeLike
Could you hit me up on e-mail (contact form); I have an update which should prevent this for you to try.
LikeLike
Michel, I meant to reply to this months ago – but the time passed me by. Thanks for the prompt response to this, I managed to run this against each of the mailboxes which had been migrated and all looks good now. Wouldn’t have managed it so easily without your script.
LikeLike
First off, i love your blog and i am glad you are keeping up with it!
Ido have a question in regard of the script you had updated for searching certain message class and deleting them; i am working on a migration project from EnterpriseVault to Exchange Online and we have ophan EV items due to restore that we would like to convert instead of deleting them. we do not care if the attachement isnt recovered…
WOuld it be possible to adjust your script so that it convert the message class from “IPM.NOTE.EnterpriseVault.Shortcut” to “IPM.NOTE” ?
LikeLike
A recent enhancement allows you to do just that, replacing the PR_MESSAGE_CLASS with a new value: see the -ReplaceClass parameter
LikeLike
Hi, WHen I add -replaceClass to replace pendingArchive, I receive error for the command.
VERBOSE: Changing messages of class IPM.Note.EnterpriseVault.PendingArchive to IPM.Note
VERBOSE: Constructing folder matching rules
WARNING: Cannot bind to MsgFolderRoot – skipping. Error: Exception calling “Bind” with “2” argument(s): “Exchange
Server doesn’t support the requested version.”
WARNING: Cannot bind to ArchiveMsgFolderRoot – skipping. Error: Exception calling “Bind” with “2” argument(s):
“Exchange Server doesn’t support the requested version.”
Thanks for your advice.
LikeLike
Great blog, and thank you for your work on this script!!
I am seeing the following error:
VERBOSE: Loading D:\temp\EV script\Microsoft.Exchange.WebServices.dll
VERBOSE: Loaded EWS Managed API v15.00.0913.015
VERBOSE: Set to trust all certificates
Processing mailbox username(username@ourdomain.ca)
VERBOSE: Looking up EWS URL using Autodiscover for Jusername@ourdomain.ca
VERBOSE: Using EWS on CAS https://email.ourdomain.ca/EWS/Exchange.asmx
VERBOSE: DeleteMode is MoveToDeletedItems
VERBOSE: Removing messages of class *EnterpriseVault*
VERBOSE: Removing messages older than 01/09/2017 00:00:00
VERBOSE: Constructing folder matching rules
WARNING: Cannot bind to MsgFolderRoot – skipping. Error: Exception calling “Bind” with “2” argument(s): “Exchange
Server doesn’t support the requested version.”
VERBOSE: Processing primary mailbox jharany
WARNING: Cannot bind to DeletedItems – skipping. Error: Exception calling “Bind” with “2” argument(s): “Exchange Server
doesn’t support the requested version.”
VERBOSE: Collecting folders containing e-mail items to process
WARNING: Error performing operation FindFolders with Search options in . Error: Exception calling “FindFolders” with
“3” argument(s): “Value cannot be null.
Parameter name: parentFolderId”
…from there it repeats.
Many thanks again. I am unsure what ‘Exchange Server doesn’t support the requested version’ may refer to.
LikeLike
…aaand I think I’ve answered my own question:
$ExchangeVersion=
LikeLike
OK I’ve resolved the Exchange version error.
But the error below persists (and repeats):
VERBOSE: Loading D:\Temp\path\Message Class scripts\Microsoft.Exchange.WebServices.dll
VERBOSE: Loading module from path ‘D:\Temp\Jeremy\Message Class scripts\Microsoft.Exchange.WebServices.dll’.
VERBOSE: Loaded EWS Managed API v15.00.0913.015
VERBOSE: Set to trust all certificates
Processing mailbox flast (first.last@ourdomain.ca)
VERBOSE: Looking up EWS URL using Autodiscover for first.last@ourdomain.ca
VERBOSE: Using EWS on CAS https://email.ourdomain.ca/EWS/Exchange.asmx
VERBOSE: DeleteMode is MoveToDeletedItems
VERBOSE: Removing messages of class IPM.Note.EnterpriseVault.Shortcut
VERBOSE: Removing messages older than 01/09/2017 00:00:00
VERBOSE: Constructing folder matching rules
VERBOSE: Processing primary mailbox flast
VERBOSE: Collecting folders containing e-mail items to process
WARNING: Error performing operation FindFolders with Search options in . Error: Exception calling “FindFolders” with
“3” argument(s): “Value cannot be null.
Parameter name: parentFolderId”
LikeLike
Hi, I think you should run it on the on exchange power shell 2013 or above.
hope this helps.
LikeLike
Opposite, should be run from basic PowerShell session. Please use EWS Managed API 2.2 (you have v15.00.0913.015 installed which is 2.0 IIRC), v2.2 supports additional EWS calls which are required.
LikeLike
Thanks for the suggestion.
I have indeed downloaded 2.2 from https://www.microsoft.com/en-us/download/details.aspx?id=42951. Problem being that in that link, MS describes it as Version: 15.00.0913.022, however, when extracted, the .dll responds like so:
VERBOSE: Loading C:\Program Files\Microsoft\Exchange\Web Services\2.2\\Microsoft.Exchange.WebServices.dll
VERBOSE: Loading module from path ‘C:\Program Files\Microsoft\Exchange\Web
Services\2.2\Microsoft.Exchange.WebServices.dll’.
VERBOSE: Loaded EWS Managed API v15.00.0913.015
…and terminates with the error:
D:\Temp\user\Message Class scripts\Remove-MessageClassItems.ps1 : Cannot access mailbox information store, error: Can
not convert the “System.Object[]” value of type “System.Object[]” to type “Microsoft.Exchange.WebServices.Data.FolderId
“.
At line:1 char:31
+ .\Remove-MessageClassItems.ps1 <<<< -Identity f.last -MessageClass IPM.Note.EnterpriseVault.Shortcut -DeleteMode MoveToDeletedItems -Before 1/9/2017 -mailboxonly -IncludeFolders Inbox -verbose
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Remove-MessageClassItems.ps1
If there is a newer version of the .dll, that is, 15.00.0913.022, I cannot seem to locate it 😦
LikeLike
My bad, v15.0.913.15 is the 2.2 one ; did you run it from a regular PowerShell session?
LikeLike
Yes, from both PS ISE and a regular PS prompt, too, both as Adminstrator, as well as just opening the shell without admin.
LikeLike
Hi Michel,
When i run the syntax with switch -replaceClass. I got this message.
VERBOSE: Changing messages of class IPM.Note.EnterpriseVault.PendingArchive to IPM.Note
VERBOSE: Constructing folder matching rules
WARNING: Cannot bind to MsgFolderRoot – skipping. Error: Exception calling “Bind” with “2” argument(s): “Exchange
Server doesn’t support the requested version.”
WARNING: Cannot bind to ArchiveMsgFolderRoot – skipping. Error: Exception calling “Bind” with “2” argument(s):
“Exchange Server doesn’t support the requested version.”
if without running the -replaclass, i got it work.
LikeLike
Are you running against Exchange 2007? If so, you need to specify the MailboxOnly switch (or else it will try Ex2010 mode, which Ex2007 doesn’t support).
LikeLike
Hello,
Just need to find out, if i use this command below does it delete the pendingArchive too?
-DeleteMode Harddelete -MessageClass IPM.Note.EnterpriseVault.Shortcut
Thank you
LikeLike
EV will set the class of those pending items to IPM.Note.EnterpriseVault.PendingArchive. So, no IPM.Note.EnterpriseVault.Shortcut will only process items which EV processed (i.e. archived).
LikeLike
Thank you Michel for clarify this! you did a great script!!!
Thank you!!!
LikeLike
Hi Michel,
Does the script recurse through non-standard subfolders? At the top level of every mailbox, we have ‘Archive X Years’ folders for 3, 5, 7, 10 years and Forever. Some of these folders have several levels of subfolders depending on how the user has their mailbox set up. After running the script using credentials, it will clean up the top levels of the Archive X Years, but items remain in the subfolders and the script says ‘0 items processed in 00:00:11…” I’ve tried it with the ScanAllFolders option and by specifying just the Archive folders:
.\Remove-MessageClassItems.ps1 -Identity first.last@contoso.com –Credentials $Credentials -Verbose -DeleteMode MoveToDeletedItems -MessageClass IPM.Note.EnterpriseVault.Shortcut –MailboxOnly –IncludeFolders \archive*\*
LikeLike
Thank you for the script. When I run it on my account using my credentials it works great. But when I run it against other users using an account with Full Access Permissions I receive:
VERBOSE: Loading C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.
Exchange.WebServices.dll
VERBOSE: Loaded EWS Managed API v15.00.0913.015
VERBOSE: Set to trust all certificates
VERBOSE: Using credentials migrationwiz@company.com
Processing mailbox user@company.mail.onmicrosoft.com
VERBOSE: Using Exchange Web Services URL https://outlook.office365.com/EWS/Excha
nge.asmx
VERBOSE: DeleteMode is MoveToDeletedItems
VERBOSE: Removing messages of class *ExShortcut*
VERBOSE: Constructing folder matching rules
WARNING: Cannot bind to MsgFolderRoot – skipping. Error: Exception calling “Bind
” with “2” argument(s): “The request failed. The remote server returned an error
: (503) Server Unavailable.”
WARNING: Cannot bind to ArchiveMsgFolderRoot – skipping. Error: Exception callin
g “Bind” with “2” argument(s): “The request failed. The remote server returned a
n error: (503) Server Unavailable.”
VERBOSE: Processing user@company.mail.onmicrosoft.com finished
Command I am using is:
$Credentials= Get-Credential
./Remove-MessageClassItems.ps1 -Server outlook.office365.com -Identity user@company.mail.onmicrosoft.com -DeleteMode MoveToDeletedItems -MessageClass *ExShortcut* -Credentials $Credentials -Verbose
What am I doing wrong?
LikeLike
Format looks OK, you sure the user@company.mail.onmicrosoft.com maps to a user (not user@company.onmicrosoft.com) and the migrationwiz account has Full Access applied properly (eg Add-MailboxPermission –Identity Nestor –User Archibald –AccessRights FullAccess –InheritanceType All)
LikeLike
Hi Michel,
Thanks a lot for the script and actively supporting it.
Can we use the script to remove messages from Recoverable Items of both primary mailbox and online archive? We have few users with 100 GBs of data already accumulated withing Recoverable Items due to a bug in the 3rd party Outlook plugin. There is a retention policy (aka hold in place).
Thank you.
LikeLike
In the current version no, but adding Recoverable Items to the process is fairly easy. Standby 🙂 Do note you need to remove the hold prior to cleaning up Recoverable Items, or it won’t help. Also note that removing the Hold may impact compliance due to the system removing items beyond retention.
LikeLike
Thank you Michel,
I am aware of the pre-reqs to delete message for mailboxes on-hold. I think we will need to temporary disable the retention policy for a user, then run your magic script and hope that managed folder assistant won’t kick-in before we re-enable the retention. The problem is that there are literally 100GB of duplicates, so it will take ages to clean up (we are on Office 365 and likely will be throttled by EOL).
BTW, I guess you are aware that Recoverable folder contains few subfolders 🙂
Looking forward to try the script in action.
LikeLike
Hi Michel,
First of all, great post and script, save us a lot of time to do the manual activity!
However, I’ve a request to modify the script to either date range or after certain date. I tried to change
If ( $Before) {
$ItemSearchFilterCollection.add( (New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsLessThan( [Microsoft.Exchange.WebServices.Data.ItemSchema]::DateTimeReceived, $Before)))
to IsMoreThan but not work. Can you please share some tips which line i can start with?
LikeLike
Hi Michel,
really great script, i got some errors running it. my exchange is a 2010 in german language
AUSFÜHRLICH: Collecting folders containing e-mail items to process
WARNUNG: Error performing operation FindFolders with Search options in . Error: Ausnahme beim Aufrufen von
“FindFolders” mit 3 Argument(en): “Der Wert darf nicht NULL sein.
Parametername: parentFolderId”
AUSFÜHRLICH: Adding folder \
WARNUNG: Error performing operation FindFolders with Search options in . Error: Ausnahme beim Aufrufen von
“FindFolders” mit 3 Argument(en): “Der Wert darf nicht NULL sein.
Parametername: parentFolderId”
any ideas ? thanks
LikeLike
No idea- using FA or impersonation?
LikeLike
No, haven’t seen that one before. To see what’s going on I need to be able to reproduce the situation. In what way are you calling the script, and what version of the EWS Managed API (DLL) are you using?
LikeLike
Hi, this is really useful and effective, but is there any way to avoid the prompts to process the deletion? I’ve tried -force (not recognised) and -confirm $false (seems to accept it and then continues to prompt for each mailbox). I am running it with impersonation which is working fine outside the prompts. Cheers, Rob
LikeLike
If you want to completely remove the prompts you can set line 197 to: ConfirmImpact = “None”
Be careful!!
LikeLike
-Confirm:$false (mind the colon)
LikeLike
Followed this tutorial and also checked the comments but I can’t seem to get this script to work. I am receiving the following messages:
WARNING: Cannot bind to MsgFolderRoot – skipping. Error: Exception calling “Bind” with “2” argument(s): “The request failed. The remote server returned an error: (401) Unauthorized.”
WARNING: Cannot bind to ArchiveMsgFolderRoot – skipping. Error: Exception calling “Bind” with “2” argument(s): “The request failed. The remote server returned an error: (401) Unauthorized.”
I’ve installed EwsManagedApi.msi and can connect to O365 and run regular PowerShell successfully. I am a global admin and gave myself full mailbox permissions to the mailbox I am targeting in my test.
LikeLiked by 1 person
Good Morning Michel and thanks for this amazing script, this will drastically improve/fasten and easy mailbox archiving and deletion. Was looking for that option since a long time
One question (and maybe idea of improvement) :
Is it possible to specify multiple classes in -MessageClass switch? Like *EnterpriseVault*, *Meeting*, *Task*
Reason for that is: if you want to delete different classes you have to run the script for each class and it takes quite long when some people have thousands of folders in their mailbox
Other possibility would be to scan all folders only once and being able to imbricate functions
Looking forward to hear from you … and again a BIG THANKS for your job
LikeLike
Pingback: Remove EnterPriseVault Shortcut Class Message after Office 365 Migration | Tech Wizard
Hi Michael, I tried the latest version of the script but am still getting the following:
WARNING: Cannot bind to MsgFolderRoot – skipping. Error: Exception calling “Bind” with “2” argument(s): “The request failed. The remote server returned an error: (401) Unauthorized.”
I assigned the ApplicationImpersonation role to the service account and given the service account full access to the mailbox.
I am using the following syntax:
.\Remove-MessageClassItems.ps1 -Identity firstname.lastname@company.mail.onmicrosoft.com -Credentials $UserCredential -Server outlook.office365.com -Verbose -DeleteMode MoveToDeletedItems -MessageClass IPM.Note.EnterpriseVault* -ScanAllFolders -MailboxOnly -impersonation
Any ideas?
Thanks, Alan C
LikeLike
Forgot to add:
The service account is exempted from Azure AD MFA
The service account is also not mailbox-enabled
LikeLike
i am running into the same problem, any ideas?
LikeLike
Hi Michel
Do you have any suggestions for changing the message class in Exchange 2016?
LikeLike
Hi Michel
Could you please provide more details on the Modern Auth, as I’m still failing to authenticate I’ve created an app registration with app level ews permissions, and using the convert-to-string to for the -secret parameter, however getting error cannot bind to MsgFolderRoot. when i check the app registration i’m not showing any authentication attempts.
Do we need to add a script block to obtain the auth token, or is this built into your script. If you could please provide details it would be a great help
LikeLike
Obtaining tokens etc. is in the script; you just need to configure app with proper permissions. You did configure basics such as autodiscover, otherwise -server outlook.office365.com might help. Also, use Verbose to get a sense of what path it walks regarding connecting.
LikeLike
The script worked fantastic on Exchange Online mailbox. Just want to say THANK YOU!
LikeLike
Hi, and thnak you so much for the script. I reeally need it! However, I am unable to run it.
No matter what parameter I use, it keeps saying:
PS D:\> ./Remove-MessageClassItems.ps1 -Identity myuser -Impersonation
D:\ADMHME\39\SCRIPT\Remove-MessageClassItems.ps1 : Parameter set cannot be resolved using the specified named parameters.
At line:1 char:1
+ ./Remove-MessageClassItems.ps1 -Identity myuser …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Remove-MessageClassItems.ps1], ParameterBindingException
+ FullyQualifiedErrorId : AmbiguousParameterSet,Remove-MessageClassItems.ps1
Please help. Thank you in advance. I already have the latest DLL version 2.2.1.2.
LikeLike
AmbiguousParameterSet – PowerShell cannot determine which set of parameters you are addressing and thus which ones it may me missing. If the example you pasted is complete, it’s missing the mandatory MessageClass parameter.
LikeLike
Hi,
The mandatory parameters have been set, also MessageClass.
What I am trying to accomplish is report as CSV or HTML the number of Enterprise Vault shortcuts in all mailboxes.
Thank you in advance.
LikeLike
Including authentication method? (see response to bobebuk)
LikeLike
Hi Michel,
Thank you! It was “-Credentials” parameter missing.
Now I have the error:
….\Remove-MessageClassItems.ps1 : Cannot access mailbox information store for ihmerouane@domain.com: Cannot find an overload for “PropertySet” and the
argument count: “3”.
At line:1 char:1
+ .\Remove-MessageClassItems.ps1 -Mailbox imerouanh -MessageClass “IPM. …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Remove-MessageClassItems.ps1
LikeLike
With the “-Verbose” parameter (just before the error):
VERBOSE: Module Microsoft.Exchange.WebServices v2.2.1.0 already loaded
VERBOSE: Module Microsoft.Identity.Client v4.25.0.0 already loaded
VERBOSE: Using credentials iadmhme@msgroupemutuel.ch
VERBOSE: DeleteMode is SoftDelete
VERBOSE: Removing messages of class IPM.Note.EnterpriseVault.Shortcut
Processing mailbox ihmerouane@msgroupemutuel.ch (ihmerouane@msgroupemutuel.ch)
VERBOSE: Using ihmerouane@msgroupemutuel.ch for impersonation
VERBOSE: Looking up EWS URL using Autodiscover for ihmerouane@msgroupemutuel.ch
VERBOSE: Using EWS endpoint https://outlook.msgroupemutuel.ch/EWS/Exchange.asmx
VERBOSE: Constructing folder matching rules
VERBOSE: Processing primary mailbox ihmerouane@msgroupemutuel.ch
VERBOSE: Collecting folders containing e-mail items to process
LikeLike
Hi Hocine. Just pushed version 2.02 where I split the construction of PropertySets.
Let me know if this solves this issue (cannot repro).
LikeLike
Hi,
I have tested your last release, and it works perfectly with the DLL you provide with the ZIP.
Great job!!
May I continue asking for a way to export to CSV, please?
LikeLike
You can use -Report to report on individual items, what WhatIf:$True to run the script without removing anything.
Use regular output redirection to output to file; currently no fancy object output to export to CSVs or further processing.
LikeLike
Good news!!! It finally works!
I reverted back to another DLL version (the one in the /bin folder of the Exchange 2016 server).
VERBOSE: Module Microsoft.Exchange.WebServices v15.0.0.0 already loaded
VERBOSE: Module Microsoft.Identity.Client v4.25.0.0 already loaded
VERBOSE: DeleteMode is SoftDelete
Is it possible to have all the result exported to CSV?
As I said, I have to scan and report for 3’000+ mailboxes.
Thank you in advance.
LikeLike
PS: Exchange 2016 CU 21
LikeLike
Hi Thank you so so much for the script. We are migrating from Gsuite to O365 and some mailboxes have duplicated items.
I’ve managed to install the modules and stuff, but when i run the script i got an error.
VERBOSE: Using Exchange Web Services URL https://outlook.office365.com/EWS/Exchange.asmx
VERBOSE: Constructing folder matching rules
WARNING: Cannot bind to MsgFolderRoot: Exception calling “Bind” with “2” argument(s): “The request failed. The remote server returned an error: (401) Unauthorized.”
WARNING: Cannot bind to ArchiveMsgFolderRoot: Exception calling “Bind” with “2” argument(s): “The request failed. The remote server returned an error: (401) Unauthorized.”
VERBOSE: Processing ss@xxx.com finished
Do i need any special authorization on Exchange Online to use this script ?
Thank you
LikeLike
* Basic using -Credential (actively deprecated and perhaps even blocked in your tenant)
* Modern Auth using TenantId, ClientId and one of the following: Secret, CertificateThumbprint, CertificateFile(+CertificatePassword as secure string)
TenantId derives from your tenant; ClientId is assigned when you register the required app (and grant consent) in Azure AD. Some pointers to that at https://eightwone.com/2020/08/05/exchange-online-management-using-exov2-module/
LikeLike
Using the -MessageClass *EnterpriseVault* or even explicit IPM… I’m not seeing any results being deleted. I know I have EV Shortcuts in a specific folder, but the script says there’s 0. Any ideas?
LikeLike
If you are sure they are there, check permissions – it’s more easy to use impersonation as it will bypass any potential blockages due to limits caused by folder permissions.
LikeLike
Already using impersonation. Not sure what else could be wrong.
PS D:\Scripts\Remove-MessageClassItems-master> .\Remove-MessageClassItems.ps1 -Identity EMAIL -Credentials $UserCredential -Impersonation -Server email.point72.com -Verbose -DeleteMode SoftDele
te -MessageClass IPM.Note.EnterpriseVault* -ScanAllFolders –MailboxOnly
LikeLike
Not to ask the obvious, but since you are using BasicAuth, have you configured Application Impersonation permissions for the account you are using with UserCredential, or are you using the credentials from the account owning the mailbox? Note that for on-prem, if it’s the account you logged in with, you can use the UseDefaultCredentials switch.
LikeLike
Hey Michel.
Great script. Works fine, for me, with an On-premises Mailbox.
However, when I try to do the same with an Online Mailbox I get an Error:
VERBOSE: Module Microsoft.Exchange.WebServices v2.2.1.0 already loaded
VERBOSE: Loading module D:\_Users\Richard\PwShFunctions\Remove-MessageClassItems-master\Microsoft.Identity.Client.dll
VERBOSE: Loading module from path ‘D:\_Users\Richard\PwShFunctions\Remove-MessageClassItems-master\Microsoft.Identity.Client.dll’.
Write-Error: D:\_Users\Richard\PwShFunctions\Remove-MessageClassItems-master\Remove-MessageClassItems.ps1:1247
Line |
1247 | Import-ModuleDLL -Name ‘Microsoft.Identity.Client’ -FileName ‘Mic …
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Problem loading module Microsoft.Identity.Client: Assembly with same name is already loaded
Any idea?!
Richard
LikeLike
Any other modules loaded/installed? Seems this might occur when a module doesn’t handle conflicts nicely, and each product team operates independently.
LikeLike
I use a PwSh script to start a ‘clean’ PwSh session. I Only load the ExchangeOnlineManagement Module. (Preview6) and some default ones.
exchangeonlinemanagement
Microsoft.PowerShell.Management
Microsoft.PowerShell.Utility
PSReadLine
LikeLike
Yeah, only PS7 has this issue (can repro). Let me see and get back to you.
LikeLike
Hi Michel, thanks for all the work you’ve put into this already! I’m running into an error in exchange 2016. The syntax I’m using looks like this:
.\Remove-MessageClassItems.ps1 -Identity UPN -MessageClass IPM.Note.EnterpriseVault* -Impersonation -DeleteMode MoveToDeletedItems -Credentials $creds
I’m receiving two errors when I run this-
1. Method invocation failed because [Microsoft.Exchange.WebServices.Data.ExchangeService] does not contain a method named
‘new’.
At C:\Users\username\Documents\Remove-MessageClassItems-master\Remove-MessageClassItems.ps1:1255 char:5
+ $EwsService= [Microsoft.Exchange.WebServices.Data.ExchangeService]::new( $Ex …
2. C:\Users\username\Documents\Remove-MessageClassItems-master\Remove-MessageClassItems.ps1 : Invalid credentials
provided: Method invocation failed because [System.Net.NetworkCredential] does not contain a method named ‘new’.
Any suggestions would be appreciated. I downloaded the repo from GitHub and am running it from within that folder. I’m not sure why it seems to be having a hard time with that Exchange method. Thanks!
LikeLike
Are you running this using PowerShell 5 or later? I believe the new constructor was introduced in PowerShell 5.x and the 2nd error messages looks like an indication you’re running it on a lower version.
LikeLike
Once I moved to a machine using ps 5 everything began working fine. Thanks for the tip!
LikeLike
Great to hear, Dameon!
LikeLike
Hi Michel,
thanks for the Script.
I’ve tried to delete the ItemClass Value IPM.Note.EnterpriseVault.Shortcut and got no errors.
My Problem is, that the Value still exists even after several different runs of the Script.
Now I tried to modify the Value and get the following Error:
Process-Mailbox : Problem modifying item: Exception calling “Bind” with “2” argument(s): “At least one recipient is not valid., The process failed to get the correct properties.”
At C:\Admin\Remove-MessageClassItems-master\Remove-MessageClassItems.ps1:1421 char:33
+ … If (! ( Process-Mailbox -Identity $emailAddress -EwsService $EwsS …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Process-Mailbox
Did you have an Idea, what the problem is?
I’m using the Script with OAuth.
thank you in advance
Felix
LikeLike
Does this only work with on-prem Exchange or can it work with EXO as well?
LikeLike
Both
LikeLike
I can’t seem to get it to work with an EXO mailbox. I keep getting the same error as Dameon when I try to run it using PowerShell 5.1 or higher. I don’t have on-prem mailboxes anymore so I can’t test it with that.
LikeLike
Install the EWS.Managed.API and Microsoft.Identity.Client modules (from NuGet) – see https://eightwone.com/2020/10/05/ews-webservices-managed-api/ Those are tied to .NET versions, so the DLLs on GitHub (with the script’s repository) might not work with your setup.
LikeLike
Hello
Thanks for the scripts .
i would like to use it to remove EV shortcut post migration to exchange online.
i’m occured the following issue.
VERBOSE: Using Exchange Web Services URL https://outlook.office365.com/EWS/Exchange.asmx
VERBOSE: Constructing folder matching rules
WARNING: Cannot bind to MsgFolderRoot: Exception calling “Bind” with “2” argument(s): “The request failed. The remote server returned an error: (401) Unauthorized.”
WARNING: Cannot bind to ArchiveMsgFolderRoot: Exception calling “Bind” with “2” argument(s): “The request failed. The remote server returned an error: (401) Unauthorized.”
The command that i’m launch is:
.\Remove-MessageClassItems.ps1 -Identity $username -MessageClass IPM.Note.EnterpriseVault.Shortcut -DeleteMode MoveToDeletedItems -Impersonation -Verbose -Credentials $credentials -Server outlook.office365.com
I’ve read that maybe i can solve my issue with App Password, but i’m not able to create it.
I know too that basic auth is depreciate since many month.
could you please tell me if there are another solution to clear all EV shortcut after migrate Mailbox to Exchange online ?
Thanks
LikeLike
For EXO, you need Modern Authentication. Credentials is Basic Authentication, which is only for local usage.
For Modern Authentication, you need to register an enterprise app in Azure AD. You need to configure the app with proper permissions (app permission full_access_as_app) and use certificate (can be self-signed) – or if you must Secret – to authenticate. How-to is mostly in the 2nd part of this blog, just use full_access_as_app instead of Exchange.ManageAsApp: https://eightwone.com/2020/08/05/exchange-online-management-using-exov2-module/
Then, run the script with parameters Organization (your tenant ID), AppId (ID of the thing your registered) and one of the following:
– CertificateThumbprint of the certificate to use for authentication (after loading it in your personal certificate store)
– CertificateFile together with CertificatePassword (pfx + password as secret string)
– Secret
LikeLike
Thanks for your quick feedback
I’m trying to run the following command but it return to me an error
.\Remove-MessageClassItems.ps1 -Server outlook.office365.com -Credentials $Credentials -Identity $UserName -DeleteMode MoveToDeletedItems -MessageClass IPM.Note.EnterpriseVault* -CertificateThumbPrint $CertThumb -ClientId $AppID -TenanId $TenantID
Return ==> Remove-MessageClassItems.ps1 : Parameter set cannot be resolved using the specified named parameters.
At line:1 char:1
+ .\Remove-MessageClassItems.ps1 -Server outlook.office365.com -Credent …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Remove-MessageClassItems.ps1], ParameterBindingException
+ FullyQualifiedErrorId : AmbiguousParameterSet,Remove-MessageClassItems.ps1
i don’t know where is my issue
LikeLike
You’re specifying certificatethumb+client+tenant as well as credentials – can only pick one authentication method
LikeLike
I’ve trying to re-run with:
– Only Tenant ID : Same error
.\Remove-MessageClassItems.ps1 -Server outlook.office365.com -Credentials $Credentials -Identity $UserName -DeleteMode MoveToDeletedItems -MessageClass IPM.Note.EnterpriseVault.Shortcut -WhatIf -Verbose -TenantId $TenantID
– Only ClientID : Same Error
.\Remove-MessageClassItems.ps1 -Server outlook.office365.com -Credentials $Credentials -Identity $UserName -DeleteMode MoveToDeletedItems -MessageClass IPM.Note.EnterpriseVault.Shortcut -WhatIf -Verbose -ClientId $AppID
– Only CertificateThumbPrint : Same Error
.\Remove-MessageClassItems.ps1 -Server outlook.office365.com -Credentials $Credentials -Identity $UserName -DeleteMode MoveToDeletedItems -MessageClass IPM.Note.EnterpriseVault.Shortcut -CertificateThumbprint $CertThumb -Report -WhatIf -Verbose
I’ve compare with example in script and i don’t see where i’ve made an mistake..
Could you please giving to me an full example of what i need to add on parameter ?
Thanks
LikeLike
# Modern Auth, certificate in your local certificate store
.\Remove-MessageClassItems.ps1 -Identity michel@contoso.com -MessageClass IPM.Note.EnterpriseVault.Shortcut -TenantId -ClientId -CertificateThumbprint
# Modern auth, certificate in external file
$PfxPwd= ConvertTo-SecureString ‘Hello’ -AsPlainText -Force
.\Remove-MessageClassItems.ps1 -Identity michel@contoso.com -MessageClass IPM.Note.EnterpriseVault.Shortcut -TenantId -ClientId -CertificateFile C:\Temp\MyCert.pfx -CertificatePassword $PfxPwd
# Modern auth, secret
$Secret= Read-Host ‘Secret’ -AsSecureString
.\Remove-MessageClassItems.ps1 -Identity michel@contoso.com -MessageClass IPM.Note.EnterpriseVault.Shortcut -TenantId -ClientId -Secret $Secret
Do *not* specify multiple authentication methods (eg Credentials *and* one of the certificate ones or tenantid or appid), as that will create ambiguity in what authentication method to use.
LikeLike
Many thanks
I’ve test quickly and retester tomorrow
but actually i’ve new error code aith both command :
.\Remove-MessageClassItems.ps1 -Identity $UserName -MessageClass IPM.Note.EnterpriseVault.Shortcut -TenantId ‘xxxxxxxxxxxxxxxxxxx’ -ClientId ‘xxxxxxxxxxxxx’ -CertificateFile .\mycert.pfx -CertificatePassword $CertificatePassword -Server outlook.office365.com -Report -WhatIf -Verbose
.\Remove-MessageClassItems.ps1 -Identity $UserName -MessageClass IPM.Note.EnterpriseVault.Shortcut -TenantId ‘xxxxxxxxxxxxxxxxxxx’ -ClientId ‘xxxxxxxxxxxxx’ -CertificateThumbprint ‘xxxxxxxxxxxxxxx’ -Server outlook.office365.com -Report -WhatIf -Verbose
WARNING: Cannot bind to MsgFolderRoot: Exception calling “Bind” with “2” argument(s): “The request failed. The remote server returned an error: (403) Forbidden.”
WARNING: Cannot bind to ArchiveMsgFolderRoot: Exception calling “Bind” with “2” argument(s): “The request failed. The remote server returned an error: (403) Forbidden.”
or other error code
.\Remove-MessageClassItems.ps1 -Identity $UserName -MessageClass IPM.Note.EnterpriseVault.Shortcut -TenantId ‘xxxxxxxxxxxxxxxxxxx’ -ClientId ‘xxxxxxxxxxxxx’ -Server outlook.office365.com -Report -WhatIf -Verbose -Secret $Secret
WARNING: Cannot bind to MsgFolderRoot: Exception calling “Bind” with “2” argument(s): “Credentials are required to make a service request.”
WARNING: Cannot bind to ArchiveMsgFolderRoot: Exception calling “Bind” with “2” argument(s): “Credentials are required to make a service request.”
LikeLike
Sounds like permission. Make sure your app is configured correctly with correct permissions (full_acces_as_app), Exchange Web Services is allowed as protocol and not blocked for unknown agents, Conditional Access is not blocking, etc.
LikeLike
thanks again for your feedback
i’ve add globaladmin rights on my App Registration this morning
i don’t see any connexion signin log on azure and i can’t exclude app registration from conditional policy.
can i request more help to know where / how i can check and solve the permission issue ?
many thanks
LikeLike
Hi, forget what i’m sayning,
I’ve successfully run your script
Many many thanks for your helps and for the script , it will help me for my job.
LikeLike
Glad you got it working – nowadays it requires a lot of planets which need to be aligned to get things going 🙂
LikeLike
Hi,
I am having issues with script on O365. Comamdn run:
.\Remove-DuplicateItems.ps1 -mailbox me@xxx.com -type mail -Impersonation -DeleteMode MoveToDeletedItems -Retain oldest -Report >> report1.txt -server outlook.office365.com -TenantId xxx -ClientId xxx -secret $secret -Mode full -Verbose
It connects to mailbox successfully, but any folder that contains data throughs the following error:
Processing folder \Inbox
WARNING: Error performing operation FindItems without Search options in Inbox. Error Exception calling “FindItems” with “1” argument(s): “Object reference not set to an instance of an object.”
Folders with no data seem to complete:
Processing folder \Junk Email
VERBOSE: Cleaning unique list (Finished Folder)
Processing folder \Sent Items
VERBOSE: Cleaning unique list (Finished Folder)
Do you have any ideas?
Thanks
LikeLike
Hi Michael, thank you for sharing the script, have been using the dedupe one and it saved alot of headaches!
Do you know if this script can be modified to search for a custom email attribute specifically “Content-Class” and search for a value present there even if null?
Centres around migration issues with EV and another 3rd party MAPI tool which is looking at these values to process mail.
Thanks
Rich
LikeLike
Any suggestions on how to get the script to work when I am getting this:
===
Problem initializing Exchange Web Services using schema Exchange2013_SP1 and TimeZone AUS Eastern Standard Time
At E:\Scripts\Remove-MessageClassItems\Remove-MessageClassItems.ps1:1320 char:9
+ Throw( ‘Problem initializing Exchange Web Services using schema {0} and …
===
Cheers!
LikeLike
Talking against Exchange Online?
LikeLike
Running on Exchange 2016 on-prem
LikeLike
Hello
I am also getting this issue, funny thing is, it was working last week when I came to test it. I am running the the script on an Exchange On Prem 2019 server, the mailboxes live in EXO. This is the command line I am attempting
.\Remove-MessageClassItems.ps1 -Identity my-name@company.mail.onmicrosoft.com -DeleteMode MoveToDeletedItems -MessageClass *EnterpriseVault* -MailboxOnly -Verbose -Server outlook.office365.com -ClientId clientid -TenantId tenentid -Secret $secret
VERBOSE: Module Microsoft.Exchange.WebServices v2.2.1.0 already loaded
VERBOSE: Module Microsoft.Identity.Client v4.25.0.0 already loaded
Problem initializing Exchange Web Services using schema Exchange2016 and TimeZone GMT Standard Time
At C:\TEMP\Remove-MessageClassItems\Remove-MessageClassItems.ps1:1320 char:9
+ Throw( ‘Problem initializing Exchange Web Services using sche …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (Problem initial…T Standard Time:String) [], RuntimeException
+ FullyQualifiedErrorId : Problem initializing Exchange Web Services using schema Exchange2016 and TimeZone GMT Standard Time
The following files live in the folder I am running the script from
Microsoft.Exchange.WebServices.Auth.dll
Microsoft.Exchange.WebServices.Auth.xml
Microsoft.Exchange.WebServices.dll
Microsoft.Exchange.WebServices.xml
Microsoft.Identity.Client.dll
Microsoft.Identity.Client.xml
Any help would be greatly appreciated.
LikeLike