Power Automate for desktop 「 null ハンドリングのこと」

## 概要

今回は Power Automate for desktop における null ハンドリングの話です。
直近のアップデートではPicture-in-PictureやPower Fxの話題が多く取り上げられています。しかし個人的に一番嬉しいのは JSON 形式のデータをカスタムオブジェクト型に変換するとき null ハンドリングのための処理が必要なくなったことです。やらなくてよくなったことをわざわざ書くなよと思いますが、思い入れが深いので書きました。

## 環境

- Windows 11 Pro 23H2
- Power Automate for desktop 2.41.170.24032 インストーラー版
- 2024年2月末の情報です

## Before

null ハンドリングされているのに気付いたのはこのバージョンでのことですが、1月末のアップデートで null のことが載っているのでそこで変わったのだと思います。

https://powerautomate.microsoft.com/ja-jp/blog/january-2024-update-of-power-automate-for-desktop/

これまでは JSON の文字列内で null を検索して空白文字 `""` に置換していました。これを行わないでnull値を参照するとエラーになっていました。かれこれ2年以上前の記事に対策などまとめてあります。APIを叩くときはほぼ必須でしたが、これでほぼ出番はなくなりそうです。

https://qiita.com/sys_zero/items/b866b4d76ec2d34d1d10

## After

このようなJSONがあったとします。

```json
{
    "test":{
        "name":"hoge",
        "age":3,
        "blog_url":null,
        "list_sample":[
            "zero",
            "one",
            "two",
            "three"
        ]
    }
}
```
これを「JSON をカスタムオブジェクトに変換する」アクションで変換します。

null は<空白>という表示になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/29b3c8c9-de35-3588-a909-fe5c756c1662.png)

これまで空白文字に置換せず参照するとエラーになっていましたが、

このように問題なく参照できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/96d3d9f6-acab-09a8-4c43-f5bef93c01ed.png)


## 空白文字に置換した場合との違い

ついでに空白文字と空白の値<空白>にどのような違いがあるのか調べました。

サンプルの JSON を「テキストを置換する」アクションで空白文字にした場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/787d69d1-0496-3579-b0d5-2672f5327788.png)
blog_url に<空白>の文字はありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/2a34e204-b013-4120-2187-66d380495414.png)
参照した場合は空のテキスト値になっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/26e14666-0c90-91ba-fec6-5d8aff716f6f.png)

### Byte数を見てみる

一時ファイルを作成し空白文字と空白の値<空白>をそれぞれUTF-8BOMなしで書き込みました。それをバイナリ データーに変換してByte数をみましたが両方とも0Byteとなっていて違いはありませんでした。特に面白くないので割愛します。興味がある方はサンプルを動かしてみてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/2e53c5b7-f06d-02f5-c4e7-f3e1c3437505.png)

### その他気づいたこと

- 空白の値<空白>はデバッグ中に一時停止したとき、手動で値を書き換えることができません
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/00c0d707-0c42-7855-608d-a66dcdf2c57a.png)
- 空白文字へ置換した場合はテキスト値の空なので手動で一時的に書き換えが可能です
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/99d272a1-cddf-003d-db32-af502f3683b9.png)


## まとめ

- テキストの空白文字とは異なり、新たに「空白の値<空白>」としてnullハンドリングされるようになりました
- これに伴い参照時エラーがなくなったので空白文字に置換する必要がなくなりました

長きにわたりPower Automate for desktop から API を叩くとき、null ハンドリングに苦しめられてきたのでとても個人的には嬉しいアップデートでした。

## 検証サンプル

```
SET SampleJson TO $'''{
    \"test\":{
        \"name\":\"hoge\",
        \"age\":3,
        \"blog_url\":null,
        \"list_sample\":[
            \"zero\",
            \"one\",
            \"two\",
            \"three\"
        ]
    }
}'''
Text.Replace Text: SampleJson TextToFind: $'''(?<=:\\s*)null(?=\\s*|,|})''' IsRegEx: True IgnoreCase: True ReplaceWith: $'''\"\"''' ActivateEscapeSequences: False Result=> Replaced
Variables.ConvertJsonToCustomObject Json: Replaced CustomObject=> JsonAsCustomObject1
Variables.ConvertJsonToCustomObject Json: SampleJson CustomObject=> JsonAsCustomObject2
SET NewVar1 TO JsonAsCustomObject1.test.blog_url
SET NewVar2 TO JsonAsCustomObject2.test.blog_url
File.GetTempPath TempFile=> TempFile1
File.GetTempPath TempFile=> TempFile2
File.WriteText File: TempFile1 TextToWrite: JsonAsCustomObject1.test.blog_url AppendNewLine: False IfFileExists: File.IfFileExists.Overwrite Encoding: File.FileEncoding.UTF8NoBOM
File.WriteText File: TempFile2 TextToWrite: JsonAsCustomObject2.test.blog_url AppendNewLine: False IfFileExists: File.IfFileExists.Overwrite Encoding: File.FileEncoding.UTF8NoBOM
File.ConvertToBinary File: TempFile1 BinaryData=> BinaryData1
File.ConvertToBinary File: TempFile2 BinaryData=> BinaryData2
@@copilotGeneratedAction: 'False'
Scripting.RunPowershellScript.RunPowershellScript Script: $'''$src = [System.IO.File]::ReadAllBytes(\"%TempFile1%\")
Write-Output $src |Format-Hex''' ScriptOutput=> PowershellOutput1
@@copilotGeneratedAction: 'False'
Scripting.RunPowershellScript.RunPowershellScript Script: $'''$src = [System.IO.File]::ReadAllBytes(\"%TempFile2%\")
Write-Output $src |Format-Hex''' ScriptOutput=> PowershellOutput2
```