Powershellで編集可能なJSONを読み込む関数を作りました!&Pester環境を更新
以下のようなことをしたい状況がありました。
しかし、PowerShell標準のコマンド ConvertFrom-Json で取得したオブジェクトは配列を除き編集できません。それを編集できるようにして取得するスクリプトを書きました。
前提環境
テスト環境の Pester は更新しました。
$PSVersionTable Name Value ---- ----- PSVersion 5.1.19041.1320 PSEdition Desktop PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...} BuildVersion 10.0.19041.1320 CLRVersion 4.0.30319.42000 WSManStackVersion 3.0 PSRemotingProtocolVersion 2.3 SerializationVersion 1.1.0.1 Get-Module Pester ModuleType Version Name ExportedCommands ---------- ------- ---- ---------------- Script 5.3.1 Pester Add-ShouldOperator, AfterAll, AfterEach, Assert-MockCalled...}
標準搭載の ConvertFrom-Json について
どういう挙動か
標準搭載のConvertFrom-Jsonで取得した時、JSONのObject型の要素は PSCustomObject となり、新しい値を設定することはできません。
色々ググりましたが、PSCustomObject を編集するには色々方法が面倒なようです。
PSCustomObjectに対してしたいこと | 方法 |
---|---|
新しい要素の追加 | Add-Member |
要素の削除 | Select-Object で -ExcludeProperty して新しいオブジェクト生成 |
理想の挙動
以下のように動いたらいいですよね。
<# 前提環境を作るコード(ファイルがあるものだと思ってください。) #> $samplejson = @" { "id":1, "name":"Dareka San", "otherInfo":{ "birthday":"2000-12-05" } } "@ Set-Content -Value $samplejson -Path 'sample.json' <# こんな感じでできたらいいなぁ、のコード #> # ①ファイル読み込み $json = Get-Content 'Sample.json' -Encoding UTF8 | ConvertFrom-Json # ②新しい要素追加 $json.otherInfo.bloodType = "RH +O" # ③保存 $json | ConvertTo-Json | Set-Content 'sample.json' -Encoding UTF8 <# 結果こうなっててほしいなぁのJSON { "id":1, "name":"Dareka San", "otherInfo":{ "birthday":"2000-12-05", "bloodType":"RH +O" } } #>
実現したこと
編集できるJSONを返す ConvertFrom-Json 、 ConvertFrom-JsonEditable を作りました。
これを使うと以下のように理想の挙動を実現できます。
$json = Get-Content 'Sample.json' -Encoding UTF8 | ConvertFrom-JsonEditable $json.otherInfo.bloodType = "RH +O" $json | ConvertTo-Json | Set-Content 'sample.json'
どのように実現しているか
ざっくりとした流れ
- 標準のConvertFrom-Jsonで文字列からオブジェクトに変換する
- オブジェクトの中で変換対象のものを変換していく(再帰的な処理)
- PSCustomObject -> OrderedDictonary([Ordered]で変換するもの) に変換し、 深さを取得する関数の追加
- Array -> List
- プリミティブ型の変数は変換なし
- 返却する
となります。
ここで新出の 深さを取得する関数 とは ConvertTo-Json の -Depthパラメーター用の関数です。 変換処理と同様、再帰的な処理を行い、JSONの階層の深さを取得します。
ひっかかったこと
ソースコードを一部引用してひっかかったことをメモります。
Unboxing/Unpacking(?)の罠
勝手に値を変換されてしまうアレで色々とひっかかり、開発ハマってました。
ハマったこと
- 要素1の配列を戻り値に渡したら配列の要素の型のオブジェクトが渡されてきた
- 関数で受け渡した配列オブジェクトが再生成されていた
- 配列オブジェクトには 深さを取得する関数 を追加しているので、それが消えた
要素1の配列を戻り値に渡したら配列の要素の型のオブジェクトが渡されてきた
下記のようなコードを実行すると挙動が分かります。
function ReturnSingle { return @(1) } function ReturnDouble { return @(1,2) } $single = ReturnSingle Write-Host "Single:$($single.GetType())" $double = ReturnDouble Write-Host "Double:$($double.GetType())"
結果はこうなります。
Single:int Double:System.Object[]
関数で受け渡した配列オブジェクトが再生成されていた
以下のコードを実行すると・・・
function GetSayHelloList { $list = [System.Collections.Generic.List[Object]]@() Add-Member -InputObject $list -Name SayHello -MemberType ScriptMethod -Value { $this | ForEach-Object { Write-Host "Hello, $_!" } } return $list } $list = GetSayHelloList $list.Add("Baki") $list.Add("Suedou") $list.Add("Katou") $list.SayHello()
結果は以下のようにエラーです。
null 値の式ではメソッドを呼び出せません。 + $list.Add("Baki") + ~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) []、RuntimeException + FullyQualifiedErrorId : InvokeMethodOnNull null 値の式ではメソッドを呼び出せません。 + $list.Add("Suedou") + ~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) []、RuntimeException + FullyQualifiedErrorId : InvokeMethodOnNull null 値の式ではメソッドを呼び出せません。 + $list.Add("Katou") + ~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) []、RuntimeException + FullyQualifiedErrorId : InvokeMethodOnNull null 値の式ではメソッドを呼び出せません。 + $list.SayHello() + ~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) []、RuntimeException + FullyQualifiedErrorId : InvokeMethodOnNull
対応のコツはカンマの1文字
どう変えれば直るか、分かりやすくWinMergeのスクショで説明すると変更点は以下のようになります。
これはどのように動いているかというと
- カンマをつける(要素1の配列になる)
- return で要素1の配列が展開されて中身だけになる
- 中身にあったオブジェクトが展開されず無傷の状態で返却される。
という感じです。
対策として配列をいちいち作っているのが解せませんが、これで想定の動作をします。
ソースコード
ソースコードは今回もGitHubに公開してみましたが、こちらにもコピペしておきます!
using namespace System.Management.Automation using namespace System.Collections using namespace System.Collections.Generic function ConvertValuesInObjectToHashtable { <# .SYNOPSIS オブジェクトの要素もしくはプロパティの値をハッシュテーブルに変換する。 .DESCRIPTION 引数の型によって動作を変える。 - PSCustomObject型のオブジェクト - 各プロパティ名をKey、値をValueとしてハッシュテーブルにする。 - Array型のオブジェクト - 各要素のインデックスをKey、値をValueとしてハッシュテーブルにする。 - それ以外は空ハッシュテーブルとする。 .PARAMETER InputObject Object型のオブジェクト .OUTPUTS Hashtable. #> [CmdletBinding()] param ( [Parameter(Mandatory)] [object] $InputObject ) $hash = [ordered]@{} if ($InputObject -is [IDictionary] ) { $InputObject.Keys | ForEach-Object { $hash.Add($_,$InputObject[$_])} }elseif ($InputObject -is [IEnumerable] -and $InputObject -isnot [string]) { for ($i = 0; $i -lt $InputObject.Count; $i++) { $hash.Add($i, $InputObject[$i]) } } elseif ($InputObject -is [PSCustomObject]) { $InputObject.PSObject.Properties | ForEach-Object { $hash.Add($_.Name, $_.Value) } } return $hash } function AddGetDepthMethod { param ( [Parameter(Mandatory)] [object] $InputObject ) if ($InputObject -is [ValueType] -or $InputObject -is [string]) { throw "対象外のオブジェクトです。" } # オブジェクトに深さ取得のオブジェクトを追加する。 Add-Member -InputObject $InputObject -MemberType ScriptMethod -Name GetDepth -Value { param() CalcDepth -InputObject $this } } function ConvertJsonObjectToEditableJson { <# .SYNOPSIS オブジェクトをハッシュテーブルもしくは配列に変換する。 .DESCRIPTION .PARAMETER InputObject Object型のオブジェクト .OUTPUTS object[]. #> param ( [parameter(Mandatory)] [Object]$InputObject ) if ($InputObject -is [ValueType] -or $InputObject -is [string]) { throw "対応していない引数の型です。" } $dict = ConvertValuesInObjectToHashtable -InputObject $InputObject $table = [ordered]@{} foreach ($kvp in $dict.GetEnumerator()) { $addValue = $kvp.Value if ($kvp.Value -is [PSCustomObject] -or $kvp.Value -is [Array]) { $addValue = ConvertJsonObjectToEditableJson -InputObject $kvp.Value } $table.Add($kvp.Key, $addValue) } # 入力が配列の場合、ハッシュテーブルを配列に変更する。 if ($InputObject -is [Array]) { $table = [List[Object]]@( $table.Keys | Sort-Object | ForEach-Object { ,$table[$_] }) } AddGetDepthMethod -InputObject $table # 配列の場合を考慮し、アンボクシングを防ぐ return , $table } function CalcDepth { <# .SYNOPSIS 入れ子の深さを算出する。 .DESCRIPTION 引数のオブジェクトが持つ要素(プロパティ/以下の条件を入れ子と判断し、再帰的に本関数を実行する。 - InputObjectがPSCustomObject型 - InputObjectがIDictionary型 - InputObjectが文字列以外のIEnumerable型 .PARAMETER InputObject Object型のオブジェクト .OUTPUTS int型の入れ子の深さ. #> param ( [Parameter(Mandatory)] [Object] $InputObject ) if ($null -eq $InputObject) { throw "引数が不正です。" } [int]$maxDepth = 0 [int]$tempDepth = 0 [Hashtable]$hashtable = ConvertValuesInObjectToHashtable -InputObject $InputObject foreach ($value in $hashtable.Values) { if ($value -is [PSCustomObject] -or $Value -is [IDictionary] -or $Value -is [IEnumerable] -and $Value -isnot [string]) { $tempDepth = CalcDepth -InputObject $value } $maxDepth = [System.Math]::Max($maxDepth, $tempDepth) } return (1 + $maxDepth) } function ConvertFrom-JsonEditable { <# .SYNOPSIS JSON文字列から編集できるJSON型オブジェクトを生成する。 .DESCRIPTION ConvertFrom-Jsonコマンド利用するため、それがエラーを起こす入力は同様にエラーを発生させる。 .PARAMETER Value 文字列のJSON .OUTPUTS [OrderedDictionary] | [Array] #> param ( [Parameter(Mandatory, ValueFromPipeline = $true)] [Array] $Value ) # パイプライン用 Begin { $jsonText = "" } Process { $jsonText += $Value } End { if (-not $jsonText) { throw "JSON文字列がnullもしくは空文字です。" } try { $json = ConvertFrom-Json -InputObject $jsonText $object = ConvertJsonObjectToEditableJson -InputObject $json return ,$object } catch { if (-not $json) { Throw "ConvertFrom-Jsonエラー:JSONの形式を確認してください。" } Throw $_ } } }
テストコード
Pester がプリインストールのバージョンだったので、アップデートしました。 Version5を前提としています。
using namespace System.Management.Automation using namespace System.Collections.Specialized BeforeAll { . $PSCommandPath.Replace('.Tests.ps1', '.ps1') } Describe "ConvertValuesInObjectToHashtable" { Context "異常ケース" { It "NULL" { { ConvertValuesInObjectToHashtable -InputObject $null } | Should -Throw } It "空配列" { $actual = ConvertValuesInObjectToHashtable -InputObject (@()) $actual | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $actual.Count | Should -BeExactly 0 } } Context "正常ケース PSCustomObject" { It "Depth:1 Count:1" { $expect = [PSCustomObject]@{a = 1 } $actual = ConvertValuesInObjectToHashtable -InputObject $expect $actual | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $actual | Should -HaveCount 1 $actual.a | Should -BeExactly $expect.a } It "Depth:1 Count:2 Array" { $expect = [PSCustomObject]@{a = "1"; b = @(2, 3) } $actual = ConvertValuesInObjectToHashtable -InputObject $expect $actual | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $actual.count | Should -BeExactly 2 $actual.a | Should -BeExactly $expect.a $actual.b | Should -BeExactly $expect.b } It "Depth:2 Count:2 Hashtable" { $expect = [PSCustomObject]@{a = "1"; b = @{c = 2 } } $actual = ConvertValuesInObjectToHashtable -InputObject $expect $actual | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $actual.count | Should -BeExactly 2 $actual.a | Should -BeExactly $expect.a $actual.b | Should -BeExactly $expect.b } } Context "正常ケース Hashtable" { It "Depth:1 Count:1" { $expect = @{a = 1 } $actual = ConvertValuesInObjectToHashtable -InputObject $expect $actual | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $actual | Should -HaveCount 1 $actual.a | Should -BeExactly $expect.a } It "Depth:1 Count:2 Array" { $expect = @{a = "1"; b = @(2, 3) } $actual = ConvertValuesInObjectToHashtable -InputObject $expect $actual | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $actual.count | Should -BeExactly 2 $actual.a | Should -BeExactly $expect.a $actual.b | Should -BeExactly $expect.b } It "Depth:2 Count:2 Hashtable" { $expect = @{a = "1"; b = @{c = 2 } } $actual = ConvertValuesInObjectToHashtable -InputObject $expect $actual | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $actual.count | Should -BeExactly 2 $actual.a | Should -BeExactly $expect.a $actual.b | Should -BeExactly $expect.b $actual.b | Should -BeOfType [Hashtable] } } Context "正常ケース Array" { It "Depth:1 Count:1" { $expect = @(1) $actual = ConvertValuesInObjectToHashtable -InputObject $expect $actual | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $actual | Should -HaveCount 1 $actual.a | Should -BeExactly $expect.a } It "Depth:1 Count:2 Array" { $expect = @(1, @(2)) $actual = ConvertValuesInObjectToHashtable -InputObject $expect $actual | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $actual.count | Should -BeExactly $expect.count $actual[0] | Should -BeExactly $expect[0] $actual[1] | Should -BeExactly $expect[1] } It "Depth:2 Count:2 Hashtable" { $expect = @(1, @{a = 2 }) $actual = ConvertValuesInObjectToHashtable -InputObject $expect $actual | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $actual.count | Should -BeExactly $expect.count $actual[0] | Should -BeExactly $expect[0] $actual[1] | Should -BeExactly $expect[1] } } } Describe "AddGetDepthMethod" { Context "異常ケース" { It "Null" { { AddGetDepthMethod -InputObject $null } | Should -Throw } It "ValueType" { { AddGetDepthMethod -InputObject 1 } | Should -Throw { AddGetDepthMethod -InputObject "1" } | Should -Throw } } Context "正常ケース" { It "Array" { $array = @() AddGetDepthMethod -InputObject $array $array.GetDepth | Should -Not -Be $null } It "Hashtable" { $array = @{} AddGetDepthMethod -InputObject $array $array.GetDepth | Should -Not -Be $null } } } Describe "ConvertJsonObjectToEditableJson" { Context "異常ケース" { It "Null" { { ConvertJsonObjectToEditableJson -InputObject $null } | Should -Throw } It "Not Hashtable or Array or PSCustomObject: ValueType" { { ConvertJsonObjectToEditableJson -InputObject 1 } | Should -Throw } It "Not Hashtable or Array or PSCustomObject: string" { { ConvertJsonObjectToEditableJson -InputObject "2" } | Should -Throw } } } Describe "CalcDepth" { Context "異常ケース" { It "Null" { { CalcDepth -InputObject $null } | Should -Throw } } Context "正常ケース Array" { It "Enpty array" { CalcDepth -InputObject @() | Should -Be 1 } It "Nested array" { CalcDepth -InputObject @(1, @()) | Should -Be 2 } It "Hashtable in array" { CalcDepth -InputObject @(1, [PSCustomObject]@{a = 2 }) | Should -Be 2 } It "Depth (1,2,3)" { CalcDepth -InputObject @(1, @(2), @(@(3), 4)) | Should -Be 3 } It "Depth (3,2,1)" { CalcDepth -InputObject @(@(@(1), 2), @(3), 4) | Should -Be 3 } } Context "正常ケース Hashtable" { It "Enpty hashtable" { CalcDepth -InputObject @{} | Should -Be 1 } It "Nested hashtable" { CalcDepth -InputObject @{a = 1; b = @{c = 3 } } | Should -Be 2 } It "Array in hashtable" { CalcDepth -InputObject @{a = 1; b = @(2, 3) } | Should -Be 2 } } Context "正常ケース PSCustomObject" { It "Enpty hashtable" { CalcDepth -InputObject ([PSCustomObject]@{}) | Should -Be 1 } It "Nested hashtable" { CalcDepth -InputObject ([PSCustomObject]@{a = 1; b = [PSCustomObject]@{c = 3 } }) | Should -Be 2 } It "Array in hashtable" { CalcDepth -InputObject ([PSCustomObject]@{a = 1; b = @(2, 3) }) | Should -Be 2 } It "Depth (1,2,3)" { CalcDepth -InputObject ([PSCustomObject]@{ a = 1; b = [PSCustomObject]@{}; c = [PSCustomObject]@{ cc = [PSCustomObject]@{ccc = 3 } } }) | Should -Be 3 } It "Depth (3,2,1)" { CalcDepth -InputObject ([PSCustomObject]@{ a = [PSCustomObject]@{ aa = [PSCustomObject]@{} }; b = [PSCustomObject]@{}; c = 3 }) | Should -Be 3 } } } Describe "ConvertFrom-JsonEditable" { Context "異常ケース" { It "Null" { { ConvertFrom-JsonEditable -Value $null } | Should -Throw } It "JSON形式でない文字列" { $value = '{"value":{}' { ConvertFrom-JsonEditable -Value $value } | Should -Throw } } Context "正常ケース Objectはじまり" { It "Without Array and Object" { $value = @" { "a":1, "b":"2", "c":true, "d":null } "@ $actual = ConvertFrom-JsonEditable -Value $value $actual.a | Should -BeExactly 1 $actual.b | Should -BeExactly "2" $actual.c | Should -BeExactly $true $actual.d | Should -BeExactly $null $actual.GetDepth() | Should -BeExactly 1 } It "With Array" { $value = @" { "a":1, "b":"2", "c":true, "d":[ 4,5,6 ] } "@ $actual = ConvertFrom-JsonEditable -Value $value $actual.a | Should -BeExactly 1 $actual.b | Should -BeExactly "2" $actual.c | Should -BeExactly $true $actual.d | Should -BeExactly @(4, 5, 6) $actual.GetDepth() | Should -BeExactly 2 $actual.d.GetDepth() | Should -BeExactly 1 } It "With Object" { $value = @" { "a":1, "b":"2", "c":false, "d":{ "da":3, "db":"4", "dc":"true" } } "@ $actual = ConvertFrom-JsonEditable -Value $value $actual.a | Should -BeExactly 1 $actual.b | Should -BeExactly "2" $actual.c | Should -BeExactly $false $actual.d | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $actual.d.da | Should -BeExactly 3 $actual.d.db | Should -BeExactly "4" $actual.d.dc | Should -BeExactly $true $actual.GetDepth() | Should -BeExactly 2 $actual.d.GetDepth() | Should -BeExactly 1 } It "With Array and Object" { $value = @" { "a":1, "b":"2", "c":false, "d":{ "da":3, "db":"4", "dc":"true" }, "e":[ 5, "6", true, {"f":7} ] } "@ $actual = ConvertFrom-JsonEditable -Value $value $actual.a | Should -BeExactly 1 $actual.b | Should -BeExactly "2" $actual.c | Should -BeExactly $false $actual.d | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $actual.d.da | Should -BeExactly 3 $actual.d.db | Should -BeExactly "4" $actual.d.dc | Should -BeExactly $true $actual.d.GetDepth() | Should -BeExactly 1 $actual.e[0] | Should -BeExactly 5 $actual.e[1] | Should -BeExactly "6" $actual.e[2] | Should -BeExactly $true $actual.e[3] | Should -BeOfType [System.Collections.Specialized.OrderedDictionary] $actual.e[3].f | Should -BeExactly 7 $actual.e[3].GetDepth() | Should -BeExactly 1 $actual.e.GetDepth() | Should -BeExactly 2 $actual.GetDepth() | Should -BeExactly 3 } } Context "正常ケース Arrayはじまり" { It "Arrayのみ" { $value = @" [ 1, "2", true, null ] "@ $actual = ConvertFrom-JsonEditable -Value $value $actual | Should -BeExactly @(1, "2", $true, $null) $actual.GetDepth() | Should -BeExactly 1 } It "Array + Array" { $value = @" [ 1, "2", true, null, [3] ] "@ $actual = ConvertFrom-JsonEditable -Value $value $actual | Should -BeExactly @(1, "2", $true, $null, @(3)) $actual.GetDepth() | Should -BeExactly 2 $actual[4].GetDepth() | Should -BeExactly 1 } } Context "シナリオテスト" { It "JSON変換 → 編集 → JSON化 Objectはじまり" { $value = @" { "a":1 } "@ $actual = ConvertFrom-JsonEditable -Value $value $actual.Add("b", @{"c" = 2; "d" = @(3, 4) }) # 結果を標準のJSONオブジェクトに変換 $actualStdJson = $actual | ConvertTo-Json -Depth $actual.GetDepth() -Compress | ConvertFrom-Json $expectStdJson = '{"a":1,"b":{"c":2,"d":[3,4]}}' | ConvertFrom-Json $actualStdJson.a | Should -Be $expectStdJson.a $actualStdJson.b.c | Should -Be $expectStdJson.b.c $actualStdJson.b.d | Should -Be $expectStdJson.b.d # 結果を本スクリプトのハッシュテーブルに変換 $actualMyJson = $actual | ConvertTo-Json -Depth $actual.GetDepth() -Compress | ConvertFrom-JsonEditable $expectMyJson = '{"a":1,"b":{"c":2,"d":[3,4]}}' | ConvertFrom-JsonEditable $actualMyJson.a | Should -Be $expectMyJson.a $actualMyJson.b.c | Should -Be $expectMyJson.b.c $actualMyJson.b.d | Should -Be $expectMyJson.b.d } It "JSON変換 → 編集 → JSON化 Arrayはじまり" { $value = @" [{ "a":1 }] "@ $actual = ConvertFrom-JsonEditable -Value $value $actual[0].Add("b", @{"c" = 2; "d" = @(3, 4) }) $actual.Add(@{"e"="f"}) # 結果を標準のJSONオブジェクトに変換 $actualStdJson = $actual | ConvertTo-Json -Depth $actual.GetDepth() -Compress | ConvertFrom-Json $expectStdJson = '[{"a":1,"b":{"c":2,"d":[3,4]}},{"e":"f"}]' | ConvertFrom-Json $actualStdJson[0].a | Should -BeExactly $expectStdJson[0].a $actualStdJson[0].b.c | Should -BeExactly $expectStdJson[0].b.c $actualStdJson[0].b.d | Should -BeExactly $expectStdJson[0].b.d $actualStdJson[1].e | Should -BeExactly $expectStdJson[1].e # 結果を本スクリプトのハッシュテーブ-BeExactly変換 $actualMyJson = $actual | ConvertTo-Json -Depth $actual.GetDepth() -Compress | ConvertFrom-JsonEditable $expectMyJson = '[{"a":1,"b":{"c":2,"d":[3,4]}},{"e":"f"}]' | ConvertFrom-JsonEditable $actualMyJson[0].a | Should -BeExactly $expectMyJson[0].a $actualMyJson[0].b.c | Should -BeExactly $expectMyJson[0].b.c $actualMyJson[0].b.d | Should -BeExactly $expectMyJson[0].b.d $actualMyJson[1].e | Should -BeExactly $expectMyJson[1].e $actualMyJson.GetDepth() | Should -BeExactly 4 } } Context "Unboxing/Unpacking検証" { It "要素1のオブジェクト" { $value = @" { "a":1 } "@ $actual = ConvertFrom-JsonEditable -Value $value $actual.a | Should -BeExactly 1 $actual.GetDepth() | Should -BeExactly 1 } It "要素1のオブジェクト" { $value = @" [ [ 1 ] ] "@ $actual = ConvertFrom-JsonEditable -Value $value $actual[0][0] | Should -BeExactly 1 $actual.GetDepth() | Should -BeExactly 2 } } }
以上!