注: 以下の翻訳の正確性は検証されていません。AIPを利用して英語版の原文から機械的に翻訳されたものです。
Microsoft Teams コネクターは、Microsoft Teams 用の Palantir 提供ドライバーです。
新しい Microsoft Teams ソースを作成するには、Palantir 提供ドライバーの標準セットアップフローに沿って進め、以下のセクションで Microsoft Teams 固有の設定とネットワーク設定を行います。プロパティの完全なリファレンスについては、Microsoft Teams ドライバーの公式ドキュメント ↗を参照してください。
| 機能 | ステータス |
|---|---|
| 探索 | 🟢 一般提供 |
| バッチ同期 | 🟢 一般提供 |
| インクリメンタル(差分連携) | 🟢 一般提供 |
| OAuth 2.0 認証 | 🟢 一般提供 |
| テーブルエクスポート | 🟢 一般提供 |
Microsoft Teams コネクターは、Microsoft Graph API を介して組織の Teams データを読み取ります。チーム、チャネル、チャット、メンバー、メッセージをリレーショナルテーブルとして表示し、ソースエクスプローラーで一覧を見ることができます。
定期的に読み取る場合は、バッチ同期を使用して Teams データをデータセットに書き込みます。対話的に読み取りや書き込みを行う場合は、関数からコード内で Microsoft Graph を呼び出します。
コネクターがアクセスできる Teams データは、認証と Microsoft Graph の権限によって決まります。認証方法を選択するには認証を、各操作に必要な権限については機能別の権限を参照してください。
Microsoft Teams コネクターは、Microsoft Entra ID を通じて Microsoft Graph に対する認証を行います。AuthScheme を使用して認証方法を選択します。
AuthScheme | 認証方法 | 使用する状況 |
|---|---|---|
AzureAD | 委任されたユーザー認証 | ソースへのアクセスをサインインしたユーザーの権限に従わせる必要があり、対話的な権限付与が許容される場合。 |
AzureServicePrincipal | クライアントシークレットを使用するサービスプリンシパル | ソースへのアクセスをサインインしたユーザーに限定すべきでない場合。Microsoft Graph の権限により、テナント全体へのアクセス、またはリソース固有の同意を通じて選択したチームに限定したアクセスを付与できます。 |
AzureServicePrincipalCert | 証明書を使用するサービスプリンシパル | ユースケースは AzureServicePrincipal と同じですが、組織で証明書ベースの資格情報が必要な場合。 |
AzureAD)AuthScheme=AzureAD の場合、ソースは対話的にユーザーとしてサインインし、そのユーザーとして Graph を読み取ります。
Microsoft Entra 管理センター ↗でアプリケーションを登録し、クライアントIDを記録して、クライアントシークレットを生成し、テナント(ID または contoso.onmicrosoft.com などのドメイン)を控えます。
CallbackURL プロパティを追加します。Foundry が自動入力する URL をコピーし、Web リダイレクト URI としてアプリケーションに追加します。AuthScheme=AzureAD、AzureTenant、OAuthClientId、OAuthClientSecret、InitiateOAuth=REFRESH を設定し、自動入力される CallbackURL プロパティを追加します。権限付与を選択し、読み取りたい Teams データを持つユーザーとしてサインインします。Foundry が対話的な OAuth のやり取りを完了し、トークンを自動的に更新します。

