Script Issue to Empty Deleted Items folder in Outlook

Hi everybody,

I wrote a script to delete the emails from the Deleted Items folder in Outlook, however the script is acting very strange, it does work but it does not delete every single email in that folder, I was trying to debug and it appears that it does not go through all objects in the loop, I saw that adding a Write-Host in the loop, however when I run the script one more time, it does delete another portion of the emails but not all of them, I need to run it some times to get it do delete everything.


$olApp = New-Object -ComObject outlook.application
$namespace = $olApp.GetNamespace("MAPI")

#Get the name space and the Deleted Items folder(the number 3)
$Folder = $namespace.GetDefaultFolder(3)

#Remove the \\ in the string name
$FolderPath = ($Folder.FolderPath).Substring(2,39)
Write-Host ("The items in the mailbox\folder: [$FolderPath] will be deleted.")

#Get all items(emails) from the Deleted Items folder
$Items = ($Folder.Items)

#Display how many items(emails) will be deleted
$Count = $Items.Count
Write-Host ("$Count emails will be deleted.")

#Delete everything
$Items | ForEach-Object {$_.Delete()}

$olApp.Quit | Out-Null
[GC]::Collect()

Any ideas on what I could be missing here ?

I’m not sure what scenario this is (unattended mailbox etc) but why not just turn on the feature in Outlook to empty the deleted items on exit, or if this is an O365 account you can set a retention policy that does the same thing

1 Like

Hey @neemobeer, you got it, was not even aware of that option and was trying to script that, lol. thanks sir.

Hi @neemobeer, I am replying to this again since I actually see the use case better now.

That option that you mentioned only works when I click the “X” to close the Outlook application at the GUI, then I get a pop up to confirm if I’d like to delete all items in the deleted item folder.

However, I created a script to shut everything down on my machine with the flag -Force, if I close the Outlook process by a PowerShell console, that option does not apply and does NOT delete those items.

How do you do that? Please share your code.

Are you sure you’re not simply killing the process? In this case Outlook does not have any chance to clean up on close. :man_shrugging:t3:

An example for Outlook would be:

 Stop-Process -Name OUTLOOK | ForEach-Object {$_.CloseMainWindow()}

I thought using the Method CloseMainWindow would stop the process gracefully, according to this:

Process.CloseMainWindow Method (System.Diagnostics) | Microsoft Learn

Doing some more research about it, it seems this process is a better fit:

process - On Windows, how can I gracefully ask a running program to terminate? - Super User

I tested with Outlook and saw the message to confirm if I wanted to confirm the deletion of the items, now I need to see if there is a way for PowerShell to automatically say Yes on that popup.

Since Stop-Process does not return any output by default there is nothing for Foreach-Object to process. :wink:

And even if you use the parameter -PassThru you will only get an object representing the already stopped process. So nothing you can do about the process anymore. :man_shrugging:t3:

Stop-Process #Outputs

Fair enough Olaf, but that still does not answer my initial question on the post on why the loop is not going through all items:

$Items | ForEach-Object {$_.Delete()}

I needed to make a “workaround” to run the script few times to get everything deleted at once.

<# For some reason that I could not figure it out yet, if I don't use the loop for the script to run multiple times
the loop seems to be stopped in the middle and it does not go through all items in the "$Items | ForEach-Object {$_.Delete()}"
However for now I worked around it using the loop.
#>

$i = 0
while ($i -le 9){
    $i++
    $olApp = New-Object -ComObject outlook.application
    $namespace = $olApp.GetNamespace("MAPI")

    #Get the name space and the Deleted Items folder(the number 3)
    $Folder = $namespace.GetDefaultFolder(3)

    #Remove the \\ in the string name
    $FolderPath = ($Folder.FolderPath).Substring(2,39)
    Write-Host ("The items in the mailbox\folder: [$FolderPath] will be deleted.")

    #Get all items(emails) from the Deleted Items folder
    $Items = ($Folder.Items)

    #Display how many items(emails) will be deleted
    $Count = $Items.Count
    Write-Host ("$Count emails will be deleted.")

    #Delete everything
    $Items | ForEach-Object {$_.Delete()}

    #Times script was processed
    Write-Host ("Script was processed $i time(s)")

    $olApp.Quit | Out-Null
    [GC]::Collect()
}

Cheers!

You want Get-Process not Stop-Process if you want to call the CloseMainWindow method

I actually don’t get why you need to empty your recycle bin that urgently in the first place. Outlook or Exchange will empty it automatically after the time you set up. :man_shrugging:t3: … but that’s my issue. :wink:

It might be for an older version but this could help:

1 Like

The reason you need to loop seems to be that the objects gets deleted from the $items list too which leads to the list index being wrong. Looping backwards should work:

    for ($i=$Count; $i -gt 0; $i--) {
        $Items[$i].Delete()
    }

or actually even

    for ($i=$Count; $i -gt 0; $i--) {
        $Items[0].Delete()
    }

:sweat_smile: