'Powershell proccessing Outlook objects, running out of memory

I've created a script to delete duplicates in large mailboxes.

This mailboxes have many duplicates since we did import of mail archives into those mailboxes.

For that, i want to use group-object cmdlet, to collect all duplicates, than remain only 1 in each group.

But running this line on folder of 50k items (i have mailboxes with folders of 120k items), producing error - "Insufficient memory to continue the execution of the program."

I don't have to bring here the entire script. i tried just those line in the code below, and i got the error after few minuts.

Details:

The command:

$user = '[email protected]'
$outlook = New-Object -com Outlook.Application
$namespace = $outlook.GetNamespace("MAPI")
$mailbox = $namespace.Stores | ? {$_.displayname -like $user}
$global:mailboxRoot = $mailbox.GetRootFolder()

$bb = $mailboxRoot.Folders[1].Items | Group-Object -Property senton, subject

Machine Memory: 32GB

Error output while: outlook memory around 520-550 MB

   WSManConfig: Microsoft.WSMan.Management\WSMan::localhost\Shell

Type            Name                           SourceOfValue   Value                                                                                                                                                          
----            ----                           -------------   -----                                                                                                                                                           
System.String   AllowRemoteShellAccess         GPO             true                                                                                                                                                            
System.String   IdleTimeout                                    7200000                                                                                                                                                         
System.String   MaxConcurrentUsers                             2147483647                                                                                                                                                      
System.String   MaxShellRunTime                                2147483647                                                                                                                                                      
System.String   MaxProcessesPerShell                           2147483647                                                                                                                                                      
System.String   MaxMemoryPerShellMB                            2147483647                                                                                                                                                      
System.String   MaxShellsPerUser                               2147483647 


Solution 1:[1]

The error you received is generated by Outlook, not powershell. The memory limits of Outlook depend on the installed version (2013, O365, 2007, etc.) and whether it is 32-bit or 64-bit. Some ways to improve memory usage are:

  • One problem you've got is that you're storing the entire message item (including the body) in memory. Try selecting only the properties you need.

  • Then group them after the query is done, saving only groups with duplicates

  • For some reason, getting the items and grouping them as one pipeline seemed to cause outlook to balloon in memory usage - maybe it keeps something open too long?

  • And when you've completed your task for that mailbox, it's probably worth closing outlook before starting a new search.

# configure outlook mailbox connection
$user        = '[email protected]'
$outlook     = New-Object -com Outlook.Application
$namespace   = $outlook.GetNamespace("MAPI")
$mailbox     = $namespace.Stores | ? {$_.displayname -like $user}
$mailboxRoot = $mailbox.GetRootFolder()
$StoreID     = $mailboxRoot.StoreID

# search for items, only keep properties you need
$items = $mailboxRoot.Folders.Items | select -First 1000 -Property senton,subject,MessageClass,EntryID

# group found items, only keep duplicates
$grouped = $items|group SentOn,subject|? count -gt 1

# get all "EnterpriseVault" shortcuts in each group
$duplicates = $grouped | foreach { $_.Group | ?{$_.MessageClass -EQ "IPM.Note.EnterpriseVault.Shortcut"} }

# find duplicate messages via ID search (much faster)
foreach ($duplicate in $duplicates) {
  $toDelete = $namespace.GetItemFromID($email.EntryID, $inboxFolderID)
  $toDelete.delete()
}

# Close outlook process
$outlook.Quit()
Get-Process outlook | Stop-Process

That said, this kind of thing should really be done on the email server-side instead of through slow outlook, and slow mapi connection.

Solution 2:[2]

Since my goal is to delete those messages, i'm afraid (correct me if i'm wrong) that finding duplicates from $inbox will not delete the real mail, just the thin copy with the few attributes which placed in $inbox.

In this case, i'll have to find the real message mutch the thin copy, and delete it. considering folder with 100K items, it can take few minutes to find each duplicated mail, like this:

$duplicates = $folder.Items | ?{$_.senton -eq $x.SentOn} | ?{$_.subject -eq $x.Subject}
            if (($duplicates | ?{$_.MessageClass -EQ "IPM.Note.EnterpriseVault.Shortcut"}) -ne $null) {
                if (($duplicates | ?{$_.MessageClass -EQ "IPM.Note.EnterpriseVault.Shortcut"}).count -gt 1) {
                    ($duplicates | ?{$_.MessageClass -EQ "IPM.Note.EnterpriseVault.Shortcut"})[-1].delete()
                } else {
                    ($duplicates | ?{$_.MessageClass -EQ "IPM.Note.EnterpriseVault.Shortcut"}).delete()
                }    
            } else {
                $duplicates[-1].delete()
            }

This is my current code, and i find out that to delete like 10-20k duplicates from each mailbox, can take 2 week. maibe more.

Besides, there is no way to increase the memory available to outlook - if this is the program that running out of memory? I can allocate 25-28 GB of memory for that.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 yosisviva