Skip to main content

Getting FreeBusy information in the Graph API using the getSchedule action and putting it to use in PowerShell

One of the recent additions to the Graph API for Exchange in Office365 has been getSchedule action https://developer.microsoft.com/en-us/graph/docs/api-reference/beta/api/calendar_getschedule . What this action allows to do is get the FreeBusy information from one or more mailboxes in your Office365 environment. If your new to Exchange (or for those that have forgotten) FreeBusy information is essential what is used to produce the Schedule Assistant in Outlook and equivalent in OWA


The above is built by Outlook using the EWS GetUserAvaliblity operation which is what the getSchedule action in the Graph is the equivalent of. GetUserAvaliblity has been in use in Outlook since Exchange 2007 where we went from using Public Folders to hold the freebusy information in previous versions to the Public Folder free utopia we have today. In the preceding years features such as Suggested Meeting times have been added to this EWS operation this feature is available in the Graph via the Graph in the findmeeting action .

If you are using the Graph API
getSchedule is a  good a solution for solving one of the more frequently asked questions of how you can get the availability of multiple meeting rooms without needing to query every Meeting Rooms calendars (or a simular question for a group of users).

Limits

There are some limits to be aware of when querying FreeBusy data which is you can query up to 62 days worth of FreeBusy information (eg the period between the Start and EndTimes). The other limit you should adhere to is no more the 100 Mailboxes per request to keep below the throttling limits.

Making the query

The REST request you need to make to get the FreeBusy information should look something like the following

{
    "schedules":  [
                      "gscales@datarumble.com",
                      "mec@datarumble.com"
                  ],
    "endTime":  {
                    "dateTime":  "2018-09-08T10:21:49",
                    "timeZone":  "AUS Eastern Standard Time"
                },
    "startTime":  {
                      "dateTime":  "2018-09-07T10:21:49",
                      "timeZone":  "AUS Eastern Standard Time"
                  },
    "availabilityViewInterval":  15
}

Time zones are an issue that usually trips up a lot of people, especially if your dealing with mailboxes in multiple locations. Its important to note the timezone specified in the query only relates to the query period your using. The timezone that you get back in the results will depend on the request header Prefer: outlook.timezone in the Request. So if your setting the TimeZone in the query and your getting back a different unexpected TimeZone In the results you need to look at the Prefer: outlook.timezone that's being used (or the absence of that header will mean you will get UTC back).

The availabilityViewInterval affects the timeslots that come back  in the availabilityView generally you would use either 15,30 or 60 minutes but you can have a value as high as 1440 (which represents 1 day) and as low a 6 minutes. If you set the availabilityViewInterval to 1440 then just having one appointment in a day will mean that day will appear as Busy.

Results 

The results you get back from this action is first the availabilityView which depending on the interval you specified will be splices of availability between then Start and End Times you specified. eg



