Wednesday, February 8, 2012

Infinite Loop of Nested Folders


A few weeks ago one user moved a subfolder of her Inbox into another subfolder beneath that one, which triggered the creation of an “infinite” loop of nested subfolders:


I tried to recreate this behaviour but every time I would get the following error (as one would expect):


So I am still not sure how all this happened... Anyway, time to delete those folders! And this is where it got interesting... First thing I tried was obviously to give myself FullAccess permissions to the mailbox and delete the folders myself. However, Outlook returned the following error:


4,000?! Humm... Let’s see how many items are in these folders and how many folders in total. To do this, I used the following two cmdlets (most output removed for simplicity):

[PS] C:\> Get-MailboxFolderStatistics “user” | ? {$_.FolderPath -eq "/Inbox/Pictures of Y"}
Name                              : Pictures of Y
FolderPath                        : /Inbox/Pictures of Y
FolderType                        : User Created
ItemsInFolder                     : 0
DeletedItemsInFolder              : 0
FolderSize                        : 0 B (0 bytes)
ItemsInFolderAndSubfolders        : 0
DeletedItemsInFolderAndSubfolders : 0
FolderAndSubfolderSize            : 0 B (0 bytes)

[PS] C:\> (Get-MailboxFolderStatistics “user”).Count
2922

Ok, so excluding all the default folders and the ones manually created by the user, there’s “only” around 2,890 folders with nothing on them. So why the error about the 4,000 limit?! Time to troubleshoot and get rid of these annoying folders!


Attempt 1
Although I had FullAccess permissions to the mailbox, decided to use ExFolders to grant myself Owner permissions on the top folder and all the subfolders. After almost 1h of propagating the permissions throughout all folders, still got the same error when trying to delete them using Outlook...

Noticed that after trying to delete the folders in Outlook, I would get the following error in the Application log of the Mailbox server (using my account to access the user’s mailbox):
Mapi session "a7198e9f-265f-4e94-b63d-7ee3d78c00c3: /o=domain/ou=exchange administrative group (fydibohf23spdlt)/cn=recipients/cn=motan" exceeded the maximum of 500 objects of type "objtFolder".


Attempt 2
Tried to delete the folders using OWA but a similar result...


Attempt 3
Tried exporting the mailbox to a PST file but it wouldn’t export it because of the folders... The export reaches 100%, then it goes down to 5%, then up again, until it eventually fails.
Tried excluding the top folder from the export using the following cmdlet:

New-MailboxExportRequest "user" -FilePath “\\server\F$\PSTs\user.pst” -ExcludeFolders “#Inbox#/Pictures of Y”

But it still didn’t work. I am not sure if the ExcludeFolders parameter also excludes subfolders or not... Both failed with the following message:
Error: MapiExceptionPartialCompletion: Unable to copy to target. (hr=0x40680, ec=0)
Operation: ISourceFolder.CopyTo
OperationSide: Source
Primary (c0e7ee8d-6f43-430a-b11f-dfba42501ee6)
PropTags: [ContainerContents; FolderAssociatedContents; ContainerHierarchy; DisplayName; RulesTable; 1071710466]


Attempt 4
Tried deleting the folders with MFCMapi but got the following error:


Attempt 5
Tried using Microsoft Exchange Server Information Store Viewer (MDBVU32) but it didn’t work as well. I wasn’t getting any errors and could create and delete other folders, but not the ones I wanted to...

MDBVU32 works “a bit” like MFCMapi. You basically logon and open the Message Store you want to access and then look for the folder (or e-mail) you want to work on.

You then change the operation to DeleteFolder() and click on Call Function... Select the flags you want and then click OK.

In my case nothing would happen for these folders although it would work for any other folders/e-mails...


Attempt 6
Thought about creating another mailbox and simply copy everything across but this would have an impact on the user and the categories wouldn’t be moved, so out of the question for now...


Attempt 7
Changing the type of the folder using MFCMapi:
  • Start MFCMapi with Outlook not set to cached mode;
  •  Logon and display store table;
  • Open mailbox/Top of Information Store;
  •  For an email sub folder that you want to delete;
  • Change PR_CONTAINER_CLASS to IPF.IMAP from IPF.Note;
  • Click OK in the property pane.

 But still the same error when deleting both from MFCMapi and Outlook...


