拡張型を利用する

freemannさんから以下のような質問がありました。
http://d.hatena.ne.jp/newpops/20051218/p1

Question

こんばんは^^
いつもお世話になっています。
ところで、PowerShell宣言でも取り上げているScriptPropertyなのですが、インスタンスを生成した時に自動で付け加えることはできないのでしょうか?
自分では使える案がちょっと今は思いつかないのですが、著書でHeiseiというプロパティを付け加えているのですが、書かれているやり方ですと、インスタンスを生成した後に付け加えているのですが、これをインスタンスを生成した時にScriptPropertyが加えられているというものです。
>$a = Get-Date
で作成すると、DateTimeというScriptPropertyができていると思うのですが、これと同じようなことができたらいいことありそうだなと・・・。

よろしくおねがいします。

Answer:可能です。PowerShellは拡張型を定義することができます。

PowerShell.NET Frameworkが提供する型を自由に利用できますが、それだけでなく、型の拡張を行うこともできます。
オブジェクトに対して動的にScriptPropertyを追加することもできますし、freemannさんの質問にあるように、事前にScriptPropertyを追加しておくことも可能です。


事前にScriptPropertyを追加するには定義ファイルに拡張型を記述しておく必要があります。
例えば、「System.DateTime」型は上記でfreemannさんが言及しているように、標準で「DateTime」という名前のScriptPropertyが追加されていますが、この定義は、PowerShellインストールフォルダの以下のファイルに記述されています。

C:\WINDOWS\System32\WindowsPowerShell\v1.0\types.ps1xml
    <Type>
        <Name>System.DateTime</Name>
        <Members>
            <ScriptProperty>
                <Name>DateTime</Name>
                <GetScriptBlock>
                    if ($this.DisplayHint -ieq  "Date")
                    {
                        "{0}" -f $this.ToLongDateString()
                    }
                    elseif ($this.DisplayHint -ieq "Time")
                    {
                        "{0}" -f  $this.ToLongTimeString()
                    }
                    else
                    {
                        "{0} {1}" -f $this.ToLongDateString(), $this.ToLongTimeString()
                    }
                </GetScriptBlock>
            </ScriptProperty>
        </Members>
    </Type>


このファイルを修正すれば、型を拡張した「拡張型」を利用することができます。
もし「平成年度」を示す「Heisei」というScriptPropertyを定義したい場合、「System.DateTime」の定義を以下のように変更してみましょう。
※編集するには、ユーザに適切な権限を与えてください。

    <Type>
        <Name>System.DateTime</Name>
        <Members>
            <ScriptProperty>
                <Name>DateTime</Name>
                <GetScriptBlock>
                    if ($this.DisplayHint -ieq  "Date")
                    {
                        "{0}" -f $this.ToLongDateString()
                    }
                    elseif ($this.DisplayHint -ieq "Time")
                    {
                        "{0}" -f  $this.ToLongTimeString()
                    }
                    else
                    {
                        "{0} {1}" -f $this.ToLongDateString(), $this.ToLongTimeString()
                    }
                </GetScriptBlock>
            </ScriptProperty>
            <ScriptProperty>
                <Name>Heisei</Name>
                <GetScriptBlock>
                    $this.Year - 1988
                </GetScriptBlock>
            </ScriptProperty>
        </Members>
    </Type>

PowerShellコンソールを再起動し、以下のようにタイプします。

PS C:\> Get-Date | Format-List

DisplayHint : DateTime
DateTime    : 2007年6月30日 4:21:34
Heisei      : 19
Date        : 2007/06/30 0:00:00
Day         : 30
DayOfWeek   : Saturday
DayOfYear   : 181
Hour        : 4
Kind        : Local
Millisecond : 595
Minute      : 21
Month       : 6
Second      : 34
Ticks       : 633187740945954636
TimeOfDay   : 04:21:34.5954636
Year        : 2007

「Heisei」というScriptPropertyが追加されていることが分かります。

補足

直接「types.ps1xml」を修正せず、別ファイルに拡張型を定義することもできます。
その場合は「Update-TypeData」コマンドレットを利用して、拡張型を読み込んでください。