PowerShell で bool 値を文字列から生成する

PowerShell で文字列型のキーと任意の文字列と変換可能な型の値を使った XML ベースの限定的な簡易 KVS があったのだけど、bool 値の挙動がおかしいという不具合報告があった。
そう、私は PowerShell の自動型変換が XmlConvert.ToBoolean() のように働くことを期待していたのだが、実際にはそんなうまい仕組みにはなっていなくて、文字列は長さが0より大きい場合に真であり、長さが0の場合だけ偽であるのだ。

PS> [bool] [string] $false
True

PS> [bool] [string] $null
False

bool 値を格納している項目が2つしかなく、それらが省略可能かつ省略時は false となる項目であったため、多くの場合で省略値としての $null を $false に変換していたことで発見が遅れ、非常にまずいことになりかねないところであった。

文字列 False が真であることで、次のような暗黙の変換も非常に危険である。

PS> Get-Member -in $obj
Field1     Property    System.String  Field1 { get; set; }
Field2     Property    System.Boolean Field2 { get; set; }

PS> $obj.Field1 = "No"
PS> $obj.Field2 = "False"

PS> Format-List -in $obj
Field1   : No
Field2   : True

このような直接的な代入文は書かないだろうが、型にゆるい PowerShell では、厳密に型指定していない変数に対して bool 値として評価できないものが格納されている…なんて可能性は多々あるだろう。数値を bool にしているつもりが、"0" という文字列を評価していたら $true として扱われる。*1

面倒なことに、

PS> $test = 0, "0", "false", "False", "FALSE"

PS> $test|%{$t=$_;trap{@{$t=$_};continue} @{$t=[bool]::Parse($_)}}|Format-Table
Name        Value                       
----        -----
0           文字列が有効な Boolean 型として認識されませんでした。
0           文字列が有効な Boolean 型として認識されませんでした。
false       False
False       False
FALSE       False

PS> $test|%{$t=$_;trap{@{$t=$_};continue} @{$t=[System.Xml.XmlConvert]::ToBoolean($_)}}|Format-Table
Name        Value                       
----        -----
0           False
0           False
false       False
False       文字列が有効な Boolean 型として認識されませんでした。
False       文字列が有効な Boolean 型として認識されませんでした。

なもんで、用途に応じて

PS> # 小文字にしてすべて判定
PS> $test|%{ [System.Xml.XmlConvert]::ToBoolean($([string] $_).ToLower()) }

PS> # true, false 以外は false
PS> $test|%{ [bool]::TryParse($_, [ref] $_) -and $_ }

PS> # true, false 以外は null
PS> $test|%{ if ([bool]::TryParse($_, [ref] $_)){$_}else{$null} }

などなどの対応が考えられるのだが、もっと手軽な方法はないのか?*2

*1:数値としての 0 は $false

*2:Function 1つ作ればいいだけなんだけども