Export Teams and Outlook Calendar Events using PowerShell

In this post, we are going to share Graph API based PowerShell script to get calendar meeting events from a specific user mailbox. From Outlook and Microsoft Teams, we can easily schedule normal meetings and group meeting events that included a Team channel. The Scheduling Assistance tool will greatly help to find user’s free/busy status and create new meeting events based on the user’s availability.

In some scenarios, we need to fetch all the events that are scheduled in a span of days and include a particular user as an attendee. Unfortunately, there is no built-in PowerShell cmdlet to list calendar events (Add comments if you know any related stuff). Here, we are going to use Microsoft Graph API to get calendar event details.

Summary

Required Graph API Permissions

For Graph API access, we need an Azure AD application and acquire Access Token with the required permissions (Application or Delegated permissions) to use in Graph API calls.

Delegated permissions

  • Calendars.Read – Allows to read events in the signed-in user calendars.
  • Calendars.Read.Shared – Allows to read events in all calendars that the signed-in user can access, including shared calendars and another user calendar where the singed-in user has delegated access.

Application permissions

  • Calendars.Read – Allows to read events from all user calendars (current user, other users, and shared calendars) without a signed-in user.

If you signed-in with Azure AD app and provides delegated permissions (Calendars.Read and Calendars.Read.Shared), you can now read events from your default calendar, other user calendars that are shared with you, and read events from another user calendars where you have delegated access. If you want to get events from all user calendars without delegate and sharing access, then we need to use the application permission (Calendars.Read). Learn more about Get shared or delegated Outlook calendar and its events.

Get Graph API Access Token

The following commands get access token for application permissions. You should have already created an Azure AD app, configured the application permission “Calendars.Read” and granted Admin consent to the permission in the app.  You can refer to this post for more details: Register and Configure Azure AD Application from Azure AD Portal.

#Provide your Office 365 Tenant Id or Tenant Domain Name
$tenantId = "contoso.onmicrosoft.com"
 
#Provide Azure AD Application (client) Id of your app. You should have granted Admin consent for this app to use the application permission “Calendars.Read” in your tenant.
$appClientId="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
 
#Provide Application client secret key
$clientSecret ="x.HB_XXXt0PWKIIed2.FTa3oR.gtc5a76-"
 
$requestBody = @{client_id=$appClientId;client_secret=$clientSecret;grant_type="client_credentials";scope="https://graph.microsoft.com/.default";}
$oauthResponse = Invoke-RestMethod -Method Post -Uri https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token -Body $requestBody
$accessToken = $oauthResponse.access_token

Export all meeting events from user calendar

Once you have acquired the required Graph access token, you can easily retrieve meeting events from the given user calendar. The following commands fetch upcoming events for the next 90 days and export the result to a CSV file.

#Provide your access token. 
#$accessToken="eyJ0eXAiOiJ......" 

#Provide the Id or UPN of the user to retrieve events 
$userId="[email protected]"

#Form request headers with the acquired $accessToken
$headers = @{'Content-Type'="application\json";'Authorization'="Bearer $accessToken"}

#Set a time zone in header to get date time values returned in the specific time zone
#$TimeZone=(Get-TimeZone).Id #Get current time zone
$TimeZone="Pacific Standard Time"
$headers.Add('Prefer', 'outlook.timezone="' + $TimeZone + '"')

#This request get all future, current and old events
#$apiUrl = "https://graph.microsoft.com/v1.0/users/$userId/calendar/events"

#We need to apply filter with meeting start time to get only upcoming events.
#Filter - the below query returns events for next 90 days
$startDate = (Get-Date (Get-Date).Date -UFormat '+%Y-%m-%dT%H:%M:%S.000Z')
$endDate = (Get-Date (Get-Date).AddDays(90).Date -UFormat '+%Y-%m-%dT%H:%M:%S.000Z')
$apiUrl = "https://graph.microsoft.com/v1.0/users/$userId/calendar/events?`$filter=start/dateTime ge '$($startDate)' and start/dateTime lt '$($endDate)'"


$Result = @()
While ($apiUrl -ne $Null)
{
$Response = Invoke-RestMethod -Method GET -Uri $apiUrl -ContentType "application\json" -Headers $headers
if($Response.value)
{
ForEach($event in  $Response.Value)
{
$Result += New-Object PSObject -property $([ordered]@{ 
Subject = $event.subject
Organizer = $event.organizer.emailAddress.name
Attendees = (($event.attendees | select -expand emailAddress) | Select -expand name) -join ','
StareTime = [DateTime]$event.start.dateTime
EndTime = [DateTime]$event.end.dateTime
IsTeamsMeeting = ($event.onlineMeetingProvider -eq 'teamsForBusiness')
Location = $event.location.displayName
IsCancelled=$event.isCancelled
})
}
}
$apiUrl = $Response.'@Odata.NextLink'
}

$Result | Export-CSV "C:\Temp\CalendarEvents.CSV" -NoTypeInformation -Encoding UTF8

Find Microsoft Teams meetings

The above commands store the details in the array object “$Result“, we can filter the result and generate different reports. Run the following command to list all the Team meetings.

$Result | Where-Object { $_.IsTeamsMeeting -eq  $true}

List cancelled meetings

Run the following command to list the cancelled meetings.

$Result | Where-Object { $_.IsCancelled  -eq  $true}

Find meetings by Attendee name

Run the below command to get events that include the given user as a meeting attendee.

$Result | Where-Object { $_.Attendees -like  "*Alex Wilber*"}

Find meetings by Organizer name

Run the below command to list events by organizer name.

$Result | Where-Object { $_.Organizer -like  "*Admin*"}

Advertisement

3 thoughts on “Export Teams and Outlook Calendar Events using PowerShell”

  1. G’day Morgan,

    This all looks *really* useful, but I’ve got this all working, no auth issues, and all I’m getting is a single weird character as the output, no events, nothing else. And the user definitely has events that should be exported. Also, when I try to use any of the “Where-Object” queries there are obviously no results.

    Also, if we can get this working, is there any way to query shared mailbox calendars this way?

    Reply

Leave a Comment