PowerAutomateでC#のカスタムコードを使って文字列のハッシュを計算する

# はじめに

PowerAutomate には多くのアクションがあらかじめ用意されていますが、プログラミングをしていると当たり前にあってほしいアクションが用意されていなかったりします。

文字列を MD5 でハッシュするといったアクションも PowerAutomate には最初から用意されていないアクションの一つです。この記事では、少し前に実装された PowerAutomate で C#のコードをそのままカスタムコネクターにする機能を使って、PowerAutomate にハッシュ計算用のカスタムコネクターを作成していきます。

# カスタムコードの概要

PowerAutomate のカスタムコードを利用すると、自前で実行環境を用意することなく、あらかじめカスタムコネクタとして登録した C# のカスタムコードを PowerAutomate や PowerApps から簡単に呼び出すことができます。

https://docs.microsoft.com/en-us/connectors/custom-connectors/write-code

https://rambosan.hatenablog.com/entry/2021/08/17/235149

# カスタムコードの制限

スクリプトの内容や実行に関しては次のような制限があります。

- スクリプトは [ScriptBase](https://docs.microsoft.com/en-us/connectors/custom-connectors/write-code#definition-of-supporting-classes-and-interfaces) クラスを継承した Script クラス内に全て記載する必要がある
- [インポート済みの名前空間](https://docs.microsoft.com/en-us/connectors/custom-connectors/write-code#supported-namespaces)のみ利用可能（外部ライブラリの参照は行えない）
- スクリプトの実行は 5 秒以内に完了する
- スクリプトのサイズは 1MB までにする
- 外部に通信する場合は、コンテキスト内の SendAsync メソッドを利用する

# カスタムコネクタの作成

では、早速作っていきましょう。

まずは、`+ カスタムコネクタの新規作成` ボタンをクリックし、`一から作成`をクリックしてコネクタの作成を開始します。コネクタ名は ComputeHash としました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36535/056b03f0-2b01-efa7-9465-251c243dc878.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36535/0f5fb771-859f-52dd-1009-2c08ee6660f8.png)
`1.全般`では、最低限ホスト名を入力する必要があります。今回はカスタムコードを利用するのでなんでも良いのですが、適当なホスト名がない場合はマイクロソフトのテストでよく使われる `contoso.com` のホスト名を入れておくと良いでしょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36535/6ca309c8-de89-99c2-0e4f-0f8225fca75e.png)
今回は認証などの仕組みは導入しないので、`2.セキュリティ`はそのままにして `3.定義`に進みます。
`＋新しいアクション`をクリックしてコネクタに含まれるアクションを追加していきます。
概要と `操作 ID` に `MD5` という名前を設定し、`+ サンプルからのインポート`をクリックしてアクションの引数を定義します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36535/60a5b490-10fc-f8b4-eeae-b1871c5c067a.png)
`value` で指定された文字列の MD5 ハッシュを計算したいので、URL としては下記のようなリクエストを想定しています。

```
GET Md5?value=hoge
```

`サンプルからのインポート`画面で次のように設定してインポートボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36535/9825fbf4-a0f7-e92c-0fa8-aa555a249266.png)
このようなパラメーターが作成されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36535/36d368c7-14c5-aeec-95ed-09b11a036011.png)

PowerAutomate で扱いやすいように返却の型定義もしておきます。今回は下記のようなレスポンスを返却する予定なので

```json
{
  "origin": "test",
  "hashedString": "CY9rzUYh03PK3k6DJie09g=="
}
```

`応答`の`＋既定の応答を追加する`からサンプルをもとにインポートします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36535/b8c3553f-5dd0-73d3-4a13-0bbddc9680f9.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36535/8d38d06a-57d3-9ecd-8b13-a49a83481d45.png)

とりあえずここまで出来たら`コネクタの作成`ボタンから作成しておきましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36535/e7430e1c-8809-4241-e9de-e4f0e6a4301b.png)

# カスタムコードの記述

カスタムコネクタの側ができたら、`コード（プレビュー）`に移動してカスタムコードを登録します。まずは`コードが無効`をクリックして`コードが有効`にします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36535/0a9e088d-6eaa-f152-2a0d-9227c7a700cc.png)
操作のドロップダウンでカスタムコードを適用するアクションを選択します。今回は前のページで定義した MD5 というアクションをカスタムコードに流すので MD5 のチェックを ON にします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36535/af7c1977-69f0-66b8-6c3d-3e4fe31fe6db.png)

コードエディターが有効になるので、おもむろに下記のコードをペーストします。
カスタムコードでは一つのクラスしか登録できないため、`1.全般` タブで割り振った `操作 ID`(OperationId) を元に処理を分岐して複数のアクションに対応しています。
今回ハッシュ計算に利用している `System.Security.Cryptography.MD5` やクエリ文字列をパースしている `System.Web.HttpUtility` などは[インポート済みの名前空間](https://docs.microsoft.com/en-us/connectors/custom-connectors/write-code#supported-namespaces)に含まれるので利用可能ですが、使いたいクラスが利用できない場合もあるので注意してください。

```cs:Script.cs
public class Script: ScriptBase
{
    public override async Task<HttpResponseMessage> ExecuteAsync()
    {
        await Task.CompletedTask;
        return Context.OperationId switch
        {
            "MD5" => ComputeMd5(),
            _ => new HttpResponseMessage(HttpStatusCode.BadRequest)
        };
    }

    private HttpResponseMessage ComputeMd5()
    {
        var query = HttpUtility.ParseQueryString(Context.Request.RequestUri?.Query ?? string.Empty);
        var origin = query.AllKeys.Any(_ => _ == "value") 
            ? query["value"] : string.Empty;

        var hashedString = MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(origin));
        var response = new HttpResponseMessage(HttpStatusCode.OK);
        response.Content = CreateJsonContent((new JObject
        {
            ["origin"] = origin,
            ["hashedString"] = hashedString,
        }).ToString());
        return response;
    }
}
```

貼り付けたら、`✓ コネクタの更新`をクリックしてコネクタを保存します。
関数のデプロイが始まり、問題が無ければコネクタが更新されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36535/e1df5b29-8a08-c9d7-5f69-a4fffc5241ac.png)
カスタムコード上に文法上の誤りや、デプロイなどに問題がある場合は画面上部にエラーメッセージが表示されるので、メッセージを確認して対応します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36535/eb5be387-ad6b-3de2-b2b2-17db38834afd.png)
`5.テスト`で動作確認をしたらコネクタの作成は完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36535/9c6da188-ac33-2cc1-8af7-890ee1134370.png)

# 作成したカスタムコネクタの利用

作成したカスタムコネクタはカスタムタブに表示されます。他のアクション同様利用することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36535/7c7f36a0-80f8-3254-dac5-0648bc6d57c7.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36535/4365c9d6-1ee8-e05f-5b81-c690b8294bf0.png)

# おわりに

カスタムコネクタ自体の開発体験には少し難がありますが、いくつかの制限はありますがこれまでのようにクラウド上のリソースを気にすることなく独自のコードをサクッとホストして PowerAutomate から利用できるのはとても楽で良いですね。

# 参考にしたページ

https://qiita.com/Rambosan/items/7cda28bac81da794b935

https://rambosan.hatenablog.com/entry/2021/08/17/235149