get-memberのパイプ入力の処理

あけましておめでとうごうざいます。
2006年はMonadが正式リリース・・・されるはずです、多分。(^^;
楽しいScriptingライフが送れることを期待しています。


さて、今年最初の記事は「get-member」にパイプでオブジェクトを渡した際の挙動についてです。

「get-member」について

利用頻度の高いCmdletである「get-member」。
もうお馴染みだと思いますが、オブジェクトのメンバ(プロパティやメソッド)などを一覧表示します。
標準のプロパティやメソッドだけでなく、ユーザが任意に追加した「NoteProperty」「ScriptProperty」「ScriptMethod」なども表示することができます。


表示可能なメンバは以下です。

  • AliasProperty
  • CodeMethod
  • CodeProperty
  • MemberSet
  • Method
  • NoteProperty
  • ParameterizedProperty
  • Property
  • PropertySet
  • ScriptMethod
  • ScriptProperty

「get-member」にパイプでオブジェクト配列を渡すと・・・

「get-member」にパイプでオブジェクト配列を渡すと、「get-member」は配列の各要素を処理します。
配列(System.Array)自体のメンバは表示しません。
その際「get-member」は要素の型に関してユニークなものだけを処理します。
つまり、同じ型の要素が配列に複数個含まれていても、その型のメンバは一度だけしか処理しません。


通常、配列には同じ型の要素のみが詰まっている事が多いため「get-member」は配列の先頭しか処理しないように見えますが、実際は、同じ型の処理をスキップしているだけです。
例えば、配列に2種類の型が含まれている場合、「get-member」は計2回処理されます。


サンプルで確認してみましょう。

オブジェクト配列内にユニークな型が1つしかない場合

以下は「get-process」の例です。
「get-process」の結果、61個の「Process」オブジェクトが$aに取得されますが、「get-member」にパイプで$a(配列)を渡しても1度しか処理されません。

MSH C:\> $a = get-process
MSH C:\> $a.getType().fullname
System.Object[]
MSH C:\> $a.count
61
MSH C:\> $a[0].getType().fullname
System.Diagnostics.Process
MSH C:\> $a | get-member


    TypeName: System.Diagnostics.Process

Name                           MemberType     Definition
----                           ----------     ----------
Handles                        AliasProperty  Handles = Handlecount
Name                           AliasProperty  Name = ProcessName
NPM                            AliasProperty  NPM = NonpagedSystemMemorySize
PM                             AliasProperty  PM = PagedMemorySize
VS                             AliasProperty  VS = VirtualMemorySize
WS                             AliasProperty  WS = WorkingSet
(中略)
オブジェクト配列内にユニークな型が2つあるの場合

「get-childitem」は子アイテムを取得するCmdletです。
アイテムがファイルの場合は「System.IO.FileInfo」オブジェクトを、
アイテムがディレクトリの場合は「System.IO.DirectoryInfo」オブジェクトを取得します。

MSH C:\> get-childitem | foreach{$_.getType().fullname} | get-unique
System.IO.FileInfo
System.IO.DirectoryInfo

確かに2種類のオブジェクトが含まれていますね。
ですから、「get-childitem」を「get-member」に渡すと2回処理されるはずです。

MSH C:\> get-childitem | get-member

    TypeName: System.IO.FileInfo

Name        MemberType     Definition
----        ----------     ----------
AppendText  Method         System.IO.StreamWriter AppendText()
(中略)

    TypeName: System.IO.DirectoryInfo

Name        MemberType     Definition
----        ----------     ----------
Create      Method         System.Void Create(), System.Void Create(...
(中略)
  • 予想通り「FileInfo」と「DirectoryInfo」が処理されました。

補足

「get-childitem」は様々なものを取得します。

Aliasの場合→System.Management.Automation.AliasInfo
Functionの場合→System.Management.Automation.FunctionInfo
Filterの場合→System.Management.Automation.FilterInfo
レジストリの場合→Microsoft.Win32.RegistryKey
証明書の場合→System.Management.Automation.Commands.X509StoreLocation
を取得します。
※他にも変数/環境変数なども取得できます。