Contents
スポンサードサーチ
条件
以下にアクセスできる Microsoft 365 Business Standard 以上の Microsoft 組織アカウントを持つ
2アカウント以上持っていると管理センター間の遷移の際、「別のアカウントでサインインする」がうまく動作しないことがあるので注意。
実施環境
- MacOS Ventura Version: 13.0
- Microsoft Teams Version: 1.6.00.16465
- Visual Studio Code Version: 1.79.0 (Universal)
- Teams Toolkit Version: 5.0.1
事前準備
Microsoft Teamsのクライアントアプリをダウンロード
Microsoft Teams をダウンロードする。
Microsoft Teams を起動したら、 Microsoft 組織アカウントでログインできるか確認する。
「開発者ポータル」アプリを追加
Microsoft Teamsにて「アプリ」から「開発者ポータル」を追加する。

Visual Studio Code にTeams Toolkitをインストール
Visual Studio Code (以下VS Code) 拡張機能の Teams Toolkit をインストールする。
「カスタムアプリをアップロード」をオンにする
Microsoft Teams 管理センターにアクセスし、
サイドメニューの「Teams のアプリ」 > 「セットアップポリシー」をクリック
グローバルのを選択し「カスタムアプリをアップロード」をオンにする。

ngrokのインストール
ngrokをインストール する
(インストール方法はリンク先で確認を)
ngrokの起動
ngrokをインストールしたら、ポート番号: 3978 で起動しておきます。
$ ngrok http 3978
プロジェクトの作成
プロジェクの作成方法は以下のパターンがあると思いますが、
1. VS CodeからTeams Toolkitを起動 → 新しいアプリを作成する
2. Microsoft Teamsの「開発者ポータル」アプリでアプリを作成 → マニフェストを設定し、VS Codeを開く
ここ紹介する「アプリの機能」はボットのみの前提のため、1.で行います。
複数機能を使いたい場合 (例えば「ボット」と「グループとチャネルアプリ」を兼ねたもの) は2.で行います。
(2.については【MS Teams】複数機能のプロジェクトを作成するに記載しているので、一度本記事を読んだ後に確認してみてください)
VS Code にて、「Teams Toolkit」 > 「新しいアプリを作成する」> 「Bot」 を選択

「Basic Bot」を選択

言語はお好みですが、ここでは「TypeScript」を選択します。

パスの指定とプロジェクト名はお好みで作成してください。
「開発者ポータル」での設定
アプリの作成
「開発者ポータル」で「アプリ」>「新しいアプリ」からアプリを作成する。
アプリ名を求められるので、名前を設定し「追加」をクリック

ボットの設定
「アプリの機能」から「ボット」を選択

「新しいボットの作成」をクリック

遷移先で「新しいボット」をクリック
ボット名を求められるので、名前を設定し「追加」をクリック

「構成する」 > 「エンドポイントアドレス」には、ngrokで生成したURLに/api/messagesを繋げたものを設定し「Save」をクリック

ここで、UXが考えられているアプリなら「アプリの機能」に戻るところなのですが、
MSにそんな気が効くことを求めても無駄なので「アプリの機能」まで戻ってください。
このとき、なぜかヘッダーは「アプリ」が選択されている状態ですが、本来は「ツール」なはずです。
現に、このエンドポイントアドレスを再設定したい場合は、
「ツール」> 「ボット管理」から、 作成したボットを選択し「構成する」から行えます。


「アプリの機能」まで戻るため、「ホーム」など適当に他のヘッダーを選択後、再び「アプリ」から作成したアプリを選択してください。
「アプリの機能」まで戻れたら、「ボット」をクリック
「既存のbotを選択」から作成したボットを選択してください。
(バグで2つずつ表示されると思いますが、気にせずどちらかを選択してください)

次に、「ボットで何ができますか?」「ユーザーがこのコマンドを使用できるようにする範囲を選択してください」は、作成したいアプリの機能に沿ってチェックを付けてください。
(範囲の考え方については別途記事でまとめようと思っています)
特になければ、ここでは
「ボットで何ができますか?」はチェックなし、
「ユーザーがこのコマンドを使用できるようにする範囲を選択してください」は「Personal」と「Team」にチェックを付けてください。
これらの設定は後で変更も可能です。
設定したら「保存」をクリック
基本情報の設定
次に「構成する」> 「基本情報」にて、必須項目を全て埋めてください。

