FormsとPower AutomateでEntra IDのゲスト招待システム&棚卸システムをつくってみる(その6)

ローコードでつくるゲスト招待システム、早くも6回目です。前回は招待するゲストが他のユーザー等から招待されて既にテナントにゲストとして存在するかどうかのチェックする処理を加えました。今回は、実際にゲストをEntra IDに追加する時点で何らかのエラーが出た場合や、その他各処理でエラーが出ていた場合に管理者に知らせるためにチャネル投稿する仕組みを追加したいと思います。
おさらい
これまでの作成経過はこちらをご覧ください。
ここまでの道のりです。少しずつ開発をすすめていますので、必要なところだけつまみ食いしてもらうのも良いかと思います。
- (その1)Formsでユーザーがゲスト招待申請を投稿する。
- (その1)クラウドフその1,その2ローがSPOリストの追加によってトリガーされる。
- (その2)入力されたゲストEmailがメールアドレスとして妥当か(正規表現が使える?)確認して、受付または却下メールを申請者へ送る(却下ならステータスを「却下」にして、備考に理由を書き込む。妥当ならステータスを「承認待ち」にして申請日を書き込む)。
- (その2)承認者ユーザーに承認要求を送る。
- (その3)承認が通ったら承認日時に書き込み、ステータスを「承認済み」に更新して次へ進む。
- (その3)却下の場合は、承認者のコメントを含めたメールを申請者に送る。
- (その3)14日間承認されない場合は、ステータスを「承認待ち14日期限切れ」に変えて申請者へメールを送る。
- (その3)各ステータスをSPOリストに書き込む。
- (その4)サービスプリンシパルを使ってHTTP要求で対象の外部ユーザーをEntra IDのゲストとして登録する。
- (その5)すでにゲストがテナントに登録済みならば、申請者へ伝える。
- (その5)登録が成功したら、SPOリストの棚卸期限列に、ゲスト招待期間の数字を加えた日付を登録する。
- (今回)登録が成功したら、承認者と申請者にメールで通知する。
- (今回)登録が失敗したら、管理者へ通知する(チャネル投稿)→Teamsチャネルを見て、エラーを確認し、手動でゲスト登録をしてSPOリストを書き換え、チャネルに行った対応を投稿する運用で回避。SPOリストにTeamsの投稿URLを入力できる列があっても良いかも。
ゲストが登録されたことを申請者へ知らせる
前回まででようやくゲストの登録をすることができたので、登録の成功を申請者と、この申請を承認したユーザーに対して教えてあげましょう。ゲスト追加処理の後ろにメール送信アクションを追加しました。
送信内容の動的なコンテンツの指定は表示されるものを追加すれば良いですが、最初に指定した承認者と、実際に承認したユーザーが異なる場合があるので、承認者の部分は配列0番目指定などちょっとだけ複雑担っています。

//申請者メール
triggerOutputs()?['body/Author/Email']
//申請者氏名
outputs('項目の更新(ステータスをゲストに更新)')?['body/Author/DisplayName']
//ゲストEmail
triggerOutputs()?['body/GuestEmail']
//ゲスト氏名
triggerOutputs()?['body/GuestName']
//ゲスト所属
triggerOutputs()?['body/GuestAffiliation']
//ゲスト期限
outputs('項目の更新(ステータスをゲストに更新)')?['body/InventoryDeadline']
//申請した理由
triggerOutputs()?['body/ApplicationReason']
//指定した承認者
triggerOutputs()?['body/ApproverEmail']
//承認したユーザー氏名
outputs('開始して承認を待機')?['body']?['responses'][0]?['responder']?['displayName']
//承認したユーザーEmail
outputs('開始して承認を待機')?['body']?['responses'][0]?['responder']?['email']
//承認者コメント
outputs('開始して承認を待機')?['body']?['responses'][0]?['comments']
申請者にはこんな感じでメールが届きました。指定した承認者はユーザー型だったので、メールアドレス以外の情報もJSON型式で届いてしまいました。JSONの中のEmail要素、DisplayName要素だけを取り出すには以下のように修正します。

//指定した承認者Email
triggerOutputs()?['body/ApproverEmail']?['Email']
//指定した承認者DisplayName
triggerOutputs()?['body/ApproverEmail']?['DisplayName']
例外をキャッチする
ここまでの作業で、ある程度の処理のまとまりを「スコープ」として分けてきました。こうしておくと全体が把握しやすくなります。また、なんの処理でエラーが起きているかも見つけやすくなります。

ここで、スコープの中にわざとエラーが出るようなアクションを加えて、スコープがどのような値を返すのかを確認してみます。
何でもよいのですが、今回は存在しないユーザーのプロフィールを取得してみます。

