Power Automate で SharePoint リストに祝祭日リストを自動生成する

# 後で運用するために祝祭日リストを持っておきたい
SharePoint リストに祝祭日リストを自動生成する Power Automate のフローを作りました。 Power Automate 上で祝祭日判定するのは他のフローでも紹介している通り可能なのですが、 SharePoint リストで使用するもしくは Power Apps で使用することを想定し、まずは SharePoint リスト上に祝祭日リストを自動生成することを目指したものです。
## 前提条件
* 祝祭日をカレンダーから取得しリスト化する
* 会社の休日（年末年始等）を含ませることができるようにする
* 一定期間で自動更新する
## 実装
全体の流れは以下の通り。
<details><summary>クリックで開く</summary>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12937/991ef1c2-e342-5099-681e-7caaeaccd246.png)
</details>

例の通りまずはトリガーを手動実行に設定しておき、完成後に繰り返しに変更しております。なお、繰り返しの設定は 3 か月頻度です。理由は実行されていないフローは 90 日で警告が発報されさらに 30 日後にフローが停止されてしまうため 3 か月ごとの自動実行としています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12937/e0ff65d9-8179-612f-e228-343215c0653e.png)
## 変数の設定
まずはフローに必要な各種変数を設定していきます。
「変数を初期化する」フローで「today」を設定しました。これはフロー実行時の現在の日付を取得する変数です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12937/54103d5e-f6d6-6b07-3e17-49cf1e1126e1.png)
値には以下のように`utcNow()`関数で UTC の時刻を取得し`convertFromUtc()`関数で UTC+9 の時間に変換しています。
```C#
convertFromUtc(utcNow(),'Tokyo Standard Time','yyyy-MM-ddT00:00:00')
```
次に「1_year_later」変数を設定しています。これは祝祭日を取得する際にフロー実行時から 1 年後の終了時間を格納しておく変数となります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12937/3a04aee4-7856-42a0-0bdc-221079c628b6.png)
値には以下のように変数「today」から`addDays()`関数で 365 日後を生成しています。おおよそ 1 年のデータが取得できればいいので、厳密に設定する必要はありません。
```C#
addDays(variables('today'),365)
```
次に祝祭日のデータを保管するための「holiday」変数と中間データを保管する「data」変数を配列型のアレイで用意しておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12937/bf01ae09-434c-b8da-bbcf-e11ffdf7242f.png)
最後に個別の休日を設定しておくための変数「addithion」を配列型のアレイとして用意し、値には配列としてデータを収めておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12937/bd035013-cd26-d341-6be9-1a6d67ad4888.png)
今回は 2023 年から 2024 年の年末年始の予定を`["休日名","日付"]`の形式で複数記載しています。創立記念日等がお休みの場合にも事前に記載しておけば祝祭日リスト内に含めておくことが可能です。
## Outlook から「日本の休日」を取得する
次に「イベントのカレンダー ビューの取得(V3)」フローを利用して Outlook のカレンダーから日本の休日を取得します。フロー実行者自身のカレンダーに日本の休日が設定してあることが必要になりますので、別途設定しておいてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12937/0dd73fcc-60d7-bdd8-e957-855739c6fc9b.png)
「カレンダー ID 」には自身のカレンダーから「日本の休日」を選択します。「開始時刻」には「today」変数を、「終了時刻」には「1_year_later」変数を設定しておきます。詳細オプションで「並べ替え順」に`start/dateTime`を設定しておくと日付順でデータを取得できますので便利です。
## 祝日の配列を作成する
Outlook から取得したデータを`Apply to each`フローを利用しループ処理で配列に配置していきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12937/38629387-46cd-d26a-c369-d86cd14073cc.png)
Outlook から取得できるデータは以下のようになっています。
```JSON
{
  "subject": "みどりの日",
  "start": "2023-05-04T00:00:00.0000000",
  "end": "2023-05-05T00:00:00.0000000",
  "startWithTimeZone": "2023-05-04T00:00:00+00:00",
  "endWithTimeZone": "2023-05-05T00:00:00+00:00",
一部省略
}
```
ここから`start`のデータを利用しようと思います。
まずは用意していた「today」変数を再利用して祝日の日付を格納します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12937/c7eae662-6519-ced7-c305-c4c25ff98406.png)
値には以下のように設定しました。
```C#
formatDateTime(items('Apply_to_each（祝日の配列作成）')?['start'],'yyyy/MM/dd')
```
## 祝日のデータに自前の休日データを差し込む
年間の祝日データをループ処理させながら、間に自身で設定した休日データを挟む処理を入れていきます。 Power Automate ではソートの機能が弱いのでできるだけ最初から挟んでおいた方が楽なような気がします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12937/a8157d99-32fd-93e3-4505-12b252357274.png)
ループ処理の中に「Apply to each」フローで「addithion」変数をループ処理させます。「条件」フローを追加し条件を以下のように設定します。