Attempt 8
Isinteg was out of the question as it would take days to run on the DB where the user is and would affect everyone on that DB. So tried moving the mailbox to another DB but it didn’t work... After more than 3h always in 5%, it finally failed with the error (some output removed for simplicity):

Alias                            : user
Status                           : Failed
StatusDetail                     : FailedMAPI
BadItemLimit                     : 5000
BadItemsEncountered              : 0
OverallDuration                  : 04:38:45
TotalFailedDuration              : 03:25:37
TotalQueuedDuration              : 00:00:03
TotalInProgressDuration          : 01:13:04
TotalTransientFailureDuration    : 00:31:19
TotalMailboxSize                 : 1.23 GB (1,320,399,499 bytes)
TotalMailboxItemCount            : 25749
BytesTransferred                 : 0 B (0 bytes)
ItemsTransferred                 : 0
PercentComplete                  : 5
FailureCode                      : -2147024882
FailureType                      : MapiExceptionNotEnoughMemory
FailureSide                      : Source
Message                          : Error: MapiExceptionNotEnoughMemory: Unable to synchronize manifest. (hr=0x8007000e,
                                    ec=1008)
                                   Diagnostic context:
                                       Lid: 55847   EMSMDBPOOL.EcPoolSessionDoRpc called [length=142]
                                       Lid: 43559   EMSMDBPOOL.EcPoolSessionDoRpc returned [ec=0x0][length=739][latency
                                   =46]
                                       Lid: 23226   --- ROP Parse Start ---
                                       Lid: 27962   ROP: ropOpenFolder [2]
                                       Lid: 27962   ROP: ropIncrCfg [112]
                                       Lid: 27962   ROP: ropUpldStStrmBegin [117]
                                       Lid: 27962   ROP: ropUpldStStrmEnd [119]
                                       Lid: 27962   ROP: ropUpldStStrmBegin [117]
                                       Lid: 27962   ROP: ropUpldStStrmEnd [119]
                                       Lid: 27962   ROP: ropUpldStStrmBegin [117]
                                       Lid: 27962   ROP: ropUpldStStrmEnd [119]
                                       Lid: 27962   ROP: ropUpldStStrmBegin [117]
                                       Lid: 27962   ROP: ropUpldStStrmEnd [119]
                                       Lid: 27962   ROP: ropFXSrcGetBufferEx [156]
                                       Lid: 17082   ROP Error: 0x3F0
                                       Lid: 23137
                                       Lid: 21921   StoreEc: 0x3F0
                                       Lid: 27962   ROP: ropExtendedError [250]
                                       Lid: 1494    ---- Remote Context Beg ----
                                       Lid: 1238    Remote Context Overflow
                                       Lid: 7155    StoreEc: 0x3F0
                                       Lid: 7155    StoreEc: 0x3F0
                                       Lid: 7155    StoreEc: 0x3F0
                                       Lid: 7155    StoreEc: 0x3F0
                                       Lid: 7155    StoreEc: 0x3F0
                                       Lid: 7155    StoreEc: 0x3F0
                                       Lid: 7155    StoreEc: 0x3F0
                                       Lid: 7155    StoreEc: 0x3F0
                                       Lid: 7155    StoreEc: 0x3F0
                                       Lid: 7155    StoreEc: 0x3F0
                                       Lid: 7155    StoreEc: 0x3F0
                                       Lid: 7155    StoreEc: 0x3F0
                                       Lid: 7155    StoreEc: 0x3F0
                                       Lid: 7155    StoreEc: 0x3F0
                                       Lid: 7155    StoreEc: 0x3F0
                                       Lid: 7155    StoreEc: 0x3F0
                                       Lid: 7155    StoreEc: 0x3F0
                                       Lid: 7155    StoreEc: 0x3F0
                                       Lid: 7155    StoreEc: 0x3F0
                                       Lid: 7155    StoreEc: 0x3F0
                                       Lid: 7155    StoreEc: 0x3F0
                                       Lid: 6131    StoreEc: 0x3F0
                                       Lid: 22184
                                       Lid: 24312   StoreEc: 0x3F0
                                       Lid: 22360
                                       Lid: 2238    StoreEc: 0x3F0
                                       Lid: 20888
                                       Lid: 24504   StoreEc: 0x3F0
                                       Lid: 24148   StoreEc: 0x3F0
                                       Lid: 23796
                                       Lid: 2478    StoreEc: 0x3F0
                                       Lid: 1750    ---- Remote Context End ----
                                       Lid: 26849
                                       Lid: 21817   ROP Failure: 0x3F0
                                       Lid: 32758
                                       Lid: 16586   StoreEc: 0x3F0
                                       Lid: 22518
                                       Lid: 28874   StoreEc: 0x3F0
                                       Lid: 29516
                                       Lid: 31820   StoreEc: 0x3F0
