Integrating Calendars Using EWS
I have recently been working on a project that required me to integrate both new and existing Outlook Calendars within my applications. I thought this would be a good opportunity to see what I could do with Exchange Web Services (EWS).
I encountered a few issues that required me to do some investigation (actually, that's just the fancy term I use for Googling!) in order to get my application fully operational. So, I just wanted to document this, in the hope that it helps out others that also find themselves encountering similar issues.
As a starting point, and as a proof-of-concept to see what what possible using Exchange Web Services, I thought I would start of with a very simple C# console application that listed the Rooms we had already setup within our Exchange Server and any Appointments that were scheduled for today in each of those rooms.
The code for this is provided below:
class Program { static void Main(string[] args) { ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013_SP1); string email = "email@domain.com"; // Change to the Email address of the account accessing EWS. string username = "someusername"; // Change to the Username of the account accessing EWS. string password = "aS3cretP4ssword!"; // Change to the Password of the account accessing EWS. string domain = "mydomain"; // Change to the Domain of on which Exchanges Server is setup on. // Set specific credentials. service.Credentials = new NetworkCredential(username, password, domain); // Look up the user's EWS endpoint by using Autodiscover. service.AutodiscoverUrl(email); Console.WriteLine($"EWS Service URL: {service.Url}"); Console.WriteLine(""); // Get the room lists (i.e. a list of lists). // Each item returned will be a list of rooms. var roomLists = service.GetRoomLists(); if(roomLists != null && roomLists.Any()) { foreach (var roomList in roomLists) { Collection rooms = service.GetRooms(roomList); foreach (EmailAddress roomAddress in rooms) { Console.WriteLine($"List: {roomList.Address}"); Console.WriteLine($"Room: {roomAddress.Address}"); // TODO: // Get the additional room data. // We can uniquely identify the data using the room email address. // We only want to get the appointments for today. // So, obtain a calender view that will include appointments that are scheduled from that start of today until the end of the day. CalendarView calendarView = new CalendarView(DateTime.Today, DateTime.Today.AddDays(1)); FolderId calendarFolderId = new FolderId(WellKnownFolderName.Calendar, roomAddress.Address); // Note: // If we want an outline of the only the current/forthcomingevents events, then we should use DateTime.Now instead on DateTime.Today // Get the appointments from the calendar view. FindItemsResults appointments = service.FindAppointments(calendarFolderId, calendarView); // Check if there are any appointments returned. // If so, we will display each one. Console.WriteLine($"Appointments for Room {roomAddress.Address}"); if (appointments.Items.Count > 0) { foreach (Appointment appt in appointments) { // TODO: // Get the additional appointment data. // We can uniqueley identify the data using appt.Id.UniqueId. Console.WriteLine($"{appt.Start} - {appt.End} : {appt.Subject}"); } } else { // No appointments were found Console.WriteLine("No appointments found for today"); } Console.WriteLine(""); } } } else { Console.WriteLine($"No lists found"); Console.WriteLine(""); } StopAutoClose(); } static void StopAutoClose(string msg) { Console.WriteLine(msg); Console.ReadKey(); } static void StopAutoClose() { StopAutoClose("Press any key to continue..."); } }
No Results Returned!?
If you run the above code, chances are, nothing will be listed. This is because the call to service.GetRoomLists() returns no items.
The reason for this is that the GetRoomsList() method actually returns a list of lists and a Room List needs to be defined on Exchange Server before any Room List will be included as a result when this method is called.
So, in order to define a Room List, we need to add it to Exchange Server. This is done using the following PowerShell command:
New-DistributionGroup -Name “Company Meeting Rooms” -OrganisationalUnit "Path/To/OU" -RoomList
Basically, the above command creates a new distribution group, but the -RoomList flag specifies that this is a group specifically for Room resources.
Next, we had to add each Room resource to the Group we just created. This was done using the following PowerShell command:
Add-DistributionGroupMember -Identity “Company Meeting Rooms” -Member room-name@mydomain.com
This command simply adds the specified Room resource to the "Company Meeting Rooms" Room list. You will need to repeat this command for each Room resource you want to add to the list.
So, the code outlined above, when run, should now list each room and the associated appointments for today’s calendar.
Meeting Subject Changed in Calendar!?
Another issue I faced was when I was setting up a meeting and invited the Room resource in order to book that room.
After the meeting got accepted, I noticed that the Subject line for the meeting, within the Room Calendar, had been changed to include the Organiser’s name as the subject line.
I did not want this! I wanted it to maintain the same title that was initially entered when the meeting was initially setup by the organiser.
I found that the only way to achieve this was to run the following PowerShell command on the server where Exchange Server was running.
Set-CalendarProcessing -Identity room-name@mydomain.com -DeleteSubject $False -AddOrganizerToSubject $False
This command needs to be executed for each Room where these settings should be applied. So, the value for the -Identity parameter should change to match the emails address for the relevant room.