Teamsで「いいね」をしてない人に対してスケジュール実行でメンションをするというフローをわたるふさんという方が2022年に作成しており、私も使わせていただいていました。
しかし、
- チームメンバー全員ではなく、特定の人物だけにメンションしたい
- 予約した投稿を簡単に取り消したい
といったことができませんでした。
上の機能をPower Appsと組み合わせることで実装しましたので紹介します。
アプリ・フローのダウンロード
アプリとフローはGitHubに公開しています。下記URLからダウンロードしてご利用いただけます。
機能など
実際のアプリ画面はこちらです。

アプリでリマインド先を設定し実行することで、チャネルにメンションしたり、いいねしてない指定した人にメンションしたり、予約投稿したりできます。

根本的にはわたるふさんのフローで、アプリでは下記2つの機能を追加しています。
- チームメンバー全員ではなく、特定の人物だけにメンションしたい
- 予約した投稿を簡単に取り消したい
解説
各パーツの機能や設定値などを紹介していきます。
データとして下記3つを追加します。

- Microsoft Teams
- Office365グループ
- PowerAutomate管理
予約投稿を取り消す方法として、下記方法で実装しています。
- 予約投稿時、自分宛てにアプリ起動URLにパラメータを付与したURLを通知する
- 通知されたURLからアプリを起動すると、Power Apps上でフローの取り消しを実行する。
アプリのAPP>OnStartに下記を設定します。
コピーしました!
//URLから起動
If(IsBlank(Param("Category")) = false, //URLパラメータに何か入っていれば //パラメーターをグローバル変数に格納 Set(varParamCategory,Text(Param("Category"))); Set(varParamId,Text(Param("Id"))); //フローキャンセル処理 PowerAutomate管理.CancelFlowRun( "Default-99b882ac-a043-4d2e-9579-dbbef4dff629", "006e853e-817a-4a13-2a04-6045298f4c69", varParamId ); Notify("予約投稿を取り消しました",NotificationType.Information)
);URL構成は下記のように”Category”と”Id”を付け加えています。
https://apps.powerapps.com/play/e/【環境ID等・略】&Category=ReminderCancel&Id=【フロー実行ID】このURLをPower Automateで作成し、Teamsへ通知。取り消す際は通知されたURLへアクセスすることで、フローが取り消されるという動作になっています。

まずは、Teamsのチームを選択できるようにします。ドロップダウンのパーツのそれぞれのプロパティに下記を設定します。
コピーしました!
Sort(MicrosoftTeams.GetAllTeams().value,displayName,SortOrder.Ascending)次に、下記2つもここで実装します。
- チャネル情報も取得し、グローバル変数に格納する
- チームメンバーをPower Automate経由で取得する
もう少し別のパーツで機能として付けてもいいと思いますが、チームが確定したタイミングで上記2つが確定するため、このタイミングでデータの取得・準備を済ませます。
同じくチームのドロップダウンのパーツのOnChangeに下記を設定します。
コピーしました!
//loading画面
UpdateContext({_loadingMenu:true});
//チームIDを格納
Set(ChannelData,Blank());
Set(ChannelData,MicrosoftTeams.GetChannelsForGroup(drp_team.Selected.id).value);
//Chatデータをリセット
Set(chatData,Blank());
//チームメンバーをリセット
UpdateContext({_colMemberList: Blank()});
//エラー検知:チームIDの空白を検知
If( IsBlank( drp_team.Selected.id), UpdateContext( { _teamIdError: "true" } ), UpdateContext( { _teamIdError: "false" } ) );
// 条件判定と処理
If( Or( _teamIdError="true" ) ,// エラーメッセージ Notify("エラーです。確認をお願いします。" & If(_teamIdError="true","「チームが選択されていません」 ","") , NotificationType.Warning); , //Power Automate実行 UpdateContext({_colMemberListtmp: メンバーリスト取得.Run(drp_team.Selected.id)}); //実行結果をテーブルへ変換 UpdateContext( { _colMemberList: ForAll( Table(ParseJSON(_colMemberListtmp.memberlist)), { id: Text(ThisRecord.Value.id), displayName: Text(ThisRecord.Value.displayName), jobTitle: Text(ThisRecord.Value.jobTitle), mail: Text(ThisRecord.Value.mail), preferredLanguage: Text(ThisRecord.Value.preferredLanguage) } ) } );
);
//loading画面 UpdateContext({_loadingMenu:false});Power Appsではチームメンバーを100人以上取得できないため、Power Automate経由で取得します。
また、取得するデータや後続の操作等で分かりやすさやエラー防止の為、すでに取得したデータについてはクリアしてからデータを取得し直しています。
ローディング画面も準備していますが、データ取得中の誤操作を防ぐためです。
Power Automateは下記の様になっています。

