Power Automate(旧Microsoft Flow)を使った上司の事務作業効率化

# はじめに

本記事は **[NSSOL Advent Calendar 2019](https://qiita.com/advent-calendar/2019/nssol)** の12日目の記事です。

今回のネタとしては、私が効率化した事例を共有します。
ツールとして、Power Automate(旧Microsoft Flow)を使いました。同じような効率化をしたい人が参考になればと思います。
※私自身もQiitaの幾つかの記事を参考にしています。

本記事は、当初取り組んでいた**2019年10月頃**を起点として、Qiita投稿のために再度見直した**2019年12月12日時点**の情報を元にしています。プレビューのアクションの内容も含んでいるため、将来的に挙動が異なる場合があります。お気づきの点はコメントいただければ幸いです。

# 現状
期限付き事務作業(例:勤怠申請、アンケートなど)は、皆様もあると思います。

私の現状として、以下のような状況でした。
 - 社会人として当然やらないといけない業務です。ただし、事務作業のため、効率かつ確実にやりたい
 - 自分だけでなく部下がやっているかの管理もやらなければいけません。ただし、部下と週に1回も顔を合わさないこともあるので直接言う機会が少ない

上記のような現状を打破して、効率かつ確実に実施したい現状があったため、着手してみました。

# 実行環境

あえてOffice365縛りで作ってみました。具体的には以下を利用しています。

- **Power Automate(旧Microsoft Flow)**
    - 今回のメイン。いわゆるMicrosoft Flow部分のみ実施しました
    - ※UIフロー(RPA)も触りたかったけど時間がなく断念しました

- **Teams,Forms,Planner**
    - 登録通知、リマインダー通知として**Teams**を利用しました
    - 入力画面として**Forms**を利用しました
    - ToDo管理として**Planner**を利用しました
     
# 機能概要

## やりたいこと(≒要件)

「自分と部下のToDo管理」を簡単に「登録可能」かつ、「チェック出来る」ような仕組みと定義付けました。

## 動作イメージ
 - Formsの決められたテンプレートに投稿することで動作開始する
 - Flowが上記トリガーに以下処理を実行する
1. 「チームToDo」のPlannerにToDoを登録する
2. 「チーム事務連絡」のTeamsのチャネルに、Flowからメンション付きで通知する

![動作イメージ.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320928/a00e3b03-1e4b-ac29-4eeb-0a07cc60eb26.gif)

# **1.Plannerでユーザを指定して登録**

Plannerで「タスクを作成する」場合に、ユーザを登録するときには、IDまたはユーザのメールアドレスが必要ということがわかりました。
Formsではわかりやすく「ユーザ名」にしているため、そのまま変数を入れても動作せず、変換が必要と判明しました。
※そりゃそうですね。

![1_planner.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320928/93d4772d-71c8-9a6b-021f-04f424a5c4b7.gif)

## **処理の流れ**
Formsで定義したチェックボックスの名前からメールアドレスに変換する必要があるので、大枠としては以下のような流れを想定しました。
![2_planner.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320928/75886e90-48ac-3a9b-ea9d-a9b4a60d29c6.gif)

実際Flowで作っていくにあたっては、上記処理をもう少しプログラムっぽく落とす必要があります。そのため、以下のように分解してみました。

1. Formsで入力したデータを取得(=Forms : 応答の詳細を取得する)
2. Formsで入力した選択肢を配列に格納
3. 名前とメアド定義をJSONで作成(=データ操作 : 作成)
4. Formsでチェックボックス入れた配列を展開してループ処理
5. JSON の解析 - UserとMailAddress(=データ操作 : JSON の解析)
6. 名前とメールアドレスを展開してループ処理
7. 「4」と「6」で名前が一致するかチェック
8. 一致した時は、Plannerでタスクを登録 (=Planner : タスクを作成する)

## **Flowでの実装**

見にくいですが、Flowでの実装は、以下となります。
処理の流れと一致できるように番号を振っています。
4~8は分岐などもあるので、スコープで囲っています。

![1_planner_20191211.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320928/e9094e68-8dc8-4a30-6549-f6064a36e5df.gif)

スコープを開くと、以下となります。

![2_planner_20191211.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320928/42fa78a5-bc07-158f-4e76-a4850052c7e9.gif)


## **各処理の簡単な解説**

### 2. Formsで入力した選択肢を配列に格納

 Formsのチェックボックスを「応答の詳細を取得する」でFlow上で取得すると、["a","b","c"]のような文字列でした。本値は、配列に格納されており、Plannerにその名前で登録して、Teamsではその名前でメンションをすることを考えていました。しかしながら、そもそも文字列だったため、まずは配列に格納するように力技で対応しました。
※正直もっと良いやり方があると思います。

 - **["a","b","c"]のような文字列を(a,b,c)の配列へ格納**
1. [ を消す
1. ] を消す
1. "を消す
1. カンマ(,)区切りで分割する
1. アレイ型の変数に格納する


「xxを消す！」は、**[replace関数](https://docs.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#replace)**を利用して消しました。**[**も**]**も**"**も全部消しています。
outputs('作成_-_メンション先')は、Formsで私が定義した名前です。Formsでどう定義したかによって変動すると思われます。<削除する記号>は、**[**や**]**や**"**になります。

```
replace(outputs('作成_-_メンション先'),'<削除する記号>','')
```

「カンマ(,)区切りで分割」は、**[split関数](https://docs.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#split)**を利用しました。詳しくは左記を参照ください。
 
```
split(<変数>,',')
```

当初は、処理の流れで書いたようにひとつひとつを変数で初期化して変数に格納していきましたが、処理が無駄に長くなるので、最終的には全部まとめて関数で処理しました。
ひとつひとつの処理の時には、「outputs('作成_-_メンション先')」では動いていました。しかしながら、全部まとめて関数処理をする過程で「outputs('応答の詳細を取得する')?['body/r0b5af0a5383a479c8b8a3d0a6d49f0e5']」ではないと動作しませんでした。
※理由は不明で、あまりまじめに調べていません。後学のために、ご存知の方が居れば教えてください。

```
split(replace(replace(replace(outputs('応答の詳細を取得する')?['body/r0b5af0a5383a479c8b8a3d0a6d49f0e5'],']',''),'[',''),'"',''),',')
```

### 3.名前とメアドの定義をJSONで作成

json形式で書きました。他にもっと良いやり方はあると思いますが、今回はベタベタにそのまま突っ込みました。
名前をuserとし、メアド(=メールアドレス)をmailaddressと付けています。

```
[
{"user":"A","mailaddress":"a@test.onmicrosoft.com"},
{"user":"B","mailaddress":"b@test.onmicrosoft.com"},
{"user":"C","mailaddress":"c@test.onmicrosoft.com"}
]
```

### 8.Plannerでタスクを登録

mailaddressを取り出すために、「Apply to each」を使ってループ処理で格納しました
これをやりたいがための今までの前処理となります。

# **2.Plannerの書式をFormsの書式に変換**

Formsで定義した「対応期限」のままだとPlannerの「期限日時」の書式と異なるため、変換しなければならなかったです。

失敗すると以下のようなエラーが出ました。

```
{
  "error": {
    "code": "",
    "message": "The request is invalid:\r\nCannot convert the literal '12/10/2019 2:01:32 PM' to the expected type 'Edm.DateTimeOffset'.",
    "innerError": {
      "request-id": "xxx",
      "date": "2019-12-10T14:01:36"
    }
  }
}
```

Plannerの書式は、以下のような書式設定の必要があるみたいです。
確かに改めてみると、違いますね。
※同じoffice365なのに・・・。

![1_planner_2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320928/d23d82c0-bf04-aa2a-55eb-eda4eee8cfa9.gif)

```Planner.開始日時/期限日時
yyyy-MM-ddTHH:mm:ssZ
```

## **処理の流れ**

Formsで入力した対応期限の日付を、Plannerへインプットできるように書式変換し、Plannerへ登録する
順番としては以下のように設定していく。

1. Formsで入力した「対応期限」を取得(=Forms : 応答の詳細を取得する)
2. 時刻の書式変換(=時刻 : タイムゾーンの変換)
3. Plannerへ登録 ※詳細割愛

## **Flowでの実装**

上記の処理の流れだけを簡易的に作ると以下のような感じです。

![0_time.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320928/ccf20e0a-e9f0-0df5-9acc-31a7bdcd437e.gif)

## **各処理の簡単な解説**
### 時刻の書式変換

関数で一発変換も出来るかもしれません。ただし、わからなかったので、タイムゾーンの「書式設定文字列」を利用して変更しました。

![3_time.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320928/eb646c61-face-e083-8c44-586ada93137e.gif)

# **3.Teamsで通知するための工夫**

事務連絡の通知として、Teamsに流すだけだと気づかない可能性があったため、メンションで通知したかったです。ユーザ本人へ通知しても良かったのですが、何かしらアクションもあるかもしれなかったので、公開しつつメンションをしました。

メンションの出し方としては、以下を参考に作りました。
[FlowからMicrosoft TeamsへBotで投稿する方法3種をまとめてみた](https://qiita.com/tfunakoshi/items/76029bcc8ac1d4d9bd71)の「メッセージをフロー ボットとしてチャンネルに投稿する」を利用することにしました。詳細は、該当URLを見て欲しいですが、簡単に言うと、Planner登録のたびに配列に\<at\>と\</at\>を付けながら格納して、変数をメッセージ投稿すれば可能となります。

## **処理の流れ**

TeamsでFormsで入力した「件名」、Formsで入力した「対応期限」、Formsで入力した「メンション先(=対応者)」、Formsで入力した「事務連絡」をTeamsで通知する。
Formsで入力した「メンション先(=対応者)」は、Teamsのメンションを付けて通知し、「事務連絡」は改行する。
順番としては以下のように設定していく。

1. Formsで入力した値を取得(=Forms : 応答の詳細を取得する)
2. Planner登録時にメンション用のHTML型を付けて格納
3. Teamsで投稿

## **Flowでの実装**
以下は、2.Planner登録時にメンション用のHTML型を付けて格納の時の処理です。
Planner登録時のため、[1.Plannerでユーザを指定して登録](#1plannerでユーザを指定して登録)の後処理に入れます。

![teams_20191211.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320928/09b0364a-f5c9-ca13-7102-ed5b7b1961fe.gif)

最後に、Teamsで「メッセージをフロー ボットとしてチャンネルに投稿する」を使ってます。

![teams_2_20191211.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320928/d0a9ac96-5656-f381-6693-e02649a86298.gif)

## **各処理の簡単な解説**
### 2.Planner登録時にメンション用のHTML型を付けて格納

Planner登録のたびにメールアドレスをconcat関数で\<at\>と\</at\>を付けて格納しています。

```
concat('<at>',items('Apply_to_each_-_UserとMailAddressのリストでループ')['mailaddress'],'</at>')
```

### 3.Teamsで投稿

Teamsの「メッセージをフロー ボットとしてチャンネルに投稿する」の中で、配列を利用できなかったので、「メンション先」を強制的にString型に変換しました。
もう一つの処理として、事務連絡がデフォルトだと改行されないので、関数を指定して対処しています。
※GUIだと変換していないように見えますが、コードだときちんと処理されて見えますね。

![teams_3_20191211.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320928/d469f0f7-2d7e-1b63-d3cb-8331bdcc874c.gif)

「メンション先」を強制的にString型に変換の処理です。
※Teamsで利用するメンション配列は、配列の変数名です。

```
string(variables('Teamsで利用するメンション配列'))
```

「事務連絡内容」については、なぜか改行されないようになりました。
調べると幾つかTIPSがあり、[FlowでOutlook→Teamsに通知する際に改行が無視されないようにする](https://qiita.com/zu_ki_/items/f652e441d060bac256b0)を参考にしました。
今回は以下のように、関数を利用して処理しています。詳細は、上記URLを参考にしてください。

```
uriComponentToString(replace(uriComponent(outputs('応答の詳細を取得する')?['body/r4158077969c8439c9dda9975905e8d7b']), '%0A', '<br>'))
```

# ***最後に***

上記のような四苦八苦を繰り返して出来たFlowの全体像です。

![flow_20191211.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320928/b61d22f3-63e8-5322-62b4-efcb4a28539a.gif)

Qiita投稿前なので、改めて情報を整理すると気づいたことがありました。それは、**ほぼ同じテンプレート**があります。
いつからあったのだろう・・・。これを使ったらもっと簡単かもしれません・・・。
※最初に気づいていたら、それこそもっと効率化出来ていたのでは・・・。

![naku.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320928/ee2da845-cb67-03fd-9192-da12a751c909.gif)

本記事が、見てくれた方の何かしらの役に立てればと思います。こうやったほうがより有用なのに！というのもあると思います。是非、ご指摘、ご指導頂けると幸いです。