PowerShell Script to Delete Unread Messages

I came across this script online that will delete all unread messages out of deleted items folder that are older than 6 months old.

Const olFolderDeletedItems = 6

 Set objOutlook = CreateObject("Outlook.Application")
 Set objNamespace = objOutlook.GetNamespace("MAPI")
 Set objFolder = objNamespace.GetDefaultFolder(olFolderDeletedItems)

 Set colItems = objFolder.Items
 Set colFilteredItems = colItems.Restrict("[UnRead] = True")

 For i = colFilteredItems.Count to 1 Step - 1
     If DateDiff("m", colFilteredItems(i).ReceivedTime, Now) > 6 Then
         colFilteredItems(i).Delete
     End If
 Next

However, I get the below error message when I try to run. Seems like a syntax issue but cannot sort it out. Any help would be appreciated.

At line:10 char:5
+  For i = colFilteredItems.Count to 1 Step - 1
+     ~
Missing opening '(' after keyword 'for'.
At line:11 char:8
+      If DateDiff("m", colFilteredItems(i).ReceivedTime, Now) > 6 Then
+        ~
Missing '(' after 'If' in if statement.
At line:11 char:22
+      If DateDiff("m", colFilteredItems(i).ReceivedTime, Now) > 6 Then
+                      ~
Missing expression after ','.
At line:11 char:23
+      If DateDiff("m", colFilteredItems(i).ReceivedTime, Now) > 6 Then
+                       ~~~~~~~~~~~~~~~~
Unexpected token 'colFilteredItems' in expression or statement.
At line:11 char:22
+      If DateDiff("m", colFilteredItems(i).ReceivedTime, Now) > 6 Then
+                      ~
Missing closing ')' in expression.
At line:11 char:60
+      If DateDiff("m", colFilteredItems(i).ReceivedTime, Now) > 6 Then
+                                                            ~
Unexpected token ')' in expression or statement.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : MissingOpenParenthesisAfterKeyword
Rammy CharlesSales EngineerAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

QlemoBatchelor, Developer and EE Topic AdvisorCommented:
This is VB Script code, no PowerShell ...
0
Haresh NikumbhSr. Tech leadCommented:
Agreed with Qlemo,

you need to use cscript to execute this VB script

save it as a .vbs format and run it from command prompt

CScript "C:\Name of the script file vbs"
0
QlemoBatchelor, Developer and EE Topic AdvisorCommented:
In PowerShell, it looks like this:
$olFolderDeletedItems = 6

$objOutlook = New-Object -Com Outlook.Application
$colItems = $objOutlook.Session.GetDefaultFolder(olFolderDeletedItems).Items
$colFilteredItems = $colItems.Restrict("[UnRead] = True")

$olddate = (Get-Date).AddMonths(-6)
$colFilteredItems | % {
   if ($_.ReceivedTime -le $olddate)   { $_.Delete()  }
}

Open in new window

0
Making Bulk Changes to Active Directory

Watch this video to see how easy it is to make mass changes to Active Directory from an external text file without using complicated scripts.

Rammy CharlesSales EngineerAuthor Commented:
I am still getting this error message when I try to run.

At line:4 char:50
+ $colItems = $objOutlook.Session.GetDefaultFolder(olFolderDeletedItems).Items
+                                                  ~
Missing ')' in method call.
At line:4 char:50
+ $colItems = $objOutlook.Session.GetDefaultFolder(olFolderDeletedItems).Items
+                                                  ~~~~~~~~~~~~~~~~~~~~
Unexpected token 'olFolderDeletedItems' in expression or statement.
At line:4 char:70
+ $colItems = $objOutlook.Session.GetDefaultFolder(olFolderDeletedItems).Items
+                                                                      ~
Unexpected token ')' in expression or statement.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : MissingEndParenthesisInMethodCall
0
Haresh NikumbhSr. Tech leadCommented:
have you tried Powershell script ? which has given by Qlemo?
0
Rammy CharlesSales EngineerAuthor Commented:
yes, I have. It gives me the above error (see attached).
0
Rammy CharlesSales EngineerAuthor Commented:
0
QlemoBatchelor, Developer and EE Topic AdvisorCommented:
Small typo, but the script can be improved anyway, so:
$objOutlook = New-Object -Com Outlook.Application
$colItems = $objOutlook.Session.GetDefaultFolder('OlFolderDeletedItems').Items

$olddate = (Get-Date).AddMonths(-6).ToShortDateString()
$colItems.Restrict("[UnRead] = True AND [ReceivedTime] <= '$olddate'") |
  % { $_.Delete() }

Open in new window

0
Rammy CharlesSales EngineerAuthor Commented:
Thanks. This seems to work great. However, I noticed that I had to runt it a few times to delete all of the unread emails older than 6 months. Seems like the script would quit before actually completing.

Also, to take this a step further, how can we execute this on a remote machine on the network or in the domain? I am assuming it would entail using the invoke-command?
0
QlemoBatchelor, Developer and EE Topic AdvisorCommented:
The script itself has to run completely on the remote machine - there are no remote commands for any part of the script. So yes, you would have to run the script with Invoke-Command, which again requires you to have set up WinRM on each remote machine to allow connection and execution.
Client OS machines (W7 etc.) do not have WinRM set up by default, server OS do.
The manual way to enable WinRM is to run WinRM quickconfig once on each client.