AzureServicePrincipal)AuthScheme=AzureServicePrincipal の場合、ソースはサインインしたユーザーではなく、アプリケーションとして認証を行います。アプリケーションは、付与された権限に応じてテナント全体のデータを読み取ることができます。
委任方式と同様に、Microsoft Entra 管理センター ↗でアプリケーションを登録し、クライアントIDとテナントを記録します。権限は異なります。
Microsoft は、ユーザーなしでアクセスを取得する ↗でフロー全体を説明しています。
AuthScheme=AzureServicePrincipal、AzureTenant、OAuthClientId、OAuthClientSecret を設定します。権限付与の手順はありません。証明書の資格情報を使用する場合は、代わりに AuthScheme=AzureServicePrincipalCert を設定し、Microsoft Teams ドライバーの公式ドキュメント ↗に従って証明書のプロパティを設定します。
ユースケースに必要な Microsoft Graph の権限のみを付与してください。テナントの同意ポリシーによって、追加の制限が課される場合があります。完全な一覧については、Microsoft の Graph のアクセス許可リファレンス ↗を参照してください。
| 実行したい操作 | 委任 | アプリケーション |
|---|---|---|
| チームとチャネルを発見可能にする | Team.ReadBasic.All および Channel.ReadBasic.All。ユーザーの同意が必要です。 | Team.ReadBasic.All および Channel.ReadBasic.All。管理者の同意が必要です。 |
| チャネルメッセージの内容を読み取る | ChannelMessage.Read.All。管理者の同意が必要です。 | ChannelMessage.Read.All はテナント全体へのアクセスを付与し、管理者の同意が必要です。ChannelMessage.Read.Group はアプリケーションがインストールされたチームへのアクセスを付与し、そのチームに対するリソース固有の同意が必要です。 |
| チャットとチャットメッセージを読み取る | — | Chat.Read.All。管理者の同意が必要です。 |
| メンバーと所有者の一覧を表示する | GroupMember.Read.All、TeamMember.Read.All、ChannelMember.Read.All。管理者の同意が必要です。 | GroupMember.Read.All、TeamMember.Read.All、ChannelMember.Read.All。管理者の同意が必要です。 |
| チャネルメッセージを送信する | ChannelMessage.Send。ユーザーの同意が必要です。 | ChannelMessage.Send.Group。アプリケーションがインストールされている各チームに対するリソース固有の同意が必要です。 |
Microsoft Teams データを Foundry に読み込むには、ソースエクスプローラーでテーブルを選択し、バッチ同期を設定します。委任認証では、サインインしたユーザーが利用可能なデータを同期で読み取ります。サービスプリンシパル認証では、アクセスはアプリケーションに付与された権限によって決まり、テナント全体または選択したチームを対象にできます。アクセスを設定するには、認証を参照してください。
Microsoft は、GET /teams/{team-id}/channels/{channel-id}/messages に対して、アプリケーションあたり毎秒200リクエスト、アプリケーションおよびテナントあたり毎秒20リクエスト、チャネルあたり毎秒1リクエストの制限を適用します。Microsoft の Teams サービスの制限 ↗を参照してください。
以下のプロパティは必須または推奨です。
| プロパティ | 必須かどうか | 説明 | デフォルト |
|---|---|---|---|
AuthScheme ↗ | 推奨 | Microsoft Teams に接続する際に使用する認証の種類を指定します。このプロパティを空白のままにすると、デフォルトの認証が使用されます。 | AzureAD |
AzureTenant ↗ | 推奨 | データへのアクセスに使用する Microsoft Teams テナントを、名前(たとえば contoso.onmicrosoft.com)または ID で識別します。(条件付き)。 | — |
InitiateOAuth ↗ | 推奨 | OAuth アクセストークンを取得または更新するプロセスを指定します。このトークンは、認証および承認されたユーザーが作業している間、そのユーザーのアクセスを維持します。 | GETANDREFRESH |
OAuthClientId ↗ | 推奨 | カスタム OAuth アプリケーションの作成時に割り当てられたクライアントIDを指定します。(コンシューマー鍵とも呼ばれます。)この ID により、カスタムアプリケーションが OAuth 認可サーバーに登録されます。 | — |
OAuthClientSecret ↗ | 推奨 | カスタム OAuth アプリケーションの作成時に割り当てられたクライアントシークレットを指定します。(コンシューマーシークレットとも呼ばれます。)このシークレットにより、カスタムアプリケーションが OAuth 認可サーバーに登録されます。 | — |
以下のテーブルは、ソースの実行に必要なアクセス先ドメインを示しています。
各ドメインに対応するエグレスポリシーを追加します。ソースがオンプレミスでホストされており、Foundry から直接アクセスできない場合は、代わりに Agent プロキシエグレスポリシーを使用します。Agent ホスト自体も、記載されているドメインにアクセスできる必要があります。詳細については、Agent をプロキシとして使用するを参照してください。
| ドメイン | 必要となる条件 |
|---|---|
| graph.microsoft.com | AzureEnvironment=GLOBAL(デフォルト)の場合 |
| login.microsoftonline.com | AuthScheme=AzureAD(デフォルト)、AzureServicePrincipal、AzureServicePrincipalCert のいずれかで、かつ AzureEnvironment=GLOBAL(デフォルト)の場合 |
| microsoftgraph.chinacloudapi.cn | AzureEnvironment=CHINA の場合 |
| login.chinacloudapi.cn | AuthScheme=AzureAD(デフォルト)、AzureServicePrincipal、AzureServicePrincipalCert のいずれかで、かつ AzureEnvironment=CHINA の場合 |
| graph.microsoft.us | AzureEnvironment=USGOVT の場合 |
| login.microsoftonline.us | AuthScheme=AzureAD(デフォルト)、AzureServicePrincipal、AzureServicePrincipalCert のいずれかで、かつ AzureEnvironment=USGOVT または USGOVTDOD の場合 |
| dod-graph.microsoft.us | AzureEnvironment=USGOVTDOD の場合 |
このコネクターは OAuth 2.0 認証をサポートしています。Palantir 提供ドライバー向けの OAuth 2.0 ガイダンスに従って、接続を設定し、認可します。
このコネクターはテーブルエクスポートをサポートしています。テーブルエクスポートを設定する方法を参照してください。
パイプラインまたは関数からチャネルメッセージを読み取るには、Microsoft Teams ソースを使用して Microsoft Graph を呼び出します。サインインしたユーザーとしてメッセージを送信するには、アウトバウンドアプリケーションを設定した REST API ソースを使用します。以下の例では、Python と TypeScript で両方のワークフローを示します。
これらの例を実行するには、Microsoft Teams ソースをコードリポジトリにインポートします。サービスプリンシパル認証とチャネルメッセージの読み取りに必要な権限を使用してソースを設定します。
プレースホルダーを、ソース、テナント、アプリケーション、チーム、チャネルの識別子に置き換えます。チームとチャネルの識別子は、ソースエクスプローラーの Teams テーブルと Channels テーブルで確認できます。TypeScript v1 の例では、MicrosoftTeamsSource をソースのAPI名から生成された識別子に置き換えます。各例は、最新のメッセージを最大20件取得し、コンテンツを含まないメタデータを返します。
Copied!1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50import pandas as pd import requests from transforms.api import Output, transform from transforms.external.systems import ResolvedSource, Source, external_systems SOURCE_RID = "<source_rid>" TENANT_ID = "<tenant_id>" CLIENT_ID = "<client_id>" TEAM_ID = "<team_id>" CHANNEL_ID = "<channel_id>" OUTPUT_RID = "<output_dataset_rid>" @external_systems(teams=Source(SOURCE_RID)) @transform.using(output=Output(OUTPUT_RID)) def read_channel_messages(teams: ResolvedSource, output) -> None: session = requests.Session() proxy = teams.get_https_proxy_uri() if proxy: session.proxies.update({"http": proxy, "https": proxy}) token_response = session.post( f"https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/token", data={ "client_id": CLIENT_ID, "client_secret": teams.get_secret("OAuthClientSecret"), "scope": "https://graph.microsoft.com/.default", "grant_type": "client_credentials", }, timeout=30, ) token_response.raise_for_status() response = session.get( f"https://graph.microsoft.com/v1.0/teams/{TEAM_ID}/channels/{CHANNEL_ID}/messages", params={"$top": 20}, headers={"Authorization": f"Bearer {token_response.json()['access_token']}"}, timeout=30, ) response.raise_for_status() rows = [ { "id": message.get("id"), "created_date_time": message.get("createdDateTime"), "web_url": message.get("webUrl"), } for message in response.json().get("value", []) ] output.write_table(pd.DataFrame(rows))
Copied!1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50import json import requests from functions.api import function from functions.sources import get_source SOURCE_ALIAS = "<source_alias>" TENANT_ID = "<tenant_id>" CLIENT_ID = "<client_id>" TEAM_ID = "<team_id>" CHANNEL_ID = "<channel_id>" @function(sources=[SOURCE_ALIAS]) def list_channel_messages() -> str: source = get_source(SOURCE_ALIAS) session = requests.Session() proxy = source.get_https_proxy_uri() if proxy: session.proxies.update({"http": proxy, "https": proxy}) token_response = session.post( f"https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/token", data={ "client_id": CLIENT_ID, "client_secret": source.get_secret("OAuthClientSecret"), "scope": "https://graph.microsoft.com/.default", "grant_type": "client_credentials", }, timeout=30, ) token_response.raise_for_status() response = session.get( f"https://graph.microsoft.com/v1.0/teams/{TEAM_ID}/channels/{CHANNEL_ID}/messages", params={"$top": 20}, headers={"Authorization": f"Bearer {token_response.json()['access_token']}"}, timeout=30, ) response.raise_for_status() messages = [ { "id": message.get("id"), "createdDateTime": message.get("createdDateTime"), "webUrl": message.get("webUrl"), } for message in response.json().get("value", []) ] return json.dumps(messages)
Copied!1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44import { ExternalSystems, Function } from "@foundry/functions-api"; import { MicrosoftTeamsSource } from "@foundry/external-systems/sources"; const TENANT_ID = "<tenant_id>"; const CLIENT_ID = "<client_id>"; const TEAM_ID = "<team_id>"; const CHANNEL_ID = "<channel_id>"; export class TeamsGraphFunctions { @ExternalSystems({ sources: [MicrosoftTeamsSource] }) @Function() public async listChannelMessages(): Promise<string> { const tokenResponse = await MicrosoftTeamsSource.fetch( `https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/token`, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: new URLSearchParams({ client_id: CLIENT_ID, client_secret: MicrosoftTeamsSource.getSecret("OAuthClientSecret"), scope: "https://graph.microsoft.com/.default", grant_type: "client_credentials", }).toString(), }, ); if (!tokenResponse.ok) throw new Error(`Microsoft token exchange returned ${tokenResponse.status}`); const token = await tokenResponse.json() as { access_token: string }; const response = await MicrosoftTeamsSource.fetch( `https://graph.microsoft.com/v1.0/teams/${TEAM_ID}/channels/${encodeURIComponent(CHANNEL_ID)}/messages?$top=20`, { headers: { Authorization: `Bearer ${token.access_token}` } }, ); if (!response.ok) throw new Error(`Microsoft Graph returned ${response.status}`); const payload = await response.json() as { value?: Array<{ id?: string; createdDateTime?: string; webUrl?: string }>; }; return JSON.stringify((payload.value ?? []).map((message) => ({ id: message.id, createdDateTime: message.createdDateTime, webUrl: message.webUrl, }))); } }
Copied!1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47import { getFetch, getSource } from "@palantir/functions-sources"; const SOURCE_RID = "<source_rid>"; const TENANT_ID = "<tenant_id>"; const CLIENT_ID = "<client_id>"; const TEAM_ID = "<team_id>"; const CHANNEL_ID = "<channel_id>"; export const config = { sources: [SOURCE_RID] }; export default async function listChannelMessages(): Promise<string> { const source = await getSource({ rid: SOURCE_RID }); const clientSecret = source.secrets.OAuthClientSecret; if (!clientSecret) throw new Error("Add OAuthClientSecret to the source"); const sourceFetch = await getFetch(source); const tokenResponse = await sourceFetch( `https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/token`, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: new URLSearchParams({ client_id: CLIENT_ID, client_secret: clientSecret, scope: "https://graph.microsoft.com/.default", grant_type: "client_credentials", }).toString(), }, ); if (!tokenResponse.ok) throw new Error(`Microsoft token exchange returned ${tokenResponse.status}`); const token = (await tokenResponse.json()) as { access_token: string }; const response = await sourceFetch( `https://graph.microsoft.com/v1.0/teams/${TEAM_ID}/channels/${encodeURIComponent(CHANNEL_ID)}/messages?$top=20`, { headers: { Authorization: `Bearer ${token.access_token}` } }, ); if (!response.ok) throw new Error(`Microsoft Graph returned ${response.status}`); const payload = (await response.json()) as { value?: Array<{ id?: string; createdDateTime?: string; webUrl?: string }>; }; return JSON.stringify((payload.value ?? []).map((message) => ({ id: message.id, createdDateTime: message.createdDateTime, webUrl: message.webUrl, }))); }
サインインしたユーザーとしてチャネルメッセージを送信するには、https://graph.microsoft.com 用の REST API ソースにアウトバウンドアプリケーションを設定します。チャネルメッセージの送信に必要な権限を付与し、メッセージを送信するユーザーとしてアウトバウンドアプリケーションを認可します。
以下の例では、Python または TypeScript v2 の関数からメッセージを送信します。REST API ソースを Functions リポジトリにインポートし、ソース、チーム、チャネルの識別子を置き換えます。各例はユーザーのアクセストークンを取得し、リクエストの Authorization ヘッダーに含めます。
選択したチームにアプリケーションからアクセスするには、リソース固有の同意を伴う ChannelMessage.Send.Group と、読み取りの例に示すアプリケーショントークンのパターンを使用します。Teamwork.Migrate.All は過去のメッセージのインポート ↗を目的としており、新しいチャネルメッセージの送信を目的としたものではありません。
この関数を Workshop または自動化されたワークフローで直接使用する前に、関数ベースのアクションを通じてアウトバウンドアプリケーションを認可してください。この関数は、呼び出し元ユーザーの認可を使用します。その認可が期限切れになるか取り消された場合、ユーザーは対話型ワークフローを通じて再度認可する必要があります。
どちらの関数を実行しても、チャネルメンバーが閲覧できるメッセージが投稿されます。入力を確認し、テスト時には非本番のチャネルを使用してください。
Copied!1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26import requests from functions.api import function from functions.sources import get_source SOURCE_ALIAS = "<source_alias>" TEAM_ID = "<team_id>" CHANNEL_ID = "<channel_id>" @function(sources=[SOURCE_ALIAS]) def send_channel_message(text: str) -> str: source = get_source(SOURCE_ALIAS) credentials = source.get_session_credentials().get() session = requests.Session() proxy = source.get_https_proxy_uri() if proxy: session.proxies.update({"http": proxy, "https": proxy}) response = session.post( f"https://graph.microsoft.com/v1.0/teams/{TEAM_ID}/channels/{CHANNEL_ID}/messages", headers={"Authorization": f"Bearer {credentials.access_token}"}, json={"body": {"content": text}}, timeout=30, ) response.raise_for_status() return response.json()["id"]
Copied!1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28import { getFetch, getSource } from "@palantir/functions-sources"; const SOURCE_RID = "<source_rid>"; const TEAM_ID = "<team_id>"; const CHANNEL_ID = "<channel_id>"; export const config = { sources: [SOURCE_RID] }; export default async function sendChannelMessage(text: string): Promise<string> { const source = await getSource({ rid: SOURCE_RID }); const credentials = await source.sessionCredentials?.get(); if (credentials?.type !== "oauth") throw new Error("Authorize the source first"); const sourceFetch = await getFetch(source); const response = await sourceFetch( `https://graph.microsoft.com/v1.0/teams/${TEAM_ID}/channels/${encodeURIComponent(CHANNEL_ID)}/messages`, { method: "POST", headers: { Authorization: `Bearer ${credentials.accessToken}`, "Content-Type": "application/json", }, body: JSON.stringify({ body: { content: text } }), }, ); if (!response.ok) throw new Error(`Microsoft Graph returned ${response.status}`); return ((await response.json()) as { id: string }).id; }