Export Microsoft Teams conversations with CLI for Microsoft 365

As more organizations adopt Microsoft 365 and, along with it, Microsoft Teams, IT pros are looking for easy ways to manage the massive productivity suite and workplace collaboration program. CLI for Microsoft 365 has become a popular choice to tweak Microsoft 365 and SharePoint settings and configurations because it provides a range of management options via its lightning-quick command-line interface. Best of all, CLI for Microsoft 365 adds functionalities that are simply not available in Microsoft Teams or Microsoft 365. For example, you may want to export Microsoft Teams conversations to a local drive quickly and easily. Of course, using CLI for Microsoft 365 means finding and using the right commands and scripts to get your tasks accomplished. Fortunately, there’s no shortage of content.

CLI for Microsoft 365

But first things first: If you haven’t installed CLI for Microsoft 365, you can do it with this one-line PowerShell command:

npm i -g @pnp/cli-microsoft365

Now, let’s move on to the nitty-gritty of this article. This helpful new PowerShell script allows you to export conversations from Microsoft Teams Channels to your local drive. This can be useful for a range of reasons, such as for archiving purposes or perhaps you want to use the conversation elsewhere. You do not have to be an admin to use this script. Microsoft says you can use it to export conversations from any team of which you are a member.

The PowerShell script was originally published on Microsoft’s Tech Community site and developed by Tech Community member Joseph Velliah. Here it is:

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 100 | Out-File $outputFilePath
Write-Host "Open $outputFilePath file to review your output" -F Green
Catch {
$ErrorMessage = $_.Exception.Message
Write-Error $ErrorMessage

You can find more scripts at the CLI GitHub site. If you have any questions or suggestions about CLI for Microsoft 365, you can reach out to the experts at its dedicated Twitter page. For a good primer on how to get started with CLI for Microsoft 365, click here.

Featured image: Shutterstock

About The Author

Leave a Comment

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

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Scroll to Top