PowerShell を使ってMicrosoft Teams のいいね一覧をCSV形式で出力する

<font color="Red">2020/10/22 に以下の章を追記しました
・保護されているAPIの使用についてMSから承認を得る</font>

#はじめに

この投稿は
[Office365 Advent Calendar 2019](https://adventar.org/calendars/3960)

の投稿です。

#いいね一覧を取ろうと思ったきっかけ

以下の記事を読んだことが「やってみよう」と思い立ったきっかけです。
コードを書かなくてもPower Automate で情報取得が実現できるのはとても便利です。

[Microsoft Teamsの特定チャネルのいいねをした人ランキングを作成しよう！その１～Azure ADにアプリを登録する～](https://blog.intracker.net/archives/2068)


この方法を "情報取得ツール"に応用したいと考えました。

「◯◯テナントの情報を取得して」

と依頼されたときに

「(ﾟ◇ﾟ)ゞ 了解。ちゃちゃっと取得します。ツール実行、ぽちっと」

こんな風にひとつのファイルとして完結したツールを実行することでアウトプットが手に入ることが理想です。
今回はGraph API を使うため、事前準備としてAzureADへのアプリ登録だけGUIで行います。

CSV形式にしたのはアウトプットの一例です。
データベースに登録するなり、Power BI のデータセットとして登録するなり、目的応じてアレンジができます。

#最終的な完成イメージ

チャネルの会話内に投稿されたリアクションをCSVに一覧出力します。
CSV の1行が１回のリアクションを表します。

リアクションとは、Teams のチャットでできる反応（= いいね、ハート、笑い、びっくり、悲しい、怒り）のことです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/357828/923bd0cb-2922-0e59-4621-608ecff5204d.png)
取得する情報は以下の通りです。
・リアクションの種類（= いいね、ハート、笑い、びっくり、悲しい、怒り）
・リアクションをした日時
・誰がリアクションをしたか（表示名とUPN）
・誰に対してリアクションをしたか（表示名とUPN）
・チャネル名
・スレッドかそれとも返信か
・リアクション対象の投稿内容
・投稿ID
・返信先のID

#途中成果物の完成イメージ

PowerShell のソースコード全文を記載すると長くなってしまうので、「指定した特定のチャネルからリアクションを取得する」処理の部分にフォーカスします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/357828/845f1aa0-a2dd-c33e-ebfe-b3e57121c31a.png)

取得する情報は以下の通りです。
・リアクションの種類（= いいね、ハート、笑い、びっくり、悲しい、怒り）
・リアクションをした日時
・誰がリアクションをしたか（<font color="Red">ユーザーID</font>）
・誰に対してリアクションをしたか（<font color="Red">ユーザーID</font>）
~~・チャネル名~~
~~・スレッドかそれとも返信か~~
・リアクション対象の投稿内容
・投稿ID
・返信先のID

チャネル内の本文を取得するAPIからユーザー名を直接取得することはできません。
ここでとれるのは<font color="Red">ユーザーID</font>です。

取得したIDをユーザー情報を取得するAPI に渡すことでユーザー名やUPN、メールアドレスを取得します。後述します。

#必要な事前準備


##AzureADにアプリを登録
Microsoft Graph API を使うために AzureADにアプリを登録します。
登録方法については下記の記事を参照してください。

[Microsoft Teamsの特定チャネルのいいねをした人ランキングを作成しよう！その１～Azure ADにアプリを登録する～](https://blog.intracker.net/archives/2068)

必要なアクセス許可は以下の通りです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/357828/6cafdd37-1dce-14b4-772d-29acbc72d2cd.png)

## AzureADアプリをPowerShellで使用するためのIDを入手する
登録したAzureADアプリの下記情報をメモに控えます
・テナントID
・クライアントID
・クライアントシークレット

##保護されているAPIの使用についてMSから承認を得る 

※この章は2020/10/22 に追記しました

「アプリケーションのアクセス許可」におけるチャネルメッセージの一覧を取得するAPIはテナント内のすべてのチームの情報にアクセスできるため、 **「保護されたAPI（Protected API）」**とされています。

保護されたAPIを使用する場合は、マイクロソフトにアプリIDとAPIの使用目的を伝えてAPI使用の承認を得る必要があります。承認を得る前にAPIにリクエストを投げるとエラーが返ってきます。

承認依頼の出し方は下記リンクのDocs の記事を参照してください。
[Microsoft Teams の保護された API](https://docs.microsoft.com/ja-jp/graph/teams-protected-apis)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/357828/dee92946-1e0f-6ed5-d80b-84868ef020ad.png)

承認がおりると下図のようなメールが送られてきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/357828/d8e61f34-b891-d188-7b48-59fe84e1eacf.png)

