Retrieving Teams meeting attendance report via the Microsoft Graph PowerShell module

Somewhere in the flurry of announcements from this Fall Ignite I run into a mention of the Get-MgCommunicationOnlineMeetingAttendanceReport cmdlet, and foolish me though we’d finally get some meaningful way of listing all meetings within a tenant, along with their corresponding “artifacts”, such as the attendance report. Alas, reality is often disappointing 🙂

Regardless, I took this opportunity to check on the latest state of working with the corresponding Graph API endpoints and Microsoft Graph PowerShell cmdlets, just to make sure I haven’t missed anything interesting. Getting the meeting attendance report is indeed possible now via the Get-MgUserOnlineMeetingAttendanceReport cmdlet, but that one runs in the context of a user, so not exactly the thing I was looking for. Getting the same via application permissions is also possible, the big unsolved issue however remains the lack of any viable method to list all online meetings within the tenant. Nothing regarding such functionality has been published on the Graph API changelog, and latest comment over at GitHub is from June. So it seem we’re still waiting on this front.

Anyway, here are some code samples that you can use to retrieve the meeting attendance report programmatically. First, let’s start with the delegate permissions model, and the Graph explorer. Two things are needed here: most importantly the meeting ID, which we can obtain via some additional Graph API queries, but to facilitate that you’d need to grant some permissions (which is the second thing). Specifically, you’d need to grant OnlineMeetingArtifact.Read.All and OnlineMeetings.Read permissions to the Graph explorer tool. Once you have the permissions, you can copy the join URL for any meeting you’ve scheduled and use it to obtain the actual meeting ID. The URL looks something like this:

https://teams.microsoft.com/l/meetup-join/19%3ameeting_ZTg0MTQ4ZmEtNmVlYi00YzM1LThlOTktM2MxNzg0ZTYyOTA1%40thread.v2/0?context=%7b%22Tid%22%3a%22923722ba-352a-4eda-bece-09d0a84d0cfb%22%2c%22Oid%22%3a%22584bdb38-888c-4285-8871-c9766cb4791b%22%7d

Having the join URL, you can run the following GET query against the /onlineMeetings endpoint and use the $filter operator to find the matching instance:

https://graph.microsoft.com/beta/me/onlineMeetings?$filter=JoinWebUrl eq ‘https://teams.microsoft.com/l/meetup-join/19%3ameeting_ZTg0MTQ4ZmEtNmVlYi00YzM1LThlOTktM2MxNzg0ZTYyOTA1%40thread.v2/0?context=%7b%22Tid%22%3a%22923722ba-352a-4eda-bece-09d0a84d0cfb%22%2c%22Oid%22%3a%22584bdb38-888c-4285-8871-c9766cb4791b%22%7d’

You can also use the /users/{userId}/onlineMeetings endpoint, however the query does NOT work if you specify a userPrincipalName as the identifier, and expects you to provide an objectID GUID value. Really helpful 🙂 Anyway, here’s how a success response would look like:

The thing we care about here is the first property, id. Once we have the meeting ID, we can request the attendance report, by issuing another GET request, this time against the /onlineMeetings/{meetingId}/meetingAttendanceReport endpoint. To mix things up a bit, I’m using an example of querying against a given user here (not the /me endpoint). Here’s how successful response looks like in the Graph explorer:

The resulting JSON should match the information presented in the CSV file which you can download from the Teams client. So yay, we do have a working way to obtain the meeting attendance report programmatically, at lest when it comes to “known” meetings and using delegate permissions. And since this whole thing started from the mention of a PowerShell cmdlet, let’s see how we can obtain the same report via PowerShell, shall we.

First, and this is important, make sure to use the beta profile, otherwise the corresponding Get-MgUserOnlineMeetingAttendanceReport cmdlet will not be loaded. Then, connect to the Graph and request the necessary permissions, you will be prompted to consent if needed. Next, you can use the Get-MgUserOnlineMeeting  to obtain the meeting id, or just skip to the next step if you have it already. With the meeting id at hand, run the Get-MgUserOnlineMeetingAttendanceReport cmdlet to obtain the actual report. Lastly, parse it.

Select-MgProfile beta
Connect-MgGraph -Tenant michev.onmicrosoft.com -Scopes OnlineMeetingArtifact.Read.All,OnlineMeetings.Read

Get-MgUserOnlineMeeting -Filter {JoinWebUrl eq 'https://teams.microsoft.com/l/meetup-join/19%3ameeting_ODI5Njg5ATEtZGJiNS00YjFiL2kwNDQtZDYxNTg2NTEyOGQw%40thread.v2/0?context={"Tid"%3a"923212ba-352a-4eda-b1ce-09d0684d0cfb"%2c"Oid"%3a"584b2h38-888c-4b85-8871-c97a6cb4791b"}'} -UserId 584b2b38-888c-4b85-8871-c9766cb4791b | select -ExpandProperty Id

