Calendar Availability (Free/Busy) Requests with Microsoft Graph
Hi All,
I recently had a customer that wanted to write an Application to read the Availability (Free/Busy) from the Calendars of theyr users.Here is how you can do that with Microsoft Graph.
First you need an Application in Azure Active Directory with an AppID / ClientID
![](https://icewolffile.blob.core.windows.net/$web/202206/GraphCalendar_GetShedule_01.jpg)
Then you need to be able to Authenticate. I usually use a Certificate for that purpose.
![](https://icewolffile.blob.core.windows.net/$web/202206/GraphCalendar_GetShedule_02.jpg)
As for the Permissions, the Application needs the following:
App needs Application Permissions:
- Calendars.Read (Only for the Mailbox where you make the Requests from - Limit with ApplicationAccessPolicy)
- Schedule.Read.All
- Calendars.Read (Only for the Mailbox where you make the Requests from - Limit with ApplicationAccessPolicy)
- Schedule.Read.All
![](https://icewolffile.blob.core.windows.net/$web/202206/GraphCalendar_GetShedule_03.jpg)
Now we need to Limit the Calendars.Read to the Mailbox where the Availability Requests (aka Free/Busy) requests are made from.
New-ApplicationAccessPolicy -AccessRight RestrictAccess -AppId b1fe3302-d057-4fe3-84ac-c507ecdb6d0d -PolicyScopeGroupId PostmasterGraphRestriction@icewolf.ch -Description "Restrict this app to members of this Group"
Get-ApplicationAccessPolicy | Where-Object {$_.AppId -eq "b1fe3302-d057-4fe3-84ac-c507ecdb6d0d"}
![](https://icewolffile.blob.core.windows.net/$web/202206/GraphCalendar_GetShedule_04.jpg)
Now we can test it
Test-ApplicationAccessPolicy -AppId b1fe3302-d057-4fe3-84ac-c507ecdb6d0d -Identity postmaster@icewolf.ch
Test-ApplicationAccessPolicy -AppId b1fe3302-d057-4fe3-84ac-c507ecdb6d0d -Identity max.muster@icewolf.ch
Test-ApplicationAccessPolicy -AppId b1fe3302-d057-4fe3-84ac-c507ecdb6d0d -Identity max.muster@icewolf.ch
![](https://icewolffile.blob.core.windows.net/$web/202206/GraphCalendar_GetShedule_05.jpg)
I've tested it with the Example from the Docs Site
![](https://icewolffile.blob.core.windows.net/$web/202206/GraphCalendar_GetShedule_07.jpg)
Only got an Error and could not figure it out. Write me if you found a Solution that works.
Connect-MgGraph -AppId $AppID -CertificateThumbprint $Thumbprint -TenantId $TenantId
Import-Module Microsoft.Graph.Users.Actions
$params = @{
Schedules = @(
"m.muster@icewolf.ch"
)
StartTime = @{
DateTime = "2022-05-09T06:00:00"
TimeZone = "W. Europe Standard Time"
}
EndTime = @{
DateTime = "2022-05-09T15:00:00"
TimeZone = "W. Europe Standard Time"
}
AvailabilityViewInterval = 60
}
$jsonArray = $Params | ConvertTo-Json -Depth 4
$UserId = "postmaster@icewolf.ch"
Get-MgUserDefaultCalendarSchedule -UserId $userId -BodyParameter $Params
$params = @{
Schedules = @(
"m.muster@icewolf.ch"
)
StartTime = @{
DateTime = "2022-05-09T06:00:00"
TimeZone = "W. Europe Standard Time"
}
EndTime = @{
DateTime = "2022-05-09T15:00:00"
TimeZone = "W. Europe Standard Time"
}
AvailabilityViewInterval = 60
}
$jsonArray = $Params | ConvertTo-Json -Depth 4
$UserId = "postmaster@icewolf.ch"
Get-MgUserDefaultCalendarSchedule -UserId $userId -BodyParameter $Params
![](https://icewolffile.blob.core.windows.net/$web/202206/GraphCalendar_GetShedule_08.jpg)
All right, i've created two Appointments in the Calendar of max.muster@icewolf.ch. The second one is private.
![](https://icewolffile.blob.core.windows.net/$web/202206/GraphCalendar_GetShedule_09.jpg)
The Calendar Permissions for "Default" are "AvailabilityOnly"
Get-MailboxFolderPermission -Identity max.muster@icewolf.ch:\Kalender
![](https://icewolffile.blob.core.windows.net/$web/202206/GraphCalendar_GetShedule_06.jpg)
So let's try it with a pure Graph Call.
This Code is also available on my GitHub Repo https://github.com/BohrenAn/GitHub_PowerShellScripts/blob/main/ExchangeOnline/GraphAPI/Get-SheduleDemo.ps1
#Variables
$AppID = "b1fe3302-d057-4fe3-84ac-c507ecdb6d0d"
$Thumbprint = '4F1C474F862679EC35650824F73903041E1E5742'
$TenantId = "icewolfch.onmicrosoft.com"
$Certificate = Get-Item "Cert:\CurrentUser\My\$Thumbprint"
#Get AccessToken with MSAL Certificate Auth
Import-Module MSAL.PS
Clear-MsalTokenCache
$RedirectUri = "https://login.microsoftonline.com/common/oauth2/nativeclient"
$Token = Get-MsalToken -ClientId $AppID -TenantId $TenantID -RedirectUri $RedirectUri -ClientCertificate $Certificate
$AccessToken = $Token.AccessToken
$AppID = "b1fe3302-d057-4fe3-84ac-c507ecdb6d0d"
$Thumbprint = '4F1C474F862679EC35650824F73903041E1E5742'
$TenantId = "icewolfch.onmicrosoft.com"
$Certificate = Get-Item "Cert:\CurrentUser\My\$Thumbprint"
#Get AccessToken with MSAL Certificate Auth
Import-Module MSAL.PS
Clear-MsalTokenCache
$RedirectUri = "https://login.microsoftonline.com/common/oauth2/nativeclient"
$Token = Get-MsalToken -ClientId $AppID -TenantId $TenantID -RedirectUri $RedirectUri -ClientCertificate $Certificate
$AccessToken = $Token.AccessToken
#Get Availability (aka Free/Busy)
$From = "postmaster@icewolf.ch"
$URI = "https://graph.microsoft.com/v1.0/users/$From/calendar/getSchedule"
$ContentType = "application/json"
$Headers = @{"Authorization" = "Bearer "+ $AccessToken}
$Body = @{
Schedules = @(
"max.muster@icewolf.ch"
)
StartTime = @{
DateTime = "2022-06-06T06:00:00"
TimeZone = "W. Europe Standard Time"
}
EndTime = @{
DateTime = "2022-06-12T19:00:00"
TimeZone = "W. Europe Standard Time"
}
AvailabilityViewInterval = 60
}
$jsonBody = $Body | ConvertTo-Json -Depth 4
$result = Invoke-RestMethod -Method "POST" -Uri $uri -Headers $Headers -ContentType $ContentType -Body $JsonBody
$Result.value.scheduleItems
$From = "postmaster@icewolf.ch"
$URI = "https://graph.microsoft.com/v1.0/users/$From/calendar/getSchedule"
$ContentType = "application/json"
$Headers = @{"Authorization" = "Bearer "+ $AccessToken}
$Body = @{
Schedules = @(
"max.muster@icewolf.ch"
)
StartTime = @{
DateTime = "2022-06-06T06:00:00"
TimeZone = "W. Europe Standard Time"
}
EndTime = @{
DateTime = "2022-06-12T19:00:00"
TimeZone = "W. Europe Standard Time"
}
AvailabilityViewInterval = 60
}
$jsonBody = $Body | ConvertTo-Json -Depth 4
$result = Invoke-RestMethod -Method "POST" -Uri $uri -Headers $Headers -ContentType $ContentType -Body $JsonBody
$Result.value.scheduleItems
![](https://icewolffile.blob.core.windows.net/$web/202206/GraphCalendar_GetShedule_10.jpg)
If we change the Permission to Reviewer
Set-MailboxFolderPermission -Identity max.muster@icewolf.ch:\Kalender -User Default -AccessRights Reviewer
We can now even see the Subject and some more Details. But not for the Item with the Private Flag. We see only that he is not available then.
$result = Invoke-RestMethod -Method "POST" -Uri $uri -Headers $Headers -ContentType $ContentType -Body $JsonBody
$Result.value.scheduleItems
$Result.value.scheduleItems
![](https://icewolffile.blob.core.windows.net/$web/202206/GraphCalendar_GetShedule_11.jpg)
Summary:
This is an easy way to read the Calendar of your Organization Mailbox Users.
It respects the MAPI Permissions set to a Calendar.
You can add your ServiceAccount as a dedicated Permission Entry on the Calendar
Add-MailboxFolderPermission -Identity max.muster@icewolf.ch:\Kalender -User postmaster@icewolf.ch -AccessRights Reviewer
Regards
Andres Bohren
![](https://icewolffile.blob.core.windows.net/$web/logos/Exchange_logo.png)