[PowerShell + Graph API] TeamsのチャネルメッセージをCSV出力

## 事前準備
### 認証・承認の準備

以下の記事と同じ形で事前準備を行う。
なお、今回必要なアクセス許可は `ChannelMessage.Read.All` である。

https://qiita.com/wataruf01/items/a4aa72c65721f1a5dd68

次のコマンドで、アクセストークンを取得できる。

```PowerShell
$body =  @{
    Grant_Type    = "client_credentials"
    Scope         = "https://graph.microsoft.com/.default"
    Client_Id     = "<クライアントID>"
    Client_Secret = "<クライアントシークレット>"
}
$Uri = "https://login.microsoftonline.com/<テナントID>/oauth2/v2.0/token"
$res = Invoke-RestMethod -Method POST -uri $Uri -Body $body
$accessToken= $res.access_token
```

#### 参考: PnP PowerShell

PnP PowerShellが使用できる場合、以下のコマンドでアクセストークンを取得しても良い。

```PowerShell
Connect-PnPOnline -Url https://<テナント名>.sharepoint.com -Interactive
$accessToken = Get-PnPAccessToken
```

PnP PowerShellのインストール方法は以下

https://pnp.github.io/powershell/articles/installation.html

使用にあたっては、下記ページも参考になった。

https://koruneko.hatenablog.com/entry/2021/06/20/034521

## 実行

取得対象のチームとチャネルの名前を入力する。

```PowerShell
$teamName = "<チーム名>"
$channelname = "<チャネル名>"
```

以下のコマンドを実行すると、チャネル内の投稿がcsv出力される。

```PowerShell
# チーム名をもとに、対象のチームを取得
$groupsListUri = "https://graph.microsoft.com/v1.0/groups?`$filter=resourceProvisioningOptions/Any(x:x eq 'Team')"
$graphResponse = Invoke-RestMethod -Method Get -Uri $groupsListUri -Headers @{"Authorization"="Bearer $accessToken"}
foreach ($group in $graphResponse.value)
{
    if ($group.displayname -eq $teamName ) {
        write-host $group.displayname = $group.id 
        $teamID = $group.id
    }
}

# チャネル名をもとに、対象のチャネルを取得
$ChannelID = ""
$channelListURI = "https://graph.microsoft.com/v1.0/teams/" + $teamID + "/channels"
$graphResponse = Invoke-RestMethod -Method Get -Uri $channelListURI -Headers @{"Authorization"="Bearer $accessToken"}

foreach ($channel in $graphResponse.value)
{
    if ($channel.displayName -eq $channelname) {
        write-host $channel.displayName = $channel.id
        $ChannelID = $channel.id
    }
}

# チャネル内の投稿をすべて取得
$result= $null
$messagesURI = "https://graph.microsoft.com/v1.0/teams/" + $teamID + "/channels/" + $ChannelID + "/messages"
$graphResponse = Invoke-RestMethod -Method Get -Uri $messagesURI  -Headers @{"Authorization"="Bearer $accessToken"}
while($graphResponse."@odata.nextLink" -ne $null)
{
    $result = $result + $graphResponse."value"
    $graphResponse = Invoke-RestMethod -Method Get -Uri $graphResponse."@odata.nextLink"  -Headers @{"Authorization"="Bearer $accessToken"}
}
$result = $result + $graphResponse."value"

# 出力用のデータを作成する
$csv = @()

foreach ($message in $result)
{
    if ($message.body -eq $null -or $message.messageType -eq "systemEventMessage") {
        continue
    }
    $messageID = $message.id 

    # 内容がHTML形式の場合、読みづらいためテキスト情報のみ取り出す
    if ($message.body.contentType -eq "html") {
        $html = New-Object -ComObject "HTMLFile"
        $html.IHTMLDocument2_write($message.body.content)
        $message.body.content = $html.IHTMLDocument2_body.innerText
    }

    # 投稿の題名がある場合、"題名: 内容" の形で出力する
    $content = $null
    if ($message.subject -ne $null) {
        $content = $message.subject + ": " + $message.body.content
    }
    else {
        $content = $message.body.content
    }

    # データを追加する
    $data = New-Object PSObject | Select-Object DateTime, From, Type, Content, Attachments
    $data.DateTime = $message.createdDateTime
    $data.From = $message.from.user.displayName
    $data.Type = "Post"
    $data.Content = $content
    # 添付ファイルはURLを記載する
    # 複数ある場合、"; "で区切る
    $temp = $message.attachments | ForEach-Object { $_.ContentUrl}
    $data.Attachments = $temp -join "; "
    $csv += $data

    # 投稿の返信を取得 (いらない場合、foreach文が閉じる部分までコメントアウトする)
    $repliesURI = "https://graph.microsoft.com/v1.0/teams/" + $teamID + "/channels/" + $ChannelID + "/messages/" + $messageID + "/replies"
    $repliesResponse = Invoke-RestMethod -Method Get -Uri $repliesURI  -Headers @{"Authorization"="Bearer $accessToken"}
    foreach ($reply in $repliesResponse.value ) {
        $replyData = New-Object PSObject | Select-Object DateTime, From, Type, Content
        $replyData.DateTime = $reply.createdDateTime
        $replyData.From = $reply.from.user.displayName
        $replyData.Type = "Reply"
        $replyData.Content = $reply.body.content
        $csv += $replyData
    }
}

# CSV形式でエクスポート
$csv | Export-Csv -Path "channel.csv" -NoTypeInformation -Encoding UTF8
```

## 参考

https://qiita.com/wataruf01/items/a4aa72c65721f1a5dd68

https://stackoverflow.com/questions/65818021/get-all-messages-and-replies-from-microsoft-teams-channel-graph-paging

https://mymetaverseday.com/2019/10/08/exporting-team-channel-messages/ 


## 追記
この記事と同様の作業を、Microsoft Graph PowerShell SDKでも行ってみた。

https://qiita.com/seilian/items/225b1fe012d502bd4172