Power Automate で Microsoft Teams の予約投稿を行う

## 経緯

定時後にふと「○○さんにメンションして連絡入れておきたい」ってなったらどうします？

「夜中でもなんでもメンションして送ってよし！相手は受信して反応しなければいいだけ」
とか、「定時後に連絡するな」とか、色々と意見は分かれると思いますが、
私は Microsoft Teams での投稿を予約したくて、Power Apps で作っていました

※PowerApps で作りかけていたやつ(返答ができてなかった)
![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_01h08_15.png)

別のことを調べている時に、Power Automate でやってのけている方がいたので、
それをインスパイヤーしながら、自分で使うように作ってみました

参考サイト：[Microsoft Teams への予約投稿を Power Automate と Adaptive Cards でつくる](https://mofumofupower.hatenablog.com/entry/2020/08/15/013257)

ハッキリ言って長いですが、作るとそんなに時間かからないです
（記事書くのは数日かかってますが...）

## 前準備

Microsoft 365 の環境はあるものとします

下記のような Teams を作成しました
[![](https://1bed.allright.life/wp-content/uploads/2021/07/2021-07-31_02h35_41-710x454.png)](https://1bed.allright.life/wp-content/uploads/2021/07/2021-07-31_02h35_41.png)

## Power Automate の構築

### アダプティブカードでの投稿作成画面

1. [ マイフロー ] -> [ + 新しいフロー ] -> [ インスタントクラウドフロー ] を選択
  ![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_01h28_55.png)

2. フロー名を入力し、トリガーに Microsoft Teams の [選択したメッセージに対して ] を選択して、[ 作成 ] をクリック
  [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_01h32_53-565x364.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_01h32_53.png)

3. [ アダプティブカードの作成 ] をクリック
  [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_01h41_51-565x134.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_01h41_51.png)

4. [ New card ] -> [ Blank card ] をクリック
  ![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_03h41_10.png)
  [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_03h51_46-565x395.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_03h51_46.png)

5. TextBlock を AdaptiveCard にドラッグ・アンド・ドロップし、Text に説明を入力します
  [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_04h00_05-565x160.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_04h00_05.png)

6. Input.ChoiceSet を AdaptiveCard にドラッグ・アンド・ドロップし
  - Id に **postType** と入力
  - Placeholder を **空** にする
  - Compact style の **チェックを外す**
  - Default value に **reply** と入力
  - Choices に下記の Label , Value を入力
     - 選択した投稿に返答する , reply
     - 同チャネルに新規投稿する , new
  [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_04h07_51-565x338.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_04h07_51.png)

7. TextBlock を AdaptiveCard にドラッグアンドロップし、Text に説明を入力します
  [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_06h53_59-565x179.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_06h53_59.png)

8. Input.Text を AdaptiveCard にドラッグ・アンド・ドロップし
  - Id に **title** と入力
  - Placeholder に **タイトルを入力してください** と入力
  [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_06h56_46-565x338.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_06h56_46.png)

9. TextBlock を AdaptiveCard にドラッグアンドロップし、Text に説明を入力します
  [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_06h59_08-565x196.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_06h59_08.png)

10. Input.Text を AdaptiveCard にドラッグ・アンド・ドロップし
  - Id に **body** と入力
  - Placeholder に **本文を入力してください** と入力
  - Multi-line にチェックを入れる
  [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_07h01_42-565x304.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_07h01_42.png)

11. TextBlock を AdaptiveCard にドラッグアンドロップし、Text に説明を入力します
  [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_07h06_27-565x247.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_07h06_27.png)

12. Input.ChoiceSet を AdaptiveCard にドラッグ・アンド・ドロップし
  - Id に **mention** と入力
  - Placeholder に **通知する相手を選択してください** と入力
  - Allow multi selection にチェックを入れる外す
  - Choices に下記の Label , Value を入力
     - テストユーザー 01 , **<テストユーザー 01 のメールアドレス>**
     - テストユーザー 02 , **<テストユーザー 02 のメールアドレス>**
     - テストユーザー 03 , **<テストユーザー 03 のメールアドレス>**
  [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_07h10_56-565x384.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_07h10_56.png)

13. TextBlock を AdaptiveCard にドラッグアンドロップし、Text に説明を入力します
  [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_07h16_44-565x336.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_07h16_44.png)

14. ColumnSet を AdaptiveCard にドラッグ・アンド・ドロップし、[ Add a column ] を 2 回クリック
  [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_07h35_06-565x360.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_07h35_06.png)

15. Input.Date を AdaptiveCard にドラッグ・アンド・ドロップし
  - Id に **reserveDate** と入力
  [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_07h44_41-565x365.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_07h44_41.png)

16. Input.Time を AdaptiveCard にドラッグ・アンド・ドロップし
  - Id に **reserveTime** と入力
  [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_07h46_38-565x367.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_07h46_38.png)

17. [ カードの保存 ] をクリック
  [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_07h57_30.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_07h57_30.png)

以上がアダプティブカードでの登録画面でした

### ※アダプティブカードでの投稿作成画面での妥協点

* 投稿タイプが変更のときだけタイトルの入力を表示したかった
* 本文の入力はリッチテキストがよかったな...
* 必須入力が設定できない
  - 恐らく AdaptiveCard Ver1.3 からしかできない
* 通知先はチームに参加している人を動的にとりたい
  - とりあえずアドレス帳として Input.ChoiceSet に登録する方法で逃げた
* 予約日時に動的に初期値を入れたかった
  - `{formatDateTime(convertTimeZone(utcNow(),'UTC','Tokyo Standard Time'),'yyyy-MM-dd')}` と入れて初期値がセットできるかと思ったんだけど...

もっといい方法ないかな...

### 変数の初期化

アダプティブカードで入力した値が、判定などで使えなかったりしたので、
必要に応じて変数に移す

1. [ + 新しいステップ ] -> [ 組み込み ] タブ -> [ 変数 ] -> [ 変数を初期化する ] を選択し
  - ステップ名を **変数 Title を初期化する** と入力
  - 名前に **Title** と入力
  - 種類は **文字列** を選択
  - 値は動的なコンテンツから **title** を選択
  [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_08h05_42-565x171.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_08h05_42.png)

2. 同様にして body, mention を変数に移す
  [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_15h02_20-565x372.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_15h02_20.png)

3. mention でチェックを入れたメールアドレスを &lt;at>&lt;/at> で囲んだ文字列としてセットするための変数を初期化する
  - ステップ名を **変数 PostMention を初期化する** と入力
  - メモに **メールアドレスを &lt;at>&lt;/at> で囲んで送信用の文字列とする** と入力
  - 名前に **PostMention** と入力
  - 種類は **文字列** を選択
  - 初期値は空とする
  [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_16h04_57-565x211.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_16h04_57.png)

変数の初期化フェーズはここまでとなります

### 通知先が設定されているときの処理

通知先が設定されているとき、各アドレスを `<at>～</at>` で囲む必要があります

変数 **Mention** に値が入っていたら、各アドレスを `<at>～</at>` で囲み、
変数 **PostMention** にセットします

※Input.ChoiceSet で複数選択されているとき、各値は半角カンマで区切られています

1. [ + 新しいステップ ] -> [ 組み込み ] タブ -> [ コントロール ] -> [ 条件 ] を選択
  - ステップ名を **Mention に値が入っているか確認** と入力
    [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_16h16_37-565x159.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_16h16_37.png)

2. 左辺の **値の選択** にカーソルを移し、表示される **式** タブをクリック
  - `empty()` と入力
  [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_16h18_24-565x401.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_16h18_24.png)

3. `empty()` のカッコの中にカーソルを持ってきて、**動的なコンテンツ** タブをクリックし、変数 **Mention** をクリックして、 [ OK ] をクリック
  [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_16h22_10-565x376.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_16h22_10.png)

4. 右辺の **値の選択** にカーソルを移し、表示される **式** タブをクリック、false と入力して [ OK ] をクリック
  [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_23h17_15-565x205.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-01_23h17_15.png)

5. **はいの場合** の [ アクションの追加 ] -> [ 組み込み ] タブ -> [ 変数 ] -> [ 変数の設定 ] を選択し
  - ステップ名を **PostMention にメンション用タグを設定** と入力
  - メモに **Mention の各メールアドレスを &lt;at>&lt;/at> で囲んで PostMention に設定する** と入力
  - 名前に **PostMention** を選択
  - 種類は **文字列** を選択
  - 値に **&lt;at>&lt;/at>&lt;br>** と入力
  [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-02_02h51_11-565x330.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-02_02h51_11.png)

6. 値の入力欄の **&lt;at>&lt;/at>** のタグ間にカーソルを移動し
  - **式** タブをクリック
  - `replace()` と入力
  - カッコの中にカーソルを持ってきて、 `,',','</at> <at>'` と入力する
     - 第一引数は空
     - 第二引数は `,`
     - 第三引数を `</at> <at>`
  [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-02_02h55_15-565x176.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-02_02h55_15.png)

7. `replace()` のカッコ内の先頭部分(第一引数部分)にカーソルを持ってきて、**動的なコンテンツ** タブをクリックし、変数 **Mention** をクリックして、 [ OK ] をクリック
  [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-02_02h57_06.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-02_02h57_06.png)

これで通知先にチェックが入れられているとき、変数 **PostMention** にメンション用のタグがセットされました

### 予約した時間まで処理を待機させる

アダプティブカードで設定した予約日時まで、処理を待機させます

1. [ + 新しいステップ ] -> [ 組み込み ] タブ -> [ 日時 ] -> [ タイムゾーンの変換 ] を選択
  - 基準時間を動的なコンテンツから、**reserveDate** と **reserveTime** を選択して、 **間に半角スペース** を入れる
  - 変換元のタイムゾーンは **(UTC+09:00) 大阪、札幌、東京** を選択
  - 変換先のタイムゾーンは **(UTC) 協定世界時** を選択
  - 書式設定文字列は **カスタム値の入力** を選択して、 **yyyy-MM-ddTHH:mm:ssZ** と入力
  [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-02_01h29_57-565x210.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-02_01h29_57.png)

2. [ + 新しいステップ ] -> [ 組み込み ] タブ -> [ スケジュール ] -> [ 延期期限 ] を選択
  - タイムスタンプに動的コンテンツから、 **変換後の時間** を選択
  [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-02_01h32_56-565x192.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-02_01h32_56.png)

これで設定した時間まで待機するようになります

### 返信、または、新規投稿を行います

最後に投稿を行います

1. [ + 新しいステップ ] -> [ 組み込み ] タブ -> [ コントロール ] -> [ 条件 ] を選択
  - ステップ名を **返信か新規投稿か判断** と入力
  - 左辺は動的なコンテンツから **postType** を選択
  - 右辺を **reply** と入力
    [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-02_01h40_52-565x158.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-02_01h40_52.png)

2. **はいの場合** の [ アクションの追加 ] -> [ 標準 ] タブ -> [ Microsoft Teams ] -> [ メッセージの返信の投稿(V2) ] を選択し
  - チームは **カスタム値の入力** を選択して、動的なコンテンツから **チームID** を選択
  - チャネルは **カスタム値の入力** を選択して、動的なコンテンツから **チャネルID** を選択
  - メッセージは動的なコンテンツから **メッセージID** を選択
  - 返信は動的なコンテンツから **PostMention** を選択
  [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-02_01h52_48-565x290.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-02_01h52_48.png)

3. 返信に選択した **PostMention** の後ろにカーソルを持っていき
  - **式** タブで `replace()` と入力
  - カッコの中にカーソルを持ってきて、動的なコンテンツから変数の **Body** を選択
  - 続けて `,decodeUriComponent('%0A'),'<br>'` と入力
  - [ OK ] をクリック
  [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-02_01h59_23-565x266.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-02_01h59_23.png)

4. **いいえの場合** の [ アクションの追加 ] -> [ 標準 ] タブ -> [ Microsoft Teams ] -> [ メッセージを投稿する(V3) ] を選択し、[ 詳細オプションを表示する ] をクリック
  - チームは **カスタム値の入力** を選択して、動的なコンテンツから **チームID** を選択
  - チャネルは **カスタム値の入力** を選択して、動的なコンテンツから **チャネルID** を選択
  - メッセージは動的なコンテンツから **PostMention** を選択
  - 34 と同じ手順で Body を追加
  - 件名は動的コンテンツから **Title** を選択
  [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-02_02h05_53-565x292.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-02_02h05_53.png)

## 利用方法

スレッドの最初の投稿の右にある ・・・ をクリックし、[ その他の操作 ] にマウスカーソルを当てると、作成したフローが出てくるのでクリックする

[![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-11_02h35_48-710x375.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-11_02h35_48.png)

アダプティブカードが表示されるので、適宜入力して [ Submit ] をクリックすると予約完了

[![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-11_02h39_18.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-11_02h39_18.png)

## 今の所の問題点

* 返答するときには、必ずスレッドの最初の投稿に返答する必要がある  
  理由不明だが、親ではない投稿に返答するとエラーになる...  
    [![](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-11_02h26_56-558x710.png)](https://1bed.allright.life/wp-content/uploads/2021/08/2021-08-11_02h26_56.png)

## 考察

Power Automate で Adaptive Cards を使って作ってみて、
PowerApps で作ると構築に手間は掛かりそうだけど、メリットはこういうのがありそう
* Team に参加している人リストを動的に作れる (メンション用)
* リッチテキストが使える