FailureTimestamp                 : 02/02/2012 10:27:38
FailureContext                   : --------
                                   Operation: ISourceMailbox.EnumerateHierarchyChanges
                                   OperationSide: Source
                                   Primary (c0e7ee8d-6f43-430a-b11f-dfba42501ee6)
                                   Catchup: True


Attempt 9
Already getting desperate, decided to temporarily increase the maximum number of objects that can be handled by Outlook clients by setting both objtfolder and objtfolderview to a value greater than 500 (KB842022 or Maximum open folder objects per logon has been changed).

WARNING: this affects everyone on the mailbox server you set this and it also needs an IS restart so be very careful!!!

As I have a few servers that only host passive DBs, decided to implement the change in one of those servers (I set the registry key value to 3000) and switched over only that DB to that server.
Tried deleting the folders but was getting the same error regarding the 4,000 limit! Not sure why this time... Increased the registry key’s value to 6000 and decided to try again. However, although there were no errors at all on the server, no one could access any mailbox in that server!... Ups! Time to quickly rollback!
Another failed attempt...


Resolution
So how did I fix this problem? Since the beginning that I was thinking about what would happen if I tried to delete the last folder? Because I didn’t feel like expanding almost 3,000 folders (probably for Outlook to complain about the 500 limit!) this had to be done using a script.

Although I love writing scripts, I was avoiding doing this for some reason. But since everything else was failing, I decided to give it a go. And the result was that it worked without any problems!   :-D

I just wanted to quickly try this, so didn’t pay much attention to performance. For this reason, the script is not very efficient because:
it goes through all the folders one by one and then deletes the last one;
starts all over again, goes through all the folders one by one and then deletes the last one;
starts all over again....

In this case it took between 30 to 60 minutes to delete 2,890 folders but it eventually got there!   :)


WARNING: as with every script, make sure you test it properly before running it for a live user!!!


You can also find the script in the Microsoft TechNet Script Repository: Delete Outlook Folders Bottom-Up

# Script: DeleteFoldersBackwards.ps1
# Purpose: This scripts deletes every folder and subfolders for a specific top-folder starting from the last one
# Author: Nuno Mota
# Date:  Feb 2012

[String] $mbxName = "motan@parliament.uk"
[Int] $intCount = 0

[String] $dllPath = "E:\Program Files\Microsoft\Exchange\Web Services\1.1\Microsoft.Exchange.WebServices.dll"
[Void] [Reflection.Assembly]::LoadFile($dllPath)

$Service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP1)
$Service.AutodiscoverUrl($mbxName, {$True})

# This is the root folder from where we want to start searching for the folder we want to delete.
# Once we find it, then we will go recursively down that folder.
# Other option would be to get the FolderID and start the search straight from there
$RootFolderID = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox, $mbxName)
#$RootFolderID = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Root, $mbxName)
$RootFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($Service, $RootFolderID)

$FolderView = New-Object Microsoft.Exchange.WebServices.Data.FolderView(1000)
$FolderView.Traversal = [Microsoft.Exchange.WebServices.Data.FolderTraversal]::Deep
$Response = $RootFolder.FindFolders($FolderView)

