Pro-Exchange,Lync & Office 365
Belgian Microsoft Unified Communications Professionals
Microsoft Exchange Server, Microsoft Lync Server & Office 365
Using Exchange Web Services (EWS) to add entries in a calendar

Introduction

A while back, I was at a customer that was looking for a way to add calendar items to all his user’s calendars.
Calendars can easily be manipulated using Exchange Web Services. The script I created, is built upon a script I’ve downloaded a while back from Mike Pfeiffer. For instance, his script uses parameters to provide details for the entries to create in the calendars. Also, his script uses AutoDiscover to retrieve the EWS-url. However; since this wasn’t a requirement for the customer, I omitted both AutoDiscover as the input through parameters in my script.

A word on the managed API

Before ‘diving’ a bit deeper, I just have to point out that I’m not a developer. So please – bear with me – if I don’t always use the 100% correct terminology Winking smile

The managed API is an object model that you can use to develop applications (and scripts) that make use of the Exchange Web Services (EWS). It is significantly easier than the legacy way of interacting with Exchange like e.g. WebDAV.

In November 2011, Microsoft introduced version 1.2 of the API. However, at time of writing version 1.1 is the latest version available for download.

The following link provides an overview of all the features included in the API and the differences between the latest version (1.2) and earlier versions:

Building the solution

Before starting: if you need more information on how to use the Managed API, MSDN offers a ton of information on this topic. Have a look at the following URL and start from there: Microsoft Exchange Web Services Managed API 1.2

If you want your PowerShell script to use the Managed API, we need to make the API available to PowerShell (and thus the script) by importing it:

Add-Type -Path "C:\Program Files\Microsoft\Exchange\Web Services\1.1\Microsoft.Exchange.WebServices.dll"

Next, we need to create an instance of Exchange WebService .NET object:

