【GraphAPI】Teams 会議の情報を取得する

# はじめに

Graph API を利用すると、Teams 会議の出席者レポートやレコーディングといった情報を取得することができます。この記事では Graph Powershell を使ってこれらの情報を取得する方法をまとめてみました。

※ Graph PowerShell については以下の記事で紹介しています。

https://qiita.com/atsmin77/items/264d10bd9d7e9dfeaace

# Graph API で Teams 会議の情報を取得する

以下のような Teams 会議の情報を Graph API で取得することができます。

* 詳細情報
* 出席者レポート
* レコーディング
* トランスクリプト


以下で Graph PowerShell を使って、ユーザー委任権限とアプリケーション許可権限のそれぞれの方法でこれらの情報を取得してみます。

## ユーザー委任権限

ユーザー委任権限では、Graph API を実行する際にサインインしたユーザーがアクセスできる Teams 会議の情報を取得することができます。

### 詳細情報

Teams 会議の詳細情報を取得する **"Get OnlineMeeting"** API を使用します。

::: note warn
Get OnlineMeeting API ではフィルタ条件 (**"$filter"**) を指定せずにすべての会議を一覧で取得することができません。$filter を指定せずに実行した場合は以下のようなエラーが返されます。
:::

```powershell
# 会議に参加したユーザーでサインインします
Connect-MgGraph -Scopes "OnlineMeetings.Read"
# Get OnlineMeeting API で会議の詳細情報を取得します
$Uri = "/v1.0/me/onlineMeetings"
$response = Invoke-MgGraphRequest -Method GET -Uri $Uri -OutputType PSObject
```

```
HTTP/1.1 400 Bad Request

{
    "error": {
        "code": "InvalidArgument",
        "message": "Filter expression expected - /onlineMeetings?$filter={ParameterName} eq '{id}'.",
        "innerError": {
            "request-id": "b9832b80-72d3-4035-8a8d-14c54490cf83",
            "date": "2025-06-06T21:58:36",
            "client-request-id": "25d23482-0842-4d99-a537-3fcfe3500f62"
        }
    }
}
```

$filter に指定できる条件はいくつかありますが、ここでは会議に参加する際の ID を指定してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2680397/fadf26a0-c4d5-46de-b2e3-5d4b82338983.png)

URI に $filter を指定して実行すると、会議の詳細情報を取得することができます。

```powershell
# 会議参加 ID を指定してください (スペースは削除してください)
$JoinMeetingId = "4408311310644"

# 会議に参加したユーザーでサインインします
Connect-MgGraph -Scopes "OnlineMeetings.Read"
# Get OnlineMeeting API で $filter に会議参加 ID を指定して会議の詳細情報を取得します
$Uri = "/v1.0/me/onlineMeetings?`$filter=joinMeetingIdSettings/joinMeetingId%20eq%20'$JoinMeetingId'"
$response = Invoke-MgGraphRequest -Method GET -Uri $Uri -OutputType PSObject
# 取得した詳細情報を表示します
$response.value | select id, subject, creationDateTime, startDateTime, endDateTime | fl
$response.value.participants | fl
```

※ 実行結果の例

```
id               : MSpjMWZlOWNiMi04N2Y5LTRhNmEtYjA0MC1hNWI2MzEwOGRjNGUqMCoqMTk6bWVldGluZ19ZVEU1TURVek0yRXRZVE01TUMwMFpUUTFMVGhpTTJNdFpUWmpPVGswTTJVMVl6RmxAdGhyZWFkLnYy
subject          : テスト会議
creationDateTime : 2025/06/06 21:54:38
startDateTime    : 2025/06/06 22:00:00
endDateTime      : 2025/06/06 22:30:00

