We utilize Teams during incidents and create channels for each. We would like to be able to export conversation history.

Problem Statements

  • Right now the only option we have is to go through Security & Compliance.
  • Teams usage is growing in every organization and it would soon become unreasonably to only have Administrators be the ones doing exports of channels for all the Teams.


This script uses Microsoft 365 CLI to export the conversations from Microsoft Teams Channels.



  • Commands m365 teams message list and reply list are based on an API that is currently in preview and is subject to change once the API reached general availability.
  • You can only retrieve a message from a Microsoft Teams team if you are a member of that team.

PowerShell Script

function  Get-Teams {
    $teams = m365 teams team list -o json | ConvertFrom-Json -AsHashtable
    return $teams
function  Get-Channels {
    param (
        [Parameter(Mandatory = $true)] [string] $teamId
    $channels = m365 teams channel list --teamId $teamId -o json | ConvertFrom-Json -AsHashtable
    return $channels
function  Get-Messages {
    param (
        [Parameter(Mandatory = $true)] [string] $teamId,
        [Parameter(Mandatory = $true)] [string] $channelId
    $messages = m365 teams message list --teamId $teamId --channelId $channelId -o json | ConvertFrom-Json -AsHashtable
    return $messages
function  Get-MessageReplies {
    param (
        [Parameter(Mandatory = $true)] [string] $teamId,
        [Parameter(Mandatory = $true)] [string] $channelId,
        [Parameter(Mandatory = $true)] [string] $messageId

    $messageReplies = m365 teams message reply list --teamId $teamId --channelId $channelId --messageId $messageId -o json | ConvertFrom-Json -AsHashtable
    return $messageReplies

Try {
    $teamsCollection = [System.Collections.ArrayList]@()
    $teams = Get-Teams
    $progressCountTeam = 1;
    foreach ($team in $teams) {
        Write-Progress -Id 0 -Activity "Processing channels in Team : $($team.displayName)" -Status "Team $progressCountTeam of $($teams.length)" -PercentComplete (($progressCountTeam / $teams.length) * 100)
        $channelsCollection = [System.Collections.ArrayList]@()
        $channels = Get-Channels $team.id
        $progressCountChannel = 1;
        foreach ($channel in $channels) {
            Write-Progress -Id 1 -ParentId 0 -Activity "Processing messages in channel : $($channel.displayName)" -Status "Channel $progressCountChannel of $($channels.length)" -PercentComplete (($progressCountChannel / $channels.length) * 100)
            $messages = Get-Messages $team.id $channel.id
            $messagesCollection = [System.Collections.ArrayList]@()
            foreach ($message in $messages) {
                $messageReplies = Get-MessageReplies $team.id $channel.id $message.id
                $messageDetails = $message
                [void]$messageDetails.Add("replies", $messageReplies)
            $channelDetails = $channel
            [void]$channelDetails.Add("messages", $messagesCollection)
        $teamDetails = $team
        [void]$teamDetails.Add("channels", $channelsCollection)
    Write-Progress -Id 0 -Activity " " -Status " " -Completed
    Write-Progress -Id 1 -Activity " " -Status " " -Completed
    $output = @{}
    [void]$output.Add("teams", $teamsCollection)
    $executionDir = $PSScriptRoot
    $outputFilePath = "$executionDir/$(get-date -f yyyyMMdd-HHmmss).json"
    # ConvertTo-Json cuts off data when exporting to JSON if it nests too deep. The default value of Depth parameter is 2. Set your -Depth parameter whatever depth you need to preserve your data.
    $output | ConvertTo-Json -Depth 10 | Out-File $outputFilePath 
    Write-Host "Open $outputFilePath file to review your output" -F Green 
Catch {
    $ErrorMessage = $_.Exception.Message
    Write-Error $ErrorMessage

I hope this script has been helpful, and don’t forget to check out this article written by Anupam Shrivastava on exporting Microsoft teams chat messages.