Get-Member で知らないコマンドの戻り値を自力で調べられる01 章で見たとおり、Bash のパイプにはテキスト行が、PowerShell のパイプにはオブジェクトが流れます。ここではそれを実際に確かめます。
Get-Process | Select-Object -First 1
実行すると、次のような表が出ます。
NPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName
------ ----- ----- ------ -- -- -----------
28 18.42 35.66 1.42 9876 1 pwsh
この表を見て「7つの項目を持つデータが返ってきた」と考えると間違いです。実際に返ってきているのは System.Diagnostics.Process というオブジェクトで、プロパティは 100 個近くあります。
表に出ていない Path も、そのまま使えます。
Get-Process | Select-Object -First 1 | Select-Object Name, Path, StartTime
ps aux の出力に無い情報は本当に存在しません。欲しければオプションを足して再実行するしかありません。Format-* は最後にだけ使う 重要な罠Format-Table や Format-List を途中に挟むと、そこでオブジェクトが「表示用の部品」に変換されてしまいます。以降のコマンドはまともに動きません。
# ✗ 動かない — Format-Table の後は表示部品になっている
Get-Process | Format-Table Name, Id | Where-Object { $_.Id -gt 1000 }
# ✓ 絞ってから最後に整形する
Get-Process | Where-Object { $_.Id -gt 1000 } | Format-Table Name, Id
Format-* を書いたら、そのパイプラインはそこで終わりです。ファイルに出す(Export-Csv)、変数に入れる、別のコマンドに渡す — どれもできなくなります。画面で見るための最後の一手と考えてください。
.Id や .Path と書くだけで中身を取り出せます。
05.1 で「表示に出ていない情報がある」と分かりました。ではどうやって中身を知るのか。その答えが Get-Member です。
Get-Process | Get-Member
TypeName: System.Diagnostics.Process
Name MemberType Definition
---- ---------- ----------
Kill Method void Kill()
Refresh Method void Refresh()
Id Property int Id {get;}
ProcessName Property string ProcessName {get;}
StartTime Property datetime StartTime {get;}
CPU ScriptProperty System.Object CPU {get=...}
...
Get-Member は型名・プロパティ・メソッドの3つを一度に教えてくれる| MemberType | 意味 | 使い方 |
|---|---|---|
Property | 元の .NET オブジェクトが持つ値 | $p.Id |
NoteProperty | PowerShell が後から足した値 | $p.PSPath |
ScriptProperty | アクセス時に計算される値 | $p.CPU |
AliasProperty | 別名。実体は他のプロパティ | $p.Name(実体は ProcessName) |
Method | 実行できる操作 | $p.Kill() |
Get-Process | Get-Member -MemberType Property
# 短縮形(gm は Get-Member のエイリアス)
Get-Process | gm -MemberType Property
| コマンド | 返るオブジェクトの型 |
|---|---|
| Get-Process | System.Diagnostics.Process |
| Get-ChildItem(ファイル) | System.IO.FileInfo |
| Get-ChildItem(フォルダ) | System.IO.DirectoryInfo |
| Get-Content | System.String |
| Import-Csv | System.Management.Automation.PSCustomObject |
Get-Member、が習慣になれば独学できる# 知らないコマンドに出会ったとき
Get-Service | Get-Member # 何が返るか調べる
Get-Service | Select-Object -First 1 | Format-List * # 実際の値を全部見る
Format-List * はすべてのプロパティを実際の値付きで表示します。Get-Member が「何があるか」なら、Format-List * は「いま何が入っているか」です。2つを組み合わせると、未知のコマンドでもすぐ扱えます。
Get-Member はリフレクション(getClass().getMethods() や GetType().GetProperties())を対話的に実行しているようなものです。IDE の補完で見ていた情報を、シェルの中で直接引ける、と考えると分かりやすいはずです。# JavaScript
files.filter(f => f.size > 1024)
# PowerShell(スクリプトブロック)
Get-ChildItem | Where-Object { $_.Length -gt 1024 }
# PowerShell(簡易構文 — 比較1つだけならこちらが読みやすい)
Get-ChildItem | Where-Object Length -gt 1024
$_ はいま流れてきた1件を指す自動変数です。$PSItem とも書けますが、$_ のほうが一般的です。
| 書き方 | 例 | 使いどころ |
|---|---|---|
| スクリプトブロック | Where-Object { $_.Length -gt 1024 } | 複数条件、複雑な式 |
| 簡易構文 | Where-Object Length -gt 1024 | 比較1つだけ。読みやすい |
| エイリアス | ? { $_.Length -gt 1024 } | 対話操作のみ。スクリプトでは使わない |
# JavaScript
files.map(f => f.name.toUpperCase())
# PowerShell
Get-ChildItem | ForEach-Object { $_.Name.ToUpper() }
1..3 | ForEach-Object -Begin { "開始" } -Process { $_ * 10 } -End { "終了" }
# → 開始 / 10 / 20 / 30 / 終了
-Begin は最初に1回、-End は最後に1回だけ実行されます。集計の初期化と結果出力に使えます。
1..10 | ForEach-Object -Parallel { Start-Sleep 1; $_ } -ThrottleLimit 5
-Parallel の中は別のセッションです。$using: を付けます($using:baseDir)。また、1件あたりの処理が軽いと並列化のオーバーヘッドのほうが大きくなります。ネットワーク待ちなど、待ち時間が長い処理にだけ使ってください。
Get-Process | Select-Object Name, Id, CPU
Get-Process | Select-Object -First 5
Get-Process | Select-Object -Property Name -Unique
-ExpandProperty — 値そのものを取り出す よく使う# オブジェクトが返る(Name というプロパティを持つ箱)
Get-Process | Select-Object -First 1 -Property Name
# → @{Name=pwsh}
# 値そのものが返る(ただの文字列)
Get-Process | Select-Object -First 1 -ExpandProperty Name
# → pwsh
Select-Object Name はName というプロパティを1つだけ持つ新しいオブジェクトを作ります。文字列そのものが欲しいときは -ExpandProperty を使うか、ForEach-Object { $_.Name } と書きます。
Get-ChildItem | Select-Object Name, @{ Name = 'MB'; Expression = { [math]::Round($_.Length / 1MB, 2) } }
Name(列名)と Expression(値の計算式)のハッシュテーブルを渡すと、その場で新しい列を作れます。N / E と略記もできます。
Select-Object を通すと型が変わります。FileInfo でも、Select-Object Name, Length を通した後は PSCustomObject になります。.Delete() のようなメソッドは呼べなくなります。Select-Object は最後に置いてください。
$_ は「いま処理している1件」を表します。JavaScript の arr.filter(x => ...) の x にあたるものが、名前を書かずに $_ として用意されている、と考えてください。$_ が外側を隠してしまうので、ネストするときは ForEach-Object { $item = $_; ... } のように名前を付けて退避させます。
Get-ChildItem | Sort-Object Length -Descending
Get-ChildItem | Sort-Object Extension, Name # 複数キー
Get-Process | Sort-Object CPU -Descending -Top 5 # 上位だけ
返るのは GroupInfo というオブジェクトで、3つのプロパティを持ちます。
| プロパティ | 中身 |
|---|---|
Name | グループのキー(例: .png) |
Count | そのグループの件数 |
Group | グループに属する元のオブジェクトすべて |
# 拡張子ごとの合計サイズを出す
Get-ChildItem -Recurse -File |
Group-Object Extension |
ForEach-Object {
[PSCustomObject]@{
拡張子 = $_.Name
件数 = $_.Count
合計MB = [math]::Round(($_.Group | Measure-Object Length -Sum).Sum / 1MB, 2)
}
} | Sort-Object 合計MB -Descending
$_.Group に元のファイルオブジェクトが全部入っているので、そこからさらに集計できます。
GROUP BY では集計関数を通した値しか取れませんが、Group-Object は元のオブジェクトを Group に丸ごと保持します。後から「やっぱり平均も欲しい」となっても、再実行せずに取り出せます。
Get-ChildItem | Measure-Object # 件数だけ
Get-ChildItem | Measure-Object Length -Sum -Average -Maximum # 集計
Count : 4
Average : 43403.5
Sum : 173614
Maximum : 48259
Property : Length
.Count で十分です。(Get-ChildItem).Count のほうが短く、速く書けます。Measure-Object が要るのは合計・平均・最大最小を同時に取りたいときです。.Count は全件をメモリに載せてから数えます。数十万件を扱うなら Measure-Object のほうが安全です。
# 直近7日に更新された .ps1 を、サイズの大きい順に5件
Get-ChildItem -Recurse -Filter *.ps1 |
Where-Object { $_.LastWriteTime -gt (Get-Date).AddDays(-7) } |
Sort-Object Length -Descending |
Select-Object -First 5 Name, Length, LastWriteTime |
Format-Table -AutoSize
絞る → 並べる → 選ぶ → 整形するの順です。Format-Table が最後に来ていることに注目してください(05.1 の罠)。
| で終わっている行は「まだ続く」と解釈されるので、上の例のように1行1コマンドで縦に並べると読みやすくなります。Get-Verb | Measure-Object # → Count: 100
Get-Verb | Where-Object Group -eq 'Common'
Get-Command -Verb Get -Noun Process # 動詞と名詞で絞る
Get-Command *service* # 名前の一部で探す
Get-Command -Module Microsoft.PowerShell.Management
Get-Help Get-ChildItem # 概要
Get-Help Get-ChildItem -Examples # 使用例だけ(最も実用的)
Get-Help Get-ChildItem -Full # 全部
Get-Help Get-ChildItem -Online # ブラウザで公式ドキュメント
-Examples を見る癖をつけてください。Update-Help で取得できます(管理者権限が必要)。
ls のような短縮表記には仕組みの異なる3種類があります。混同すると「一覧はどこにあるのか」が分からなくなります。
| 種類 | 例 | 一覧を出せるか |
|---|---|---|
| ① コマンドのエイリアス | ls → Get-ChildItem | できるGet-Alias |
| ② パラメータのエイリアス | -Recurse の別名が -s / -r | できるコマンドごとに調べる |
| ③ パラメータの前方一致 | -Rec → -Recurse | できないその場で解決される |
Get-Alias で一覧できるGet-Alias # 全部見る
Get-Alias ls # ls の正体を調べる
Get-Alias -Definition Get-ChildItem # 逆引き → dir, gci, ls の3つ
Get-Help about_Aliases # 公式の解説
初期値は PowerShell 本体に組み込まれています。設定ファイルに書かれているわけではないので、Get-Alias が唯一の確実な一覧です。
| 環境 | 初期のエイリアス数 |
|---|---|
| 5.1 Windows PowerShell | 約 153 個 |
| pwsh 7 PowerShell 7 | 約 135 個 |
Get-Alias の Source 列を見ると出どころが分かります。ほとんどはエンジン組み込みですが、モジュールを読み込むと増えます。「一覧を控えておく」のではなく、必要になったらその場で Get-Alias を叩くのが正しい使い方です。
7 では 19 個のエイリアスが削除されました。特に次の2つは挙動が変わります。
| 別名 | 5.1 での正体 | pwsh 7 | 削除の理由 |
|---|---|---|---|
| curl | Invoke-WebRequest | 本物の curl.exe が動く | 実在のコマンドを隠していた |
| sc | Set-Content | 本物の sc.exe が動く | 同上(サービス制御コマンド) |
| gwmi | Get-WmiObject | 存在しない | コマンド自体が 7 で削除(03 章) |
curl と書いたスクリプトは、5.1 と 7 で全く違う動作をします。Invoke-WebRequest が、7 では Windows 同梱の curl.exe が動きます。引数の書き方が全く違うため、移植したとたんに動かなくなります。これがエイリアスを避けるべき最も具体的な理由です。
(Get-Command Get-ChildItem).Parameters['Recurse'].Aliases
# → s, r
(Get-Command Get-ChildItem).Parameters['LiteralPath'].Aliases
# → PSPath, LP
これは正式に定義された別名なので、前方一致とは違って安定しています。とはいえ読み手に伝わりにくいため、スクリプトでは正式名を使います。
パラメータ名は他と区別できるところまで縮められます。ただし一覧はなく、何に解決されるかが状況で変わります。
Get-ChildItem -Rec # → Recurse に解決される ✓
Get-ChildItem -Fil # → Filter に解決される ✓
Get-ChildItem -F # → エラー
# Parameter cannot be processed because the parameter name 'F' is ambiguous.
# Possible matches include: -Filter -Force.
-File が出てこない点に注目してください。Get-ChildItem には -File も -Filter もあるのに、-Fi は -Filter に解決されます。-File は FileSystem プロバイダの動的パラメータで、-Filter はコマンド自身の静的パラメータのため、扱いが異なるからです。| よく使う別名 | 正式名 |
|---|---|
| ls / dir / gci | Get-ChildItem |
| cat / type / gc | Get-Content |
| % | ForEach-Object |
| ? | Where-Object |
| select | Select-Object |
| gm | Get-Member |
Set-Alias を書けば ls の意味を変えられます。つまり配布したスクリプトが相手の環境で別の動きをする可能性があります。| やりたいこと | コマンド | JavaScript |
|---|---|---|
| 中身を調べる | | Get-Member | —(IDE の補完に相当) |
| 実際の値を全部見る | | Format-List * | console.dir() |
| 絞る | | Where-Object | .filter() |
| 変える | | ForEach-Object | .map() |
| プロパティを選ぶ | | Select-Object | 分割代入 |
| 値そのものを取る | -ExpandProperty | .map(x => x.name) |
| 並べる | | Sort-Object | .sort() |
| まとめる | | Group-Object | .reduce() |
| 数える・集計する | | Measure-Object | .length / .reduce() |
| コマンドを探す | Get-Command | — |
Format-* は行き止まりなので最後にだけ置くGet-Member。型名・プロパティ・メソッドが一度に分かる。型名で検索すれば公式ドキュメントに直行できるGet-Command と Get-Help -Examples で探す。エイリアスは対話専用if や foreach は他言語とほぼ同じですが、関数の戻り値の扱いだけは PowerShell 独特で、経験者ほど引っかかります。「return したつもりの値以外も混ざって返ってくる」問題を正面から扱います。