Also if you have the FreeBusy,Subject and location permission on the Target calendars (or higher) you will get an array of calendar appointments (as long as they aren't private) back for each Target Mailbox. eg


In EWS you also got back the HexEntryId of the appointment object meaning you could then retrieve more information for a specific Appointment without first doing a search which seems to be missing in the Graph operation at the moment. Lets hope that comes back as its an important function and the workaround is messy and will cause a lot of development pain for people 🙏🙏.

Using this in PowerShell

I've added the ability to use this action to my Exch-Rest PowerShell library which is what the above screen shots where produced using this module is available from the PowerShell Gallery https://www.powershellgallery.com/packages/Exch-Rest and GitHub https://github.com/gscales/Exch-Rest.

The Module has the following Cmdlet

Get-EXRSchedule

this takes an array of Mailboxes you want to run it against so to use it first create a blank array

$Mailboxes = @()

then populate that with the Mailboxes you want to run against eg

$Mailboxes += "gscales@datarumble.com"
$Mailboxes += "mec@datarumble.com"

Then run the cmdlet with the Start and EndTime and availability period you want by default these aren't need and it will return the freebusy information for the next 24 hours in 15 minutes intervals eg

Get-EXRSchedule -Mailboxes $mailboxes 

However usually you would want to run something like the following

$StartTime = [DateTime]::Parse((Get-Date).ToString("yyyy-MM-dd HH:00:00"))
$EndTime = [DateTime]::Parse((Get-Date).AddHours(6).ToString("yyyy-MM-dd HH:00:00"))
Get-EXRSchedule -Mailboxes $mailboxes -Start $StartTime -EndTime $Endtime -availabilityViewInterval 15

Which would get the freebusy information for the next 6 hours in 15 minute increments

The Module is useful for getting the data so lets look at a few fun ways you can use it. eg if you want to have the results stored in a collection you could export as CSV or Graph you could use something like the following

$rptCollection = @()
$StartTime = [DateTime]::Parse((Get-Date).ToString("yyyy-MM-dd HH:00:00"))
$EndTime = [DateTime]::Parse((Get-Date).AddHours(6).ToString("yyyy-MM-dd HH:00:00"))
$avResults = Get-EXRSchedule -Mailboxes $mailboxes -Start $StartTime -EndTime $Endtime -availabilityViewInterval 15
foreach($fbResult in $avResults){
 $CurrentTime = $StartTime 
 $fbResult.availabilityView.ToCharArray() | ForEach-Object{
  $rptobj = "" | select Time,User,FreeBusyStatus
  $rptobj.Time = $CurrentTime.ToString("HH:mm")
  $rptobj.User = $fbResult.scheduleId
  switch($_){
     0 {$rptobj.FreeBusyStatus = "Free"}
     1 {$rptobj.FreeBusyStatus = "Tentative"}
     2 {$rptobj.FreeBusyStatus = "Busy"}
     3 {$rptobj.FreeBusyStatus = "Out of Office"}
     4 {$rptobj.FreeBusyStatus = "Working Elsewhere"}
  }
   $rptCollection += $rptobj
  $CurrentTime = $CurrentTime.AddMinutes(15)
 }
}
return $rptCollection 


Or we can create a FreeBusy board using this information that would look like the following


Where I'm using both the avaiblitiyview data to create the Table and also the calendar details so when you hover over one of the busy table cells it will show the subject of that meeting. I've put the code up for the freebusy board here https://github.com/gscales/Powershell-Scripts/blob/master/fbBoardGraph.ps1 .

Hire me - If you would like to do something similar to this or anything else you see on my blog I'm currently available to help with any Office365, Exchange or Active Directory related development work or scripting, please contact me at gscales@msgdevelop.com(nothing too big or small).

Popular posts from this blog

Downloading a shared file from Onedrive for business using Powershell

I thought I'd quickly share this script I came up with to download a file that was shared using One Drive for Business (which is SharePoint under the covers) with Powershell. The following script takes a OneDrive for business URL which would look like https://mydom-my.sharepoint.com/personal/gscales_domain_com/Documents/Email%20attachments/filename.txt This script is pretty simple it uses the SharePoint CSOM (Client side object Model) which it loads in the first line. It uses the URI object to separate the host and relative URL which the CSOM requires and also the SharePointOnlineCredentials object to handle the Office365 SharePoint online authentication. The following script is a function that take the OneDrive URL, Credentials for Office365 and path you want to download the file to and downloads the file. eg to run the script you would use something like ./spdownload.ps1 ' https://mydom-my.sharepoint.com/personal/gscales_domain_com/Documents/Email%20attachments/filena

Export calendar Items to a CSV file using EWS and Powershell

Somebody asked about this last week and while I have a lot of EWS scripts that do access the Calendar I didn't have a simple example that just exported a list of the Calendar events with relevant information to a CSV file so here it is. I've talked on this one before in this howto  but when you query the calendar folder using EWS you need to use a CalendarView which will expand any recurring appointments in a calendar. There are some limits when you use a calendarview in that you can only return a maximum of 2 years of appointments at a time and paging will limit the max number of items to 1000 per call. So if you have a calendar with a very large number of appointments you need to break your query into small date time blocks. In this example script I'm just grabbing the next 7 days of appointments if you want to query a longer period you need to adjust the following lines (keeping in mind what I just mentioned) #Define Date to Query $StartDate = (Get-Date) $EndDate

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