【2018/10/07追記】
最新の情報をふまえて本エントリを新しく書き直しました。
上記エントリをご覧ください。
PowerShellの基本的なことがわかってなかったシリーズ第6弾です。
便利なCountプロパティ
コマンドを実行して出力した結果の件数を取得したい場合、([コマンド]).Count
とするとその件数を取得することができます。
たとえば以下の様にコマンドを実行するとC:\Program Files
配下にあるEXEファイルの総数を取得することができます。
# Countプロパティを使うと、評価した結果(System.IO.FileInfo[])の要素数を取得することができます。 PS C:\> (ls -Path "C:\Program Files" -File -Filter "*.exe" -Recurse).Count 217
Countプロパティの実体
System.Array.Count?
このCount
、要はコマンドを実行した結果(この場合はSystem.IO.FileInfo[]
)の要素数を取得しているだけなのですが、しかしながら、.NETの配列(System.Array
)にはLength
プロパティはあれどもCount
プロパティはありません。
それでもPowerShellではCount
プロパティを利用することができています。
Countプロパティの実体
この謎めいたCount
プロパティの実体はSystem.Array
に追加された型データになります。
型データとは.NETの型にPowerShell独自のデータを付与できる機能になります。
詳細については牟田口先生の以下のエントリを参照してください。
型データの定義が記載されているC:\Windows\System32\WindowsPowerShell\v1.0\types.ps1xml
を見るとCount
プロパティは以下の様に定義されており、System.Array.Length
に対するAliasProperty
となっていることがわかります。
# C:\Windows\System32\WindowsPowerShell\v1.0\types.ps1xmlより抜粋 <Type> <Name>System.Array</Name> <Members> <AliasProperty> <Name>Count</Name> <ReferencedMemberName>Length</ReferencedMemberName> </AliasProperty> </Members> </Type>
Get-Member
で空の配列@()
のメンバを確認してみるとこんな結果を返します。
PS C:\> Get-Member -InputObject @() -View Extended
TypeName: System.Object[]
Name MemberType Definition
---- ---------- ----------
Count AliasProperty Count = Length
この型データにより本来System.Array
には存在しないCount
プロパティを利用することができます。
型データでは説明のつかないCountプロパティの進化
PowerShell 2.0までの動作
このCount
プロパティはSystem.Array
に対するものなので配列以外では使うことができません。
PowerShell 2.0では以下の様なコードは$null
を返し、配列以外ではCount
プロパティが存在しないことがわかります。
# PowerShell 2.0 PS C:\> $PSVersionTable.PSVersion Major Minor Build Revision ----- ----- ----- -------- 2 0 -1 -1 PS C:\> (123).Count PS C:\>
配列でないオブジェクトに対してCount
プロパティを使いたいときは配列化してやる必要があります。
# PowerShell 2.0 # 要素数1の配列化してCountプロパティを取得 PS C:\> @(123).Count 1
PowerShell 3.0以降の動作
ただし、この動作はPowerShell 3.0以降になると変わります。
先ほどのコードをPowerShell 3.0以降の環境で実行すると以下の様になり1
を返す様になります。
# PowerShell 3.0 以降 (以下の例では4.0) PS C:\> $PSVersionTable.PSVersion Major Minor Build Revision ----- ----- ----- -------- 4 0 -1 -1 PS C:\> (123).Count 1
ちなみに$null
を渡すと0
が返されます。
# PowerShell 3.0 以降 PS C:\> ($null).Count 0
型データでは説明のつかないCountプロパティの進化
この変更についてはWindows PowerShell Blogのこの記事で触れられる程度の情報しかなく、機能の実体については正直謎です。
とはいえ$null
にプロパティを生やして0
を返す事が出来るというのはどう考えても普通の動作ではないのでシェルまたはスクリプトエンジンレベルでの機能追加と思われます。*1
この変更により対象オブジェクトが配列かどうかを気にすることなくCount
プロパティで件数を取得できる様になりました。
残念な点の残るCountプロパティ
これで万事OKかと思いきや一点だけ残念な点があります。
ぎたぱそ先生の以下のエントリによるとPScustomObject
に対してはCount
プロパティは$null
を返してしまいます。
実際に試してみると確かに$null
を返します。
# PowerShell 3.0 以降 PS C:\> ([PScustomObject]@{hoge = "hoge"}).Count PS C:\>
PScustomObject
に対してCount
プロパティを使用する際は注意が必要になります。
本当に残念です。
*1:もしかしたら機能追加ではなく糖衣構文なのかもしれません…