The script might fail only because of one issue - the sequence of mails. Outlook is very delicate if you try to access moved or deleted mails in an order (that is the reason the VBS code starts with the last mail going towards the first one in the filter list).

This slight variation might help with that, and shows how to execute the code remotely.
Invoke-Command -Computer 'pc1', 'pc2'  -Script {
  $objOutlook = New-Object -Com Outlook.Application
  $colItems = $objOutlook.Session.GetDefaultFolder('OlFolderDeletedItems').Items

  $olddate = (Get-Date).AddMonths(-6).ToShortDateString()
  $filtered = $colItems.Restrict("[UnRead] = True AND [ReceivedTime] <= '$olddate'")
  $filtered |
    % { $_.Delete() }
  }

Open in new window

0
Rammy CharlesSales EngineerAuthor Commented:
Thanks. It still looks like it is taking a few executions to get all of the messages. How can I have the script automatically run 3 or 4 times? Is there a way to loop the job "x" times?
0
QlemoBatchelor, Developer and EE Topic AdvisorCommented:
In that case we should make it failsafe, similar to the original.
Invoke-Command -Computer 'pc1', 'pc2'  -Script {
  $objOutlook = New-Object -Com Outlook.Application
  $colItems = $objOutlook.Session.GetDefaultFolder('OlFolderDeletedItems').Items

  $olddate = (Get-Date).AddMonths(-6).ToShortDateString()
  $filtered = $colItems.Restrict("[UnRead] = True AND [ReceivedTime] <= '$olddate'")
  if ($filtered.Count)
  {
     foreach ($i in $filtered.count..1) { $filtered.Item($i).Delete() }
  }
}

Open in new window

This code could also work, as it processes a copy of the collation instead of the (changing) original collation of search results:
Invoke-Command -Computer 'pc1', 'pc2'  -Script {
  $objOutlook = New-Object -Com Outlook.Application
  $colItems = $objOutlook.Session.GetDefaultFolder('OlFolderDeletedItems').Items

  $olddate = (Get-Date).AddMonths(-6).ToShortDateString()
  $filtered = $colItems.Restrict("[UnRead] = True AND [ReceivedTime] <= '$olddate'")
  foreach ($mail in @($filtered) { $mail.Delete() }
}

Open in new window

0
Rammy CharlesSales EngineerAuthor Commented:
Unfortunately neither of these scripts work.

This is the error message that I get

At line:6 char:34
+   foreach ($mail in @($filtered) { $mail.Delete() }
+                                  ~
Unexpected token '{' in expression or statement.
At line:6 char:33
+   foreach ($mail in @($filtered) { $mail.Delete() }
+                                 ~
Missing closing ')' after expression part of foreach loop.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : UnexpectedToken
0
Rammy CharlesSales EngineerAuthor Commented:
Additionally, is there anyway to do this directly from the Exchange server rather than targeting the Outlook application?
0
Rammy CharlesSales EngineerAuthor Commented:
So I tried executing the below script. It just hangs but does not execute on the remote PC. Any thoughts?

$ComputerName = Read-Host "Type he PC that you want to remove messages from:"
Invoke-Command -ComputerName $ComputerName -Credential (Get-Credential -Credential domain\user) -Script {
$objOutlook = New-Object -Com Outlook.Application
$colItems = $objOutlook.Session.GetDefaultFolder('OlFolderDeletedItems').Items

$olddate = (Get-Date).AddMonths(-1).ToShortDateString()
$colItems.Restrict("[UnRead] = True AND [ReceivedTime] <= '$olddate'") |
  % { $_.Delete() }
  }
0
Rammy CharlesSales EngineerAuthor Commented:
I've requested that this question be closed as follows:

Accepted answer: 0 points for Narvaezj's comment #a40286827

for the following reason:

Closed due to lack of response
0
QlemoBatchelor, Developer and EE Topic AdvisorCommented:
Sorry, didn't receive any notice about your posts.
0
QlemoBatchelor, Developer and EE Topic AdvisorCommented:
Re: http:#a40286033
Yes, there is a syntax error in the second script (a closing paren missing), but you didn't show why the first one should not work. I suppose it only doesn't change the issue with not deleting all mails in one go still.

The second script should be:
Invoke-Command -Computer 'pc1', 'pc2'  -Script {
  $objOutlook = New-Object -Com Outlook.Application
  $colItems = $objOutlook.Session.GetDefaultFolder('OlFolderDeletedItems').Items

  $olddate = (Get-Date).AddMonths(-6).ToShortDateString()
  $filtered = $colItems.Restrict("[UnRead] = True AND [ReceivedTime] <= '$olddate'")
  foreach ($mail in @($filtered)) { $mail.Delete() }
}

Open in new window


Re: http:#a40286048
Using Exchange is totally different. Exchange 2010 has own cmdlets. This is certainly out of scope of this question, as working with the server requires different techniques. As a hint: Search-Mailbox will do that.

Re: http:#a40286827
Probably there is an access issue with the respective mail profile. I forgot that you need to have access to the Outlook session of a particular user - your code is using an admin user, which will not have the profile you search for. But honestly, wanting to run the script remotely is a severe twist in the question - and I doubt it is possible, as the remote session isn't interactive nor has it access to the current user session (AFAIK), and hence to the Outlook if running.

I consider this question answered.

Please ask a new one, about how to do it with Exchange 2010 for particular or all user mailboxes. If you want to perform that action for others, it is the only proper way to do. Describe exactly what you want to do from start, to get sound and effective advise.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Powershell

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.