loading...

Accessing Microsoft Teams summary records (CDR's) for Calls and Meetings using Exchange Web Services

gscales profile image Glen Scales ・3 min read

Whenever you make a Call in Microsoft Teams or have a Teams Meeting the Office 365 substrate will create a CDR (Call details record) for the call or meeting and save this back into you mailbox in a folder off the Non_IPM_Subtree (which makes this effectively hidden from the user). The CDR's and Meeting records are then made discoverable via eDiscovery for compliance purposes (the process is detailed here). In this Post I'm going to look at how you can get to this folder in a Mailbox, access the containing items and also how you can relate the CDR's for a meetings back to the actual Meeting object in the Calendar. For this I'm using Exchange Web Services because of the ItemClass of these items make them not easily accessible via the Microsoft Graph. An Output example of what you see you run the script associated with this post looks like.

Containing Folder

The folder that contains these Meeting and Call CDR’s is located in the Non_IPM_Subtree of a Mailbox eg looking at this folder in the ewsEditor

To Access this Folder easily using EWS you can use an Extended property that is set on the RootFolder of the Mailbox which provides the HexEntryid of the Folder in question which can then be converted to an EWSId using the ConvertId operation. Here is Gist for doing this using PowerShell with EWS

Once you have access to this Folder (or even just the EWSId for it) you can then access the Items in the underlying folder using the FindItems and GetItems operations in EWS. The Items themselves have an underlying Item Class of IPM.AppointmentSnapshot.SkypeTeams.Call and IPM.AppointmentSnapshot.SkypeTeams.Meeting and the sanitized version of the Call Log is in the Body of the Message while a JSON version is available in an extended property on the Message. The JSON version contains all the raw Identifiers in the data that would need to be sanitized to make is useful (eg resolving the Guids to users etc) so I haven’t used it for this reason (if you want to view these properties yourself just use a Mapi editor like OutlookSpy or MFCMapi).

Relating the Meeting CDR to the actual Meeting object in Mailbox Calendar

The CDR only has a subset of the meeting information so if you want to do some enhanced reporting you will need to access the actual meeting object in the Calendar. To do this you need someway of relate these two separate objects to each other. When I first looked at this i found the Meeting Goid property on the snapshot item and the meeting item and thought I should just be able to relate the items this way . However these properties don't match so I had to look for another solution to relate the CDR to the meeting object. For Teams Meeting some extra Extended properties are created on the Item that is created in the Calendar which contains the ThreadId for the meeting eg

This ThreadId is available as part of the Subject of the CDR so this was the easy way to go about relating the Appointments. Another way is the Meeting's iCalUid is also available in the CDR in an extended property but there is more work to parse this out. In the following script i have a separate function that queries the calendar items and indexes them via the Meeting cid (if available) this is then available when the TeamsMeeting items are queried and the final output is created.

To run this script use

Get-TeamsCDRItems -MailboxName mailbox@domain.com

The final script to access the items looks like the following

Posted on by:

gscales profile

Glen Scales

@gscales

Developer specializing in Office 365

Discussion

pic
Editor guide
 

Hi Glen,

Looks like exactly what I'm after for a current project I'm working on. Probably something stupid that I've missed, but I don't seem to be able to get it to run. I've copied the code and run the script, but there's no output shown and no errors either.

Are you able to clarify any prerequisites that need to be in place for this to run?

Thanks in advance,

Chris

 

Disregard this request - it was a very stupid mistake on my part. Worked great. Now I just need to expand to cover multiple users.

 

Any chance you could share your solution to save myself and a colleague some time? We seemed to have hit the same wall you did. We assumed it was a missing call to a function to kick this off, however, it doesn't seem to act as expected.