Office 365 Usersコネクタを使ってPower AppsからExcelを操作する📊

# *Power Automate*なしで*Excel*を*Power Apps*で操りたい
*Office Scripts*やら何やら*Excel*操作自動化の手段は複数あります。
しかし*Power Apps*単体でとなると・・・。

そう思いながら[Graph Explorer](https://developer.microsoft.com/en-us/graph/graph-explorer)をポチポチしていると、下記のような`Graph API`があるではありませんか👀

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/4c1df922-104a-5b35-8f83-a5bd189120a2.png)

https://developer.microsoft.com/en-us/graph/graph-explorer

コネクタを経由した`HTTP要求`を実行すれば案外Excel操作自動化もできるのでは！ということでチャレンジしてみました。

# [Office 365 Users](https://learn.microsoft.com/ja-jp/connectors/office365users/)コネクタ
今回使用するのは[Office 365 Users](https://learn.microsoft.com/ja-jp/connectors/office365users/)コネクタです。
*Power Apps*で
1. [データ]から[データの追加]
1. [Office 365 ユーザー]を検索しクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/e32dbae4-a504-4f33-9585-732f79d7005f.png)

上記の設定をすると、[Office 365 Users](https://learn.microsoft.com/ja-jp/connectors/office365users/)コネクタのメソッドを使うことができます。

[HTTP要求](https://learn.microsoft.com/ja-jp/connectors/office365users/#http-%E8%A6%81%E6%B1%82%E3%82%92%E9%80%81%E4%BF%A1%E3%81%99%E3%82%8B)もその対象です。

```plaintext:Office365ユーザー.HttpRequest
Office365ユーザー.HttpRequest(
    "{Uri}",
    "{Method}",
    "{file - bodyの要素}"
    // その他のプロパティ
)
```

上記のような式で、[HTTP要求](https://learn.microsoft.com/ja-jp/connectors/office365users/#http-%E8%A6%81%E6%B1%82%E3%82%92%E9%80%81%E4%BF%A1%E3%81%99%E3%82%8B)が実行できます。

https://learn.microsoft.com/ja-jp/connectors/office365users/#http-%E8%A6%81%E6%B1%82%E3%82%92%E9%80%81%E4%BF%A1%E3%81%99%E3%82%8B

# まずはExcelを一覧化する
今回は下記のエンドポイントを使用して、**まずExcelファイルを取得します。**

```plaintext:URI - OneDriveのxlsxファイルを取得する
https://graph.microsoft.com/v1.0/me/drive/root/search(q='.xlsx')?select=name,id,webUrl
```

> Microsoft Graph REST API リクエストを作成し呼び出します。 次のセグメントがサポートされています: 第 1 セグメント: /me、/users/ 第 2 セグメント: messages、mailFolders、events、calendar、calendars、outlook、inferenceClassification。
>> [Office 365 Users - HTTP要求](https://learn.microsoft.com/ja-jp/connectors/office365users/#http-%E8%A6%81%E6%B1%82%E3%82%92%E9%80%81%E4%BF%A1%E3%81%99%E3%82%8B)

`/me`セグメントから、サインインしているユーザーの`OneDrive`の情報を取得します。
`.xlsx`のファイルを対象にして
 - name
 - id
 - webUrl

上記のプロパティが返されます。


::: note info
[Graph Explorer](https://developer.microsoft.com/en-us/graph/graph-explorer)で試すことができるので気になる方は検証してみてください！
:::

こちらをもとに`Set 関数`を使って`グローバル変数`に`HTTP要求`の結果を取得してみます。

```plaintext:OnSelect
Set(
    GraphXlsxFiles,
    Office365ユーザー.HttpRequest(
        "https://graph.microsoft.com/v1.0/me/drive/root/search(q='.xlsx')?select=name,id,webUrl",
        "GET",
        ""
    )
)
```

こちらを実行すると、`GraphXlsxFiles`は[UntypedObject 型](https://learn.microsoft.com/ja-jp/power-platform/power-fx/untyped-object)とチョットよくわからない単語で表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/9e716b31-41c1-8a76-245e-3028ec395f70.png)

`ビュー 変数`で見てみると、値は取得できているには取得できていそうです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/5c768a1d-4ce2-add1-ccbb-0a9a6b4912fa.png)

*型指定されていないオブジェクト*は、直接使用することはできないため、明示的に型を変換する必要があります。

https://learn.microsoft.com/ja-jp/power-platform/power-fx/untyped-object

例えば`テーブル コントロール`の`Items`に設定する場合は、
`戻り値.value`が配列なので、コチラを[ForAll 関数](https://learn.microsoft.com/ja-jp/power-platform/power-fx/reference/function-forall)で明示的に型を指定します。

```javascript:Items
ForAll(
    GraphXlsxFiles.value,
    {
        id: Text(ThisRecord.id),
        name: Text(ThisRecord.name),
        webUrl: Text(ThisRecord.webUrl)
    }
)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/09583edb-1596-0bbe-a394-e88fb16c6498.png)

これにより、`Excelファイルの一覧を取得すること`ができました。

# ブック内のワークシートを取得する
[Graph Explorer](https://developer.microsoft.com/en-us/graph/graph-explorer)に沿って、今度はExcelブックの`ワークシート`の取得を試してみます。
`https://graph.microsoft.com/v1.0/me/drive/root/search(q='.xlsx')?select=name,id,webUrl`で取得した`drive-item-id`を使用すると、ブック内のワークシートを取得できるようです。

```Graph API: ブック内のワークシートを取得
https://graph.microsoft.com/v1.0/me/drive/items/{drive-item-id}/workbook/worksheets
```

下記のサンプルを使ってみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/ffdbfb76-7cca-e34c-9ace-80a9df367d93.png)

`ID`は`01FGLN35TPWLZOHFXXOBB3KTBB73KAARUY`です。こちらが`drive-item-id`に該当します。

```javascript:OnSelect
Set(
    GraphResponse,
    Office365ユーザー.HttpRequest(
        "https://graph.microsoft.com/v1.0/me/drive/items/01FGLN35TPWLZOHFXXOBB3KTBB73KAARUY/workbook/worksheets",
        "GET",
        ""
    )
)
```

下記が返ってきました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/dd8c3d1c-8553-206e-9b1f-59e012b78ebf.png)


`value`を分解すると下記が取得できます。

|キー|データ型|内容|
|---|---|---|
|name|文字列|シート名|
|position|整数|ブック内のシート番号|
|visibility|文字列|可視性|

上記が取得できました。

# ワークシートの使用範囲を取得する
上記と同様にワークシートの使用範囲も取得できます。
非常に雑なダミーデータですが、`シート名`を引数に、値を取得することができます。

```javascript:Items
ForAll(
    GraphRange.text,
    {
        employeeId: Text(First(ThisRecord)),
        name: Text(
            Last(
                FirstN(
                    ThisRecord,
                    2
                )
            )
        ),
        department: Text(
            Last(
                FirstN(
                    ThisRecord,
                    3
                )
            )
        ),
        position: Text(
            Last(
                FirstN(
                    ThisRecord,
                    4
                )
            )
        ),
        hireDate: Text(
            Last(
                FirstN(
                    ThisRecord,
                    5
                )
            )
        ),
        salary: Text(
            Last(
                FirstN(
                    ThisRecord,
                    6
                )
            )
        ),
        email: Text(
            Last(
                FirstN(
                    ThisRecord,
                    7
                )
            )
        ),
        phone: Text(
            Last(
                FirstN(
                    ThisRecord,
                    8
                )
            )
        )
    }
)
```

`GraphRange.text`が二次元配列のため値の取得が手間ですね💦

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/84a01224-a442-08fc-6709-45b409542fd4.png)

特に`テーブル`にしていなくてもデータ参照ができるので、ちょっと利用できるシーンはあるかな🧐

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/6ee61b18-1cb5-fd63-6f38-a4b154d092fb.png)


# グラフ チャートを取得する
比較的目玉になる機能は`グラフ チャート`だと思います。

[Graph Explorer](https://developer.microsoft.com/en-us/graph/graph-explorer)に下記のエンドポイントが紹介されていますが、こちらで取得できるのは、グラフの高さや幅、名前などです。

本命はグラフ チャートを取得することな気もするので、下記のエンドポイントを使って、[グラフの画像を取得](https://learn.microsoft.com/ja-jp/graph/api/chart-image?view=graph-rest-1.0&tabs=http)してみます。
シート名`chart`のグラフ`myCharts`の画像を取得してみます。

```javascript:OnSelect
Set(
    GraphCharts,
    Office365ユーザー.HttpRequest(
        "https://graph.microsoft.com/v1.0/me/drive/items/01FGLN35TPWLZOHFXXOBB3KTBB73KAARUY/workbook/worksheets('chart')/charts/myCharts/image",
        "GET",
        ""
    )
)
```

実行すると`base64文字列`で値が返って来ます。
画像コントロールの`Image`プロパティに、データ型の指定も含めて

```plaintext:Image
$"data:image/png;base64,{Text(GraphCharts.value)}"
```

と指定するとグラフが表示されました📊

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/dcbd0173-a335-1b19-3e4b-5dd496d94577.png)

https://learn.microsoft.com/ja-jp/graph/api/resources/excel?view=graph-rest-1.0

# 値のコントロールは！？
さて、ここまで実行してきたことは、ほとんど`GET`です。
値の更新やワークシートの追加は
- POST
- PATCH

上記の領域になります。
こちらの手間なところは引数が`file`型なのです・・・。

ファイルコントロールに`json`をアップしたりなど、Power Apps単体でやることが無駄では🧐と思い割愛しました。

やってみようと思ったらもう既にやられているのですよね。さすがです。

https://mofumofupower.hatenablog.com/entry/2023/03/31/174813