May 18 2022 06:52 AM
I'm using the below script to export channel conversations. It works fine per channel. But I want to be able to export all channel conversations in a Team. I tried using ForEach ($Channel in $Channels) but it's not working. Can someone help please. Credit to PSGuy for the original script: https://www.psguy.eu/how-to-export-ms-teams-chat-to-html-file-for-backup/
[CmdletBinding(DefaultParameterSetName='default')]
param
(
[Parameter(ParameterSetName='Channel')]
$Team,
[Parameter(Mandatory=$false,ParameterSetName='default')]
[Parameter(Mandatory=$true,ParameterSetName='Channel')]
$Channel
)
Write-Host "Exporting Team Chats Homie"
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
$Date = Get-Date -Format "MM-dd-yyyy-HHmm"
$clientId = "YourClientID"
$tenantName = "YourTenantName"
$clientSecret = "YourClientSecret"
$resource = "https://graph.microsoft.com/"
$ReqTokenBody = @{
Grant_Type = "Password"
client_Id = $clientID
Client_Secret = $clientSecret
Username = 'YourTeamsAdmUserName'
Password = 'YourTeamsAdmPassword'
Scope = "https://graph.microsoft.com/.default"
}
$TokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token" -Method POST -Body $ReqTokenBody
#Getting all Groups
$apiUrl = "https://graph.microsoft.com/beta/groups"
$Data = Invoke-RestMethod -Headers @{Authorization = "Bearer $($TokenResponse.access_token)"} -Uri $apiUrl -Method Get -ErrorVariable RespErr
$Groups = ($Data | Select-Object Value).Value
if ($Team -eq $NULL){
Write-Host "You have" -NoNewline
Write-Host " $($Groups.Count)" -ForegroundColor Yellow -NoNewline
Write-Host " teams."
Write-Host ""
Write-Host "Messages from which Team do you want to export to the HTML format?" -ForegroundColor Yellow
$Groups | FT DisplayName,Description
$Team = Read-Host "Type one of the Team (DisplayName)"
}
$TeamID = ($Groups | Where-Object {$_.displayname -eq "$($Team)"}).id
$apiUrl = "https://graph.microsoft.com/v1.0/teams/$TeamID/Channels"
$Data = Invoke-RestMethod -Headers @{Authorization = "Bearer $($TokenResponse.access_token)"} -Uri $apiUrl -Method Get
if ($Channel -eq $NULL){
Write-Host "You choose" -NoNewline
Write-Host " $($Team)" -ForegroundColor Yellow -NoNewline
Write-Host " Team."
Write-Host ""
$Channels = ($Data | Select-Object Value).Value
Write-Host "Messages from which Channel do you want to export to the HTML format?" -ForegroundColor Yellow
$Channels | FT DisplayName,Description
$Channel = Read-Host "Type one of the Channel(DisplayName)"
}
$ChannelID = (($Data | Select-Object Value).Value | Where-Object {$_.displayName -eq "$($Channel)"}).ID
$apiUrl = "https://graph.microsoft.com/beta/groups/$TeamID/members"
$Data = Invoke-RestMethod -Headers @{Authorization = "Bearer $($TokenResponse.access_token)"} -Uri $apiUrl -Method Get
class messageData
{
[string]$dateTime
[string]$from
[string]$body
messageData()
{
$this.dateTime = ""
$this.from = ""
$this.body = ""
}
}
function parseMessage($Data) #returns resultset
{
$messages = ($Data | Select-Object Value).Value
foreach ($message in $Messages)
{
$messageID = $message.id
$messageSet = New-Object System.Collections.ArrayList;
$result = New-object messageData
#parse message
if ($NULL -eq $message.from.user.displayName) {
$result.dateTime = $message.createdDateTime
$result.from = $message.from.application.displayName
}
else {
$result.dateTime = $message.createdDateTime
$result.from = $message.from.user.displayName
}
$bodyOut = ""
if ($NULL -eq $message.summary)
{
foreach ($attachment in $message.attachments)
{
$output = $attachment.content
$output = $output.substring(14)
$output = $output.substring(0,$output.length-4)
$bodyOut = $bodyOut + $output
}
}
else {
$bodyOut = $message.summary;
}
$bodyOut = $bodyOut + $message.body.content
$result.body = $bodyOut;
$messageSet.Add($result)
#parse replies
$repliesURI = "https://graph.microsoft.com/beta/teams/" + $TeamID + "/channels/" + $ChannelID + "/messages/" + $messageID + "/replies?`$top100"
$repliesResponse = Invoke-RestMethod -Method Get -Uri $repliesURI -Headers @{Authorization = "Bearer $($TokenResponse.access_token)"}
foreach ($reply in $repliesResponse.value )
{
$replyData = New-Object messageData
if ($NULL -eq $reply.from.user.displayName) {
$replyData.dateTime = $reply.createdDateTime
$replyData.from = $reply.from.application.displayName
}
else {
$replyData.dateTime = $reply.createdDateTime
$replyData.from = $reply.from.user.displayName
}
$bodyOut = ""
if ($NULL -eq $message.summary)
{
foreach ($attachment in $reply.attachments)
{
$output = $attachment.content
$output = $output.substring(14)
$output = $output.substring(0,$output.length-4)
$bodyOut = $bodyOut + $output
}
}
else {
$bodyOut = $message.summary
}
$replyData.body = $bodyOut + $reply.body.content
$messageSet.Add($replyData)
}
$resultList.Add($messageSet)
}
return
}
$TokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token" -Method POST -Body $ReqTokenBody
$resultList = New-Object System.Collections.ArrayList;
$apiUrl = "https://graph.microsoft.com/beta/teams/$TeamID/channels/$ChannelID/messages?`$top=100"
$sourceData = Invoke-RestMethod -Headers @{Authorization = "Bearer $($TokenResponse.access_token)"} -Uri $apiUrl -Method Get
parseMessage($sourceData)
$nextLink = $sourceData.'@Odata.NextLink'
while ($NULL -ne $nextLink)
{
$nextURL = $nextLink;
$sourceData = Invoke-RestMethod -Headers @{Authorization = "Bearer $($TokenResponse.access_token)"} -Uri $nextURL -Method Get
parseMessage($sourceData)
$nextLink = $sourceData.'@Odata.NextLink'
}
$resultFieldSet = New-Object System.Collections.ArrayList
foreach($resultData in $resultList) {
$resultFields = $resultData | Select-Object @{Name = 'DateTime'; Expression = {Get-Date -Date (($_).dateTime) -Format 'MM/dd/yyyy hh:mm:ss.fff tt'}}, @{Name = 'From'; Expression = {((($_).from))}}, @{Name = 'Message'; Expression = {(($_).body) -replace '<.*?>',''}}| Sort-Object DateTime
$resultFieldSet.Add($resultFields)
}
$Header = @"
<style>
h1, h5, th { text-align: center; }
table { margin: auto; font-family: Segoe UI; box-shadow: 10px 10px 5px #888; border: thin ridge grey; }
th { background: #0046c3; color: #fff; max-width: 400px; padding: 5px 10px; }
td { font-size: 11px; padding: 5px 20px; color: #000; }
tr { background: #b8d1f3; }
tr:nth-child(even) { background: #dae5f4; }
tr:nth-child(odd) { background: #b8d1f3; }
</style>
"@
$count = 0
foreach ($resultCount in $resultList){
$count = $count + $resultCount.Count
}
$body = "<body><b>Generated:</b> $(Get-Date -Format 'MM/dd/yyyy hh:mm tt') <br><br> <b>Team Name:</b> $($Team) <br> <b>Channel Name:</b> $($Channel) <br><br>" + "<b>number of messages:</b> " + $count + " <br><br>"
$body = $body + "</head>"
$resultHtml = ""
foreach ($resultFields in $resultFieldSet){
$tempHtml = $resultFields | ConvertTo-Html -Head $header
$resultHtml = $tempHtml + "<br>" + $resultHtml
}
$resultHtml = $body + "<br>" + $resultHtml
$Export = "$dir\TeamsHistory\$Team-$Channel"
New-Item -ItemType Directory -Path $Export -ErrorAction Ignore
$resultHtml | Out-File $Export\$Team-$Channel-$Date.html
Write-Host "
"
Write-Host "Messages from the" -NoNewline
Write-Host " $($Team)" -NoNewline -ForegroundColor Yellow
Write-Host " team and" -NoNewline
Write-Host " $($Channel)" -NoNewline -ForegroundColor Yellow
Write-Host " channel were generated and saved to the" -NoNewline
Write-Host " $($Export)" -NoNewline -ForegroundColor Yellow
Write-Host " as a" -NoNewline
Write-Host " $($Team)-$($Channel)-$($Date).html" -NoNewline -ForegroundColor Yellow
Write-Host " file."
Write-Host "
"
May 19 2022 01:13 PM - edited May 19 2022 01:19 PM
@AshMSport To export messages from all Channels within a team, you need to loop through the Channels. Here is a slightly modified script (All credit to original author you mentioned in your post).
Ensure your app has the required permissions. For my test, I gave the following permissions. It may be more permissions than what is really needed. You can remove permissions one by one and test to determine the minimal permissions required.
[CmdletBinding(DefaultParameterSetName='default')]
param
(
[Parameter(ParameterSetName='Channel')]
$Team,
[Parameter(Mandatory=$false,ParameterSetName='default')]
[Parameter(Mandatory=$true,ParameterSetName='Channel')]
$Channel
)
Write-Host "Exporting Team Chats Homie"
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
$Date = Get-Date -Format "MM-dd-yyyy-HHmm"
#TODO: Update for your tenant
$clientId = "XXXXXXX"
$tenantName = "YYYYYY"
$clientSecret = "ZZZZZZZ"
$resource = "https://graph.microsoft.com/"
class messageData
{
[string]$dateTime
[string]$from
[string]$body
messageData()
{
$this.dateTime = ""
$this.from = ""
$this.body = ""
}
}
function parseMessage($Data) #returns resultset
{
$messages = ($Data | Select-Object Value).Value
foreach ($message in $Messages)
{
$messageID = $message.id
$messageSet = New-Object System.Collections.ArrayList;
$result = New-object messageData
#parse message
if ($NULL -eq $message.from.user.displayName) {
$result.dateTime = $message.createdDateTime
$result.from = $message.from.application.displayName
}
else {
$result.dateTime = $message.createdDateTime
$result.from = $message.from.user.displayName
}
$bodyOut = ""
if ($NULL -eq $message.summary)
{
foreach ($attachment in $message.attachments)
{
$output = $attachment.content
if ($output)
{
$output = $output.substring(14)
$output = $output.substring(0,$output.length-4)
}
$bodyOut = $bodyOut + $output
}
}
else {
$bodyOut = $message.summary;
}
$bodyOut = $bodyOut + $message.body.content
$result.body = $bodyOut;
$messageSet.Add($result)
#parse replies
$repliesURI = "https://graph.microsoft.com/beta/teams/" + $TeamID + "/channels/" + $ChannelID + "/messages/" + $messageID + "/replies?`$top100"
$repliesResponse = Invoke-RestMethod -Method Get -Uri $repliesURI -Headers @{Authorization = "Bearer $($TokenResponse.access_token)"}
foreach ($reply in $repliesResponse.value )
{
$replyData = New-Object messageData
if ($NULL -eq $reply.from.user.displayName) {
$replyData.dateTime = $reply.createdDateTime
$replyData.from = $reply.from.application.displayName
}
else {
$replyData.dateTime = $reply.createdDateTime
$replyData.from = $reply.from.user.displayName
}
$bodyOut = ""
if ($NULL -eq $message.summary)
{
foreach ($attachment in $reply.attachments)
{
$output = $attachment.content
if ($output)
{
$output = $output.substring(14)
$output = $output.substring(0,$output.length-4)
}
$bodyOut = $bodyOut + $output
}
}
else {
$bodyOut = $message.summary
}
$replyData.body = $bodyOut + $reply.body.content
$messageSet.Add($replyData)
}
$resultList.Add($messageSet)
}
return
}
$ReqTokenBody = @{
Grant_Type = "Password"
client_Id = $clientID
Client_Secret = $clientSecret
#TODO: Update for your tenant
Username = 'admin@XXXXXXXX.onmicrosoft.com'
Password = 'YYYYYYYYYY'
Scope = "https://graph.microsoft.com/.default"
}
$TokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token" -Method POST -Body $ReqTokenBody
#Getting all Groups
$apiUrl = "https://graph.microsoft.com/beta/groups"
$Data = Invoke-RestMethod -Headers @{Authorization = "Bearer $($TokenResponse.access_token)"} -Uri $apiUrl -Method Get -ErrorVariable RespErr
$Groups = ($Data | Select-Object Value).Value
if ($Team -eq $NULL){
Write-Host "You have" -NoNewline
Write-Host " $($Groups.Count)" -ForegroundColor Yellow -NoNewline
Write-Host " teams."
Write-Host ""
Write-Host "Messages from which Team do you want to export to the HTML format?" -ForegroundColor Yellow
$Groups | FT DisplayName,Description
$Team = Read-Host "Type one of the Team (DisplayName)"
}
$TeamID = ($Groups | Where-Object {$_.displayname -eq "$($Team)"}).id
$apiUrl = "https://graph.microsoft.com/v1.0/teams/$TeamID/Channels"
$Data = Invoke-RestMethod -Headers @{Authorization = "Bearer $($TokenResponse.access_token)"} -Uri $apiUrl -Method Get
if ($Channel -eq $NULL){
Write-Host "You choose" -NoNewline
Write-Host " $($Team)" -ForegroundColor Yellow -NoNewline
Write-Host " Team."
Write-Host ""
$Channels = ($Data | Select-Object Value).Value
#Write-Host "Messages from which Channel do you want to export to the HTML format?" -ForegroundColor Yellow
#$Channels | FT DisplayName,Description
#$Channel = Read-Host "Type one of the Channel(DisplayName)"
}
foreach ($Channel in $Channels)
{
#$ChannelID = (($Data | Select-Object Value).Value | Where-Object {$_.displayName -eq "$($Channel)"}).ID
$ChannelID = $Channel.id
Write-Host "Channel ID: " + $ChannelID
#$apiUrl = "https://graph.microsoft.com/beta/groups/$TeamID/members"
$apiUrl = "https://graph.microsoft.com/v1.0/groups/$TeamID/members"
$Data = Invoke-RestMethod -Headers @{Authorization = "Bearer $($TokenResponse.access_token)"} -Uri $apiUrl -Method Get
$TokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token" -Method POST -Body $ReqTokenBody
$resultList = New-Object System.Collections.ArrayList;
#Correct URL with escape
$apiUrl = "https://graph.microsoft.com/beta/teams/$TeamID/channels/$ChannelID/messages?`$top=100"
Write-Host $apiUrl
$sourceData = Invoke-RestMethod -Headers @{Authorization = "Bearer $($TokenResponse.access_token)"} -Uri $apiUrl -Method Get
parseMessage($sourceData)
$nextLink = $sourceData.'@Odata.NextLink'
while ($NULL -ne $nextLink)
{
$nextURL = $nextLink;
$sourceData = Invoke-RestMethod -Headers @{Authorization = "Bearer $($TokenResponse.access_token)"} -Uri $nextURL -Method Get
parseMessage($sourceData)
$nextLink = $sourceData.'@Odata.NextLink'
}
$resultFieldSet = New-Object System.Collections.ArrayList
foreach($resultData in $resultList) {
$resultFields = $resultData | Select-Object @{Name = 'DateTime'; Expression = {Get-Date -Date (($_).dateTime) -Format 'MM/dd/yyyy hh:mm:ss.fff tt'}}, @{Name = 'From'; Expression = {((($_).from))}}, @{Name = 'Message'; Expression = {(($_).body) -replace '<.*?>',''}}| Sort-Object DateTime
$resultFieldSet.Add($resultFields)
}
$Header = @"
<style>
h1, h5, th { text-align: center; }
table { margin: auto; font-family: Segoe UI; box-shadow: 10px 10px 5px #888; border: thin ridge grey; }
th { background: #0046c3; color: #fff; max-width: 400px; padding: 5px 10px; }
td { font-size: 11px; padding: 5px 20px; color: #000; }
tr { background: #b8d1f3; }
tr:nth-child(even) { background: #dae5f4; }
tr:nth-child(odd) { background: #b8d1f3; }
</style>
"@
$count = 0
foreach ($resultCount in $resultList){
$count = $count + $resultCount.Count
}
$body = "<body><b>Generated:</b> $(Get-Date -Format 'MM/dd/yyyy hh:mm tt') <br><br> <b>Team Name:</b> $($Team) <br> <b>Channel Name:</b> $($Channel) <br><br>" + "<b>number of messages:</b> " + $count + " <br><br>"
$body = $body + "</head>"
$resultHtml = ""
foreach ($resultFields in $resultFieldSet){
$tempHtml = $resultFields | ConvertTo-Html -Head $header
$resultHtml = $tempHtml + "<br>" + $resultHtml
}
$resultHtml = $body + "<br>" + $resultHtml
$channelDisplayName = $Channel.displayName
$Export = "$dir\TeamsHistory\$Team-$channelDisplayName"
New-Item -ItemType Directory -Path $Export -ErrorAction Ignore
$resultHtml | Out-File $Export\$Team-$channelDisplayName-$Date.html
Write-Host "
"
Write-Host "Messages from the" -NoNewline
Write-Host " $($Team)" -NoNewline -ForegroundColor Yellow
Write-Host " team and" -NoNewline
Write-Host " $($channelDisplayName)" -NoNewline -ForegroundColor Yellow
Write-Host " channel were generated and saved to the" -NoNewline
Write-Host " $($Export)" -NoNewline -ForegroundColor Yellow
Write-Host " as a" -NoNewline
Write-Host " $($Team)-$($channelDisplayName)-$($Date).html" -NoNewline -ForegroundColor Yellow
Write-Host " file."
Write-Host ""
}#end foreach ($Channel in $Channels)
May 20 2022 08:04 AM