$report = Get-MgUserOnlineMeetingAttendanceReport -OnlineMeetingId 'MSo1ODRiMmIzOC04ODhjLTRiODUtODg3MS1jOTc2NmNiNDc5MWIqMCoqMTk6bWVldGluZ19aVGcwTVRRAFptRXRObVZsWWkwMFl6TTFMVGhsT1RrdE0yTXhOemc2WlRZeU9UQTFAdGhyZWFkLnYy' -UserId 58a32b38-888c-4b85-8871-c9366cf4791b

$report | ConvertTo-Json -Depth 5

{
"AttendanceRecords": [
{
"AttendanceIntervals": [
{
"DurationInSeconds": 156,
"JoinDateTime": "2021-11-05T08:00:32.3651334Z",
"LeaveDateTime": "2021-11-05T08:03:08.856403Z"
}
],
"EmailAddress": "vasil@michev.info",
"Identity": {
"DisplayName": "Vasil Michev",
"Id": "584b2b38-xxxx-xxxx-xxxx-c9766cb4791b"
},
"Role": "Organizer",
"TotalAttendanceInSeconds": 156
},
{
"AttendanceIntervals": [
{
"DurationInSeconds": 119,
"JoinDateTime": "2021-11-05T08:00:38.6778309Z",
"LeaveDateTime": "2021-11-05T08:02:38.5855885Z"
}
],
"EmailAddress": "pesho@michev.info",
"Identity": {
"DisplayName": "Pesho",
"Id": "421117a2-xxxx-xxxx-xxxx-927b04839c9b"
},
"Role": "Presenter",
"TotalAttendanceInSeconds": 119
}
],
"Id": "df48df70-7184-4598-af7e-c913d000ecb8",
"TotalParticipantCount": 2,
"AdditionalProperties": {}
}

Now, one thing I didn’t mention above is that in this case, I’m connected to the Graph via the credentials of the user who is the meeting organizer. To cover scenarios where you want to run this against other users, or even better, run in the context of an application, few additional steps will be needed. Most importantly, you will need to configure an Application access policy as detailed for example here. Make sure to scope this policy to any user you’d like to cover, or even to the whole tenant. Otherwise, you will run into errors.

You will of course have to take care of authenticating against the Graph too, with the latest versions of the MG PowerShell module supporting only certificate-based flows. Once connected, use the Get-MgUserOnlineMeeting and Get-MgUserOnlineMeetingAttendanceReport cmdlet, similar to the above examples:

Select-MgProfile beta
Connect-MgGraph -CertificateThumbprint "6AE56AE5E52DF081A868776F39AECF49FEE623BC" -TenantId michev.onmicrosoft.com -ClientId 9dd50c8b-xxxx-xxxx-xxxx-80d200b11505

Get-MgUserOnlineMeetingAttendanceReport -OnlineMeetingId 'MSo1ODRiMmIzOCA3ODhjLTRiODUtODg3MS1jOTc2NmNiNDc5MWIqMCoqMTk6bWVldGluZ19aVGcwTVRRNFptRXRObVZsWWkwMFl6TTFMVGhsT1RrdE0yTXhOemcwWlRZeU9UQTFAdGhyZWFkLnYy' -UserId 584b2b38-xxxx-xxxx-xxxx-c9766cb4791b -Verbose | fl *

AttendanceRecords : {Microsoft.Graph.PowerShell.Models.MicrosoftGraphAttendanceRecord, Microsoft.Graph.PowerShell.Models.MicrosoftGraphAttendanceRecord}
Id : df48df70-7184-4598-af7e-c913d000ecb8
TotalParticipantCount : 2
AdditionalProperties : {[@odata.context, https://graph.microsoft.com/beta/$metadata#users('584b2b38-xxxx-xxxx-xxxx-c9766cb4791b')/onlineMeetings('MSo1ODRiMmIzOC04ODhjLTRiODUtODg3MS1jOTc2NmNiNDc5MWIq
MCoqMTk6bWVldGluZ19aVGcwA1RRNFptRXRObVZsWWkwMFl6TTFMVGhsT1RrdE0yTXhOemcwWlRZeU9UQTFAdGhyZWFkLnYy')/meetingAttendanceReport/$entity]}

All good, but this still doesn’t answer how we can use the Get-MgCommunicationOnlineMeetingAttendanceReport, as mentioned in that announcement, nor the Get-MgCommunicationOnlineMeeting cmdlet to retrieve all meetings. Documentation of course is nowhere to be found, apart from the automatically generated syntax, which is sadly the norm when it comes to MG PowerShell cmdlets. The corresponding Graph API endpoint also do not mention any ways to make this work without a user context, so unless I’ve missed something obvious here, that announcement was made ahead of its time…

 

UPDATE 12/11/2021: Microsoft just announced a change to the above, which you can read about here. Serves me well for publishing stuff on the beta endpoint 🙂

This entry was posted in Graph API, Microsoft 365, Microsoft Teams, Office 365. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.