Skip to main content

Looking into the Microsoft Team's TeamChat folder in an Office365 Mailbox using EWS

If you looked at the folder structure in an Office365 Mailbox (or older Exchange Mailbox) using a MAPI editor so you could see all the Non_IPM_Subtree and hidden folders around 5 years ago it was a relatively simple picture. Today with the rapid pace of the change in Office365 its a little bit of minefield on new folders and hidden data that is stored and used by various applications in your Mailbox. A good case in point is the Files Hidden folder which Tony explains about in https://www.petri.com/mysterious-files-folder . Microsoft Teams is the new kid on the block in terms of collaboration applications that integrate into Mailboxes and other Office365 workloads. As you chat using the Microsoft Teams client as part of it compliance/discoverability process associated with Microsoft Teams a cloud-based process creates conversation items in a Hidden folder in your Office365 Mailbox called TeamChat (this is a Subfolder of the Conversation history). Because its a hidden folder users won't be able to see the content but the data stored is searchable (at the time of writing this there is very little official documentation that I can find Tony's post https://www.petri.com/teams-compliance-story and a few other forum posts give the best guide to what this is and how it works).

So because this is a hidden folder using the new Graph API won't work (although you can actually get to the Items using the Graph API by searching) so using EWS is the best approach for now as it gives the most flexibility if you want to start playing around with this data programmatically.

Binding to the folder in EWS

You could use a few different ways to get the TeamChat folder the approach I've used is to make use of the Extended Property TeamChatFolderEntryId which is set on the Root Folder of a Mailbox. This contains the PR_EntryId of the Folder in question so once you convert this to an EWSId using the CovertId operation in EWS you can then bind directly to the folder. eg here's what the code looks like


$folderid= new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Root,$MailboxName)   $TeamChatFolderEntryId = new-object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition([System.Guid]::Parse("{E49D64DA-9F3B-41AC-9684-C6E01F30CDFA}"), "TeamChatFolderEntryId", [Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Binary); $psPropset= new-object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties) $psPropset.Add($TeamChatFolderEntryId) $RootFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$folderid,$psPropset) $FolderIdVal = $null
if ($RootFolder.TryGetProperty($TeamChatFolderEntryId,[ref]$FolderIdVal))  {    $TeamChatFolderId= new-object Microsoft.Exchange.WebServices.Data.FolderId((ConvertId -HexId ([System.BitConverter]::ToString($FolderIdVal).Replace("-","")) -service $service))    $TeamChatFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$TeamChatFolderId);   } }
Once you have access to the Folder you can start pulling basic folder statistics like the Number of Items, Sizes, AttachmentCounts etc (or more interestingly things you won't be able to do using Get-MailboxFolderstatitistics). But the more interesting thing to do is to look at the data stored on the conversation items, because these aren't your normal email Messages extended properties are used to hold the different data from Teams/Skype (also the normal Attachment and recipients collections of a message are also used). There are a few properties in use (which generally aren't documented either so if your interested I would suggest taking a look yourself with a MAPI editor at a few items). But the one that is of most interest to me anyway is the SkypeMessagePropertyBag which contains a lot the Metadata from the chat message. This is a string property that contain JSON so accessing and decoding it into something usable in Powershell is pretty easy using ConvertFrom-Json.

I've put together a sample script module for accessing this folder using EWS that has a couple of different functions. The first Get-TeamChatStats accesses the folder and does some simple aggregation of folder and items properties including the ConversationId from the SkypeMessagePropertyBag  to aggregated the number of conversations.


Get-TeamChatSkypeMessagePropertyBag enumerates all the Items in the TeamChat Folder and then outputs the SkypeMessagePropertyBag to the pipeline so you can then do any of you own aggregation or investigation etc eg



My current TeamChat data is pretty simple so there could be a few bugs in these scripts due to the limited data I had to run against. I've put the code up for these script on GitHub at https://github.com/gscales/Powershell-Scripts/blob/master/TeamChatStats.ps1 so fell free to log an issue you experience and I'll path the code.

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

How to test SMTP using Opportunistic TLS with Powershell and grab the public certificate a SMTP server is using

Most email services these day employ Opportunistic TLS when trying to send Messages which means that wherever possible the Messages will be encrypted rather then the plain text legacy of SMTP.  This method was defined in RFC 3207 "SMTP Service Extension for Secure SMTP over Transport Layer Security" and  there's a quite a good explanation of Opportunistic TLS on Wikipedia  https://en.wikipedia.org/wiki/Opportunistic_TLS .  This is used for both Server to Server (eg MTA to MTA) and Client to server (Eg a Message client like Outlook which acts as a MSA) the later being generally Authenticated. Basically it allows you to have a normal plain text SMTP conversation that is then upgraded to TLS using the STARTTLS verb. Not all servers will support this verb so if its not supported then a message is just sent as Plain text. TLS relies on PKI certificates and the administrative issue s that come around certificate management like expired certificates which is why I wrote th

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