コードを読むの楽しいですね。
さて、今回はみんな大嫌いなレジストリをPowerShellで扱うものです。
【リリース後に確認された問題】2014 年 8 月 13 日公開の更新プログラムの適用により問題が発生する場合があるがいま話題です。
早速、できる大人@kkamegawaさんが問題のレジストリ走査をするスクリプトを書いてくださっています。
今回はこのスクリプトをパイプラインでちょいんとつなげてみることで、PowerShellのパイプラインな書き心地を楽しんでみましょう。
パイプラインを使うなら
判定はWhere-Object
単純な成否のフィルタリングなら、Where-Object
が使えます。
もちろんif
での判定でもいいのですが、成否それぞれに処理をするのではなく、狙ったものだけを次のパイプラインに渡すのであればとても便利です。
Foreach か Foreach-Objectか
今回は、パイプラインをつなげるのでForeach-Obejct
を使います。
賛否両論なのか、なにか知りませんが(!? )、この2つは正確が異なります。
Foreachの場合は、いったんコレクションを舐めてから、一斉に操作
Foreach ($x in $collection) { }
Foreach-Objectは、コレクションをとりだして一件ずつパイプラインの先に渡します。処理に要したメモリはパイプラインをすぎると解放されます。
$collection | %{$_}
両社の性質の違いからForeach
は比較的高速に動作しますが、コレクションをいったんメモリにのせてから処理をするのでメモリを多く食う傾向にあります。
一方で、Foreach-Object
は、パイプラインを渡すコストもあり、処理がForeach
より遅くなりがちですがメモリが適正に処理されるので好ましい時が多いでしょう。
検証環境
Windows 8.1 Update1で動かしているPowerShell V5 May Previewです。
PowerShell 3.0以上でないと動きませんので、Windows 7な方はご注意ください。 (Windows 7のデフォルトはV2なので)
コード
1行にできますが、わかりやすいように改行しています。
改行
はい
$message = "font '{0}' found! Your environmet will trouble with MS14-045. See https://support.microsoft.com/kb/2982791" $fontregistory = 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts\' (Get-Item -Path $fontregistory).Property ` | % { (Get-ItemProperty -path $fontregistory).$_ ` | where {$_.EndsWith('.otf')} ` | where {Test-Path $_} ` | %{ Write-Host ($message -f $_) -ForegroundColor Red;return} } Write-Host 'Your environment is OK.'
V2 な冗長な書き心地
もうヤダ
$message = "font '{0}' found! Your environmet will trouble with MS14-045. See https://support.microsoft.com/kb/2982791" $fontregistory = 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts\' (Get-Item -Path $fontregistory) | select -ExpandProperty Property | % {$x=$_; Get-ItemProperty -path $fontregistory | select -ExpandProperty $x | where {$_.EndsWith('.otf')} | where {Test-Path $_} | %{ Write-Host ($message -f $_) -ForegroundColor Red;return}} Write-Host 'Your environment is OK.'
まとめ
やってることは変わりません。が、こういう書き方もあるんだよーということで。
ちなみに処理速度は、おおよそ同じですね。メモリもわずかな違いです。
- Foreach
TotalSeconds : 7.2915443
- パイプライン
TotalSeconds : 7.1580007
レジストリは二度舐めが発生して面倒です。