В этой статье мы рассмотрим, как получить доступ к содержимому чата Microsoft Teams и экспортировать сообщения из него с помощью PowerShell.
Чаты Teams хранятся в скрытой папке Conversation history\Team Chat в общем почтовом ящике, который создается автоматически при создании новой группы Microsoft 365 (при этом сращу создается группа Teams, сайта, сайт и библиотека в SharePoint Online, группа Yammer и т.д.
Однако вы не сможете получить доступ к этой защищенной папке с историей чата Teams через Outlook или другое приложения. Вы можете экспортировать содержимое почтового ящика Exchange Online в PST файл с помощью Content Search в Security and Compliance Center, и потом подключить PST файл в Outlook. Но это не очень удобно. Гораздо проще получить список сообщений в чате Teams через PowerShell.
Для подключения к тенанту Microsoft 365 мы будем использовать Microsoft Graph API.
- Создайте новое приложение appTeamsView через Azure Portal (Azure AD -> App registration -> New registration);
- Скопируйте значения:
Application (client) ID: your_app_ID
Directory (tenant) ID: your_tenant_ID - Перейдите в API Permissions, выберите Microsoft Graph -> Application permissions -> Channel -> и выберите Channel.Basic.ReadAll и ChannelMessage.Read.AllДобавьте права Group -> Group.Read.All.Предоставьте аналогичные разрешения в Microsoft Graph -> Delegated permissions и дополнительно Directory.AccessAsUser.AllЕсли не предоставить права на доступ от пользователя, то при получении списка сообщений из чата Teams появится ошибка
Invoked API requires Protected API access in application-only context when not using Resource Specific Consent. - Нажмите “Grant Admin Consent for..»;

- еперь нужно создать секрет для доступа к приложению. Перейдите в Certificates & secrets -> New client secrets, укажите имя ключа и срок действия.
Скопируйте значение из поля Value
Value: your_secret

Теперь можно подключиться к Azure AD из PowerShell и получить токен доступа.
$clientId = "your_app_ID"
$tenantName = "yourtenant.onmicrosoft.com"
$clientSecret = "your_secret"
$resource = "https://graph.microsoft.com/"
$Username = "user@yourtenant.onmicrosoft.com"
$Password = "yourpassword"
$ReqTokenBody = @{
Grant_Type = "Password"
client_Id = $clientID
Client_Secret = $clientSecret
Username = $Username
Password = $Password
Scope = "https://graph.microsoft.com/.default"
}
$TokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token" -Method POST -Body $ReqTokenBody
Теперь вы можете получить различные данные из Azure AD.
Выведем список Teams в вашем тенанте:
#Getting all Teams
$header= @{Authorization = "Bearer $($TokenResponse.access_token)"}
$BaseURI = "https://graph.microsoft.com/beta"
$AllMicrosoftTeams = (Invoke-RestMethod -Uri "$($BaseURI)/groups?`$filter=resourceProvisioningOptions/Any(x:x eq 'Team')" -Headers $header -Method Get -ContentType "application/json").value
$AllMicrosoftTeams| FT id, DisplayName,Description
Теперь выведем список каналов в нужной вам группе Teams (укажите ее ID):
# List channels in Teams $TeamsID="your_team_id" $TeamsChannels = (Invoke-RestMethod -Uri "$($BaseURI)/teams/$($TeamsID)/channels" -Headers $Header -Method Get -ContentType "application/json").value $TeamsChannels | FT id, DisplayName,Description

Теперь вы можете получить список сообщений и ответов на них из чата указанного канала:
$ChannelID="your_chat_id "
$Header =@{Authorization = "Bearer $($Tokenresponse.access_token)"}
$apiUrl = "https://graph.microsoft.com/beta/teams/$TeamsID/channels/$ChannelID/messages"
$Data = Invoke-RestMethod -Uri $apiUrl -Headers $header -Method Get
$Messages = ($Data | Select-Object Value).Value
class messageData
{
[string]$dateTime
[string]$from
[string]$body
[string]$re
messageData()
{
$this.dateTime = ""
$this.from = ""
$this.body = ""
$this.re = ""
}
}
$messageSet = New-Object System.Collections.ArrayList;
foreach ($message in $Messages)
{
$result = New-object messageData
$result.DateTime=Get-Date -Date (($message).createdDateTime) -Format 'yyyy/MM/dd HH:mm'
$result.from = $message.from.user.displayName
$result.body = $message.body.content
$messageSet.Add($result)
#parsing replies
$repliesURI = "https://graph.microsoft.com/beta/teams/" + $TeamsID + "/channels/" + $ChannelID + "/messages/" + $message.ID + "/replies?`$top100"
$repliesResponse = Invoke-RestMethod -Method Get -Uri $repliesURI -Headers $header
foreach ($reply in $repliesResponse.value)
{
$replyData = New-Object messageData
$replyData.dateTime = Get-Date -Date (($reply).createdDateTime) -Format 'yyyy/MM/dd HH:mm'
$replyData.from = $reply.from.user.displayName
$replyData.body= $reply.body.content
$replyData.re="RE"
$messageSet.Add($replyData)
}
}
$messageSet|ConvertTo-Html | Out-File c:\ps\teams_chat_history.html -Encoding utf8
Этот скрипт получает список обсуждений из указанного канала, для каждого обсуждения получает список ответов и формирует HTML файл с полным содержимым чата. Ответы на обсуждения в таблице содержат ключевое поле RE.
Полный код доступен в нашем репозитории на GitHub: https://github.com/winadm/posh/blob/master/teams/teams_chat_export_msgs.ps1



Большое спасибо за скрипт, однозначно пригодится в свете грядущей миграции с Тимса!
С большим удивлением обнаружил, что для бесплатного Тимса описанная схема экспорта тоже работает, думал что в нем API под корень зарезан.
Замечу что само получение сообщений написано не полностью, их надо получать в цикле, так как по умолчанию выдается только 20 сообщений, да и максимума в 50 тоже для реальной переписки никак не хватит.
Для получения следующей порции нужно использовать $Data.’@odata.nextLink’