Removing Messages by Message Class

powershellLast 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.:

StubsOutlook

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:

SearchFromOutlook

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

SampleOutput

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.

This entry was posted in Exchange Server and tagged , , , by Michel de Rooij. Bookmark the permalink.
Unknown's avatar

About Michel de Rooij

Michel de Rooij, with over 25 years of mixed consulting and automation experience with Exchange and related technologies, is a consultant for Rapid Circle. He assists organizations in their journey to and using Microsoft 365, primarily focusing on Exchange and associated technologies and automating processes using PowerShell or Graph. Michel's authorship of several Exchange books and role in the Office 365 for IT Pros author team are a testament to his knowledge. Besides writing for Practical365.com, he maintains a blog on eightwone.com with supporting scripts on GitHub. Michel has been a Microsoft MVP since 2013.

277 thoughts on “Removing Messages by Message Class

  1. 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.)?

    Like

    • 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”

      Like

        • 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).

          Like

    • 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.

      Like

  2. 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

    Like

  3. 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!

    Like

    • 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!

      Like

  4. 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

    Like

  5. 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

    Like

    • 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.

      Like

      • 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

        Like

        • 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

          Like

          • 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

            Like

          • 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

            Like

          • i tried with .\ as well and gives me same error, very weird, must be something on our side i will need to investigate further

            Like

          • 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 }

            Like

  6. 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?

    Like

    • 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!

      Like

  7. 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?

    Like

  8. 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?

    Like

        • 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.

          Like

      • 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.

        Like

          • 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.

            Like

  9. 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” ?

    Like

      • 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.

        Like

  10. 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.

    Like

      • 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”

        Like

        • 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.

          Like

          • 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 😦

            Like

          • Yes, from both PS ISE and a regular PS prompt, too, both as Adminstrator, as well as just opening the shell without admin.

            Like

  11. 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.

    Like

  12. 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

    Like

  13. 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*\*

    Like

  14. 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?

    Like

  15. 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.

    Like

    • 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.

      Like

      • 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.

        Like

  16. 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?

    Like

  17. 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

    Like

  18. 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

    Like

  19. 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.

    Liked by 1 person

  20. 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

    Like

  21. Pingback: Remove EnterPriseVault Shortcut Class Message after Office 365 Migration | Tech Wizard

  22. 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

    Like

  23. 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

    Like

    • 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.

      Like

  24. 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.

    Like

    • 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.

      Like

      • 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.

        Like

          • 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

            Like

          • 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

            Like

          • 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?

            Like

          • 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.

            Like

          • 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.

            Like

  25. 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

    Like

  26. 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?

    Like

      • 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

        Like

        • 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.

          Like

  27. 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

    Like

  28. 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!

    Like

  29. 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

    Like

  30. 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

    Like

    • 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

      Like

      • 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

        Like

          • 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

            Like

          • # 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.

            Like

          • 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.”

            Like

          • 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.

            Like

          • 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

            Like

          • 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.

            Like

  31. 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

    Like

  32. 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

    Like

  33. 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!

    Like

        • 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.

          Like

  34. 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

    Like

  35. 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 !

    Like

  36. 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

    Like

  37. 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

    Like

Leave a reply to Ahmad Cancel reply