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

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.)


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

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

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") |

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")

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:


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

Comments (5)

  1. Anonymous says:

    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:scriptsExchange ScriptsCreateNewFoldersInOutlook.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 OfficeOffice14 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!

  2. Anonymous says:

    Hey Scripting Guy, i need your help on how to move emails from Folder A to Folder B , then delete folder A

    Please Help

  3. jrv says:

    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

  4. Simon Jackson says:

    How to you execute the $namespace.Logon method – passing the correct parameters in?
    Having read and tried this (http://msdn.microsoft.com/en-us/library/office/ff861594(v=office.14).aspx), I cannot get this working in powershell!

    I can read mailboxes, pull back lists of folders and inbox items, even calendars and message rules (inc Out of Office Rule[0]).

    Can you help?

  5. Thom Lamb says:

    How do you add a PowerShell script as the "Action" of a server side rule? There are options for "Applicaiton", "Script", and "Custom Action"; none of these support the the use/selection of a PowerShell script.

Skip to main content