organizer : @{upn=testuser01@atsmin.net; role=presenter; identity=}
attendees : {@{upn=testuser02@atsmin.net; role=attendee; identity=}}
```

::: note
ここで取得された **"id"** を使用して、特定の会議の出席者レポートやレコーディングといった情報を取得することができます。
:::

::: note warn
会議参加 ID とは異なりますので注意が必要です。
:::

(参考：OnlineMeeting を取得する)
https://learn.microsoft.com/ja-jp/graph/api/onlinemeeting-get?view=graph-rest-1.0&tabs=http

### 出席者レポート

会議の出席者レポートは、**"Get meetingAttendanceReport"** API で取得することができます。

以下は出席者レポートを取得して CSV ファイルとして出力するスクリプトの例です。

```powershell
# Get OnlineMeeting API で取得した id を指定してください
$MeetingId = "MSpjMWZlOWNiMi04N2Y5LTRhNmEtYjA0MC1hNWI2MzEwOGRjNGUqMCoqMTk6bWVldGluZ19ZVEU1TURVek0yRXRZVE01TUMwMFpUUTFMVGhpTTJNdFpUWmpPVGswTTJVMVl6RmxAdGhyZWFkLnYy" 
# 取得したレコーディングの保存先フォルダを指定してください
$OutputDir = "C:\Temp"

# 会議の開催者または共同開催者のユーザーでサインインします
Connect-MgGraph -Scopes "OnlineMeetingArtifact.Read.All"
# Get meetingAttendanceReport API で会議の出席者レポートを取得します
$Uri = "/v1.0/me/onlineMeetings/$MeetingId/attendanceReports"
$response = Invoke-MgGraphRequest -Method GET -Uri $Uri -OutputType PSObject
# 会議の各セッションの出席者レポートを取得します
$count = 1;
foreach ($value in $response.value) {
  # 出席者レポートを取得して CSV で保存します
  $OutputFilePath = $OutputDir + "/attendanceReport$($count).csv"
  $report = Invoke-MgGraphRequest -Uri ($Uri + "/$($value.id)/attendanceRecords") -OutputType PSObject
  $report.value | select id, emailAddress, role, totalAttendanceInSeconds | Export-Csv -Path $OutputFilePath -NoTypeInformation -Encoding UTF8
  $count++
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2680397/f652cb03-e6dd-4822-8eba-a526aeaf21ad.png)

※ 出力される CSV ファイルの例

```
"id","emailAddress","role","totalAttendanceInSeconds"
"c1fe9cb2-87f9-4a6a-b040-a5b63108dc4e","testuser01@atsmin.net","Organizer","53"
"0963c34e-f94e-49cf-bab8-b6b620fdb66f","testuser02@atsmin.net","Presenter","47"
"ecd80e02-bc39-461e-a7dc-c9a749db27a9","testuser03@atsmin.net","Presenter","44"
...
```

::: note
今回は割愛していますが、Get meetingAttendanceReport API によって取得される情報には、Teams クライアントから取得できる出席者レポートと同様に、誰がいつ会議に参加したか、退出したかの情報も含まれています。
:::

(参考：会議の取得AttendanceReport)
https://learn.microsoft.com/ja-jp/graph/api/meetingattendancereport-get?view=graph-rest-1.0&tabs=http

### レコーディング

会議のレコーディングは、**"Get callRecording"** API で取得することができます。