後に作成したアプリをTeamsクライアントアプリに追加する際に以下のエラーが出た場合、
ここでの項目が埋まっていないことが原因の可能性があります。

URLを埋める項目にて、特にサイトを用意していない場合は適当なページでいいのでとりあえず項目を埋めてしまいましょう。
この段階では入力したURL先が正しいかどうかは判定されていないと思います。もちろん、アプリを公開する場合など審査が入る前にはきちんと用意しましょう。
(念の為、モラルとして悪意のあるページへのリンクを設定するのはやめましょう)
「アプリケーション (クライアント) ID」は、
後述する「Azure Active Directory」での「「アプリケーション (クライアント) ID」か、
「ツール」 > 「ボット管理」から、作成したボットの「ボットID」で確認できます。

「Azure Active Directory」での設定
「開発者ポータル」は一旦そのままで、次はMicrosoft Entra 管理センター または Azure AD ポータル からAzure Active Directoryにアクセスしてください。
アクセス方法
Microsoft Entra 管理センターの場合、
サイドメニューにある、「管理センター」 > 「Azure Active Directory」を選択

Azure AD ポータル の場合、
「Azure サービス」から「Azure Active Directory」を選択

クライアントシークレットの追加
「Azure Active Directory」にアクセスしたら、
サイドメニューの「アプリケーション」> 「アプリの登録」から、「開発者ポータル」で作成したボットが表示されると思うので、リンクとなっているボット名のをクリック

次にサイドメニューの「証明書とシークレット」のページに遷移し、
「新しいクライアントシークレット」をクリック

右サイドに「クライアント シークレットの追加」が表示されると思うので、
「説明」と「有効期限」を設定し、「追加」をクリック。
この時、「説明」は空白でも大丈夫です。
「有効期限」は 最大24ヵ月(カスタムでも24ヵ月以上にはできない) のようですが、クライアント シークレットの追加より、推奨は12ヵ月未満のようです
Microsoft では、有効期限の値は 12 か月未満に設定することをお勧めしています。

作成したら「値」をコピーして保持しておいてください。
この値が後述の BOT_PASSWORD になります。

アプリケーション (クライアント) ID
前述の「開発者ポータル」において、アプリの「基本情報」で設定した「アプリケーション (クライアント) ID」は、
「Azure Active Directory」で確認したい場合は、アプリの詳細ページに表記されています。

