Power AutomateでSharePointのファイル・フォルダの存在を調べる

# はじめに
`Power Automate`を使う中で`SharePoint`の操作自動化は、つねづね焦点に当たります。
なかでも`ファイルの作成'、業務の中で活躍するシーンが多い印象です。

しかしながら`ファイルの作成`は、既にあるファイルを上書きしてしまいます。

:::note info

`新しいフォルダーの作成`は、存在するフォルダを指定してもエラーになりません
2024.03.31検証

2024.03.30 - 2024.03.31の期間に掲載した情報に誤りがあったこと、お詫び申し上げます。

:::

また`ファイルの作成`に限らず、`ファイル`・`フォルダ`の存在チェックはフローの中で必要とするシーンが発生します。

# 手っ取り早いファイル・フォルダの存在チェック方法（Power Automateで）
今回、その方法を編み出そうとしたことが記事のきっかけです。
将来的に`ファイルの存在確認`のアクションも登場しそうですが、現時点での対策の検討として記事に残します。

:::note info
記事の記載時期は2024年3月30日です
:::

# 対策方法の検討
Power Automateのアクションで対策する方法は、下記の二点で考えられます。
1. `ファイルの取得 (プロパティのみ)`を`フィルター クエリ`を用いて活用する
1. `SharePoint REST サービス`で何とかする

:::note warn
`Apply to each`、`For each`、`それぞれに適用する`は検討対象から外します。
:::

`SharePoint REST サービス`は個人的に難易度が高い印象ですが、選択肢に含めて検証をしてみました。

# 検証結果
 - `SharePoint REST サービス`による`フォルダー`・`ファイル`の抽出
 - 既定のアクションによる`フォルダー`・`ファイル`の抽出

上記のアプローチを検証してみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/ff2f8f56-4f8f-fb15-21d6-4255db441f11.png)


## 結論
1. （ファイルの場合）`ファイルの取得 (プロパティのみ)`の`フィルター クエリ`でカバーできそう
1. `GetFolderByServerRelativeUrl` + `/ListItemAllFields` が万能

https://learn.microsoft.com/ja-jp/sharepoint/dev/sp-add-ins/working-with-folders-and-files-with-rest

## 1. （ファイルの場合）`ファイルの取得 (プロパティのみ)`の`フィルター クエリ`でカバーできそう
`ファイルの取得 (プロパティのみ)`では、`フィルター クエリ`が活用できます。
ファイル名（拡張子付き）でファイルを特定するには、このような形。

:::note info
[Microsoft 吉野さんの記事](https://qiita.com/Satoshi_Yoshino/items/3e00ac6fc972fae243ed)を参考にさせていただきました🙇🙇
:::

https://qiita.com/Satoshi_Yoshino/items/3e00ac6fc972fae243ed

対象にしたフォルダの階層を度外視して、複数ファイルを抽出することができます。
`FileLeafRef eq 'ファイル名.拡張子'`で特定できることは **非常に楽**。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/4a745ef2-ab49-4a23-5bfd-2fb5965f61bd.png)


[length関数](https://learn.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#length)で判定条件を設定できるため、扱いやすい印象です。

```plaintext:example
length(outputs('ファイルの取得_(プロパティのみ)')?['body/value'])
```

https://learn.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#length


### ■ フォルダーの場合

[`フォルダーの一覧`アクション](https://learn.microsoft.com/ja-jp/sharepoint/dev/business-apps/power-automate/sharepoint-connector-actions-triggers#list-folder)が挙げられます。
しかし`ファイルの取得 (プロパティのみ)`と異なり、`フィルター`のオプションが既定で存在しません。

https://learn.microsoft.com/ja-jp/sharepoint/dev/business-apps/power-automate/sharepoint-connector-actions-triggers#list-folder

:::note warn
`2024.03.30現在`
:::

`アレイのフィルター処理`を使い、抽出する方法が検討できますが、処理速度に課題が発生するかもしれません。
一度に大きなデータをアクションで取得することは遅延の原因につながります。

:::note warn
（大きなデータになるような）運用をするな！と言いたいところですが・・・、むずかしい現場もあるでしょう
:::

**ファイルの場合は `ファイルの取得 (プロパティのみ)`が活用できそうですが、フォルダの場合に課題があります**

## 2. `SharePoint REST サービス GetFolderByServerRelativeUrl(Value)/ListItemAllFields` 

:::note info
[GetFolderByServerRelativeUrl](https://learn.microsoft.com/ja-jp/dotnet/api/microsoft.sharepoint.client.web.getfolderbyserverrelativeurl?view=sharepoint-csom) は、SharePointサイト内の**相対パス**でフォルダを取得します
:::

https://learn.microsoft.com/ja-jp/dotnet/api/microsoft.sharepoint.client.web.getfolderbyserverrelativeurl?view=sharepoint-csom


検証を進める中で、ファイル・フォルダ問わず [SharePoint REST サービス `GetFolderByServerRelativeUrl(Value)/ListItemAllFields`が万能](https://learn.microsoft.com/ja-jp/sharepoint/dev/sp-add-ins/working-with-folders-and-files-with-rest) という印象を受けました。

https://learn.microsoft.com/ja-jp/sharepoint/dev/sp-add-ins/working-with-folders-and-files-with-rest

前提として`GetFolderByServerRelativeUrl`には、存在する`ドキュメントライブラリ`が設定されていることが必要です。

### アクションの詳細
`SharePoint に HTTP 要求を送信` アクションを下記の通り実施します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/44beb557-d9fe-1d59-d824-ec7864543e14.png)

|項目|値|
|---|---|
|サイトのアドレス|SharePointサイトの名前|
|方法|GET|
|URL|_api/web/GetFolderByServerRelativeUrl('ファイルかフォルダの相対パス')/ListItemAllFields|

- ヘッダー

|項目|値|
|---|---|
|Accept|application/json;odata=verbose|
|Content-Type|application/json|

```json
{
  "Accept " : "application/json;odata=verbose",
  "Content-Type" : "application/json"
}
```

:::note info
`ファイルかフォルダの相対パス`は、エンコードの有無問わず実行することができます
:::


`GetFolderByServerRelativeUrl`の引数が`ファイル`であれ`フォルダ`であれ、`ドキュメントライブラリ`が存在している場合、結果を得られます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/b0dca88e-c782-9fbf-5aaf-ed9f9a34cb16.png)

```plaintext:存在しないファイル
{
  "d": {
    "ListItemAllFields": null
  }
}
```

一貫した戻り値が返ってくるので、**判定がシンプルです。**

```plaintext:GUIDで存在を確認する
empty(body('アクションの名前')?['d']?['GUID'])
```

存在していれば`false`、そうでなければ`true`を返します。
`相対パス`がフォルダーの場合でも同様の結果が得られます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/77afd258-8107-4b48-c1d9-c14795eeb8c6.png)

`ドキュメントライブラリ`内の`ID`も取得でき、汎用的に扱える印象を受けます。

# 今後の対策
私の対策としては、`ファイル`、`フォルダー`問わず、`GetFolderByServerRelativeUrl('ファイルかフォルダの相対パス')/ListItemAllFields`で判定を一本化させたいなと感じました。

`SharePoint REST サービス`は難解に見えますが
- レスポンスの速さ
- 万能さ

といった利点が大きい。
APIをひらすら検証してみる中で思わぬ収穫がありましたが、もっと良いやり方も模索していきたいものです🧐