前記事、前編の続きです。
前記事はこちら↓
いよいよ親フローを作成します。
おさらいですが、多階層のテスト用グループはこのような構成になっています。
親グループ1
├ アデルさん
└ 子グループ2
├ メーガンさん
└ 孫グループ3
├ アレックスさん
└ ひ孫グループ4(メール付きセキュリティグループ)
└グラディーさん
この記事では子フローを使ってセキュリティグループのメンバーをグループごとに取得しようとしています。
実際にはこんなことをしなくても、多階層グループはGraph APIの専用のエンドポイントを使えば取得できます。
簡単な方法はこちらをご参照ください。
子フローの役割
前編では子フロー部分を作成しました。
子フローがグループIDを受け取って、そのなかのメンバーであるユーザーをCSV化し、ユーザーではなくグループがメンバーとして含まれていた場合には、その情報を親フローへ返すという動作を担ってます。
親フローの役割
親フローは、子フローにグループIDを渡すことです。
子フローが処理できなかったグループIDを返して来たら、そのグループIDを再度子フローに渡します。
子フローがグループIDを返してこなくなったら終了です。
早速実装してみる
まずはシンプルにグループIDを渡して、どのような値が戻ってくるか確かめてみます。子フローの実行アクションを配置し、先ほど作った子フローを選択します。

子フローの入力に設定した「group_id」が求められましたので、一番親グループのIDを渡します。

これは、子フロー側の「実行のみユーザー」設定が、指定したユーザー参照を使う状態になっていないからです。
フローの作成者の接続を使用するように変更して「保存」します。

フローチェッカーの警告が消えたのでテスト実行しました。
子フローの出力本文には、これまた戻り値に設定した「group」という名前で配列が文字列として帰ってきているのがわかります。

JSON関数でテキストから戻す
文字列で帰ってきた内容をJSON関数に渡します。
json(outputs('子フローの実行')?['Body']?['group'])
結果は配列なので、これをくるくる子フローに渡し続けたい
1つのグループIDを渡すだけならばこれで済みますが、戻ってきた処理できないグループIDをもういちど子フローに渡すにはどうしたらよいでしょうか?
子フローに渡すグループIDを配列の形で準備して、ぐるぐるループを回し、グループIDが返ってきたときには配列に加えてやるということをすればよさそうです。
Do untilをつかう
ループの定番 Aplly to eachは、配列を一つずつ処理して終わりまで来たら止まるものです。
これだと途中で配列に値を加えてやることができません。
配列というか順番待ちをしている列の最後尾に行儀よくならばせるイメージを実現するには、Do untilを使えばよさそうです。
Do untilは、ループの停止条件を決められます。条件は順番待ちがなくなったとき。つまり配列の長さがゼロになったときです。
早速実装してみましょう。
ループの中で値をキープするには変数を作る
値を保持するときには、よく「作成」を使いますが、これだとループが回ったときに、前の値を使いまわすことができません。
今回は、順番待ちの列を queue配列、すでに処理したグループIDをvisited配列に保持することにします。
queue配列には初期値としてグループIDを配列の1つとして設定しました。

Do untilを設置し、左辺にはlength関数でqueue変数の配列の数を調べます。0になったら止まる設定です。
length(variables('queue'))
Do until の中に子フローの実行を移動します。group_idの欄には、queue配列の先頭に入っているIDを与えます。
first(variables('queue'))
そのままだとループが止まらないので、とりあえずqueue変数の中身を空っぽにしました。

テスト実行すると、Do untilループは1回だけ回って止まりました。子フローには配列先頭(今回は要素が1つだけでしたが)のグループIDを渡して戻り値を得ています。

子フローで配列の先頭の値をつかったので、いったん「作成」でつくったtmpにskip関数を使って先頭要素をマスクした配列を保存します。最初に与えた配列の要素は1つだけでしたので、この時点で配列は空っぽになっています。
skip(variables('queue'),1)
次の「選択」の「開始」欄には、先ほど子フローの結果をJSONで戻した式を入れます。
json(outputs('子フローの実行')?['Body']?['group'])
「選択」をマップモードにしてIDだけを取り出します。選択のマップモードに与えると配列を作ってくれます。
item()?['id']
最後に「変数の設定」をつかって、queue配列を書き換えます。
「tmp」にはすでに子フローに渡した残りのグループIDが配列として入っており、「選択」には同じく子フローで処理できなかったグループIDが配列として入っています。
この二つを重複なく合体させた配列をつくるには union関数を使います。
union(outputs('tmp'),body('選択'))
テストしてみる
これを実行すると、親フローのDo untilループは4回回りました。

テストで用意したグループは以下の通りです。
親グループ1
├ アデルさん
└ 子グループ2
├ メーガンさん
└ 孫グループ3
├ アレックスさん
└ ひ孫グループ4(メール付きセキュリティグループ)
└グラディーさん
正しく子フローが処理を実行できていれば、4つのグループ名のCSVファイルができていて、その中に1名ずつ存在するメンバーの情報が記録されているはずです。

グループ4にはグラディーさんが記録されています。そのほかのグループも想定どおり。ばっちりです!

あとがき
この記事ではやったことをまとめると
- 子フローが返した結果をもう一度子フローに渡しなおすために、キューを使いました。
- 配列の先頭要素をfirst関数で取得しました。
- 使い終わった先頭要素は skip関数で見えなくした状態で配列変数に書き戻しました。
- 書き戻すときに、union関数を使って配列を混ぜました。こうすることで「配列へ追加」とループ処理を使わなくても済みます。Power Automateのループはともかく遅いので、関数を使って回避します。
- 配列変数への設定の際には、自身の配列を設定する値として利用できないので、いったんtmpに逃がしておきました。
何度も書いていますが、多階層のグループメンバーの取得はGraph APIで一発で行えます。
今回はQueueの手法をPower Automateで使えるのかの実験だと思ってあたたかく見守ってください。
Queueと子フローを組み合わせることで、処理全体をぐっと短くすることができました。
おや?何か忘れている
追加しなくても特に問題はないと思いますが、いちど処理したグループIDは無視する処理も入れておいてよいかもしれません。
条件でvisited配列にqueue配列の先頭要素が含まれているかを確認し、含まれていなければ子フローにグループIDをわたし、visited配列にグループIDを追加しました。これで多階層のグループのなかに同じグループが紛れ込んでいてもスキップできるはずです。
こんな人が書いています
こちらの記事はランゲルハンス島のDDさんが紹介しました。ブログでクラウドフローのTIPSのようなものを書いたり、Qiita記事を書いたりしていますのでご贔屓に。
フォローやいいねいただけると嬉しいです。
関西のPowerPlatform系の勉強会にときどき出没しますので、「あのアイコンの顔の人だ!」と、気軽に声をかけていただけると喜びます!