`items('Apply_to_each')[1]`　次の値以下　「today」変数

結果が`true`だけ処理を行えばいいので「はいの場合」に「配列変数に追加」フローで「holiday」変数に値を追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12937/d94b2227-9757-6208-b749-4b8c4513ab67.png)
この時値にはカンマ区切りで以下のような 2 つの値を設定しています。
```C#
items('Apply_to_each')[0]
```
```C#
items('Apply_to_each')[1]
```
カンマも含めた数式としては入力できなかったので、数式 2 つをカンマ区切りとしています。

この後のループですでに追加したデータは省いておきたいので、配列変数から追加済みのデータを削除します。しかし、設定済みの配列から 1 行だけ簡単に削除できなかったのでちょっと工夫してます。
まず「作成」フローを利用して最初の 1 行だけ削除した配列のデータを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12937/5847cd8c-8392-4c2c-d43f-a3a6c69b6822.png)
入力には以下のように設定しています。
```C#
skip(variables('addition'),1)
```
「addition」変数から`skip`関数を利用して 1 行飛ばしたデータを取得しています。
次に「変数の設定」フローで配列を書き換えています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12937/e1bed3fb-e2b2-3151-0e7a-9bc5940fab8c.png)
「配列変数に追加」フローで複数の配列データの追加はできなかったこと、直接変数に`skip`関数で書き込もうとすると、代入する変数と「値」で処理する変数が同じ場合できなかったためこのような方法を取りました。
## 配列に祝日のデータを書き込み
取得した祝日データを自身のデータを書き込みながら配列に追加していきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12937/bc92f3e1-daa2-fbb7-7746-7aac2165aad3.png)
「値」には Outlook で取得した「件名」と「today」変数をカンマ区切りで書き込みます。
これで祝日データのリストが配列で作成できました。
## SharePoint リストの祝祭日データを取得しクリアする
3 か月置きに毎回 1 年分のデータを取得するので、 SharePoint リストのデータは一度クリアしてしまい、最新のデータを書き込むようにしています。リストを取得してループ処理させて新しいデータの追記でも良いのですが、この方が処理的にも早いかなと思ってこの方法にしました。

まずは「複数の項目の取得」フローで SharePoint リストで事前に作成していた「祝祭日リスト」を読み込みます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12937/81401e9f-e580-c49e-bac8-af56776fe549.png)
この時「フィルター クエリ」に`Title ne ''`としておくと警告がでません。 ODATA クエリで何らかの処理を入れておかないとデータを絞り込めと警告されますが、今回すべてのデータを取得したいためタイトル欄が空のデータを省くとしています。

次に「Apply to each」フローを利用し取得したデータをループ処理で全削除しています。「項目の削除」フローを利用し ID を指定することですべてのデータが消えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12937/da348bb3-7343-10d3-aab2-f54a233be3f4.png)
## SharePoint リストに祝日のデータを書き込む
最後にループ処理で生成した祝日のデータ配列をリストに書き込めば完了です。
「Apply to each」フローを利用し「holiday」変数をループ処理させデータを書き込みます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12937/fa061039-6659-a0ad-8e91-82390e53aa9e.png)
「変数の設定」フローで書き込むデータを生成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12937/5c439230-f997-af88-37eb-0657b9a12d91.png)
「data」変数に以下の記述で書き込むデータを作成しています。
```C#
split(items('Apply_to_each（祝日）'),',')
```
変数内にカンマ区切りでデータが格納されているため、`split`関数で分割して「data」変数に配列として入力しなおしています。
これを「項目の作成」フローで SharePoint リストに書き込みます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12937/402cc269-cf44-aabd-776d-a2f9bf56d1a8.png)
「タイトル」は以下の記述で
```C#
variables('data')[0]
```
「日付」には以下の記述で
```C#
variables('data')[1]
```
それぞれデータを書き込みます。

これで SharePoint リスト「祝祭日リスト」に実行時から 1 年間のリストが生成できました。
## まとめ
会社独自の休日も含めた祝祭日リストをリストとして持っておきたかったため自動で生成するフローを作成しました。今回のキーは以下の通りです。
* 祝日のデータは Outlook の「日本の休日」から取得できる
* 自前のデータは配列を作成しておいてループ処理で挟み込めばリストに含められる
* アレイ変数の一部削除はちょっと面倒、ソートも面倒

ちなみに、作ったリストは他のリストから「参照」で読み込むことは簡単にできます。しかし本当は入力された日付から祝日かどうかを判定したかったのですけど、 SharePoint リストだけではちょっと無理っぽいです。 Power Apps とかとの連携になるかな？