tech.guitarrapc.cóm

Technical updates

PowerShell で MS14-045の問題が起きる環境かどうかチェックするのを楽しもう

コードを読むの楽しいですね。

さて、今回はみんな大嫌いなレジストリをPowerShellで扱うものです。

【リリース後に確認された問題】2014 年 8 月 13 日公開の更新プログラムの適用により問題が発生する場合があるがいま話題です。

早速、できる大人@kkamegawaさんが問題のレジストリ走査をするスクリプトを書いてくださっています。

MS14-045で問題が起きる環境かどうかチェックする

今回はこのスクリプトをパイプラインでちょいんとつなげてみることで、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行にできますが、わかりやすいように改行しています。

MS14-045 issue check by piepline.

改行

はい

$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\'
&#40Get-Item -Path $fontregistory&#41.Property `
| % {
    &#40Get-ItemProperty -path $fontregistory&#41.$_ `
    | where {$_.EndsWith&#40'.otf'&#41} `
    | where {Test-Path $_} `
    | %{ Write-Host &#40$message -f $_&#41 -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\'
&#40Get-Item -Path $fontregistory&#41 | select -ExpandProperty Property | % {$x=$_; Get-ItemProperty -path $fontregistory | select -ExpandProperty $x | where {$_.EndsWith&#40'.otf'&#41} | where {Test-Path $_} | %{ Write-Host &#40$message -f $_&#41 -ForegroundColor Red;return}}
Write-Host 'Your environment is OK.'

まとめ

やってることは変わりません。が、こういう書き方もあるんだよーということで。

ちなみに処理速度は、おおよそ同じですね。メモリもわずかな違いです。

  • Foreach
TotalSeconds      : 7.2915443

image

  • パイプライン
TotalSeconds      : 7.1580007

image

レジストリは二度舐めが発生して面倒です。