Forum Discussion
Script for Teams-Chat backup
Sometimes it is necessary to save the chat history of a Teams-Channel. I wrote a simple script, where you can select the needed Team(s) and outputting the Chat-Content to a html File. If there are any comments, I'm open for suggestions.
Here is the Script:
#Install-Module -Name SharePointPnPPowerShellOnline
$SecurityScope = @("Group.Read.All")
Connect-PnPOnline -Scopes $SecurityScope
$PnPGraphAccessToken = Get-PnPGraphAccessToken
,$Headers = @{
"Content-Type" = "application/json"
Authorization = "Bearer $PnPGraphAccessToken"
}
$Date = Get-Date -Format "dd.MM.yyyy, HH:mm"
$DOCTYPE = "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'><html xmlns='http://www.w3.org/1999/xhtml'>"
$Style ="<style>table {border-collapse: collapse; width:100%;} table th {text-align:left; background-color: #004C99; color:#fff; padding: 4px 30px 4px 8px;} table td {border: 1px solid #004C99; padding: 4px 8px;} td {background-color: #DDE5FF}</style>"
$Head = "<head><title>Backup: Teams-Chat</title></head>"
$Body = "<body><div style='width: 100%;'><table><tr><th style='text-align:center'><h1>Backup: Teams-Chat from $Date</h1></th></tr></table>"
$Table_body = "<div style='width: 100%;'><table><tr><th>TimeStamp</th><th>User Name</th><th>Message</th></tr>"
$Content =""
$Footer = "</body>"
$response_teams = Invoke-RestMethod -Uri "https://graph.microsoft.com/beta/groups" -Method Get -Headers $Headers -UseBasicParsing
$response_teams.value | Where-Object {$_.groupTypes -eq "Unified"} | Select-Object -Property displayName, ID | Out-GridView -PassThru -Title 'Which Team-Chat do you want to backup?' |
ForEach-Object {
$Team_ID = $_.ID
$Team_displayName = $_.displayName
Write-Progress -Activity "Bckup Team Chat Mesasages" -Status "Get Team: $($Team_displayName)"
Start-Sleep -Milliseconds 50
$Content += "</br></br><hr><h2>Team: " + $Team_displayName + "</h2>"
$response_channels = Invoke-RestMethod -Uri "https://graph.microsoft.com/beta/teams/$Team_ID/channels" -Method Get -Headers $Headers -UseBasicParsing
$response_channels.value | Select-Object -Property ID, displayName |
ForEach-Object {
$Channel_ID = $_.ID
$Channel_displayName = $_.displayName
Write-Progress -Activity "Bckup Team Chat Mesasages" -Status "Get Channel: $($Channel_displayName)"
Start-Sleep -Milliseconds 50
$Content += "<h3>Channel: " + $Channel_displayName + "</h3>"
$response_messages = Invoke-RestMethod -Uri "https://graph.microsoft.com/beta/teams/$Team_ID/channels/$Channel_ID/messages" -Method Get -Headers $Headers -UseBasicParsing
$response_messages.value | Select-Object -Property ID, createdDateTime, from |
ForEach-Object {
$Message_ID = $_.ID
$Message_TimeStamp = $_.createdDateTime
$Message_from = $_.from
$response_content = Invoke-RestMethod -Uri "https://graph.microsoft.com/beta/teams/$Team_ID/channels/$Channel_ID/messages/$Message_ID" -Method Get -Headers $Headers -UseBasicParsing
Write-Progress -Activity "Bckup Team Chat Mesasages" -Status "Get Team: $($Team_displayName), Gett Message-ID: $($Message_ID), from Channel: $($Channel_displayName)"
Start-Sleep -Milliseconds 50
$Content += $Table_body + "<td>" + $Message_TimeStamp + "</td><td style='width: 10%;'>" + $Message_from.user.displayName + "</td><td style='width: 75%;'>" + $response_content.body.content + $response_content.attachments.id + "</td></table></div>"
$response_Reply = Invoke-RestMethod -Uri "https://graph.microsoft.com/beta/teams/$Team_ID/channels/$Channel_ID/messages/$Message_ID/replies" -Method Get -Headers $Headers -UseBasicParsing
$response_Reply.value | Select-Object -Property ID, createdDateTime, from |
ForEach-Object {
$Reply_ID = $_.ID
$Reply_TimeStamp= $_.createdDateTime
$Reply_from = $_.from
$response_Reply = Invoke-RestMethod -Uri "https://graph.microsoft.com/beta/teams/$Team_ID/channels/$Channel_ID/messages/$Message_ID/replies/$Reply_ID" -Method Get -Headers $Headers -UseBasicParsing
Write-Progress -Activity "Bckup Team Chat Mesasages" -Status "Gett Reply-Message-ID: $($Reply_ID)"
Start-Sleep -Milliseconds 50
ForEach-Object {
$Content += $Table_body + "<td>" + $Reply_TimeStamp + "</td><td style='width: 10%;'>" + $Reply_from.user.displayName + "</td><td style='width: 75%;'>" + $response_Reply.body.content + $response_Reply.attachments.id + $response_Reply.attachments.name + "</td></table></div>"
}
}
}
}
}
$DOCTYPE + $Style + $Head + $Body + $Content + $Footer | Out-File -FilePath "C:\Backup.html"
& "C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe" "C:\Backup.html"
- Jojo90Copper ContributorGood work! Is There anyway to import after the export?
- Dominik SchneiderCopper Contributor
Doesn't seem to work for me:AADSTS70011: The provided request must include a 'scope' input parameter. The provided value for the input parameter 'scope' is not valid. The scope https://graph.microsoft.com/.default https://graph.microsoft.com/Group.Read.All offline_access openid profile is not valid. .default scope can't be combined with resource-specific scopes.- dimitreesamuelCopper Contributor
Probably a little late, you need to ensure you have the Group Read-All permissions is granted in Azure Active directory. I'm pretty sure this is granted from portal.azure.com
when executing a script like this in powershell you should get prompted to input your credentials. I did this for a Microsoft Planner script to export and report from Tenant A to Tenant B.
- BarryGoblonIron Contributor
365CS I have some improvements of the script:
# Install-Module -Name SharePointPnPPowerShellOnline
# Set up necessary permissions
$SecurityScope = @("Group.Read.All")
Connect-PnPOnline -Scopes $SecurityScope
$PnPGraphAccessToken = Get-PnPGraphAccessToken# Update the headers with valid scopes
$Headers = @{
"Content-Type" = "application/json"
Authorization = "Bearer $PnPGraphAccessToken"
"scope" = "https://graph.microsoft.com/.default"
}
Rest of your script you can leave unchanged. If you're looking for a smoother backup experience, consider trying NAKIVO. It's user-friendly and reliable for your backup needs.