Skip to main content

EWS Managed API and Powershell How-To Series Part 6 FreeBusy and OOF Operations

In this post I'm going to continue looking at the special operations in EWS that allows you to get and set the unconventional data that is stored in an Exchange mailbox like the FreeBusy information and the Out of Office Message. First off lets look at the FreeBusyTime.
 

Getting Freebusy time

Freebusy information is one of the more useful calendar features that Exchange offers in EWS the ability to access the freebusy information is provided by the GetUserAvailiblity operation. This operation can be useful in a number of scenarios especially when you may want to query a large number of calendars. One example is a freebusy board or meeting room website

When you make a FreeBusy request there are two constraints on the request that are outlined in http://technet.microsoft.com/en-us/library/hh310374.aspx  "By default, Exchange 2007 accepts availability requests for 42 days of free/busy information and Exchange 2010 may request 62 days of free/busy information. If the request exceeds the default 42 limit imposed by Exchange 2007, the request will fail." The other constraint in the number of users you can query at one time is limited to 100 per call.

The detail level of information that is returned by this operation is also controlled by the value of RequestedFreeBusyView that you set. Essentially two different data-sets could be returned by this operation the first is the MergedFreeBusyStatus which are the FreeBusy Slots from a mailbox by default in 30 minutes increments. The second dataset is a detailed array of calendar appointment during the freebusy period if you have requested Calendar Details and you have enough rights on the Calendar to see Subject and Location information (Otherwise you will just get Start and EndTimes).

Lets look at an example of getting the freebusy time with the EWS Managed API for one user is this example we look at the CalendarDetails array to show the information that can be returned.

  1. $StartTime = [DateTime]::Parse([DateTime]::Now.ToString("yyyy-MM-dd 0:00"))  
  2. $EndTime = $StartTime.AddDays(7)  
  3.   
  4. $drDuration = new-object Microsoft.Exchange.WebServices.Data.TimeWindow($StartTime,$EndTime)  
  5. $AvailabilityOptions = new-object Microsoft.Exchange.WebServices.Data.AvailabilityOptions  
  6. $AvailabilityOptions.RequestedFreeBusyView = [Microsoft.Exchange.WebServices.Data.FreeBusyViewType]::DetailedMerged  
  7.   
  8. $listtype = ("System.Collections.Generic.List"+'`'+"1") -as "Type"
  9. $listtype = $listtype.MakeGenericType("Microsoft.Exchange.WebServices.Data.AttendeeInfo" -as "Type")
  10. $Attendeesbatch = [Activator]::CreateInstance($listtype)
  11.   
  12. $Attendee = new-object Microsoft.Exchange.WebServices.Data.AttendeeInfo("user@domain.com")  
  13. $Attendeesbatch.add($Attendee)  
  14.   
  15. $availresponse = $service.GetUserAvailability($Attendeesbatch,$drDuration,[Microsoft.Exchange.WebServices.Data.AvailabilityData]::FreeBusy,$AvailabilityOptions)  
  16. foreach($avail in $availresponse.AttendeesAvailability){  
  17.     foreach($cvtEnt in $avail.CalendarEvents){  
  18.         "Start : " + $cvtEnt.StartTime  
  19.         "End : " + $cvtEnt.EndTime  
  20.         "Subject : " + $cvtEnt.Details.Subject  
  21.         "Location : " + $cvtEnt.Details.Location  
  22.         ""  
  23.     }  
  24. }  