特に特別なことはせず、Power AppsからTeamIDを受け取り、「グループメンバーの一覧表示」でメンバーを取得しアプリへ文字列にして返してています。(有料プランの場合はHTTPアクション等で返却しても良いと思います)
「グループメンバーの一覧表示」の設定の改ページを設定することで、より多くの人数分のデータが取得できます。


選択したチームに応じて、チャネルを表示し選択できるようにします。チーム選択時、「ChannelData」というグローバル変数に格納しているので、Itemsにそのまま入れます。(Sortで並べ替えしています)
コピーしました!
Sort(ChannelData,displayName,SortOrder.Ascending)チャネルを選択することで、リマインド投稿したい投稿先が確定します。このタイミングでチャットデータを取得します。
コピーしました!
//チャットデータを変数に格納
Set(chatData,Blank());
Set(chatData,MicrosoftTeams.GetMessagesFromChannel(drp_team.Selected.id,drp_channel.Selected.id).value);
リマインドをしたい投稿を選択できるようにします。閉じたり開いたりできるようにしていますが、ギャラリーに直接表示するだけで十分だと思います。閉じたり開いたりする設定などは、GitHubからダウンロードしたアプリをインポートしてご確認ください。ココでは最低限紹介します。
ギャラリーに下記を設定します。
コピーしました!
chatData
「チャネルにメンションする」か「いいねしてない人にメンションする」かを選択できるようにします。
ドロップダウンのItemsに下記を設定します。
コピーしました!
Table( { id: 1,choices: "チャネルにメンションする" }, { id: 2,choices: "いいねしてない人にメンションする" }
)
「いいねしてない人にメンションする」の場合にのみ表示させ、チームメンバーを選択できるようにします。チームメンバーはチーム選択時にAutomate経由で取得したデータを利用します。
わたるふさんのフローでは決まってチームメンバー全員が対象でしたが、ここでチームメンバー内の特定の数人を選択して実行することが可能になります。
コンテナで囲っているので、コンテナのVisibleに、「いいねしてない人にメンションする」(idが2)のときに表示できるように設定します。
コピーしました!
If(drp_メンション宛先.Selected.id=2,true,false)メンバー選択のコンボボックスには下記を設定します。
コピーしました!
_colMemberList複数人に対してのメンションも動作するようになっていますので、「複数人の選択を許可」をONにします。

「いますぐ」か「日時を指定する」かを選択できるようにします。
ドロップダウンのItemsに下記を設定します。
コピーしました!
Table( { id: 1,choices: "いますぐ" }, { id: 2,choices: "日時を指定する" }
)
予約投稿の場合のみ表示し、予約する日時を設定できるように、日付の選択やドロップダウンを配置しています。
コンテナで囲っているので、コンテナのVisibleに、「日時を指定する」(idが2)のときに表示できるように設定します。
コピーしました!
If(drp_いつ.Selected.id=2,true,false)
予約投稿の場合にのみ表示し、選択肢として「チャネルに投稿する」、「自分だけに知らせる」を選択できるようにします。
予約投稿の場合にのみ表示させる方法は先程と同じですので、割愛します。
選択肢として、ドロップダウンに下記を設定します。
コピーしました!
Table( { id: 1,choices: "チャネルに投稿する" }, { id: 2,choices: "自分だけに知らせる" }
)
リマインド時にテキストを付けられるように、リッチテキストエディターを作成します。

