ルドルフもわたるふもいろいろあってな

Microsoft 365、Power Platform、PowerShellについて調べたことや検証したことなどを投稿します。技術の話は面白い。

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

はじめに

この投稿はOffice365 Advent Calendar 2019 に投稿した内容です。
adventar.org

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

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


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

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

と依頼されたときに

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

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

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

最終的な完成イメージ

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

リアクションとは、Teams のチャットでできる反応(= いいね、ハート、笑い、びっくり、悲しい、怒り)のことです。
f:id:wataruf01:20220321230957p:plain


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

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

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

f:id:wataruf01:20220321231020p:plain

取得する情報は以下の通りです。
・リアクションの種類(= いいね、ハート、笑い、びっくり、悲しい、怒り)
・リアクションをした日時
・誰がリアクションをしたか(ユーザーID
・誰に対してリアクションをしたか(ユーザーID)
・リアクション対象の投稿内容
・投稿ID
・返信先のID

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

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

必要な事前準備

AzureADにアプリを登録

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

Microsoft Teamsの特定チャネルのいいねをした人ランキングを作成しよう!その1~Azure ADにアプリを登録する~

必要なアクセス許可は以下の通りです。
f:id:wataruf01:20220321231116p:plain

AzureADアプリをPowerShellで使用するためのIDを入手する

登録したAzureADアプリの下記情報をメモに控えます
・テナントID
・クライアントID
・クライアントシークレット

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

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

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

承認依頼の出し方は下記リンクのDocs の記事を参照してください。
docs.microsoft.com

f:id:wataruf01:20220321231136p:plain

承認がおりると下図のようなメールが送られてきます。
f:id:wataruf01:20220321231147p:plain

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

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

取得方法は以下の参照ください。
blog.intracker.net

指定したチャネルのいいね一覧を取得するPowerShellソースコード

ソースコード

下記5つはメモに控えたものに置き換えてください
・【テナントID】
・【クライアントID】
・【クライアントシークレット】
・【チームID】
・【チャネルID】

指定したチャネルのいいね一覧を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.pngf:id:wataruf01:20220321231338p:plain

これを改良して

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

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

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

最終的な完成イメージ(再掲)

f:id:wataruf01:20220321231352p:plain
以上です。