PowerShell で AOP

いや、あんまり AOP っぽいことはしないんですが...良いタイトルが思いつかなかったので。

最近の .NET Framework は DLR のような仕組みを取り入れつつありますが、.NET の世界の基本は強い型付けのあるクラス型OOPがベースになっています。もちろん、それは .NET 対応のプログラミング言語が必ずしもクラス型のOOPLでなければならないというわけではありませんが、型システムや標準ライブラリなどがそのように構築されていることにはかわりありません。
C# 3.0 で拡張メソッドが導入されるなど、CLR の機能拡張を伴わないプログラム言語レベルの拡張の仕組というのは色々とありますが、PowerShell でもそういった仕組みが準備されています。

PowerShell では、任意のオブジェクトに対してメンバを自由に追加することができるようになっています。たとえば、大量のファイルからいくつかのファイルをマーキングしておき、マーキングしたファイルだけを処理するような場合に使えます。

# SYSTEM32 の DLL 一覧を取得
PS > $files = Get-Item C:\Windows\System32\*.dll

# 名前が MS で始まるものと、6番目のファイルをマーキング
PS > $files |? { $.Name -Like "MS*" } | Add-Member NoteProperty SumIt $true
PS > Add-Member NoteProperty SumIt $true -in $files[5]

# マーキングしたファイルのサイズを集計
PS > $files |? { $_.SumIt } | measure -Sum -Ave -Min -Max Length
Count    : 14
Averate  : 629840
Maximum  : 17786368
Minimum  : 2048
Property : Length

NoteProperty は定数をメモするためのプロパティで、お手軽に使える便利なプロパティです。この例では SumIt という名前のプロパティを作成し、その値を $true に設定しています。すでに同じ名前のプロパティがある場合はメモプロパティの作成は失敗しますが、-Force を指定していると上書きすることもできるので、オブジェクトに何らかのメモを好きに貼り付けることができます。
似たようなものに、ScriptProperty があります。これは任意のスクリプトをプロパティとして登録できます。

# すべてのオブジェクトに Smaller プロパティを追加
PS > $files | Add-Member ScriptProperty Smaller { $this.Length -lt 1MB }
PS > $files | group Smaller
Count Name
----- -----
 1745 True
  261 False

$this はオブジェクト自身を表します。この Smaller プロパティはオブジェクト自身の Length が 1MB 未満の場合に $true になるので、1745 個の DLL が 1MB 未満であるということがわかります。

Add-Member では、様々なものを追加することができますが、とりあえずは NoteProperty と ScriptProperty の2つがあれば、PowerShellスクリプトを書くときにオブジェクトに関連付けて情報を保存するのに非常に便利になるはずです。

余談ですが、特定の .NET の型に NoteProperty や ScriptProperty を自動的に付与することもできます。そのためには XML で types.ps1xml というファイルを作成して Update-TypeData コマンドを使用するのですが、必要なオブジェクトだけ Add-Member すればいいんじゃないかな?と思います。興味がある人は help about update-typedata と help about_types でもどうぞ。