switch文のfileオプションの2つの落とし穴

1つ目 Shift_JISで全角文字が化ける

switch文にはfileオプションがあり、指定したファイルの各行をイテレート処理できる。しかしファイルがShift_JISの時は――

$fname = "test.txt"
$txt = @"
1:Shift_JISにおける
2:全角のテスト
"@

if(-not (Test-Path $fname)){ ni -Type file $fname >$null }
# encoding defaultでshift-jisになる
sc $fname -Encoding default $txt

# 文字化けする
switch -regex -file $fname
{
	"^\d:(.*)" { $matches[1] }
}

# fileオプションをやめてGet-Contentで取得すればおk
switch -regex (gc $fname)
{
	"^\d:(.*)" { $matches[1] }
}

これがこうなる。

Shift_JIS???????
?S?p??e?X?g
Shift_JISにおける
全角のテスト

2つ目 $switchが使えない

switch文の内側では、$switchでswitchループのイテレータにアクセスできる。
$switch.currentで現在の値を取得。$switch.movenext()で次の値にイテレータを進める。foreach文における$foreachと同様の機能。
この$switchを『Windows PowerShell In Action』では、switch loop enumerator(スイッチループ列挙子)と呼んでいる。

$switchは便利な機能だが、どうやらfileオプション指定時には利用できない。

$fname = "test.txt"
$txt = @"
aaa
bbb
# ccc
ddd
<#
eee
fff
#>
ggg
"@

if(-not (Test-Path $fname)) { ni -Type file $fname >$null }

こういうテキストファイルがあって、PowerShell風にコメントアウトした部分を除いて取得したい。

しかし、次のコードは、「null 値の式ではメソッドを呼び出せません」とエラーになる。fileオプション指定時は$switchがnullになる模様。

sc $fname $txt
switch -regex -file $fname
{
	'^#' { continue }
	'^<#' {
		while($switch.current -notmatch '^#>') { [void]$switch.movenext() }
	}
	default { $_ }
}

1つ目の落とし穴と同様、fileオプションをやめてGet-Contentを用いればうまくいく

switch -regex (gc $fname)
{
	'^#' { continue }
	'^<#' {
		while($switch.current -notmatch '^#>') { [void]$switch.movenext() }
	}
	default { $_ }
}
aaa
bbb
ddd
ggg