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 V3 以上でないと動きませんので、Windows 7な方はご注意ください。 (Windows 7 のデフォルトは V2なので)

コード

ということで、ちょいん

MS14-045 issue check by piepline.

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

f:id:guitarrapc_tech:20140816203436p:plain

  • パイプライン
TotalSeconds      : 7.1580007

f:id:guitarrapc_tech:20140816203607p:plain

レジストリは二度舐めが発生するのが面倒ですにぇ。