TeamsのIncomming Webhookコネクタが廃止されるようなのでPowerAutomateのワークフローに移行してみる

要約
---------

https://aka.ms/O365ConnectorDeprecation

2024-11-25追記: @ecormaksin さんに 2025-10-16に上記記事のアップデートがあったことを教えていただきました。前回からの変更箇所は太字にしておきます。

- TeamsのIncomming WebhookやRSSなどのO365系のコネクタが **最短 2025-01-31** に廃止される (前回は2024-12-31)
   - **2025-01-31** までにURL変更を行うことで 2025-12末 まで延長できる
- 代替としてPowerAutomateのワークフローが案内されている
- [Microsoft Graphを使ったTeamsのチャネルへのメッセージ投稿](https://learn.microsoft.com/en-us/graph/api/chatmessage-post?view=graph-rest-1.0&tabs=http#example-1-send-a-hello-world-message-in-a-channel) ができそうです (@ecormaksin さんより)
  - (TODO:後で試す...)

<details>
<summary>過去の追記内容は折りたたんでおきます</summary>

2024-07-24追記: 廃止スケジュールが少し緩和されましたが、廃止されることは変わっていません

- TeamsのIncomming WebhookやRSSなどのO365系のコネクタが **最短 2024-12-31** に廃止される
  - **2024-12-31までにURL変更を行うことで 2025-12 まで延長できるようになった** (2025-12で廃止なのかは明言されていない)
- 作成自体は 2024-08-15 から作成できなくなる
- 代替としてPowerAutomateのワークフローが案内されている
  - ワークフローは個人の所有として作られ、変更できない。（ライセンス次第では所有者を変更できるようですが、よくわかってないです…）
  - 投稿者やアイコンのカスタマイズができないっぽい

Office365コネクタという括りがよくわかりませんが、Incomming WebhookやRSSは影響を受けそうです。

Incomming Webhookが廃止されるにあたり、次の対応が必要そうです。

- [PowerAutomate](https://make.powerautomate.com/) のワークフローの作成
- （[MessageCard形式](https://learn.microsoft.com/ja-jp/microsoftteams/platform/task-modules-and-cards/cards/cards-format)の場合）AdaptiveCard形式への変換
- Webhook URLの差し替え

2024-07-24追記: 「[Stop the Retirement of Webhooks within Microsoft Teams](https://feedbackportal.microsoft.com/feedback/idea/80ed6877-b642-ef11-b4ad-000d3a7aba8b)」というFeedbackが挙げられています。中の人も見ているようです。困る人はUpvoteやコメントしておきましょう。

もう少し詳しい情報は今後出てくるかと思いますが、準備はしたほうがよいでしょう。
</details>



背景
----------

~~おそらく 2024-07-08頃からIncomming WebhookやRSSからの投稿に以下のような文言がでるようになりました~~

> Action Required: O365 connectors within Teams will be deprecated and notifications from this service will stop.  [Learn more](https://aka.ms/O365ConnectorDeprecation) about the timing and how the Workflows app provides a more flexible and secure experience. If you want to continue receiving these types of messages, you can use a workflow to post messages from a webhook request. Set up workflow

~~文言の通りで、まぁWorkflowのほうが柔軟だし履歴も残るしで便利なのはその通りなんですが、あのお手軽さがよかったんですけどね…~~

追記: 投稿にフッターメッセージは出なくなりましたが、引き続き廃止予定となっています。手順変わっちまった！

> Update 07/17/2024: Due to customer feedback received around the footer message, it will be removed from the cards that are posted within Microsoft Teams.

ということでやっていきましょう。

作業
------------

### AdaptiveCard形式の場合

「[Webhook 要求を受信するとチャネルに投稿する](https://make.powerautomate.com/galleries/public/templates/d271a6f01c2545a28348d8f2cddf4c8f)」というテンプレートがあり、AdaptiveCard形式を想定されています。ここから始めると簡単です。

一度まずは上記テンプレートから作成まで進めましょう。

次に編集していきます。「Teams Webhook要求を受信したとき」のトリガーを選択するとパラメーターの画面が出ます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52527/5d9353e6-3053-0973-c058-8cb9922f7fa4.png)

「フローをトリガーできるユーザー」は「誰でも」がデフォルトですが、今までのWebhook通り使う場合は「誰でも」にする必要があります。

HTTP URLは一度作成までしていると表示されているはずです。詳細設定モードの場合は保存後に表示されます。

次に「Post card in a chat or channel」を選択し、パラメーターを設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52527/7dde4f06-87bd-23ba-5544-c64ea02a3271.png)

Teams, Channelを設定してください。デフォルトでは`@`が入っていますが、これを削除しないと補完されないので注意です。ログイン済みのユーザが現在参加しているTeamとChannelから選べるようになっています。

「Adaptive Card」の値は"content"が入っていますが、一旦このままにしてください。これはWebhookに投稿された本文中の"attachments"配列の中にあるオブジェクトの"content"の値を使う設定になっています。この後にお試し実行をするので、そのJSONデータの構造をみてください。

あとは実行するだけです。

「Teams Webhook要求を受信したとき」のアクションのパラメータにあるHTTP URLをコピーし、Bash上のcurlを使ってお試し実行し、投稿してみましょう。

```sh
# 変数設定（適宜書き換え）
WEBHOOK_URL="https://prod-**.japaneast.logic.azure.com:443/workflows/***********/triggers/manual/paths/invoke?api-version=2016-06-01&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=******"

# 投稿テスト
curl -s -i -H "Content-Type: application/json" --data-binary @- "$WEBHOOK_URL" << '__EOF__'
    {
       "type":"message",
       "attachments":[
          {
             "contentType":"application/vnd.microsoft.card.adaptive",
             "contentUrl":null,
             "content": {
                "$schema":"http://adaptivecards.io/schemas/adaptive-card.json",
                "type":"AdaptiveCard",
                "version":"1.4",
                "body":[
                    {
                    "type": "TextBlock",
                    "text": "Hello World"
                    }
                ]
             }
          }
       ]
    }
__EOF__

```

うまくいくと投稿されるはずです。

![Pasted image 20240709134429.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52527/a75badbe-1270-49c8-87cb-0ff3c7930361.png)

テンプレートを使っていることをPRしてくるのが鬱陶しいですが、ひとまず良しとしましょう。

### Webhook URLを使っている実装を変更する

Webhook URLを使っている箇所を書き換えましょう。

MessageCard形式の場合は実装も修正しましょう…

また、非同期なAPIになってしまうので、Webhookを呼ぶ側から見ると本文に問題があってもJSONとして正しいと一旦受け付けられてしまいます。ワークフロー側でエラーを検知できますが、PowerAutomateの運用の事を少し考える必要はあるでしょう。

一応、実行に失敗しているとメールでお知らせされます。普段から失敗が無いようにしておきましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52527/2e99b79b-8e0b-57c1-5096-6c28457a838c.png)


おまけ
--------

### デザイナーツールでAdaptiveCardを作成する

もっとおしゃれな投稿をしたい場合はデザイナーツールを使うと簡単です。直感的な操作で作成できます。

https://adaptivecards.io/designer/

ただし、Teamsで使う場合は、versionを`1.4`にしてください。`1.5`,`1.6`では投稿されたアダプティブカードの内容が`We're sorry, this card couldn't be displayed`というメッセージだけになってしまいます。（これで正常終了するので辛い）

![Pasted image 20240709140112.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52527/b4601a28-d80a-8359-37fb-eabadefe112e.png)

なお、Webhookに投げつけるには以下のスキームに従っていることを想定しているため注意しましょう。

```json
    {
       "type":"message",
       "attachments":[
          {
                "contentType":"application/vnd.microsoft.card.adaptive",
                "contentUrl":null,
                "content": { ここにAdaptiveCardを埋め込む }
          }
        ]
    }
```

AdaptiveCardを扱ったことがある人なら多分大丈夫ですが、デザイナーツールの内容を張り付けても動かないということです。attachmentsで複数つけられる必要性やscheme定義があるのに外側でcontentTypeを指定する意味の不明さは我慢しましょう。

### ただのテキストを投稿したい

:::note warn
本来の使い方とは異なるため動作しなくなる可能性があります
:::

そんなリッチな機能いらん！ちょっとしたテキスト(HTML)が投稿できればそれでいいんだ！`{"text":"Message"}`で投稿できてたじゃん！！という場合。

まず、「Teams Webhook要求を受信したとき」のトリガは、スキーマが定義されていますが**バリデーションチェックが行われることはないようで独自のJSONでも読み取れます**。それを利用します。よって、attachementsという配列も使わなくなるのでループを回す必要もなくなります。

次に、アクションに「チャットまたはチャネルでメッセージを投稿する」がありますので、そちらを使います。カードではないです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52527/4740b349-4780-c6ea-677e-8eb60b6585a6.png)

追加したらパラメーターを修正します。

![Pasted image 20240709135636.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52527/a67768bc-176f-3f57-d47b-7f69ff9378e4.png)

Messageは 右の`<>` をクリックするとHTML入力に切り替えができます。

Messageには`@{triggerBody()?['text']}`と入力しましょう。上記の画像のように赤いブロックになりますが、そういうものです。ちなみに`{"text":"Hello World"}`という入力があったら"Hello World"が埋め込まれます。

もちろん、自由にテキスト入力もできます。ちょっとしたHTMLも書けます。

動作確認はcurlで行います。

```sh
# 変数設定（適宜書き換え）
WEBHOOK_URL="https://prod-**.japaneast.logic.azure.com:443/workflows/***********/triggers/manual/paths/invoke?api-version=2016-06-01&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=******"

# テキスト投稿テスト
curl -s -i -H "Content-Type: application/json" --data-binary "{\"text\":\"Hello World\"}" "$WEBHOOK_URL"
```

投稿すると次のようになります。シンプルですね。

![Pasted image 20240709134501.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52527/77eb4014-63c9-e8c8-98c5-39d276f96fdf.png)

### 投稿者を変える…ことはできない

アクションで投稿者の欄がありますが、任意の投稿者名に変えられるわけではありませんでした。

![Pasted image 20240709140219.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52527/ba7a56a8-352d-f0b1-21f8-370e789cf8fd.png)

フローボットの場合は上記の通り「Workflows経由の～」と付き、アイコンもWorkdlowsのものになります。

ユーザの場合はただ自分が投稿したように見えるだけです。（テキストだと見分けがつかない）

![Pasted image 20240709140405.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52527/41d9af90-3448-7cc0-20b1-8916a598c743.png)

Power Virtual Agentsは[Microsoft Copilot Studio](https://learn.microsoft.com/ja-jp/microsoft-copilot-studio/fundamentals-what-is-copilot-studio)に置き換わったらしく、おそらくチャットボット的なものに変わりを投稿させるといったものではないかと思います。試していないのでわかりません。

2024-07-25追記: [@yume_yu さんがPower Virtual Agents選択時の挙動を検証されています。投稿先にチャネルが出てこない模様。](https://qiita.com/fukasawah/items/896c3638c203a973c2f0#comment-7274eb4791f10f239aa6)

カスタム値を入力は、投稿者(poster)の内部値を使えるというだけでした。任意の値を設定できるわけではなさそうです。

### 共同所有者は設定できるが、所有者は変更できない

https://make.powerautomate.com/ から該当のフローにある「共有」から他の人に読み書きさせる権限（共同所有者）をあたえることができます。

しかし、所有者を変更することはできませんでした。引継ぎの時に困りそうです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52527/b3ea8160-43e6-bb43-b0e0-23f516cb6f53.png)

> これは非ソリューション フローです。所有者を変更できません。 

"非ソリューション フロー"ってなんだよ！用語増やさんでくれ！！と思いつつ、この「["詳細情報"の先の項目](https://learn.microsoft.com/ja-jp/power-platform/admin/power-automate-licensing/faqs#the-owner-of-a-flow-left-the-organization-how-can-we-ensure-it-works-without-interruptions)」を見た感じ、以下のように読み取れました。

- "Power Automate プロセス ライセンス"か"Power Automate ホスト プロセス"のライセンスを取得し、それに割り当てる
- エクスポートして別の人がインポートすればよい（URL変わっちゃうじゃん…）

ライセンス周りはよくわからなくなってきたので考えることをやめました。

### 所感:ワークフローにしてよいところ・ダメなところ

- よいところ
    - ワークフロー上で通知先を自由にカスタマイズできる
    - ワークフロー上でロジックを少し書ける
    - ワークフローの書き方次第で通知先を増やすこともできる（1:1ではなく1:Nの通知にできる）
    - ワークフローの実行履歴が残る・再試行が容易
- ダメなところ
    - ワークフローの所有者が個人に紐づいてしまう
    - アイコンや投稿者名を自由に変えられない

メリットはあるといえばあるんですが、ただの通知をワークフローでやることでもないなとも思ったり。

また会社で使うにはダメなところが際立って辛い。

Botを建てたほうがよさそうな気がしてきます。OpenHackでBot作成に苦戦した苦い思い出が蘇る…