# Go through all folders under the Inbox folder looking for the folder we want to delete
ForEach ($folder in $Response.Folders)
{
 # Check if the current folder is the folder we want to delete
 If ($folder.DisplayName -eq "Pictures of Y")
 {
  # Found the folder, so start a new Deep search across all its sub-folders
  $FolderView = New-Object Microsoft.Exchange.WebServices.Data.FolderView(3000)
  $FolderView.Traversal = [Microsoft.Exchange.WebServices.Data.FolderTraversal]::Deep
  $Response = $folder.FindFolders($FolderView)
  $RootFolder = $folder
  
  # Loop to go through all sub-folders while there are any
  While ($($Response.Folders).Count -gt 0)
  {
   # Get the last folder so we can then delete it (not very efficient...)
   ForEach ($folder in $Response.Folders)
   {
    #$folder.DisplayName
    $lastFolder = $folder
   }

   Write-Host "Deleting", $lastFolder.DisplayName
   $lastFolder.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
   $intCount++
   Write-Progress -Activity "Deleting Folders" -Status "Folders Deleted: $intCount"

   $Response = $RootFolder.FindFolders($FolderView)
  }

  # Delete the top folder and exit the first ForEach
  #Write-Host "Deleting Top ""$($RootFolder.DisplayName)"""
  $RootFolder.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
  Break
 }
}

