Hey, Scripting Guy! How Do I Use Windows PowerShell to Work with Junk E-Mail in Office Outlook?

Hey, Scripting Guy! How Do I Use Windows PowerShell to Work with Junk E-Mail in Office Outlook?

  • Comments 3
  • Likes

Hey, Scripting Guy! Question

Hey, Scripting Guy! I need to find out how many e-mail messages are in my Junk folder. I found a script that does this with VBScript, but I need to be able to do it in Windows PowerShell. I do not want to delete the junk e-mail, because there are times when it is not junk. But because Office Outlook automatically moves e-mail to the Junk folder, users are often not aware they could have a considerable number of messages marked as junk. Can you help me?

- EC

SpacerHey, Scripting Guy! Answer

Hi EC,

It is Monday morning, and I have just finished answering all the scripter@microsoft.com e-mail messages (about 65 e-mail messages just this morning) and nearly a dozen of them were dealing with Office Outlook. Yours caught my eye. You know, I am glad you have been trolling around in the "Hey, Scripting Guy!" archives. It makes me feel that what I write will not end up in the bottom of virtual parrot cages. The good thing about scripting Office Outlook is that the object model is basically the same whether you are using Windows PowerShell or VBScript. This means that ideas you find in VBScript can be easily translated to Windows PowerShell, and vice versa.

This week we are looking at scripting Office Outlook. Interestingly enough, the Office Outlook object model is not as rich as you might suspect. Certainly Office Word and Office Excel have far more capability for automation than Office Outlook. This having been said, a basic familiarity with Office Outlook automation can lend rich results for the enterprising network administrator, consultant, or power user.

If you are interested in VBScript examples of working with Office Outlook, start with the "Hey, Scripting Guy!" archive, and then move on to the Office Space archive. Finally, you would probably like to see some examples of scripts for automating Office Outlook. You are in luck here because we have dozens of well-written scripts in the Community-Submitted Scripts Center. Read on, this is going to be a cool week. If you need help with Windows PowerShell, you can find download links and getting started information in the Windows PowerShell technology hub.

If you want to find out how many e-mail messages you have in the Junk folder of Office Outlook, you can use the CountItemsInJunkFolder.ps1 script. (Amazing that such a cool script has such a short name. Like I said, it is Monday morning. I'm on my second pot of English Breakfast tea. Don't worry though; I wrote the script last Friday.)

CountItemsInJunkFolder.ps1

[Reflection.Assembly]::LoadWithPartialname("Microsoft.Office.Interop.Outlook") | 
out-null
$olFolders = "Microsoft.Office.Interop.Outlook.OlDefaultFolders" -as [type]
$outlook = new-object -comobject outlook.application
$namespace = $outlook.GetNameSpace("MAPI")
$folder = $namespace.getDefaultFolder($olFolders::olFolderJunk)
$folder.items.count

The first thing we want to do is to load the Microsoft.Office.Interop.Outlook assembly. (Dude, why do we want to do that? I mean, it is Monday after all.) We do not really need to load the Microsoft.Office.Interop.Outlook assembly, but doing so will give us a nice advantage, and it is simply cool that we can do such a thing. In VBScript, one of the hardest things to find was what was called enumeration values. These things are the magic numbers. You would find them casually sneaking around near the beginning of various VBScripts. Many of the e-mail messages we receive include some variation of the question, "Where did you find that number?" Enumeration values are constants that are created by the developers who wrote the application. In other programming languages, you would set a reference to a particular library, and voila you have access to the enumeration constants. Knowing these constant values is often the key to understanding the code samples we see on MSDN. VBScript does not have access to these enumerations, so a common practice—indeed a best practice—is to create a constant with the name of the enumeration and set its value to the value you discovered via MSDN. The problem with this approach is that at times it can be a major pain (or sometimes even a 5-star general pain) to identify the numeric equivalent of an enumeration. Here is an example from the VBScript you referred to in your e-mail of setting the Office Outlook Junk folder enumeration:

Const olFolderJunk = 23

Did you ever wonder why we Microsoft Scripting Guys created such stupid looking constant names? I mean, jeez, if we go to the trouble of creating a constant, couldn't we at least give it something easy to type like JunkFolder or simply Junk? The reason we use these constant names is they are the actual enumeration names. This is good news. You can search MSDN for olFolderJunk and come up with the olDefaultFolders enumeration (number one hit on Live.com). You might not have known that was the enumeration name, but it is easily discoverable via a quick MSDN search.

To load the Microsoft.Office.Interop.Outlook interop assembly, we need to use the static LoadWithPartialName method from the Reflection.Assembly .NET Framework class. Static methods are methods that are always available and are called in Windows PowerShell by using double colons instead of the normal period. When loading the Microsoft.Office.Interop.Outlook assembly, it produces feedback that tells you the assembly has been loaded. This is seen here:

