Accessing non-default calendar in Outlook 2010 from PowerShell code RRS feed

  • Question

  • Hi,

    I'm trying to write a PowerShell script that will detect and remove duplicates in a non-default Outlook 2010 calendar.

    I understand I need to navigate the available calendars to find the one I want, as described in

    I'm trying to get a CalendarModule instance (getting inspiration from as follows:


    Add-Type -assembly "Microsoft.Office.Interop.Outlook"
    $Outlook = New-Object -comobject Outlook.Application
    # Ensure we are logged into a session
    $session = $outlook.Session

    [Microsoft.Office.Interop.Outlook.CalendarModule] $module = $outlook.Application.ActiveExplorer().NavigationPane.Modules.GetNavigationModule([Microsoft.Office.Interop.Outlook.OlNavigationModuleType]::olModuleCalendar)


    but all I get is:

     Cannot convert the "Microsoft.Office.Interop.Outlook.NavigationModuleClass" value of type
    "Microsoft.Office.Interop.Outlook.NavigationModuleClass" to type "Microsoft.Office.Interop.Outlook.CalendarModule".

     It seems GetNavigationModule() returns an instance of NavigationModuleClass, not of NavigationModule.

    What's wrong in my reasoning / code?

    P.S. if this is the wrong place to ask, and there's a better place to ask questions about Outlook automation (from PowerShell or using the PIA) just do redirect me there.

    • Edited by sba923 Saturday, July 6, 2013 8:01 AM
    • Moved by Bill_Stewart Sunday, December 29, 2013 2:07 PM Moving to more appropriate forum
    Saturday, July 6, 2013 7:57 AM

All replies

  • Why are you typing the return. PowerShell will return the type correctly.  This is not a compiled language.

    The use of these constructs as a carry over from C# is a bad habit that accomplishes nothing.  Don't do it.

    Do not use Logon() - this is automatic with  Outlook.

    This is all of the code that you have that is meaningful.

    $outlook = New-Object -comobject Outlook.Application
    # next line is pointless and will cause excess references
    $session = $outlook.Session
    # do not use type declaration (cast)
    Of course none of this will get you anything useful. What, exactly, is it you are trying to do?


    • Edited by jrv Saturday, July 6, 2013 12:12 PM edit
    Saturday, July 6, 2013 12:12 PM
  • I had started using the COM object approach, but thought using PIA throughout would be better.

    I need to enumerate all appointments from a calendar that is not the default one, including all occurrences of recurrent appointments, to determine whether there are duplicates (same start/end/subject) in order to remove them.

    Saturday, July 6, 2013 12:51 PM
  • Just get the folder and enumerate its contents.  You are using UI components to do a script job.


    Saturday, July 6, 2013 12:57 PM
  • Start with this very simple example:
    $ol=New-Object -comobject Outlook.Application
    $cal=$ns.Folders.Item(1).Folders|?{$ -eq 'Calendar'}
    $cal.Items|select subject,start,end
    Assuming one mailbox and one calendar this will get the calendar and all of its items.


    Saturday, July 6, 2013 1:07 PM
  • How do I get the folder?

    The following code (derived from works, but only for the default calendar, not for other calendars:


    $outlook = New-Object -ComObject Outlook.Application

    # Ensure we are logged into a session
    $session = $outlook.Session

    $olFolderCalendar = 9
    $apptItems = $session.GetDefaultFolder($olFolderCalendar).Items
    $apptItems.IncludeRecurrences = $true

    $restriction = "[Start] >= '{0}' AND [Start] <= '{1}'" -f [datetime]::now.ToString("g"), ([datetime]::now.AddDays(1000)).ToString("g")

    $apptItems.Restrict($restriction) | sort-object  -property @{Expression = "start"; ascending = $true}, @{Expression = "end"; ascending = $true}

    Saturday, July 6, 2013 1:16 PM
  • You have to know the name.

    $ns.Folders.Item(1).Folders|select name, DefaultItemType, DefaultMessageClass


    Saturday, July 6, 2013 1:20 PM
  • I know this will work, but I have more than one mailbox (one ISP / POP account, one account) and more than one calendar (the default Outlook one, and the one).

    I need to enumerate appointments in the non-default calendar.

    Saturday, July 6, 2013 1:25 PM
  • Get the store root then get the calendar.

    For each user has a different store so you will haveto code a search for the correct store.

    This gets a custom calendar in the default store.

    $ol=New-Object -comobject Outlook.Application
    $ns.Stores contains all opened stores.  Each has a name and a path.  Take you pick then get the calendar you need.


    Saturday, July 6, 2013 1:36 PM
  • Here is how to get a specific store by account mail address:


    Note that most code is not correct for PowerShell or for basic operations.  It is extrapolated from the MSDN documentation for developing add-ins to Outlook.  This is not needed fro PowerShell access and will give you a lot of problems.


    Saturday, July 6, 2013 1:56 PM
  • You can also use this as long as you are using the default Calendar in that store (each store has a default calendar).



    Saturday, July 6, 2013 2:00 PM
  • I guess you are totally confused now.  Don't feel bad.  Even the most experienced Outlook VBA programmers get lost when they move to PowerShell.  The reason is that the object model for VBA is not exactly the same as for PowerShell.

    Another issue with using VBA examples is that they assume ex3ecution under a Windows application.  PowerShell is NOT a Windows application (Forms) .  PowerShell is a Windows 'Console' application which does not have a current or main window.  It has one Console window which is not forms based.  Any API that assumes a form will not work directly and must be used indirectly.

    Note also that access to items in Outlook is direct just like a database when just reading items.  When we try to edit or change an item the security will kick in and ask for permission on every item that you are trying to modify.

    If you are trying to access OWA such as Outlook 365 or an Exchange 2007 or later server then use EWS.  It is actually easier.


    Saturday, July 6, 2013 3:09 PM
  • I almost forgot.

    Here is the de-duping code you asked about.

    $store.GetDefaultFolder(9).Items|group subject,start,end|?{$_.Count -gt 1}

    This returns all elements where there is more than one in the group.  Each object has a 'Delete' method.


    Saturday, July 6, 2013 4:17 PM