これで、スコープのなかでエラーが発生すれば、それを含むスコープもエラーになります。どんなエラーだったかを拾うにはこちらのサイトで紹介されていたresult関数が使えそうです。
Result関数でどんな結果が拾えるか中身を確認するために、エラーでも動作するよう条件指定した「作成」アクションに関数を設定しました。

作成に記録された結果はこちらの通り。スコープの中のアクションが配列の1要素担っています。エラーになったアクションは body>error>message という項目を持つので、statusがFailedのものだけフィルタリングしてエラーメッセージとアクションのnameを通知してあげれば良さそうです。

そこで、スコープが成功した場合は次へ。失敗した場合は処理を分岐するように並列アクションに分岐させてみました。
result関数の結果は配列なので、そのなかからstatusがfailedになっているものだけにフィルタリングします。
フィルタリングした結果も配列ですが、普通は実行条件を指定していても配列0番目が問題のエラーのはずなので、Teamsチャネルへの投稿には0番目のアクション名とエラーメッセージを表示させます。

//エラーが発生したアクション名
body('アレイのフィルター処理')[0]?['name']
//エラーが発生した内容
body('アレイのフィルター処理')[0]?['outputs']
投稿された結果は以下のような表示になりました。ちょっとエラーメッセージ部分が読みにくいですね。

必要なのはエラー情報なのでoutputs>body の中身だけに絞り、カンマ部分で改行させます。うっかり改行文字にreplace関数で置き換えてしまいそうになりますが、Teamsチャネルへの投稿はHTMLなので改行文字は無視されます。<br>タグに置き換えるが正解です
// エラーメッセージ
replace(string(body('アレイのフィルター処理')[0]?['outputs']?['body']),',', '<br>')
スッキリしました。

クラウドフローの実行履歴URLを手に入れて保守性を高める
さらに、せっかく通知するならば、エラーが確認できるクラウドフローの履歴画面へのリンクも表示させたいです。これによって保守がずいぶん楽になるはずです。
こちらのブログにそのテクニックが紹介されていましたので、さっそく使わせてもらいます。
クラウドフローの先頭のほうに文字列型の変数を初期化します。この書き方でクラウドフローが実行されている環境ID、フローのIDと実行のたびに変わる実行IDが履歴画面を開くURLの適切な箇所に割り当てられます。

https://make.powerautomate.com/environments/@{workflow()['tags']['environmentName']}/flows/@{workflow()['name']}/runs/@{workflow()['run']['name']}
いちどテスト実行すると変数の中にURLが入りますので、そいつをブラウザで開くとこの通り。

文字列の変数の中身をHTMLのaタグに加工して、リンクできるように修正します。その変数をチャネル投稿の中に仕込んでやればすぐさま実行結果を確認できるようになります。ちなみに、実行結果もクラシック画面のほうが好みの方は、URLの最後に「?v3=false」と追加してあげると幸せになれます。
<a href="https://make.powerautomate.com/environments/@{workflow()['tags']['environmentName']}/flows/@{workflow()['name']}/runs/@{workflow()['run']['name']}?v3=false">こちら</a>

すばらしい!

他のスコープにもエラー通知を仕込む
ここまでできたら、各スコープの下にエラーの場合の処理を仕込んでいきましょう。エラー通知処理もスコープに入れると塊のままコピーができるので便利です。
アレイのフィルターアクションに設定しているresult関数が参照するスコープをそれぞれ変更するのを忘れないようにしましょう。
ちょっと横長になりましたが、エラー通知の仕組みも整いました。

まとめ
- ゲストがテナントに追加されたら、申請者に結果を伝える処理を加えました。ユーザー型はJSONなので、承認者のEmailやDisplayNameを取得するには指定してやる必要がありました。
- スコープの中でエラーが発生していることを知るにはresult関数を使えば可能でした。この関数の戻り値は、スコープの中に存在するアクションが配列で管理されていました。
- エラーが発生しているアクションだけを取得するには、「アレイのフィルター処理」を使ってstatusがfailedになっているものだけを抽出しました。
- アレイのフィルター処理の結果も配列ですが、スコープの中で発生しているエラーは0番目だけを捕まえればよいでしょう。
- チャネルに通知する際に、フローの実行結果のURLを加えると保守性が高まります。JBSさんの記事がとても参考になりました。
こんな人が書いてます。
細かい点では修正したほうが良いところもまだまだありますが、プロトタイプとしてはこれで十分ではないでしょうか? Gitで公開とかできると良いのですが、そのあたりの勉強をしたら公開します。
次からは、申請者に対してゲストの棚卸通知を送る別のクラウドフロー作成に移ります!
QiitaやこのブログではPower Automateの話題を中心に投稿を行っていますので、ぜひ「いいね」してくださると励みになります。
ディスカッション
コメント一覧
まだ、コメントがありません