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.

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

Peter King

Peter King has been Managing Editor at TechGenix since July 2016. As a technology editor, reporter, and columnist, he has worked at some of the biggest U.S. newspapers and technology magazines, directing coverage of breaking news stories and steering award-winning projects from conception to publication. As a professor of Journalism at Hofstra University in New York, he has taught and inspired the next generation of journalists.

Published by
Peter King

Recent Posts

Enterprise considerations when purchasing laptops

You're tasked with purchasing and provisioning laptops for a bunch of users at your company.…

1 day ago

IKEA experiencing internal phishing attacks

IKEA is currently in a state of disarray thanks to an internal reply-chain email attack.

1 day ago

How to Fix Exchange Mailbox Corruption?

If transaction logs get corrupt, deleted or the server shuts down before the logs are…

2 days ago

2.4GHz or 5GHz WiFi: Which one to choose?

WiFi is not just for laptops and smartphones. It is also an essential part of…

2 days ago

Is cloud security an illusion?

Migrating your infrastructure into the cloud boosts your security and helps you avoid cyberattacks. Or…

3 days ago

How to delete a sprint when using Azure DevOps

The process of trying to delete a sprint in Azure DevOps is not straightforward. This…

3 days ago