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.
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
Superb thank you so much for your hard work. This works really well for our recently moved users to O365 using REST and automation – with a Service Principal created in O365 (App Registration) – and granted the correct rights, using a self signed Certificate. This has just made our migration project so much easier. Thank you
LikeLike
Hi Michael, thank you for sharing the script. We are using On Prem Exchange 2019 server, and we get an error with the schema.
+ FullyQualifiedErrorId : Problem initializing Exchange Web Services using schema Exchange2016
Do you have any plans to update the script for Exchange 2019 schema ?
Thanks !
LikeLike
HI
I am getting the below error, what can be wrong?
[PS] C:\Remove-MessageClassItems-master>.\Remove-MessageClassItems.ps1 -Identity ahmad.khattab@dar.com -Verbose -DeleteMode MoveToDeletedItems -MessageClass IPM.Note.EnterpriseVault.Shortcut -Report -WhatIf -Credentials $Credentials -Debug
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 darbeirut\amkhattab
VERBOSE: DeleteMode is MoveToDeletedItems
VERBOSE: Removing messages of class IPM.Note.EnterpriseVault.Shortcut
Processing mailbox ahmad.khattab@dar.com (ahmad.khattab@dar.com)
VERBOSE: Looking up EWS URL using Autodiscover for ahmad.khattab@dar.com
VERBOSE: Using EWS endpoint https://owa.dar.com/EWS/Exchange.asmx
VERBOSE: Constructing folder matching rules
VERBOSE: Detected Exchange Server version 15.2.1118.21 (V2017_07_11, requested schema Exchange2013_SP1)
VERBOSE: Processing primary mailbox ahmad.khattab@dar.com
VERBOSE: Collecting folders to process
C:\Remove-MessageClassItems-master\Remove-MessageClassItems.ps1 : Cannot access mailbox information store for ahmad.khattab@dar.com: Exception setting “PropertySet”: “Cannot convert the
“Microsoft.Exchange.WebServices.Data.PropertySet” value of type “Microsoft.Exchange.WebServices.Data.PropertySet” to type “Microsoft.Exchange.WebServices.Data.PropertySet”.”
At line:1 char:1
+ .\Remove-MessageClassItems.ps1 -Identity ahmad.khattab@dar.com -Verb …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Remove-MessageClassItems.ps1
LikeLike
Hello!
I am so glad I found your script but I am running into an issue when trying to run it and it seems to be permission related.
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 domain\orgainization management role account
VERBOSE: DeleteMode is HardDelete
VERBOSE: Removing messages of class IPM.Note.EnterpriseVault.Shortcut
Processing mailbox username@domain.com (username)
VERBOSE: Using username@domain.com for impersonation
VERBOSE: Using Exchange Web Services URL https://servername.domain.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: username@domain.com finished
LikeLike
Check permissions, eg use an app, use cert/secret to authenticate together with tenant and app id, grant the app ManageAsApp (delegate won’t work) and give admin consent
https://learn.microsoft.com/en-us/powershell/exchange/app-only-auth-powershell-v2?view=exchange-ps#set-up-app-only-authentication
Also check you have not disabled EWS protocol etc. Azure sign-in logs might provide hints when filtering on the app you created to this purpose.
LikeLike