Removing Messages by Message Class (Updated)

powershellLast version: 1.52, February 17th, 2017.

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:


Now I wouldn’t have started this article if the same thing wasn’t possible with a little bit of scripting against Exchange Web Services and so the script Remove-MessagesClassItems.ps1 was born. Using this script requires Exchange 2007 or later and Exchange Web Services Managed API 1.2 (or later) which you can download here or you can copy the Microsoft.Exchange.WebServices.DLL locally and adjust the DLL path mentioned in the script when necessary. The script has been developed and tested against Exchange 2007, meaning it’s a PowerShell 1.0 script which should be compatible with later versions of PowerShell or Exchange.

Also take notice that since you’ll be processing user mailboxes, you’ll need to have full mailbox access or impersonation permissions; the latter is preferred. For details on how to configure impersonation for Exchange 2010 using RBAC, see this article or check here for details on how to configure impersonation for Exchange 2007.

The script Remove-MessagesClassItems.ps1 uses the following syntax:

Remove-MessageClassItems.ps1 [-Identity] <String> [-MessageClass] <String> [-Server <String>] [-Impersonation] [-Credentials <PSCredential>] [-DeleteMode <String>] [-ScanAllFolders] [-Before <DateTime>] [-MailboxOnly] [-ArchiveOnly] [-IncludeFolders <String[] [-IncludeFolders <String[]>] [-ExcludeFolders <String[]>] [-WhatIf] [-Confirm] [<CommonParameters>] 

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.
  • 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.
  • Credentials specifies the user credentials to use.
  • 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 of at the end to include folders containing or starting with this string, e.g. ‘Projects*’ or ‘*Project*’. Matching is always case-insensitive. You can also well-known folders, by using this format: #WellKnownFolderName#, e.g. #Inbox#. Supported are Calendar, Contacts, Inbox, Notes, SentItems, and Tasks.
  • ExcludeFolders specifies one or more folder(s) to exclude. Usage of wildcards and well-known folders identical to IncludeFolder.

So for 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 process 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, you can use:

$Credentials= Get-Credential
Remove-MessageClassItems.ps1 -Identity -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 Mailbox field. An example of how the CSV could look:


The cmdlet could then be something like:

Import-CSV users.csv1 | Remove-MessageClassItems.ps1 -MessageClass IPM.Note.EnterpriseVault.Shortcut -DeleteMode HardDelete -Impersonation

You’re feedback is welcomed through the comments; if you got scripting suggestions, please use the contact form.

You can download the script from the Technet Gallery here.

Revision History
See TechNet Gallery page.

164 thoughts on “Removing Messages by Message Class (Updated)

  1. Pingback: Removing Messages by Message Class (Updated) | EighTwOne (821) | JC's Blog-O-Gibberish

  2. Michel, I would appreciate to learn more about the migration from EV to Exchange archiving. We are planning on moving from an Exchange 2007/EV 9.0.2 implementation to Exchange 2013 and the road block is the 34TB of data in EV and how best to get it back to exchange. On the plus side, we are not stubbing our emails.

    • Transvault 🙂
      Nb : when you say 34TB is y compressed and duplicated DATA (singleinstanceless) ? Or just the DATA in disk ?

    • Depends on scenario and setup. This customer cut off their archived data (ie isolated, available when required using vendor tools) and will move not (yet) archived mailbox data to the new e-mail environment, facilitating large mailboxes. Otherwise, they’d have to inject the original mail items using the stubs from the archive, but as that data is rarely consulted but has a significant storage footprint, they chose to cut it off.

  3. Fantastic script! This is extremely useful in removing third-party voice mail messages from the Exchange environment. Not being very adept at EWS scripitng(but learning); I’d like to know how would the script be modified to find messages of a specific class older than, let’s say, 45-days?
    (define in base property set and then filter?)

    • The line with “[Microsoft.Exchange.WebServices.Data.ItemSchema]::ItemClass, $MessageClass)” defines the item filter. It’s a single condition; if you want to combine multiple conditions, you need to utilize a SearchFilterCollection where you add all the individual conditions. Then, pass that collection instead of the single condition to FindItems, e.g.

      $ItemSearchFilter1= New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo( [Microsoft.Exchange.WebServices.Data.ItemSchema]::ItemClass, $MessageClass)
      $ItemSearchFilter2= New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsLessThanOrEqualTo( [Microsoft.Exchange.WebServices.Data.ItemSchema]::DateTimeReceived, (Get-Date).AddDays(-45))
      $SearchFilterCollection= New Microsoft.Exchange.WebServices.Data.SearchFilter+SearchFilterCollection([Microsoft.Exchange.WebServices.Data.LogicalOperator]::And);
      $SearchFilterCollection.add( $ItemSearchFilter1)
      $SearchFilterCollection.add( $ItemSearchFilter2)

      Do {
      $ItemSearchResults= $SubFolder.FindItems( $ItemSearchFilterCollection, $ItemView)

      Let me know if there’s more animo for this; I could make item age a parameter of course 🙂

      • Thank you for the prompt reply. When I replace the code to create the SearchFilterCollection..I get an error regarding “New”…seems to run, then remove all messages, not just message class specified. (Of course, working in a test environment)
        [PS] E:\hold\msgclass>.\Remove-MessageClassItems45days.ps1 -Mailbox mbxrestore -MessageClass IPM.Note.Adomo.VM -DeleteMode MoveToDeletedItems -Impersonation -Verbose
        Processing mailbox mbxrestore
        VERBOSE: Loading Microsoft.Exchange.WebServices.dll
        VERBOSE: Set to trust all certificates
        VERBOSE: Using MBX.Restore@xxxxxx.xxxfor impersonation
        VERBOSE: Looking up EWS URL using Autodiscover for
        VERBOSE: Using EWS on CAS
        VERBOSE: DeleteMode is MoveToDeletedItems
        VERBOSE: Removing messages of class IPM.Note.Adomo.VM
        VERBOSE: Processing folder Drafts
        The term ‘New’ is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spellin
        g of the name, or if a path was included, verify that the path is correct and try again.
        At E:\hold\msgclass\Remove-MessageClassItems45days.ps1:166 char:38
        + $SearchFilterCollection= New <<<< Microsoft.Exchange.WebServices.Data.SearchFilter+SearchFilterCollec
        + CategoryInfo : ObjectNotFound: (New:String) [], CommandNotFoundException
        + FullyQualifiedErrorId : CommandNotFoundException

        You cannot call a method on a null-valued expression.
        At E:\hold\msgclass\Remove-MessageClassItems45days.ps1:167 char:35
        + $SearchFilterCollection.add <<<< ( $ItemSearchFilter1)
        + CategoryInfo : InvalidOperation: (add:String) [], RuntimeException
        + FullyQualifiedErrorId : InvokeMethodOnNull

        • Change:

          $ItemSearchFilter= New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo( [Microsoft.Exchange.WebServices.Data.ItemSchema]::ItemClass, $MessageClass)

          Do {
          $ItemSearchResults= $SubFolder.FindItems( $ItemSearchFilter, $ItemView)


          $ItemSearchFilter1= New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo( [Microsoft.Exchange.WebServices.Data.ItemSchema]::ItemClass, $MessageClass)
          $ItemSearchFilter2= New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsLessThanOrEqualTo( [Microsoft.Exchange.WebServices.Data.ItemSchema]::DateTimeReceived, (Get-Date).AddDays(-45))
          $ItemSearchFilterCollection= New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+SearchFilterCollection([Microsoft.Exchange.WebServices.Data.LogicalOperator]::And);
          $ItemSearchFilterCollection.add( $ItemSearchFilter1)
          $ItemSearchFilterCollection.add( $ItemSearchFilter2)

          Do {
          $ItemSearchResults= $SubFolder.FindItems( $ItemSearchFilterCollection, $ItemView)

          • Fantastic! Works perfectly! Thanks so much for your effort. I enjoy your blog and the UC Podcasts.

  4. Pingback: The UC Architects » Episode 22: A Game of Clouds

  5. Fantastic !! Can’t thank you enough. Is it possible to make age as one of the parameters and also parameter to include a specific folder.


  6. Thanks for the script. I am going to try to use it to see if my novice PS skills can change it from deleting items with a specified message class to changing them to a similiar but different message class. If you happen to catch this and have suggestions they would be appreciated.

    Thanks again for your contributions to date.


  7. I found a similar solution using the search-mailbox command. I chose this meathod because I’m not using Exchange Web Services.

    Search-Mailbox -Identity $UserName -SearchQuery “IPM.NOTE.EnterpriseVault.Shortcut” -DeleteContent

    You can test with the following commands.

    This produces a report with the number of hits
    Search-Mailbox -Identity $UserName -SearchQuery “IPM.NOTE.EnterpriseVault.Shortcut” –EstimateResultOnly

    This will search a mailbox, and all hits will be copied to another mailbox. You can look at that mailbox and see exactly what would be deleted if you used the -DeleteContent command.

    Search-Mailbox -Identity $UserName -SearchQuery “IPM.NOTE.EnterpriseVault.Shortcut” -TargetMailbox “TestMB” -TargetFolder “$UserName”

    • Mike,

      sorry to latch on so late, but i’ve tried doing the search way (because i thought it would be faster), but the content detected doesn’t seem to catch everything. I’d like to use search because it’s faster.


  8. Just tried this script today but unfortunately it’s not working for me. In verbose mode I can see it’s processing all the folders, but it didn’t find any e-mails with the class “IPM.Note.EnterpriseVault.Shortcut”.

      • After reading the comment below, I know why it’s not working for me. The stub mail items are all in the archive mailbox. Because the script did show all folders including the ones in the archive mailbox I thought it was also working for the archive. I will use the search-mailbox cmdlet for now. If you include the option to process the archive it will be a great script. Keep up the good work!

  9. This is an awesome script. Thank you so much for taking the time to publish it.

    What if the stub is already in the user’s Personal Archive? Can we use the script to remove stubs that have already been moved to the user’s archive?

  10. Hello Michel,

    when I run the script I get the following. I’m running the script as a Exchange Administrator and I have full mailbox rights on this test account. I doesn’t remove any of the EAS messageClass items.

    [PS] C:\>.\Remove-MessageClassItems.ps1 -Mailbox Training6 -DeleteMode SoftDelete -MessageClass IPM.Note.EAS -ScanAllFolders -verbose
    Processing mailbox Training6
    VERBOSE: Loading Microsoft.Exchange.WebServices.dll
    VERBOSE: Set to trust all certificates
    VERBOSE: Looking up EWS URL using Autodiscover for Training6@****.com
    VERBOSE: Using EWS on CAS https://mail.****.com/EWS/Exchange.asmx
    VERBOSE: DeleteMode is SoftDelete
    VERBOSE: Removing messages of class IPM.Note.EAS
    VERBOSE: Scanning all folders
    VERBOSE: Processing folder Calendar
    VERBOSE: Processing folder Contacts
    VERBOSE: Processing folder Conversation Action Settings
    VERBOSE: Processing folder Drafts
    VERBOSE: Processing folder Inbox
    VERBOSE: Processing folder Journal
    VERBOSE: Processing folder Junk E-Mail
    VERBOSE: Processing folder Notes
    VERBOSE: Processing folder Outbox
    VERBOSE: Processing folder Quick Step Settings
    VERBOSE: Processing folder RSS Feeds
    VERBOSE: Processing folder Sent Items
    VERBOSE: Processing folder Suggested Contacts
    VERBOSE: Processing folder Sync Issues
    VERBOSE: Processing folder Conflicts
    VERBOSE: Processing folder Local Failures
    VERBOSE: Processing folder Server Failures
    VERBOSE: Processing folder Tasks

  11. Great script. Thanks for it. I have a few suggestions that you can take or leave.

    Enhancement Suggestions:
    – Include a parameter to specify the EWS API location of not installed to the default location
    – Include a parameter to run as a desired account to impersonate.
    -Include a parameter to change the default EWS Exchange2007_SP1 config to other versions of Exchange
    + I did this as part of Troubleshooting my issues and it appeared to not be the root cause of the issue. Perhaps this is not required because of it.
    – Provide a parameter to output verbose output to a log file (I know we can pipe it… but it would be nice to have on screen and off screen output)

    Thanks again for the hard work and responsive assistance

  12. Hi,

    I’ve managed to get the script to run without error now (had various syntax issues), but it doesn’t seem to be doing anything. After hitting enter, I just get a line showing ‘>>’ and no further action happens.

    I am trying to permanently remove EV stubs in Exchange 2010:

    .\Remove-MessageClassItems.ps1″ -Mailbox TomU -MessageClass IPM.Note.EnterpriseVault.Shortcut -DeleteMode HardDelete -Impersonation –Verbose

    Any ideas please?

    • You shouldn’t have to edit the script. If you copied/pasted the exact cmdlet, there’s a quote mismatch (the >> means its waiting for more input since you didn’t enter a closing quote). Try this:
      .\Remove-MessageClassItems.ps1 -Mailbox TomU -MessageClass IPM.Note.EnterpriseVault.Shortcut -DeleteMode HardDelete -Impersonation –Verbose

      • My bad, I didn’t edit the script, just the cmdlet. Your amendment now generates an error telling me it is not digitally signed? Appreciate your help.

        File C:\2010\Remove-MessageClassItems.ps1 cannot be loaded. The file C:\2010\Remove-MessageClassItems.ps1 is not digitally signed. The script will not execute on the system. Please see “get-help about_signing” for more details..
        At line:1 char:31
        + .\Remove-MessageClassItems.ps1 <<<< -Mailbox TomU -MessageClass IPM.Note.EnterpriseVault.Shortcut -DeleteMode HardDe
        lete -Impersonation -Verbose
        + CategoryInfo : NotSpecified: (:) [], PSSecurityException
        + FullyQualifiedErrorId : RuntimeException

          • Thanks, getting there…. A whole host of errors now though. Appreciate your time but understand if you have better things to be doing!

            Processing mailbox TomU
            VERBOSE: Loading Microsoft.Exchange.WebServices.dll
            Exception calling “LoadFile” with “1” argument(s): “The system cannot find the file specified. (Exception from HRESULT:
            At C:\2010\Remove-MessageClassItems.ps1:253 char:46
            + [void][Reflection.Assembly]::LoadFile <<<< ( $EwsDll)
            + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
            + FullyQualifiedErrorId : DotNetMethodException

            Unable to find type [Microsoft.Exchange.WebServices.Data.ExchangeVersion]: make sure that the assembly containing this
            type is loaded.
            At C:\2010\Remove-MessageClassItems.ps1:257 char:80
            + $ExchangeVersion= [Microsoft.Exchange.WebServices.Data.ExchangeVersion] <<<< ::Exchange2007_SP1
            + CategoryInfo : InvalidOperation: (Microsoft.Excha…ExchangeVersion:String) [], RuntimeException
            + FullyQualifiedErrorId : TypeNotFound

            New-Object : Cannot find type [Microsoft.Exchange.WebServices.Data.ExchangeService]: make sure the assembly containing
            this type is loaded.
            At C:\2010\Remove-MessageClassItems.ps1:258 char:32
            + $EwsService= New-Object <<<< Microsoft.Exchange.WebServices.Data.ExchangeService( $ExchangeVersion)
            + CategoryInfo : InvalidType: (:) [New-Object], PSArgumentException
            + FullyQualifiedErrorId : TypeNotFound,Microsoft.PowerShell.Commands.NewObjectCommand

            Property 'UseDefaultCredentials' cannot be found on this object; make sure it exists and is settable.
            At C:\2010\Remove-MessageClassItems.ps1:259 char:21
            + $EwsService. <<<< UseDefaultCredentials= $true
            + CategoryInfo : InvalidOperation: (UseDefaultCredentials:String) [], RuntimeException
            + FullyQualifiedErrorId : PropertyNotFound

            VERBOSE: Set to trust all certificates
            VERBOSE: Using for impersonation
            Unable to find type [Microsoft.Exchange.WebServices.Data.ConnectingIdType]: make sure that the assembly containing this
            type is loaded.
            At C:\2010\Remove-MessageClassItems.ps1:270 char:165
            + $EwsService.ImpersonatedUserId= New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Micros
            oft.Exchange.WebServices.Data.ConnectingIdType] <<<< ::SmtpAddress, $EmailAddress)
            + CategoryInfo : InvalidOperation: (Microsoft.Excha…onnectingIdType:String) [], RuntimeException
            + FullyQualifiedErrorId : TypeNotFound

            VERBOSE: Looking up EWS URL using Autodiscover for
            Write-Error : A positional parameter cannot be found that accepts argument 'You cannot call a method on a null-valued e
            At C:\2010\Remove-MessageClassItems.ps1:286 char:28
            + Write-Error <<<< "Autodiscover failed: " $error[0]
            + CategoryInfo : InvalidArgument: (:) [Write-Error], ParentContainsErrorRecordException
            + FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.WriteErrorCommand

          • @Tom: “Using this script requires Exchange 2007 or later and Exchange Web Services Managed API 1.2 (or later) which you can download here or you can copy the Microsoft.Exchange.WebServices.DLL locally and adjust the DLL path mentioned in the script when necessary. “

          • @No need to install; you can install it elsewhere, copy the Microsoft.Exchange.WebServices.DLL in the same location as the script and change the location (in the script) accordingly. Updated version of script will have additional logic to look for that DLL by the way.

          • Me again…. Now I’ve got this far… “Can’t access mailbox information store” ?


            Processing mailbox TomU
            VERBOSE: Loading Microsoft.Exchange.WebServices.dll
            VERBOSE: Set to trust all certificates
            VERBOSE: Using for impersonation
            VERBOSE: Looking up EWS URL using Autodiscover for TomU@xxx
            VERBOSE: Using EWS on CAS https://xxx/EWS/Exchange.asmx
            C:\2010\Remove-MessageClassItems.ps1 : Can’t access mailbox information store
            At line:1 char:31
            + .\Remove-MessageClassItems.ps1 <<<< -Mailbox TomU -MessageClass IPM.Note.EnterpriseVault.Shortcut -DeleteMode HardDe
            lete -Impersonation -Verbose
            + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
            + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Remove-MessageClassItems.ps1

  13. Is it possible to target only one folder? For instance I want to delete the
    IPM.Note.Microsoft.Conversation files from the ConversationHistory folder on 139 mailboxes. I have my csv file ready but I was hoping to avoid running the script against all of the folders in each mailbox.


  14. Hi,

    I wanted to know whether this script will work on a 2013 exchange evironment? i have followed the directions posted in reference to impersonation, but still running into errors whether i excute the script from a CAS or MBX server. I am trying to delete stubs from a legacy email archive solution.


  15. Thanks for this script.. I’m trying to purge EV Shortcuts from a broken EV environment before a mail migration to O365. Script works fine for the most part but for a few users I get the “Can’t access mailbox information store” at line 1 char:31. These are users that are on the exact same mailbox database that users that the script works fine for. Impersonation is set on the account I’m using to run the script and again seems to work for the other users. Size issue? (these are fairly large Exchange 2010 mailboxes) I went so far as to specifically add Full right and send as to these problem mailboxes with no luck

      • Figured it out.. I did a

        get-mailbox -identity “username” | export-csv user.csv -notype

        On the users that were not working and discovered that despite showing as a regular User Mailbox in Exchange 2010 Management Console these mailboxes were apparently Linked Mailboxes. I discovered this by comparing all the properties of the mailboxes that did not work vs the ones that did and discovered that the failing mailboxes had a Linked Maser Account value (I have a very old Exchange environment that originally started as Exchange 5.5 so somewhere along the way during the migrations some mailboxes came across as Linked)

        So I ran

        Set-User -Identity -LinkedMasterAccount $null

        against the failing mailboxes and now the script is working.

  16. Will this work against office 365. I have tried several times without luck. Getting the following error.

    C:\Scripts\Remove-MessageClassItems.ps1 : Can’t access mailbox information store

  17. Pingback: Script Updates | EighTwOne (821)

  18. Hi,

    I’m running the script and it seems to be working great, (both against on prem and cloud users), however on certain users it just stalls out on various folders. They don’t seem to be that large but they just can’t process past them. I’ve run it in verbose but i don’t see anything specific being reported.

  19. I dont think the “before” switch is working, or I am using the wrong format. What format does the -before switch need. Does it need the date that you want all items older than that to be deleted, or is it the number of days before. If it is date, what format do you need date? I tried MM/DD/YYYY and YYYY/MM/DD and it does not work properly with any of those. Or at least it’s not parsing it correctly. See the results below. Using the -before, it is still trying to remove ALL my stubs, not just the ones before the date I have specified. I am running it against an Exchange 2007 SP3 environment in preparation for moving to Exchange 2013 SP1

    [PS] C:\Download>.\Remove-MessageClassItems.ps1 -Mailbox %USERNAME% -MessageClass IPM.Note.MimosaStubmimosa1 -Server cas2.MYDOMAIN.COM -DeleteMode har
    ddelete -Before 2013/06/01 -Verbose
    VERBOSE: Loading C:\Program Files\Microsoft\Exchange\Web Services\2.0\\Microsoft.Exchange.WebServices.dll
    Processing mailbox USERNAME (%USERNAME%@MYDOMAIN.COM)
    VERBOSE: Set to trust all certificates
    VERBOSE: Using Exchange Web Services URL https://cas2.MYDOMAIN.COM/EWS/Exchange.asmx
    VERBOSE: DeleteMode is harddelete
    VERBOSE: PartialMatching is False
    VERBOSE: Removing messages of class IPM.Note.MimosaStubmimosa1
    VERBOSE: Removing messages older than 06/01/2013 00:00:00
    VERBOSE: Scanning all IPF.Note (E-mail) folders
    VERBOSE: Processing folder Deleted Items
    VERBOSE: Processing folder Drafts
    VERBOSE: Processing folder Inbox

    Are you sure you want to perform this action?
    Performing operation “Remove-MessageClassItems.ps1” on Target “Remove 431 items from Inbox”.
    [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is “Y”):

    • The format provided should be in the current locale, e.g. mm/dd/yyyy (it’s of type datetime so you could fit in a time as well). This is evaluated against the item’s Received attribute. To see the expected format, use:
      (Get-Culture).dateTimeFormat | Select *Pattern
      (don’t have Ex2007 at hand, should this be a PoSH 1 quirk, you can run it from system running a more recent version of PoSH – it will run against your mailbox on Ex2007SP1+).

      • I ended up finding out it was an issue with impersonation. When I use impersonation it works fine. I also ran it from a 2012 server running Powershell 3 and the Exchange 2013 tools on it. One additional thing, when it goes to delete the items, it always prompts you to confirm. This is a good thing by and large. But it seems for whatever reason when it calculates the number of items in the inbox, it is more than double what the actual stubbed email count is. Every other folder it seems to be 100% accurate. Can you think of a reason for this, or perhaps it might be a quirk?
        At any rate, I have to compliment you on this and a couple other powershell scripts I have found on your site (the delete duplicate items one), they have saved me a ton of hassle. I was planning on just using managed default folder policy to just delete all emails older than a certain thresshold just to purge the stubs, but this is much more palatable to the end user…

      • Michael, I found another thing I cannot explain. When running the script, it appears to not parse certain mail folders inside certain users mailboxes at all. Nothing special about these folders. I thought it might be a permissions thing, but looking at folder permissions, it seems that there would be nothing inhibiting it. Plus I thought with Impersonation, folder permission should be irrelavent. I could look at something in MFCMapi or PFDavAdmin if you want, but I am not sure what to look for. I did verify the messageclass is identical across all instances, (IPM.Note.MimosaStubMimosa1), so it’s not like some stubs have different message class than others. Every test user I have run this against has similar results. It’s just not hitting all folders.

      • Michael, I think I may have found my problem, let me know if you think. When looking at the script run, I found this text when running in verbose mode: “VERBOSE: Scanning all IPF.Note (E-mail) folders”. This led me to go into MFCMapi and look at the folders not being parsed. It appears none of these folders have the “PR_CONTAINER_CLASS” of IPF.Note. In fact, the folders do not have even have the “PR_CONTAINER_CLASS” field at all. Not just not poplulated, they do not have that attribute at all. For your information, about 80% of my users were migrated to Exchange from Groupwise many years ago, and it’s possible that when these folders were created in Exchange at that time by the (Quest) Migration tool, it created the folders as some odd type? Just throwing this out there. You may or may not have a way to fix this… thanks again.

    • All roads lead to Rome. Yet, that requires Ex2010 or up, EMS or being member of the Discovery Management role group to name a few. There are lots of pre-Ex2010 customers that want to get rid of the stubs before moving data over (On-Prem or ExO). The script is not meant to be a replacement for Search-Mailbox (as indicated in another comment).

    • The search-mailbox command does not exist in Exchange 2007. Just a heads up that there are thousands of customers out there still using Exchange older than 2010. Sometimes Microsoft forgets that. We cant all be bleeding edge.

  20. For those wanting to actually bring their Enterprise Vault archived data to their new environment (Exchange 2010, Exchange 2013, Office 364 or Google Apps for Business), our Archive Accelerator Restore product can do that. (link removed)

  21. Pingback: Remove EnterPriseVault Shortcut Class Message after Office 365 Migration | Microsoft Technologies Blog

  22. Hi Michel,

    Thanks for the script!
    I was using search-mailboxformessageclass.ps1 first, but this one seems easier to use. (especially that you can use the partial parameter)

    I do have a problem however that no emails are found.
    When I run it with the other powershell, it does find results.

    I’m looking in the correct mailbox (not archive)

  23. I Love the script ! Its saved no end of time and effort, its very easy to use and does exactly what it says,

    What it does do though, is if a read reciept had been archived and it removed the reciept stub, Exchange sends an email to sender of message stating that the item was deleted and not read.

    Is there anyway to prevent this happening ?

    This will no doubt generate quite a few bits of confusion on mass mailbox enviroments.

  24. Any other options for processing against multiple mailboxes?
    I’ve tried the imiport-csv option but I get an error that The term ‘Remove-MessageClassItems.ps1’ is not recognized as the name of a cmdlet. I would like to be able to run this on a per database level.

    get-mailboxdatabase | get-mailbox | The term ‘Remove-MessageClassItems.ps1

  25. Getting issue as below…..
    C:\Remove-MessageClassItems.ps1 : Can’t access mailbox information store
    At line:1 char:1
    + .\MessageClass1.ps1 -Mailbox Test1 -MessageClass IPM.Note.Aftermail …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Remove-MessageClassItems.ps1

  26. My comment on the get-mailboxdataBase | removemessageclass was a request. It would be nice to run this on a database level.

  27. Does the script work against Office 365 mailboxes? I have ~200 mailboxes on Office 365 and I get below error when I run the script:
    C:\Scripts\Remove-MessageClassItems.ps1 : A positional parameter cannot be found that accepts argument ‘Exception
    calling “AutodiscoverUrl” with “2” argument(s): “The Autodiscover service couldn’t be located.”‘.
    At line:1 char:1
    + .\Remove-MessageClassItems.ps1 -Mailbox -Messa …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidArgument: (:) [Remove-MessageClassItems.ps1], ParameterBindingException
    + FullyQualifiedErrorId : PositionalParameterNotFound,Remove-MessageClassItems.ps1

    • As already answered through e-mail, check your Autodiscover configuration, DNS entries, firewall settings etc.
      You could bypass Autodiscover process directly specifying the EWS endpoint (using Server parameter), e.g.
      Are you using Hybrid configuration?

  28. Yes this is a Hybrid configuration. As a matter of fact, i have also tried a pure Office 365 tenant, from different location and got excat same error.
    I have used the -server switch with and got “can’t access mailbox information store” error.

    In both cases, i have given a user account that has tenant global admin, Exchange Org Managrnt and impersonation rights (I followed the instructions and assigned the right using the GUI)
    Thanks for your help

  29. Thanks for the script. It ran successfully however as it ran, I received couple undelivered messages which I did not send and also don’t have on my sent items. I tested with another user got the same issue. Any idea, could it be read receipt of unread emails?

  30. Can you provide me a resource as to make this script work. I have no knowledge of scripting with EWS. I have installed the API but all attempts to make it work have failed.

  31. Script runs but doesn’t delete anything. I have tried exact message class name and partialmatching switch with general class name and neither will delete the items from my deleted items.

  32. Folder permissions from Outlook are Default and Anon. – None. Shouldn’t I get an error if I don’t have rights? I will read more into the impersonation.

  33. Hi Michael,

    Thanks for the script. it is working fantastically for most of our mailboxes and folders within it. we are triggering the script from Exchange 2010 and we have exchange 2010 as well as exchange 2013 in our environment.

    We have processed most of the mailboxes and folders within it but suddenly for one of the folder of anyone mailbox we faced following error as shown below. we tried accessing this folder and we could access it. the common thing is that we are facing issue only with mailboxes located in exchange 2013. we have verified personification permission and are good on that side for user credentials being used. also, it is working for all folders except few from exchange 2013. request you to kindly look into it.

    PS>TerminatingError(): “Exception calling “FindItems” with “2” argument(s): “The request failed. The operation has timed out””
    C:\do not delete\remove\Remove-MessageClassItems.ps1 : Can’t access mailbox
    information store

    • Default timeout for EWS operations is 100 sec. Extend that period inserting the following line below “$EwsService.UseDefaultCredentials= $true”:
      $EwsService.Timeout= X
      where X is the timeout in milliseconds
      A ‘timeout’ parameter is on the wishlist.

      • hi Michael,

        Thanks for the suggestions. However, we are facing another issue with the same script. for some folders it prompts the previous error and for some the one that is displayed below.
        I verified on permission side and also tried accessing those folders by logging to users profile by admin account, it is accessible in that way. Any kind of help or suggestions would be helpful. also, any link or blog with in depth information about EWS operations and flow and specifically in regards to this script would be of a great help to us.

        C:\do not delete\remove\Remove-MessageClassItems.ps1 : Can’t access mailbox information store
        At D:\Messaging_ShortcutReport\shrtct_rpt_ForTesting.ps1:9 char:26
        + Import-CSV .\users.csv | .\Remove-MessageClassItems.ps1 -MessageClass IPM.Note.E …
        + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
        + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Remove-MessageClassItems.ps1

        Transcript stopped, output file is C:\Do not delete\remove\ShrtctCounts-09-04-2015.txt


        Rohit M. Dhole

        • just to add that it processed most of the folders very well in this mailbox. However, failed for a specific folder which is different than the todays folder.


          Rohit M. Dhole

            • Yes, permissions are very much in order and so it is working fine with other users and folder on the same server. However, if you want me to verify some permissions please let me know so that I could verify and get back with result.

              • Hi Michael,

                At the beginning of the script I saw another error message, don’t know if it has anything to do with the error. I have given that error below which is related to EWSManagedAPI.

                WARNING: Active Directory server settings remained unchanged.
                Load-EWSManagedAPIDLL : The term ‘Load-EWSManagedAPIDLL’ is not recognized as the name of a cmdlet, function, script
                file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct
                and try again.
                At C:\do not delete\remove\Remove-MessageClassItems.ps1:341 char:5
                + Load-EWSManagedAPIDLL
                + ~~~~~~~~~~~~~~~~~~~~~
                + CategoryInfo : ObjectNotFound: (Load-EWSManagedAPIDLL:String) [], CommandNotFoundException
                + FullyQualifiedErrorId : CommandNotFoundException


                Rohit M. Dhole

                • After making changes in EWS time out as suggested by you, here is the next error.

                  PS>TerminatingError(): “Exception calling “FindItems” with “2” argument(s): “An internal server error occurred. Try again later.””
                  C:\do not delete\remove\Remove-MessageClassItems.ps1 : Can’t access mailbox information store

                  Any help or any pointer would really be of great help !


                  Rohit M. Dhole

      • Hi Michel,

        Thanks a ton for your solution. I believe the first solution for Time Out value worked for me, I am able to complete the reports fluently. it gave above errors and I just increased the Time out value and it started working.

        I am further looking for a script which could help me to remove older data which is older than specific date in a Mailbox.. it would be great if you could guide me to any script which could help me in this case.

        Also, tough the reports are successful. I am getting this error at the beginning of all users information. do we have any workaround to overcome it ?

        $EwsService.Timeout= X
        where X is the timeout in milliseconds
        A ‘timeout’ parameter is on the wishlist.


        Rohit M. Dhole

          • Hi Michel,

            Yes, it is the one time task and need to do on multiple users at a time. so just for one time activity we can’t go ahead and have retention tags and policies for multiple users.

            Also, I pasted the error that I am getting in current script. Thanks for looking into it.


            Rohit M. Dhole

  34. I believe I pasted wrong error,

    Load-EWSManagedAPIDLL : The term ‘Load-EWSManagedAPIDLL’ is not recognized as
    the name of a cmdlet, function, script file, or operable program. Check the
    spelling of the name, or if a path was included, verify that the path is
    correct and try again.


    Rohit M. Dhole

  35. Hello Michael,

    I am wondering when the messages are being deleted from the mailbox, if there is a way to suppress responses to and silently delete delivery receipts/read receipts. I am finding when we remove these messages for any archives messages that had any of these requests tagged a lot of auto responses get generated like “not read: re..” etc


  36. Hi Michel, great script! I am trying to use it to delete stubs from Enterprise Vault old than xx/xx/xxxx and it seems to be working as far as scanning the mailbox, etc. However, no items get deleted as it finds none. I notice that it is not scanning a folder that our PST migration process creates in the mailbox called _Personal Archive. This folder is created directly under the user mailbox such as:
    >_Personal Archive

    I also tried -ScanAllFolders with no luck.

    Am I missing something as to why it wont scan this particular folder? I read through entire blog and comments and didn’t see anything jump out.

    Thanks for any guidance you can provide!!!

  37. Hi Michel,
    we are doing the same migration but i can’t delete anything for now… i need to create a search folder in everyone’s outlook with all the message Class IPM.NOTE.EnterpriseVault.Shortcut in it so the user can clean their own vault.
    can you help me please?

  38. Hi:

    I’m trying to execute this command against a specific database and get an error. The command is

    Get-MailboxDatabase DB_xxx | Get-Mailbox | .\Remove-MessageClassItems.ps1 -Impersonation -Verbose -DeleteMode SoftDelete -MessageClass EnterpriseV
    ault -PartialMatching -ScanAllFolders -Before ((Get-Date).AddDays(-730))

    The error is:
    The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.At line:1 char:79

    Any ideas?



    • The name of the mailbox parameter is mailbox, and you’re not passing that one via Get-Mailbox. Instead, try:
      Get-MailboxDatabase DB_xxx | Get-Mailbox | ForEach { .\Remove-MessageClassItems.ps1 -Mailbox $_.Identity -Impersonation -Verbose -DeleteMode SoftDelete -MessageClass EnterpriseV
      ault -PartialMatching -ScanAllFolders -Before ((Get-Date).AddDays(-730)) }

      • Hi Michel:
        Thanks for your quick response. !!!!That worked¡¡¡¡

        I only had to change $_.Identity for $_.Alias to make it work, as the Identity value has spaces, and Alias does not.

        Thank you very much for your help. It saved me a lot of time

        Best regards


  39. Hi Michel:
    Another tricky question, at least for me…
    Running your script to all mailboxes of a specific database, asks for deletion confirmation for every mailbox it encounters. Is there any way to automate this response (for example A to delete all ítems, etc.) to avoid typing this for every mailbox?

    Thanks for your great Support.


  40. Hi Michel,
    Awesome script. It’s weird that MS decided not to allow this in the “advanced” search applets of Exchange 2013.
    I do have a feature request:
    It is possible to move the items to the deleted items folder, but what I want to do is to export the items to a PST file and remove them. If it was possible to move the items to a random new empty folder, that would be great. If this folder could be located in a different mailbox, that would be even better. Is this something that would be hard to add on?
    Thank you in advance!

    • Exporting to PST yes, as I’m interacting with the mailbox through EWS and have no ‘PST library’ at my disposal. I could create a ‘Duplicates’ folder and dump everything in there; noted on the wish list.

      • Ofcourse, I thought exporting to a PST would be difficult at the least. But moving items to a new seach folder should be straight forward …
        Thank you for putting it on the wish list.

      • Could you give an indication on how much trouble this would be and when you could possibly come around to it, if ever? I apologise for sounding a bit snobby, i don’t mean to be, but we’re kind of in a jam with this being the only option and no EWS expertise or experience…

        Bedankt voor het antwoord alvast!

        • As a work-around, could you not clear out the deleted items folder temporarily, and allow for a “Move to Deleted Items” execution? This would isolate your results into the Deleted Items Folder.

          • This is not an option, users often have good reasons for keeping messages in their Deleted Items Folder (I only have one, but hey …). Also using the Deleted items folder for live data, or actually anything else but junk, makes my techy-sences tingle inappropriately.

  41. I’m no Powershell expert, but I can’t seem to be able output this to a log-file using redirection or piping to an “out-file.”

    Am I missing something easy?

  42. For the record, the following works to pipe the Get-Mailbox command to the script:

    Get-Mailbox -database databasename | select samaccountname | Select-Object @{ expression={$_.samaccountname};label=’Mailbox’ } | .’C:scriptsRemove-MessageClassItems.ps1′ -MessageClass IPM.Note.EnterpriseVault.Shortcut -Confirm:$false -DeleteMode SoftDelete -Verbose -Impersonation -ScanAllFolders -Before ((Get-Date).AddDays(-30))

  43. I am getting this error while deleting the EV shortcuts from Office 365 mailbox:

    Remove-MessageClassItems.ps1 : Can’t access mailbox information store
    At line:1 char:1

    I am running this command:

    .\Remove-MessageClassItems.ps1 -Mailbox -Verbose -DeleteMode MoveToDeletedItems -MessageClass IPM.Note.EnterpriseVault.Shortcut -MailboxOnly -WhatIf -Server

    The account used to run this command has got the Full Access and Impersonation rights on the mailbox. Any help with this will be appreciated a lot.

    Thanks in advance.

      • I do not have mailto in the command which I am running, it’s just when you hover your mouse you get to see that, which is expected, I think. The same command worked on one of my colleague’s machine. I have installed the same version of EWS Managed API, still no go. Will try few more things and keep you updated.

        • Ah, I replied to the notification mail which showed the mailto HTML tag as plain text. Odd. Anyway, cmd looks ok – can’t access information store is usually something with access (permissions). You did specify Credentials, providing credentials with sufficient access?

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

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

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

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

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

  46. 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 -Verbose -DeleteMode MoveToDeletedItems -MessageClass IPM.Notes.EnterpriseVault.Shortcut -ArchiveO
    nly -WhatIf -Server
    VERBOSE: Loading C:\Program Files\Microsoft\Exchange\Web Services\2.2\\Microsoft.Exchange.WebServices.dll
    Processing mailbox (
    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
    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

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

    • As a former programmer, I would say the error is already thrown in a catch block 🙂
      Only thing is I could add $Error to the output, however it’s usually the same one (access denied). Cheers!

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

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s