$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService -ArgumentList ([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2007_SP1)

Note: in the cmdlet, you also need to specify the version of Exchange you are connecting to. Obviously in this example, I was connecting to a server running Exchange 2007 SP1.

After we’ve created the instance, we need to connect to Exchange. This can be done various ways (for instance using AutoDiscover), but in this example, we’ll provide the web-services URL directly:

$service.Url = [system.URI] "https://servername.domain.local/ews/exchange.asmx"

Now that we’ve connected to Exchange through the specified URL, it’s time to add some functionality to the script. Because I want the script to be re-usable, I needed a way of providing info to the script. You could use parameters, but because you might want to add multiple items at once, using a CSV-file seemed the best option to me. So, I had to import the csv-file:

$calendaritems = import-csv "calendaritems.csv"

In this script, the customer was looking for a way to add simple “informational” calendar items (such as public holidays from different countries), therefore I kept the amount of info provided through the csv-file as simple as possible. The content of the csv-file looks like this:

Subject,Body,Start,End,AllDayEvent
Event1,”This is event 1”,01/01/2011,01/01/2011,True
Event2,”This is event 2”,”Wednesday, November 02, 2011 1:00:00 PM”,”Wednesday, November 02, 2011 2:00:00 PM”,False

As you can see from the input above, there are different way in which you can define the contents. You can keep the start- and end date simple (useful for all-day events), but you could also add a more complex time-notation for events that take up a certain amount of time.

Now that we have the contents to add to the calendar(s), we now need to know to what calendar(s) to add them to. If you have to target all your users you could add the following:

$users = Get-Mailbox

But because I wanted to have full control (without having to built another query) over who gets the new calendar items, I again make use of a csv-file. The CSV is – again – extremely simple: I only need the user’s SMTP Address (PrimartySMTPAddress):

$users = import-csv “users.csv”

Next, we’re going to loop through the array $users (the list of all users that need to get the content of the “calendaritems.csv”-file) and add the items to their calendar. To loop through the array we use the following cmdlet:

foreach($user in $users){
    }

Before we can add an item to a user’s calendar, the account that is used to run this script needs to impersonate the user. That’s why we need the Primary SMTP Address for the user. This also means that we have to give that account “Application Impersonation” rights. Check out the following URL for more information: http://msdn.microsoft.com/en-us/library/bb204095%28v=exchg.140%29.aspx

$service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId -ArgumentList([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress,$user.PrimarySMTPAddress)

Note that $user.PrimarySMTPAddress refers to the value in the users.csv file.

Now that we’ve set that straight, we need to build the entries and save them to the user’s calendar:

foreach($item in $calendaritems){
            $appointment = New-Object Microsoft.Exchange.WebServices.Data.Appointment -ArgumentList $service
            $appointment.Subject = $item.Subject
            $appointment.Body = $item.Body
            $appointment.Start = $item.Start
            $appointment.End = $item.End
            $appointment.LegacyFreeBusyStatus = "Free"
            if($item.AllDayEvent = "true"){
            $appointment.IsAllDayEvent = $true
            }
         else{
            $appointment.IsAllDayEvent = $false
        }

            $appointment.Save([Microsoft.Exchange.WebServices.Data.SendInvitationsMode]::SendToAllAndSaveCopy)
        }

Taking a look at the code above, there are some things we need to explain:

We start by creating a new instance of a calendar object using:

$appointment = New-Object Microsoft.Exchange.WebServices.Data.Appointment -ArgumentList $service

Then we define the entry’s Subject, Body, Start- & End-date, all have been defined through the calendaritems.csv file.

$appointment.Subject = $item.Subject
$appointment.Body = $item.Body
$appointment.Start = $item.Start
$appointment.End = $item.End

Hard-coded in the script, we define the Free/Busy status as “Free” because the entry added to the user’s calendar is a pure informational entry.

$appointment.LegacyFreeBusyStatus = "Free"

Next, we sett the “IsAllDayEvent”-flag, based on the value we’ve entered in the calendaritems.csv file:

if($item.AllDayEvent = "true"){
    $appointment.IsAllDayEvent = $true
}
else{
    $appointment.IsAllDayEvent = $false
}

In the end, we save the appointment to the calendar:

$appointment.Save([Microsoft.Exchange.WebServices.Data.SendInvitationsMode]::SendToAllAndSaveCopy)

That’s it. Easy, wasn’t it? Winking smile

 

Bringing it all together

If we bring all the pieces together, the script finally ends up looking like this:

Add-Type -Path "C:\Program Files\Microsoft\Exchange\Web Services\1.1\Microsoft.Exchange.WebServices.dll"

$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService -ArgumentList ([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2007_SP1)
$service.Url = [system.URI] https://servername.domain.local/ews/exchange.asmx

$calendaritems = Import-CSV "calendaritems.csv"
$users = import-csv “users.csv”

foreach($user in $users){
   
$service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId –ArgumentList ([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress,$user.PrimarySMTPAddress)

    foreach($item in $calendaritems){
        $appointment = New-Object Microsoft.Exchange.WebServices.Data.Appointment -ArgumentList $service
        $appointment.Subject = $item.Subject
        $appointment.Body = $item.Body
        $appointment.Start = $item.Start
        $appointment.End = $item.End
        $appointment.LegacyFreeBusyStatus = "Free"
       
       
if($item.AllDayEvent = "True"){
            $appointment.IsAllDayEvent = $true
        }
        else{
            $appointment.IsAllDayEvent = $false
        }

        $appointment.Save([Microsoft.Exchange.WebServices.Data.SendInvitationsMode]::SendToAllAndSaveCopy)
    }

}

Sources & Extra Information

If you’re looking for some great examples (and tutorials) and need some more idea’s on what you can do with EWS and PowerShell, check out the following blogs:

 


Posted 11-12-2011 6:17 by Michael Van Horenbeeck

Comments

Office 365 wrote Assigning Application Impersonation permissions in Exchange Online (Office 365)
on 01-16-2012 10:49

Some 3rd-party applications require you to provide them with a user account that has got the permission

breasts naturally wrote breasts naturally
on 10-03-2014 2:31

Using Exchange Web Services (EWS) to add entries in a calendar - Exchange 2010 - Pro-Exchange,Lync & Office 365