::: note warn
この Graph API を実行するためには [管理者の同意](https://qiita.com/atsmin77/items/b6bd8def4b9ddc5ab49b#43-%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E8%A8%B1%E5%8F%AF%E3%81%AE%E4%BB%98%E4%B8%8E-%E7%AE%A1%E7%90%86%E8%80%85%E3%81%AE%E5%90%8C%E6%84%8F) が必要です。
:::

以下はレコーディングの mp4 ファイルをダウンロードするスクリプトの例です。

```powershell
# Get OnlineMeeting API で取得した id を指定してください
$MeetingId = "MSpjMWZlOWNiMi04N2Y5LTRhNmEtYjA0MC1hNWI2MzEwOGRjNGUqMCoqMTk6bWVldGluZ19ZVEU1TURVek0yRXRZVE01TUMwMFpUUTFMVGhpTTJNdFpUWmpPVGswTTJVMVl6RmxAdGhyZWFkLnYy" 
# 取得したレコーディングの保存先フォルダを指定してください
$OutputDir = "C:\Temp"

# 会議に参加したユーザーでサインインします (管理者の同意が必要です)
Connect-MgGraph -Scopes "OnlineMeetingRecording.Read.All"
# Get callRecording API で会議のレコーディングを取得します
$Uri = "/v1.0/me/onlineMeetings/$MeetingId/recordings"
$response = Invoke-MgGraphRequest -Method GET -Uri $Uri -OutputType PSObject
# 会議の各セッションのレコーディングを取得します
$count = 1;
foreach ($value in $response.value) {
  # レコーディングをダウンロードして保存します
  $OutputFilePath = $OutputDir + "/recording$($count).mp4"
  Invoke-MgGraphRequest -Uri $value.recordingContentUrl -OutputFilePath $OutputFilePath
  $count++
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2680397/ff56266a-9e82-4563-b919-1116c1f6b340.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2680397/eddd75a2-2b4d-4f44-a8c0-f51666012c1d.png)

(参考：callRecording を取得する)
https://learn.microsoft.com/ja-jp/graph/api/callrecording-get?view=graph-rest-1.0&tabs=http

### トランスクリプト

会議のトランスクリプトは、**"Get callTranscript"** API で取得することができます。

以下はトランスクリプトをダウンロードするスクリプトの例です。

::: note warn
この Graph API を実行するためには [管理者の同意](https://qiita.com/atsmin77/items/b6bd8def4b9ddc5ab49b#43-%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E8%A8%B1%E5%8F%AF%E3%81%AE%E4%BB%98%E4%B8%8E-%E7%AE%A1%E7%90%86%E8%80%85%E3%81%AE%E5%90%8C%E6%84%8F) が必要です。
:::

```powershell
# Get OnlineMeeting API で取得した id を指定してください
$MeetingId = "MSpjMWZlOWNiMi04N2Y5LTRhNmEtYjA0MC1hNWI2MzEwOGRjNGUqMCoqMTk6bWVldGluZ19ZVEU1TURVek0yRXRZVE01TUMwMFpUUTFMVGhpTTJNdFpUWmpPVGswTTJVMVl6RmxAdGhyZWFkLnYy" 
# 取得したトランスクリプトの保存先フォルダを指定してください
$OutputDir = "C:\Temp"

# 会議に参加したユーザーでサインインします (管理者の同意が必要です)
Connect-MgGraph -Scopes "OnlineMeetingTranscript.Read.All"
# Get callTranscript API で会議のトランスクリプトを取得します
$Uri = "/v1.0/me/onlineMeetings/$MeetingId/transcripts"
$response = Invoke-MgGraphRequest -Method GET -Uri $Uri -OutputType PSObject
# 会議の各セッションのトランスクリプトを取得します
$count = 1;
foreach ($value in $response.value) {
  # トランスクリプトをダウンロードして保存します
  $OutputFilePath = $OutputDir + "/transcript$($count).vtt"
  Invoke-MgGraphRequest -Uri $value.transcriptContentUrl -OutputFilePath $OutputFilePath
  $count++
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2680397/c0a2eeca-2cbd-4735-962e-790cf7747963.png)

※ 出力されるトランスクリプトの例

```
WEBVTT

00:00:17.506 --> 00:00:18.346
<v テスト ユーザー01>こんにちは。</v>

00:00:39.586 --> 00:00:40.346
<v テスト ユーザー02>テストです。</v>
```

::: note
トランスクリプトは [WebVTT形式](https://ja.wikipedia.org/wiki/WebVTT) で取得されます。
:::

(参考：Get callTranscript)
https://learn.microsoft.com/ja-jp/graph/api/calltranscript-get?view=graph-rest-1.0&tabs=http

## アプリケーション許可権限

Teams 会議の情報はアプリケーション許可権限でも取得することができます。アプリケーション許可権限の場合は、ユーザー ID を指定し特定のユーザーの会議情報を取得することができます。

特定のユーザーの Teams 会議の詳細情報、出席者レポート、レコーディング、トランスクリプトをすべて取得するスクリプトの例を作ってみました。

::: note
以下の 4 つのアクセス許可を追加して Connect-MgGraph コマンドにより認証した状態で実行してください。
* OnlineMeetings.Read.All
* OnlineMeetingArtifact.Read.All
* OnlineMeetingRecording.Read.All
* OnlineMeetingTranscript.Read.All
:::

```powershell
# 会議情報を取得するユーザーの ID を指定してください
# アプリケーション許可権限ではアプリケーションアクセスポリシーを割り当てたユーザーの ID を指定してください
# ユーザー委任権限ではサインインするユーザーの ID を指定してください
$UserId = "c1fe9cb2-87f9-4a6a-b040-a5b63108dc4e"
# 会議参加 ID を指定してください (スペースは削除してください)
$JoinMeetingId = "4408311310644"
# 出席者レポート/レコーディング/トランスクリプトの保存先フォルダを指定してください
$OutputDir = "C:\Temp"

# Get OnlineMeeting API で $filter に会議参加 ID を指定して会議の詳細情報を取得します
$BaseUri = "/v1.0/users/$UserId/onlineMeetings"
$Uri = "$($BaseUri)?`$filter=joinMeetingIdSettings/joinMeetingId%20eq%20'$JoinMeetingId'"
$response = Invoke-MgGraphRequest -Method GET -Uri $Uri -OutputType PSObject
# 取得した詳細情報を表示します
$response.value | select id, subject, creationDateTime, startDateTime, endDateTime | fl
$response.value.participants | fl

# Get OnlineMeeting API で取得した id を指定します
$MeetingId = $response.value.id

# Get meetingAttendanceReport API で会議の出席者レポートを取得します
$Uri = "$($BaseUri)/$MeetingId/attendanceReports"
$response = Invoke-MgGraphRequest -Method GET -Uri $Uri -OutputType PSObject
# 会議の各セッションの出席者レポートを取得します
$count = 1;
foreach ($value in $response.value) {
  # 出席者レポートを取得して CSV で保存します
  $OutputFilePath = $OutputDir + "/attendanceReport$($count).csv"
  $report = Invoke-MgGraphRequest -Uri ($Uri + "/$($value.id)/attendanceRecords") -OutputType PSObject
  $report.value | select id, emailAddress, role, totalAttendanceInSeconds | Export-Csv -Path $OutputFilePath -NoTypeInformation -Encoding UTF8
  $count++
}

# Get callRecording API で会議のレコーディングを取得します
$Uri = "$($BaseUri)/$MeetingId/recordings"
$response = Invoke-MgGraphRequest -Method GET -Uri $Uri -OutputType PSObject
# 会議の各セッションのレコーディングを取得します
$count = 1;
foreach ($value in $response.value) {
  # レコーディングをダウンロードして保存します
  $OutputFilePath = $OutputDir + "/recording$($count).mp4"
  Invoke-MgGraphRequest -Uri $value.recordingContentUrl -OutputFilePath $OutputFilePath
  $count++
}

# Get callTranscript API で会議のトランスクリプトを取得します
$Uri = "$($BaseUri)/$MeetingId/transcripts"
$response = Invoke-MgGraphRequest -Method GET -Uri $Uri -OutputType PSObject
# 会議の各セッションのトランスクリプトを取得します
$count = 1;
foreach ($value in $response.value) {
  # トランスクリプトをダウンロードして保存します
  $OutputFilePath = $OutputDir + "/transcript$($count).vtt"
  Invoke-MgGraphRequest -Uri $value.transcriptContentUrl -OutputFilePath $OutputFilePath
  $count++
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2680397/7afa5b70-c693-4f73-90ac-b311b67fb04b.png)

### アプリケーション許可権限で会議情報を取得するために必要な設定

アプリケーション許可権限で会議の情報を取得するためには、いくつか事前の設定が必要です。

#### 1. アプリケーションへのアクセス許可の追加と認証

Entra ID アプリケーションに必要なアクセス許可を追加し、アプリケーション許可権限によって Connect-MgGraph コマンドを実行し認証を行います。

※ 参考

https://qiita.com/atsmin77/items/6bcc9fb88b305e124399

#### 2. アプリケーションアクセスポリシーの作成とユーザーへの割り当て

アプリケーション許可権限で Teams 会議の情報を取得するためには、以下の設定も行う必要があります。

* アプリケーションアクセスポリシーを作成する
* 作成したアプリケーションアクセスポリシーをユーザーに割り当てる

::: note
アプリケーションは **"アプリケーションアクセスポリシー"** が割り当てられているユーザーが参照できる Teams 会議の情報のみ取得することができます。
:::

::: note warn
通常の Graph API ではアプリケーション許可権限を追加すればテナント内の情報を取得することができます。しかし、会議の情報を取得する Graph API の場合は、アクセス許可を追加するだけでは以下のようなエラーが返され、情報を取得することができません。
:::

```
HTTP/1.1 403 Forbidden

{
    "error": {
        "code": "General",
        "message": "No application access policy found for this app.",
        "innerError": {
            "request-id": "b789520b-4460-4bf5-9ce6-ed56cd5914d3",
            "date": "2025-06-07T00:33:15",
            "client-request-id": "45789257-8105-46f3-834f-f320af3bb0db"
        }
    }
}
```

以下はアプリケーションアクセスポリシーを作成して、ユーザーに割り当てるスクリプトの例です。

::: note
Teams PowerShell のコマンドを使用します。
アプリケーションアクセスポリシーの作成は **New-CsApplicationAccessPolicy** コマンド、アプリケーションアクセスポリシーの割り当ては **Grant-CsApplicationAccessPolicy** コマンドで行います。
:::

```powershell
# アプリケーション許可権限で使用する Entra アプリケーションの ClientId を指定してください
$AppIds = "a9719270-aba5-4a18-921c-d7b4e11af86f"
# 複数指定する場合はカンマ区切りで指定してください
# $AppIds = "a9719270-aba5-4a18-921c-d7b4e11af86f", "0e70f9f1-197a-4682-896f-fb9b9c513a84"
# 会議情報を取得するユーザーの ID を指定してください
$UserId = "c1fe9cb2-87f9-4a6a-b040-a5b63108dc4e"
# 作成するアプリケーションアクセスポリシーに設定する任意の名前を指定してください
$PolicyName = "TestApplicationAccessPolicy"

# Teams 管理者でサインインしてください
Connect-MicrosoftTeams
# アプリケーションアクセスポリシーを作成します
New-CsApplicationAccessPolicy -Identity $PolicyName -AppIds $AppIds
# 作成したアプリケーションアクセスポリシーの情報を表示します
Get-CsApplicationAccessPolicy -Identity $PolicyName
# 作成したアプリケーションアクセスポリシーをユーザーに割り当てます
Grant-CsApplicationAccessPolicy -PolicyName $PolicyName -Identity $UserId
# ユーザーに割り当てられているアプリケーションアクセスポリシーを表示します
Get-CsOnlineUser -Identity $UserId | select displayName, applicationAccessPolicy
```

※ 実行結果の例

```
DisplayName       ApplicationAccessPolicy
-----------       -----------------------
テスト ユーザー01 TestApplicationAccessPolicy
```

(参考：オンライン会議または仮想イベントへのアプリケーション アクセスを構成する)
https://learn.microsoft.com/ja-jp/graph/cloud-communication-online-meeting-application-access-policy