比較してもらえればと思いますが、
「開発者ポータル」での「ボットID」と同値であることが確認できると思います。
それなら「開発者ポータル」では、なんで「ボットID」って表記なんやねん。
って感じはしますが、MSにそんな気が効くことを求めても無駄です。
(個人的には「ボットID」じゃなくて「Azure AD アプリ ID」なんて表記にすればいいのに。とは思いますね)
プロジェクトの設定
アプリ側の設定は一通り完了したので、次はプロジェクトの方を設定していきます。
Dockerの設定
以下のような docker-compose.yml をプロジェクト直下に設置します。
version: '3'
services:
teams-bot-app:
image: node:18.16
volumes:
- .:/app
working_dir: /app
entrypoint:
- sh
command:
- -c
- |
npm install
npm run build
npm run dev
ports:
- '3978:3978'
tty: true
command に関してですが、
package.json の scripts が以下のように記載されているはずなので、それを実行する形になります。
なので、npm run dev の代わりに npm run start, npm run watch でもいいかもです。
"scripts": {
"dev:teamsfx": "env-cmd --silent -f .localConfigs npm run dev",
"dev": "nodemon --exec node --inspect=9239 --signal SIGINT -r ts-node/register ./index.ts",
"build": "tsc --build && shx cp -r ./adaptiveCards ./lib/",
"start": "node ./lib/index.js",
"watch": "nodemon --exec \"npm run start\"",
"test": "echo \"Error: no test specified\" && exit 1"
},
ボット認証の設定
ボットの認証に関しては、 VS Codeから Tool kit を使ってビルドした場合は
自動で「Azure Active Directory」でのアプリ作成とクライアントシークレット追加がされ、env > env.local の値も自動設定されるなど 、なんかゴニョゴニョ動きますが、
(Azureは詳しくないので プロジェクト作成で生成される infra ディレクト内を確認してみるといいかもです)
docker化する場合は、その辺りの動作は不要なので設定します。
ここでは dotenv を使おうと思うので、まずはインストール。
$ npm install dotenv
.env ファイルを作成します。
BOT_ID:「開発者ポータル」での「ボットID」または「Azure Active Directory」での「アプリケーション (クライアント) ID」
BOT_PASSWORD: 「Azure Active Directory」で「クライアント シークレットの追加」を行った際の「値」
BOT_ID=
BOT_PASSWORD=
環境変数名はご自由ですが、ここでは単に config.ts に記載されているのに合わせた感じです。
(この時点で察している人がいるかもしれませんが、docker化したら config.ts は不要になります)
const config = {
botId: process.env.BOT_ID,
botPassword: process.env.BOT_PASSWORD,
};
export default config;
最後に、 MicrosoftAppId と MicrosoftAppPassword の値を .env から設定します。
+ import * as path from "path";
// This bot's main dialog.
import { TeamsBot } from "./teamsBot";
- import config from "./config";
+ import { config } from "dotenv";
+ const envFilePath = path.join(__dirname, ".env");
+ config({ path: envFilePath });
// Create adapter.
// See https://aka.ms/about-bot-adapter to learn more about adapters.
const credentialsFactory = new ConfigurationServiceClientCredentialFactory({
- MicrosoftAppId: config.botId,
- MicrosoftAppPassword: config.botPassword,
+ MicrosoftAppId: process.env.BOT_ID,
+ MicrosoftAppPassword: process.env.BOT_PASSWORD,
MicrosoftAppType: "MultiTenant",
});
起動
ここまで設定したら、以下のコマンドで起動します。
$ docker compose up
余談ですが、Docker Desktop 3.4 以降なら docker
コマンドのサブコマンドに compose
が追加されているので docker-compose
のように – (ハイフン) で繋げなくても実行できると思います。
https://www.docker.com/blog/announcing-compose-v2-general-availability/#proposed-compose-v1-end-of-lie-timeline
Teamsクライアントアプリからボットを動作させる
dockerを起動したらTeamsのクライトアプリ上で動作させます。
「開発者ポータル」で「アプリ」から、作成したアプリ の「アプリ パッケージをダウンロード」をクリックします。
すると {アプリ名}.zip をダウンロードできると思います。

次に、Teamsクライアントアプリにて
「アプリ」> 「アプリを管理」> 「アプリをアップロード」をクリック

モーダルが表示されたら「カスタムアプリをアップロード」を選択し、
先ほどダウンロードしたzipファイルを選択します。

アプリをどこに追加するかのモーダルが表示されたら、そのまま追加してください。

追加し、adapciveCards > welcome.json を使用したサンプルが実行されたら成功です!!!

お疲れ様でした。
サンプルとしてリポジトリを用意しているので、設定に関してはそちらでも確認できます。
ファイルの整理
docker化できたことですし、
もし、今後アプリを公開するにあたって、サーバーはAzureでなくAWSやGCPを使う場合、以下は不要かもしません。 (Azureはわからない)
.webappignore
.localConfigs
config.ts
env/
infra/
teamsapp.local.yml
teamsapp.yml
web.config
表記揺れ
MSはわかりづらい。っと、よく聞きますが、その理由の1つに表記揺れがあるかと思います。
本記事でも「ボットID」,「アプリケーション (クライアント) ID」の話をしましたが、
他には「MICROSOFT-APP-ID」なんて表記があったのでメモしておきます。
開発者ポータル > ツール > ボット管理 | ボットID |
Azure Active Directory | アプリケーション (クライアント) ID |
Bot Connector API を使用した認証 | MICROSOFT-APP-ID |
また、Bot Connector API を使用した認証での MICROSOFT-APP-PASSWORD は、
「Azure Active Directory」でのシークレットの「値」でもあります。
(これはなんとなく連想できなくもない?)