## チームとチャネルのIDを入手する

いいね一覧を取得したいチャネルの下記情報をメモに控えます
・チームID
・チャネルID

取得方法は以下の参照ください。

[Microsoft Teamsの特定チャネルのいいねをした人ランキングを作成しよう！その２～GraphAPIで出力を確認しよう～](https://blog.intracker.net/archives/2092)

#指定したチャネルのいいね一覧を取得するPowerShellソースコード
##ソースコード
下記5つはメモに控えたものに置き換えてください
・【テナントID】
・【クライアントID】
・【クライアントシークレット】
・【チームID】
・【チャネルID】

```powershell:指定したチャネルのいいね一覧をPowerShellで取得する
#トークンを取得
$url = "https://login.microsoftonline.com/【テナントID】/oauth2/token"
 
$body = @{
    "grant_type" = 'client_credentials'
    "resource" = 'https://graph.microsoft.com'
    "client_id" = '【クライアントID】'
    "client_secret" = '【クライアントシークレット】'
}
 
$contentType = "application/x-www-form-urlencoded"
$oauth = Invoke-RestMethod -uri $url -Method post -Body $body -ContentType $contentType

#チャネル内のスレッドをすべて取得
$url = "https://graph.microsoft.com/beta/teams/【チームID】/channels/【チャネルID】/messages/" -f $channel.id
$headerParams  = @{'Authorization'="$($oauth.token_type) $($oauth.access_token)"}
$contentType = "application/json"
$responseFromAPI = Invoke-RestMethod -uri $url -Method Get -header $headerParams -ContentType $contentType

$messagesWithOutReply = @()
$messagesWithOutReply += $responseFromAPI.value

$messagesWithReply = @()
$messagesWithReply += $responseFromAPI.value


#返信をすべて取得
foreach($m in $messagesWithOutReply)
{
    $url = "https://graph.microsoft.com/beta/teams/0ad9e708-d8ef-4f9f-9188-6b2f875c0cf0/channels/19:aba0636cec624f7e8fa720cf10f8ec4c@thread.skype/messages/{0}/replies" -f $m.id
    $headerParams  = @{'Authorization'="$($oauth.token_type) $($oauth.access_token)"}
    $ContentType = "application/json"
    $responseFromAPI = Invoke-RestMethod -uri $url -Method Get -header $headerParams -ContentType $ContentType

    $messagesWithReply += $responseFromAPI.value
}

#いいねをCSVに出力
foreach($message in $messagesWithReply)
{
    if($message.reactions.Count -eq 0)
    {
        continue
    }
   
    $reactions = @()
    $reactions += $message.reactions

    foreach($reaction in $reactions)
    {
        $obj = New-Object PSObject | Select "ReactionType","CreatedDateTime","From","To","Content","ID","ReplyToID"
 
        #リアクションの種類
        $obj.ReactionType =  $reaction.reactionType

        #リアクションをした日時
        $obj.CreatedDateTime = $reaction.createdDateTime

        #誰がリアクションをしたか
        $obj.From =  $reaction.user.user.id

        #誰に対してリアクションをしたか
        $obj.To =  $message.from.user.id

        #リアクション対象の投稿内容
        $obj.Content = $message.body.content

        #投稿ID
        ##スレッドでも返信でも投稿IDを持っている
        $obj.ID = $message.id

        #返信先のID
        ##この値が空白値の場合は返信ではなくスレッド
        $obj.ReplyToId = $message.replyToId

        $obj |  Export-Csv -Path ".\output.csv" -Encoding UTF8 -NoTypeInformation -Append
    }#foreach($reaction in $reactions)
}#foreach($message in $messagesWithReply)
```
##取得したCSVのイメージ（再掲）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/357828/845f1aa0-a2dd-c33e-ebfe-b3e57121c31a.png)

##これを改良して

チームIDをAPIに渡してチャネル一覧をPowerShellの処理内で取得するようにします
https://graph.microsoft.com/beta/teams/【チームID】/channels

ユーザーIDをAPIに渡してユーザー名とUPNをPowerShellの処理内で取得するようにします
https://graph.microsoft.com/v1.0/users/【ユーザーID】

加えて、下記２つも出力対象にします。
後者は「返信先のID」をIsNullOrEmptyメソッドに渡した返り値で判定できます。
・チャネル名
・スレッドかそれとも返信か

#最終的な完成イメージ（再掲）
以上です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/357828/923bd0cb-2922-0e59-4621-608ecff5204d.png)