One useful example is to do this for a Group of users so first you will need a Distribution Group and we will then use the ExandGroup EWS operation to get all the members of that group which will give us all the Email address's of the users that we will then get the FreeBusy information for. You also need some code to ensure you can relate the information in the CalendarDetails array to that of the request because by default in this array there is no information relating the recipient this data belongs to. (Not you can actually use the Distribution Groups address instead of doing the expand but if you do this the results do get merged into one Entry which is hard to separate).

  1. $GroupAddress = "testinggroup@domain.com"  
  2. $StartTime = [DateTime]::Parse([DateTime]::Now.ToString("yyyy-MM-dd 0:00"))  
  3. $EndTime = $StartTime.AddDays(7)  
  4.   
  5. $drDuration = new-object Microsoft.Exchange.WebServices.Data.TimeWindow($StartTime,$EndTime)  
  6. $AvailabilityOptions = new-object Microsoft.Exchange.WebServices.Data.AvailabilityOptions  
  7. $AvailabilityOptions.RequestedFreeBusyView = [Microsoft.Exchange.WebServices.Data.FreeBusyViewType]::DetailedMerged  
  8.   
  9. $listtype = ("System.Collections.Generic.List"+'`'+"1") -as "Type"
  10. $listtype = $listtype.MakeGenericType("Microsoft.Exchange.WebServices.Data.AttendeeInfo" -as "Type")
  11. $Attendeesbatch = [Activator]::CreateInstance($listtype)
  12.   
  13. $GroupMembers = $service.ExpandGroup($GroupAddress)  
  14. $adrHash = @{}  
  15. $adcnt = 0  
  16. foreach($Address in $GroupMembers.Members){  
  17.     $Attendee = new-object Microsoft.Exchange.WebServices.Data.AttendeeInfo($Address.Address)  
  18.     $Attendeesbatch.add($Attendee)  
  19.     $adrHash.add($adcnt,$Address.Address)  
  20.     $adcnt++  
  21.     $Address.Address  
  22. }  
  23. $adcnt = 0  
  24. $availresponse = $service.GetUserAvailability($Attendeesbatch,$drDuration,[Microsoft.Exchange.WebServices.Data.AvailabilityData]::FreeBusy,$AvailabilityOptions)  
  25. foreach($avail in $availresponse.AttendeesAvailability){  
  26.       
  27.     foreach($cvtEnt in $avail.CalendarEvents){  
  28.         "Mailbox : " + $adrHash[$adcnt]  
  29.         "Start : " + $cvtEnt.StartTime  
  30.         "End : " + $cvtEnt.EndTime  
  31.         "Subject : " + $cvtEnt.Details.Subject  
  32.         "Location : " + $cvtEnt.Details.Location  
  33.         ""  
  34.     }  
  35.     $adcnt++  
  36. }  
Out of Office Information

EWS provides access to the Out of Office information via GetUserOofSettings and SetUserOofSettings  Operations. Or one other way of displaying the OOF setting for a user which doesn't require rights on a users mailbox is to use MailTips. Using the OOF via GetUserOofSettings/SetUserOofSettings setting is pretty easy lets looks at the basics of Getting and Displaying the OOF settings.

  1. $oofSetting = $service.GetUserOofSettings("user@domain.com")  
  2. "OOF State : " + $oofSetting.State  
  3. "InternalReply : " + $oofSetting.InternalReply  
  4. "ExternalReply : " + $oofSetting.ExternalReply  
  5. "AllowExternalOof : " + $oofSetting.AllowExternalOof  
To set the OOF State and or the Message property you should first get the current setting modify the property you want to modify and then update the OOF.

eg to set the OOF of the currently logged on user you could use the following code.

  1. $MailboxName = "user@domain.com"  
  2. $oofSetting = $service.GetUserOofSettings($MailboxName)  
  3. $oofSetting.State.ToString()  
  4. $oofSetting.InternalReply = new-object Microsoft.Exchange.WebServices.Data.OofReply("Test 123")  
  5. $oofSetting.ExternalReply.ToString()  
  6. $oofSetting.State = [Microsoft.Exchange.WebServices.Data.OofState]::Enabled  
  7. $service.SetUserOofSettings($MailboxName$oofSetting);   

An example of using MailTips to get the OOF needs a little more code because there are no methods in the EWS Managed API to make use of the MailTips operations you need to use some Raw XML instead.

  1. $MailboxName = "user@domain.com"  
  2.   
  3. $expRequest = @"   
  4. <?xml version="1.0" encoding="utf-8"?>   
  5. <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">   
  6. <soap:Header><RequestServerVersion Version="Exchange2010_SP1" xmlns="http://schemas.microsoft.com/exchange/services/2006/types" />   
  7. </soap:Header>   
  8. <soap:Body>   
  9. <GetMailTips xmlns="http://schemas.microsoft.com/exchange/services/2006/messages">   
  10. <SendingAs>   
  11. <EmailAddress xmlns="http://schemas.microsoft.com/exchange/services/2006/types">$MailboxName</EmailAddress>   
  12. </SendingAs>   
  13. <Recipients>   
  14. "@     
  15.     
  16. foreach($mbMailbox in $Mailboxes){     
  17.     $expRequest = $expRequest + "<Mailbox xmlns=`"http://schemas.microsoft.com/exchange/services/2006/types`"><EmailAddress>$mbMailbox</EmailAddress></Mailbox>"      
  18. }     
  19.     
  20. $expRequest = $expRequest + "</Recipients><MailTipsRequested>OutOfOfficeMessage</MailTipsRequested></GetMailTips></soap:Body></soap:Envelope>"    
  21. $mbMailboxFolderURI = New-Object System.Uri($service.url)     
  22. $wrWebRequest = [System.Net.WebRequest]::Create($mbMailboxFolderURI)     
  23. $wrWebRequest.KeepAlive = $false;     
  24. $wrWebRequest.Headers.Set("Pragma""no-cache");     
  25. $wrWebRequest.Headers.Set("Translate""f");     
  26. $wrWebRequest.Headers.Set("Depth""0");     
  27. $wrWebRequest.ContentType = "text/xml";     
  28. $wrWebRequest.ContentLength = $expRequest.Length;     
  29. $wrWebRequest.Timeout = 60000;     
  30. $wrWebRequest.Method = "POST";     
  31. $wrWebRequest.Credentials = $cred    
  32. $bqByteQuery = [System.Text.Encoding]::ASCII.GetBytes($expRequest);     
  33. $wrWebRequest.ContentLength = $bqByteQuery.Length;     
  34. $rsRequestStream = $wrWebRequest.GetRequestStream();     
  35. $rsRequestStream.Write($bqByteQuery, 0, $bqByteQuery.Length);     
  36. $rsRequestStream.Close();     
  37. $wrWebResponse = $wrWebRequest.GetResponse();     
  38. $rsResponseStream = $wrWebResponse.GetResponseStream()     
  39. $sr = new-object System.IO.StreamReader($rsResponseStream);     
  40. $rdResponseDocument = New-Object System.Xml.XmlDocument     
  41. $rdResponseDocument.LoadXml($sr.ReadToEnd());     
  42. $RecipientNodes = @($rdResponseDocument.getElementsByTagName("t:RecipientAddress"))     
  43. $Datanodes = @($rdResponseDocument.getElementsByTagName("t:OutOfOffice"))     
  44. for($ic=0;$ic -lt $RecipientNodes.length;$ic++){     
  45.     if($Datanodes[$ic].ReplyBody.Message -eq ""){     
  46.         $RecipientNodes[$ic].EmailAddress + " : In the Office"    
  47.     }     
  48.     else{     
  49.         $RecipientNodes[$ic].EmailAddress + " : Out of Office"    
  50.     }     
  51. }     