41 comments:

  1. hi nonu... will this script work from win 7?

    i installed exchage web server sdk 1.2 and changed the location in script but getting the below error while running.. any idea.

    Exception calling "AutodiscoverUrl" with "2" argument(s): "The Autodiscover service couldn't be located."
    At C:\users\schauhan30\Desktop\DeleteFoldersBottomUp.ps1:14 char:25
    + $Service.AutodiscoverUrl <<<< ($mbxName, {$True})
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

    Exception calling "Bind" with "2" argument(s): "The Url property on the ExchangeService object must be set."
    At C:\users\schauhan30\Desktop\DeleteFoldersBottomUp.ps1:21 char:65
    + $RootFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind <<<< ($Service, $RootFolderID)
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

    You cannot call a method on a null-valued expression.
    At C:\users\schauhan30\Desktop\DeleteFoldersBottomUp.ps1:25 char:36
    + $Response = $RootFolder.FindFolders <<<< ($FolderView)
    + CategoryInfo : InvalidOperation: (FindFolders:String) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

    ReplyDelete
    Replies
    1. Hi,
      Yes, you can run it from Windows 7! You can also use Remote PowerShell to run cmdlets or scripts remotely on your Exchange servers, but is there a reason why you don’t want to run it on the server?

      Do you have autodiscover configured properly? Try http://www.mikepfeiffer.net/2011/08/testing-exchange-autodiscover-with-powershell-and-the-ews-managed-api/

      Is that workstation on the network and domain?

      Does the account that you’re using to run the script have a mailbox?

      Does the account you are running the script under have FullAccess to the mailbox? Is it an Exchange Admin account?

      Delete
  2. hi Nuno, i tried running script on my lab mailbox server and it worked for my test mailbox and deleted 1 or 2 nested folder, it worked well in lab, but when i tried it in production on effected mailbox it is returning the below error, i could not understand how to work with this error. can you please help.


    Exception calling "Delete" with "1" argument(s): "Object cannot be deleted."
    At C:\Users\jpbn64-xadm\Desktop\tool\deletefolderloop.ps1:49 char:22
    + $lastFolder.Delete <<<< ([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

    ReplyDelete
    Replies
    1. Hi Sunil,

      Sorry to hear it is not working for you.
      Do you know approximately how many subfolders you have?
      For some reason it can’t delete the object... Can you please try the “Attempt 1” I mention on the post (give yourself FullAccess to all the folders) and then try again?
      Does the Write-Host cmdlet prints the folders’ names as expected?

      Regards,
      Nuno

      Delete
  3. I got the same error as Sunil. But when I closed outlook, and therefore the mailbox, the script ran successfully.

    ReplyDelete
    Replies
    1. Glad to know it worked for you, thank you for sharing!

      Sunil, any luck yet?

      Delete
  4. Hello,
    i need to delete some specific user created folders (same level as inbox)
    how can i do this?
    i treid with:

    [String] $mbxName = "cgr"
    #[String] $topFolderName = "Name of Top Folder"
    #[Int] $intCount = 0

    [String] $dllPath = "C:\Program Files\Microsoft\Exchange\Web Services\1.2\Microsoft.Exchange.WebServices.dll"
    [Void] [Reflection.Assembly]::LoadFile($dllPath)

    $Service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP1)
    $Service.AutodiscoverUrl($mbxName, {$True})


    $response = get-mailbox $mbxName | Get-MailboxFolderStatistics -folderscope all | where {$_.name -match "KIS*"} | Select-Object name
    ForEach ($Folder in $Response)
    {
    $Folder
    $folder([Microsoft.Exchange.WebServices.Data.DeleteMode]::SoftDelete)
    Write-Progress -Activity "Deleting Folders" -Status "Folders Deleted: $folder"
    }


    but it wont work :(
    can you help me?

    Regards,

    chris
    chjg24@hotmail.com

    ReplyDelete
    Replies
    1. Hi Chris,

      Your script is completely different than my one, and it is a mix of Exchange cmdlets and EWS, which will never work to be honest...

      First of all, have you tried all the steps I mentioned on this post? For example, deleting the folder using the New-MailboxExportRequest cmdlet or even Outlook? Remember this script is only needed when none of these steps work!

      In your case, all you have to do is change a couple of lines in my script :)
      Regarding the following lines (notice one is commented):

      $RootFolderID = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox, $mbxName)

      #$RootFolderID = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Root, $mbxName)


      which will search only the Inbox folder, you want to delete (or comment) the first $RootFolderID line and uncomment the second $RootFolderID so that you start your search at the root level of your mailbox.

      Then, all you need to do is update the DisplayName so that the script looks for the name of the folder you want to delete:

      If ($folder.DisplayName -eq "Pictures of Y")

      Remember it will delete that folder and everything inside it!


      If you are still having problems, please let me know and I will send you by e-mail the entire script updated to your requirements.

      Regards, Nuno

      Delete
  5. Hi,

    Your script works well. thanks for posting this. I have a one user for which the script does nto work for and throws up the following error.

    Exception calling "Delete" with "1" argument(s): "Object cannot be deleted."
    At D:\tools\EWSEditor\loopdave.ps1:45 char:22
    + $lastFolder.Delete <<<< ([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

    Have you come across this type of error before?

    The script does work for other users including myself, I was able to test this.

    Regards
    David

    ReplyDelete
  6. Hi David,

    Sorry to hear it is not working for that user. Not sure what could be causing it...
    A couple of questions:
    1. Have you tried all the other methods I mentioned in this post first?
    2. Does it delete anything at all?

    Regards,
    Nuno

    ReplyDelete
  7. Thanks. The script works well and did the job.
    May I add that for this line to work you need to download and install exchange web services api from http://www.microsoft.com/en-us/download/details.aspx?id=35371

    ReplyDelete
  8. Also get Exception calling "Delete" with "1" argument(s): "Object cannot be deleted."

    Any ideas?

    ReplyDelete
    Replies
    1. Hi,

      Have you tried all other methods first before running the script?

      Regards, Nuno

      Delete
  9. Hello Nuno,

    I have an issue something similar to this. One of our users had a bizarre mobile sync issue withe activesync and now the user has 1 million Contacts. You read that correctly. :) I have tried search-mailbox cmdlet parameter to search for these contacts and delete them, but the search times out and throws an error. Any way to tweak this script and loop through those Contacts one by one and delete it ? Thanks for any tips or suggestions.

    ReplyDelete
    Replies
    1. Hi,

      “Only” 1 million? Good luck with that! :)
      We could certainly adapt the script as with EWS you can basically do anything in a mailbox! I can’t change/test it at the moment but I can during the weekend if you still need it.
      But I would expect the Search-Mailbox cmdlet to be easier and not timeout... Can you post here the exact cmdlet you are running?
      What about using MFCMapi, no luck?

      Regards, Nuno

      Delete
    2. Hello Nuno,

      I posted the cmdlet and error message. I don't see my post here.

      Delete
  10. I tried mfcmapi and that didn't work. The error I get when using "search-mailbox -identity username -searchquery kind:contacts -deletecontent" is this:

    The search on mailbox CN=username,CN=Users,DC=company,DC=com did not complete because the search folder time
    d out.
    + CategoryInfo : ReadError: (0:Int32) [Search-Mailbox], SearchFolderTimeoutException
    + FullyQualifiedErrorId : 4A6CEE62,Microsoft.Exchange.Management.Tasks.SearchMailbox

    ReplyDelete
  11. Hello Nuno,

    Did you receive my last reply with the cmdlet and error message ?

    ReplyDelete
    Replies
    1. Hi,

      Sorry for the delay but I have been really busy and didn’t have time to change and test the script over the weekend...
      But here it is. The following script will look into the Contacts folder of a particular user and delete the first 250,000 contacts it finds. In your case you can either increase this limit or run the script a few times until all contacts are deleted.
      It doesn’t look for any “subfolders”, only contact items.
      Don’t forget to update $mbxName and $dllPath accordingly.
      Let me know how it goes!

      [String] $mbxName = "nuno@letsexchange.com"
      [String] $dllPath = "C:\Program Files\Microsoft\Exchange\Web Services\2.0\Microsoft.Exchange.WebServices.dll"
      [Void] [Reflection.Assembly]::LoadFile($dllPath)

      $Service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP2)
      $Service.autodiscoverurl($mbxName,{$true})

      $RootFolderID = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Contacts, $mbxName)
      $ContactsFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($Service, $RootFolderID)

      $view = new-object Microsoft.Exchange.WebServices.Data.ItemView(250000)
      $itemsResult = $ContactsFolder.FindItems($view)

      ForEach ($item in $itemsResult.Items)
      {
      #Write-Host "Deleting", $item.DisplayName
      $item.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
      }

      Delete
  12. Hi Nuno,

    Great script and works, mostly :-)

    I have a loop of 2957 folders but the loop starts several folders deep from the TopOfStore.
    I am unable to get your script to delete the loop.

    Any suggestions?

    Thanks
    Brendan

    ReplyDelete
    Replies
    1. Hi Brendan,

      The script will search everything in the Inbox folder for a folder called "Pictures of Y". If your loop happens somewhere inside Inbox, then all you need to do is update "Pictures of Y" to the name of the top folder you want to delete.

      But if I understood you correctly the folder you want to delete is not a subfolder of Inbox. Is this correct? In that case, comment the line:

      $RootFolderID = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox, $mbxName)

      And “un-comment” the following one right beneath it:
      #$RootFolderID = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Root, $mbxName)

      This way the script will search the entire mailbox! Just update "Pictures of Y" and you should be ready to go! :)

      Just make sure you also comment:
      $lastFolder.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)

      So you can check what the script will be deleting before it actually deletes anything :)

      Let me know how it goes!

      Regards, Nuno

      Delete
  13. Hi Nuno,
    Hmmm, little bit strange.

    Correct, the loop is not under the inbox but under another folder several folders deep.
    I have modified the script as suggested and it seems to delete the folders.

    [PS] D:\Tools\EWSEditor>.\DeleteLoop.ps1
    Deleting Pension Payments
    Deleting Pension Payments
    Deleting Pension Payments
    Deleting Pension Payments
    Deleting Pension Payments
    Deleting Pension Payments
    Deleting Pension Payments

    This continues forever even pass the total number of possible folders in the loop.

    But when I check nothing has actually been deleted. If I uncomment out the last statememt from your script
    #$lastFolder.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)

    I receive,

    Deleting Pension Payments
    Exception calling "Delete" with "1" argument(s): "Object cannot be deleted."
    At D:\Tools\EWSEditor\DeleteLoop.ps1:45 char:22
    + $lastFolder.Delete <<<< ([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

    Any further suggestions
    kind regards

    ReplyDelete
  14. Hi Numo,

    Any ideas with this issue? The script works fine on other mail accounts with the nested loop.

    Deleting Benefits&Compensation&Salary
    Exception calling "Delete" with "1" argument(s): "Object cannot be deleted."
    At D:\Tools\EWSEditor\DeleteLoop.ps1:45 char:22
    + $lastFolder.Delete <<<< ([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

    ReplyDelete
    Replies
    1. Hi Brendan,

      So the script works fine on other mailboxes with the same Loop folder, just not on that one? Do other mailboxes have the same number of folders in the "loop"? How did this loop got created in multiple mailboxes?!
      For this one that is not working, did you try the other methods in the post?

      Regards, Nuno

      Delete
    2. Hi Nuno -
      I've tried the numerous attempts above with no luck. So I thought I'd give the EWS script a whirl. I downloaded and installed the API to my Windows 7 machine and also to one of the Exchange servers. I wasn't sure what to do next so, I read the instructions on "Getting Started" (I've never used this tool b4). It appears that I also need Microsoft Visual Studio Project to add the reference of the .dll; its that correct?

      Delete
    3. Nuno -

      I get the following error when trying to run the script in powershell from Exchange SP3:
      [PS] C:\Windows\system32>$RootFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($Service, $RootFolderID)
      Exception calling "Bind" with "2" argument(s): "Connection did not succeed. Try again later."
      At line:1 char:65
      + $RootFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind <<<< ($Service, $RootFolderID)
      + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
      + FullyQualifiedErrorId : DotNetMethodException

      [PS] C:\Windows\system32>$Response = $RootFolder.FindFolders($FolderView)
      You cannot call a method on a null-valued expression.
      At line:1 char:36
      + $Response = $RootFolder.FindFolders <<<< ($FolderView)
      + CategoryInfo : InvalidOperation: (FindFolders:String) [], RuntimeException
      + FullyQualifiedErrorId : InvokeMethodOnNull

      Delete
    4. Hi Cake1896,

      No, you do not need anything else other then the Exchange Web Services Managed API.

      Can you please tell me exactly how you are running the script? The easiest way is to install the API in an Exchange server and run the script from there (don't forget to update the $dllPath variable).

      Regards, Nuno

      Delete
  15. Will this work with Exchange 2007 as I am getting an error?
    I believe this script is for Exchange 2010.

    ReplyDelete
    Replies
    1. Hi Farzana,

      Which method are you referring to, EWS? Did you update the $dllPath and $Service variables? I have not tested this with Exchange 2007 to be honest.

      Best regards, Nuno

      Delete
  16. Hi Nuno,
    Great article...Even I am facing this issue with one of my user, ran the script and I get below errors..Kindly help:

    Exception calling "AutodiscoverUrl" with "1" argument(s): "The Autodiscover service returned an error."
    At C:\scripts\test1.ps1:16 char:25
    + $Service.autodiscoverurl <<<< ("gorais@emc.com")
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

    Exception calling "Bind" with "2" argument(s): "The Url property on the ExchangeService object must be set."
    At C:\scripts\test1.ps1:18 char:65
    + $RootFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind <<<< ($Service, $RootFolderID)
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

    You cannot call a method on a null-valued expression.
    At C:\scripts\test1.ps1:23 char:36
    + $Response = $RootFolder.FindFolders <<<< ($FolderView)
    + CategoryInfo : InvalidOperation: (FindFolders:String) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

    Thanks in advance,
    Manu

    ReplyDelete
    Replies
    1. Hi Manu,

      This error seems to be related to AutoDiscover. Is AutoDiscover working properly? Can you test this using the Test-OutlookWebServices cmdlet?

      You can also try changing:
      $Service.AutodiscoverUrl($mbxName, {$True})

      To:
      $windowsIdentity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
      $sidbind = "LDAP://"
      $aceuser = [ADSI] $sidbind
      $Service.AutodiscoverUrl($aceuser.mail.ToString())

      but I would look into AutoDiscover first.
      Let me know how it goes.

      Best regards,
      Nuno

      Delete
  17. Hi Getting below error:-

    Exception calling "Bind" with "2" argument(s): "The specified object was not found in the store."
    At C:\Temp\DeleteFoldersBottomUp.ps1:21 char:65
    + $RootFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind <<<< ($Service, $RootFolderID)
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

    You cannot call a method on a null-valued expression.
    At C:\Temp\DeleteFoldersBottomUp.ps1:25 char:36
    + $Response = $RootFolder.FindFolders <<<< ($FolderView)
    + CategoryInfo : InvalidOperation: (FindFolders:String) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull


    Below is the start of script I used :-

    # Script: DeleteFoldersBottomUp.ps1
    # Purpose: This scripts deletes every folder and subfolders for a specific top-folder starting from the last one
    # Author: Nuno Mota
    # Date: Feb 2012

    [String] $mbxName = "User@domail.com"
    [String] $topFolderName = "Clients"
    [Int] $intCount = 0

    [String] $dllPath = "C:\Program Files\Microsoft\Exchange\Web Services\2.0\Microsoft.Exchange.WebServices.dll"
    [Void] [Reflection.Assembly]::LoadFile($dllPath)

    $Service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP1)
    $Service.AutodiscoverUrl($mbxName, {$True})

    # This is the root folder from where we want to start searching for the folder we want to delete.
    # Once we find it, then we will go recursively down that folder.
    # Other option would be to get the FolderID and start the search straight from there
    $RootFolderID = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox, $mbxName)
    #$RootFolderID = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Root, $mbxName)
    $RootFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($Service, $RootFolderID)

    $FolderView = New-Object Microsoft.Exchange.WebServices.Data.FolderView(1000)
    $FolderView.Traversal = [Microsoft.Exchange.WebServices.Data.FolderTraversal]::Deep
    $Response = $RootFolder.FindFolders($FolderView)

    Total 989 folders are there.... The folder is under Inbox...

    Pls help...

    ReplyDelete
    Replies
    1. Hi Amit,

      Try giving the account you are using to run script FullAccess permissions to the user's mailbox using the Add-MailboxPermission cmdlet.
      Let me know if it helps.

      Best regards,
      Nuno

      Delete
  18. Full mailbox perms were missing...Now it worked fine... Thanks Nuno...

    ReplyDelete
    Replies
    1. Excellent, glad to hear that! :)

      Regards, Nuno

      Delete
  19. I have had this twice now and really would like to know why it happens.

    Both occasions I exported the mailbox to a PST (Attempt 3) then removed the mailbox and created a new one not forgetting to change the legacyExchangeDN setting on the new mail account. If you dont do this people replying will get a bounced email.

    Once the PST was exported I was able to scan and repair the PST with SCANPST.

    When the PST opened in Outlook I was able to remove the offending folder then import the PST into Exchange.

    ReplyDelete
  20. An interesting account, and one I'm almost tempted to reproduce myself, just for fun. But did you ever try right-clicking the folder in Outlook, and selecting the Empty Folder option? I'm wondering if this would initiate a different kind of process that would circumvent the item count limits?

    ReplyDelete
    Replies
    1. Hi Lee,

      Yes, I tried a million and one things before writing that script, but nothing other than the script worked!...

      Delete
  21. I tried the script but it did not work. However I was able to able to delete the 938 nested folder tree with MFCMAPI as follows:
    I went partially down the nested folder tree. With right-click, I selected Display hierarchy table (yes= check box to pass convenient_depth). You may have to do this several times. Finally the hierarchy table lists all the folders in a flat hierarchy. Next, I went down near the bottom (maybe 50-100 folders above the last one) and with another rt-click chose "open item". Then with right-click, I chose the "Delete folder" option and because I was close enough to the innermost folder all subfolders below my current node were deleted. I repeated these step till the topmost folder of my 938 recursive folders were deleted. -Elsa Braun

    ReplyDelete
    Replies
    1. Hi Elsa,

      Thank you very much for the tip! Glad you were able to resolve the issue and delete all folders.

      Regards,
      Nuno

      Delete