PS C:\> [Reflection.Assembly]::LoadWithPartialname("Microsoft.Office.Interop.Out
look")

GAC    Version        Location
---    -------        --------
True   v1.1.4322      C:\Windows\assembly\GAC\Microsoft.Office.Interop.Outlo... 

To avoid that distraction, we pipeline the results to the Out-Null cmdlet:

[Reflection.Assembly]::LoadWithPartialname("Microsoft.Office.Interop.Outlook") | 
out-null

After we have loaded the assembly, we have access to the enumerations. We can even peruse the enumeration names by using the static method GetNames from the [enum] .NET Framework class:

PS C:\> [enum]::GetNames("Microsoft.Office.Interop.Outlook.OlDefaultFolders")
olFolderDeletedItems
olFolderOutbox
olFolderSentMail
olFolderInbox
olFolderCalendar
olFolderContacts
olFolderJournal
olFolderNotes
olFolderTasks
olFolderDrafts
olPublicFoldersAllPublicFolders
olFolderConflicts
olFolderSyncIssues
olFolderLocalFailures
olFolderServerFailures
olFolderJunk
olFolderRssFeeds
olFolderToDo
olFolderManagedEmail

We want to have access to the enumerations. To do this, we use the as operator to cast the string "Microsoft.Office.Interop.Outlook.OlDefaultFolders" into a type. This is a very powerful technique and is seen here:

$olFolders = "Microsoft.Office.Interop.Outlook.OlDefaultFolders" -as [type] 

We did not need to do all that work, but by doing so we are taking advantage of one of the great aspects of Windows PowerShell. In many cases, when you are unable to find out the value of an enumeration, remembering these techniques can save many hours of frustration.

Now we want to create an instance of the Outlook.Application object. This is the main object we use when automating Office Outlook. There is documentation on MSDN for each version of Office Outlook. I am using documentation for Office Outlook 2007 because it absolutely rocks and works so much better on my laptop than previous versions. For this script, there are no differences between the Office Outlook 2007 object model and previous versions. But as a best practice and to avoid frustration, you should always consult the version of the documentation that applies to your specific version of Office Outlook.

The Outlook.Application object is a COM object, and we use the comobject parameter with the New-Object cmdlet. We store the returned instance of the object in the $outlook variable:

$outlook = new-object -comobject outlook.application

We can use the GetNameSpace object after we have created an instance of the application object. The GetNameSpace takes a single argument, which is the name of the namespace to connect to. There is only one allowed value for this—MAPI. This is documented on MSDN. The command is shown here:

$namespace = $outlook.GetNameSpace("MAPI")

After we have created our Namespace object, we use the GetDefaultFolder method to connect to the Junk folder in Office Outlook. The Namespace object is documented on MSDN. We store the returned folder object in the $folder variable:

$folder = $namespace.getDefaultFolder($olFolders::olFolderJunk)

We now need to count the number of items that are in the Junk folder. To do this, we use the count property:

$folder.items.count

The output from the script will simply display the number of items in the Junk folder. We did not even bother to add any verbiage to the output, but you can easily do that if you wish.

Well, EC, that is it for today's script. Sorry for the lack of pretty pictures today. I did think about using a picture of a parrot fish I took while I was scuba diving in Aruba, but like I said it is Monday and it is cold here in Charlotte, North Carolina, USA. I am going to go grab a bowl of chili the Scripting Wife made and play around some more with scripting Office Outlook. See you tomorrow. Stay warm.

 

Ed Wilson and Craig Liebendorfer, Scripting Guys

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Hey Scripting Guy, i need your help on how to move emails from Folder A to Folder B , then delete folder A

    Please Help

  • Okay, this is very frustrating as no one can give me an answer to this. When I try the above script, or any script that uses the following lines:

           $Outlook = new-object -Com Outlook.Application

    $Namespace = $Outlook.GetNamespace("MAPI")

    I get the following error:

        Exception calling "GetNamespace" with "1" argument(s): "Unable to cast COM object of type 'Microsoft.Office.Interop.Out

        look.ApplicationClass' to interface type 'Microsoft.Office.Interop.Outlook._Application'. This operation failed because

        the QueryInterface call on the COM component for the interface with IID '{00063001-0000-0000-C000-000000000046}' failed

        due to the following error: Error loading type library/DLL. (Exception from HRESULT: 0x80029C4A (TYPE_E_CANTLOADLIBRARY))."

        At C:\scripts\Exchange Scripts\CreateNewFoldersInOutlook.ps1:14 char:36

        +     $Namespace = $Outlook.GetNamespace <<<< ("MAPI")

            + CategoryInfo          : NotSpecified: (:) [], ParentContainsErrorRecordException

            + FullyQualifiedErrorId : DotNetMethodException

    I have copied the Microsoft.Office.Interop.Outlook.dll froma Visual Studio workstation into my C:\Program Files (x86)\Microsoft Office\Office14\ directory. No luck.

    I have tried to include the [Reflection.Assembly] in my code. No luck.

    I have searched my registry and found the COM component referenced and it is in my registy. The only weirdness I have is that I am running Windows 7 Enterprise w/SP1 for 64-bit with the Office 2010 for 32-bit. We have to do this for some compatibility reasons with other software.

    Any help you can provide would be greatly appreciated!

  • Will Smothers -HI. This is really not a hel forum but a bit of help;

    The Interop has to be theone deieverd with teh vrion of Office you are running.  Install it from the CD/DVD using the office installer.  It s a optional install.

    For further assistance try the cripting Guy's forum: social.technet.microsoft.com/.../ITCG