一番下に配置している実行ボタンです。
処理をいくつかに分けて説明します。
チームの未選択や、メンション先の未選択の場合、フローが動作する条件を満たさない為、未選択かどうかを判定し、コンテキスト変数に格納しています。
コピーしました!
// --- 基本エラーフラグ(boolean)を一括設定 -------------------------------
UpdateContext({ _teamIdErrorB: IsBlank(drp_team.Selected.id), //エラー検知:チームIDの空白を検知 _channelIdErrorB: IsBlank(drp_channel.Selected.id), //エラー検知:チャネルIDの空白を検知 _channelReplyIdErrorB: IsBlank(gal_リマインド先.Selected.id), //エラー検知:リマインド先、返信用IDの空白を検知 _mentionAtesakiErrorB: IsBlank(drp_メンション宛先.Selected.id), //エラー検知:メンションの宛先の空白を検知 _implementationTimingErrorB: IsBlank(drp_いつ.Selected.id) //エラー検知:いつ実施かの空白を検知
});予約投稿の場合のエラーチェックや日時をAutomateに渡す形に加工しています。
エラーのチェックは下記2つのチェックです。
- 設定した日時が過去ではないか
- 設定した日時は30日以内か(Automateの実行最大時間)
コピーしました!
// 予約投稿のタイミングの選択状態を保持(boolean)
Set(_isReserveB, drp_いつ.Selected.id = 2);
// --- 予約投稿のときだけ日時を合成 & 差分(分)を計算 ----------------------
If( _isReserveB, // SelectedDateTime = 選択した日付 + 時 + 分 Set( SelectedDateTime, DateAdd( DateAdd( DateValue(dte_予約日時_日.SelectedDate), Value(drp_予約日時_時.Selected.Value), TimeUnit.Hours ), Value(drp_予約日時_分.Selected.Value), TimeUnit.Minutes ) ); Set(DaysDifference, DateDiff(Now(), SelectedDateTime, TimeUnit.Minutes)); UpdateContext({ _yoyakuJouhouErrorB: IsBlank(drp_予約情報.Selected.id), //エラー検知:予約情報の通知先空白 _dateTimeErrorB: DaysDifference >= 43200, // 30日 = 43200分 _dateTimeMiniErrorB: DaysDifference <= 0 // 過去 }), // 日時指定でない場合は日時系エラーなし UpdateContext({ _yoyakuJouhouErrorB: false,_dateTimeErrorB: false, _dateTimeMiniErrorB: false })
);メンションの宛先が「いいねしてない人」の場合、対象者のメールアドレスを配列でまとめておきます。また、チャネル宛の場合は空白を渡してエラーになるので、適当に「1」を渡すように設定します。
コピーしました!
// --- メンションの宛先作成:メンションの宛先------------------ If( drp_メンション宛先.Selected.id=2 , //いいねしてない人にメンションの場合:宛先のメールアドレスだけを配列で渡す為に変換 Set(_channelMentionMember, JSON(ShowColumns(cmb_メンションメンバー.SelectedItems,mail),JSONFormat.Compact)); , //チャネルにメンションの場合:フローで不要なので適当に「1」を送る Set(_channelMentionMember, "1"); );エラーの変数とメッセージのコレクションを作り、エラーの判定を行い、エラーがゼロの場合、Power Automateを実行する形にしています。
コピーしました!
// --- エラーコレクションを作って、まとめて通知 or 成功処理 ------------------
ClearCollect( _errorsB, { flag: _teamIdErrorB, msg: "「チームが選択されていません」" }, { flag: _channelIdErrorB, msg: "「チャネルが選択されていません」" }, { flag: _channelReplyIdErrorB, msg: "「リマインド先が選択されていません」" }, { flag: _mentionAtesakiErrorB, msg: "「メンションの宛先が選択されていません」" }, { flag: _implementationTimingErrorB,msg: "「『いつ実施しますか?』が選択されていません」" }, { flag: _dateTimeErrorB, msg: "「予約投稿は720時間(30日)未満で設定してください」" }, { flag: _dateTimeMiniErrorB, msg: "「予約投稿が過去の日時になっています。」" }, { flag: _yoyakuJouhouErrorB, msg: "「予約投稿の通知先が選択されていません。」" }
);
If( CountRows(Filter(_errorsB, flag)) > 0, // ---- エラーあり:まとめて警告 ---- Notify( "エラーです。確認をお願いします。 " & Concat(Filter(_errorsB, flag), msg & " "), NotificationType.Warning ), // ---- エラーなし:Power Automate 実行 → JSON をテーブル化 ---- Powerapps_リマインド.Run( drp_team.Selected.id, //チームID drp_channel.Selected.id, //チャネルID gal_リマインド先.Selected.id, //リマインド先チャットID drp_メンション宛先.Selected.id, //メンションの宛先 _channelMentionMember, //メンションの宛先メンバー drp_いつ.Selected.id, //いつ実行か Text(SelectedDateTime,DateTimeFormat.UTC), //予約投稿日時 drp_予約情報.Selected.id, //予約情報どこに投稿か User().Email, //実行者メール drp_channel.Selected.displayName, //チャネル名 rtx_本文.HtmlText //本文 );
);