Popular posts from this blog

The MailboxConcurrency limit and using Batching in the Microsoft Graph API

If your getting an error such as Application is over its MailboxConcurrency limit while using the Microsoft Graph API this post may help you understand why. Background   The Mailbox  concurrency limit when your using the Graph API is 4 as per https://docs.microsoft.com/en-us/graph/throttling#outlook-service-limits . This is evaluated for each app ID and mailbox combination so this means you can have different apps running under the same credentials and the poor behavior of one won't cause the other to be throttled. If you compared that to EWS you could have up to 27 concurrent connections but they are shared across all apps on a first come first served basis. Batching Batching in the Graph API is a way of combining multiple requests into a single HTTP request. Batching in the Exchange Mail API's EWS and MAPI has been around for a long time and its common, for email Apps to process large numbers of smaller items for a variety of reasons.  Batching in the Graph is limited to a m

Sending a Message in Exchange Online via REST from an Arduino MKR1000

This is part 2 of my MKR1000 article, in this previous post  I looked at sending a Message via EWS using Basic Authentication.  In this Post I'll look at using the new Outlook REST API  which requires using OAuth authentication to get an Access Token. The prerequisites for this sketch are the same as in the other post with the addition of the ArduinoJson library  https://github.com/bblanchon/ArduinoJson  which is used to parse the Authentication Results to extract the Access Token. Also the SSL certificates for the login.windows.net  and outlook.office365.com need to be uploaded to the devices using the wifi101 Firmware updater. To use Token Authentication you need to register an Application in Azure https://msdn.microsoft.com/en-us/office/office365/howto/add-common-consent-manually  with the Mail.Send permission. The application should be a Native Client app that use the Out of Band Callback urn:ietf:wg:oauth:2.0:oob. You need to authorize it in you tenant (eg build a small ap

How to test SMTP using Opportunistic TLS with Powershell and grab the public certificate a SMTP server is using

Most email services these day employ Opportunistic TLS when trying to send Messages which means that wherever possible the Messages will be encrypted rather then the plain text legacy of SMTP.  This method was defined in RFC 3207 "SMTP Service Extension for Secure SMTP over Transport Layer Security" and  there's a quite a good explanation of Opportunistic TLS on Wikipedia  https://en.wikipedia.org/wiki/Opportunistic_TLS .  This is used for both Server to Server (eg MTA to MTA) and Client to server (Eg a Message client like Outlook which acts as a MSA) the later being generally Authenticated. Basically it allows you to have a normal plain text SMTP conversation that is then upgraded to TLS using the STARTTLS verb. Not all servers will support this verb so if its not supported then a message is just sent as Plain text. TLS relies on PKI certificates and the administrative issue s that come around certificate management like expired certificates which is why I wrote th
All sample scripts and source code is provided by for illustrative purposes only. All examples are untested in different environments and therefore, I cannot guarantee or imply reliability, serviceability, or function of these programs.

All code contained herein is provided to you "AS IS" without any warranties of any kind. The implied warranties of non-infringement, merchantability and fitness for a particular purpose are expressly disclaimed.