【保存版】PowerShellのForEach-Object徹底解説|パイプライン処理とスクリプトブロックの使い方

プログラミング・IT

PowerShellのスクリプトでよく見かける「ForEach-Object」。

一見すると「ループ処理?」と思われがちですが、実はこのコマンドレットは、パイプラインと連携する最強の処理ツールなのです。

foreach構文との違いや、{}(スクリプトブロック)での使い方、変数の扱い方など、正しく使うことで処理の効率が大きく向上します。

この記事では、PowerShell初心者〜中級者向けに、ForEach-Objectの基本から応用までを、具体例付きでわかりやすく解説していきます。

スポンサーリンク

ForEach-Objectとは?

ForEach-Objectは、PowerShellのパイプラインで1件ずつ処理を実行するためのコマンドレットです。

パイプライン(|)で前のコマンドから流れてきたオブジェクトを、ひとつずつ取り出して処理します。このコマンドレットにより、大量のデータも効率的に処理することができます。

エイリアス(別名)として、%も使えます:

# この2つは同じ
Get-Process | ForEach-Object { $_.Name }
Get-Process | % { $_.Name }

基本構文とパイプライン処理の流れ

基本構文:

<オブジェクトのリスト> | ForEach-Object { スクリプトブロック }

例:1〜5を出力して2倍にする

1..5 | ForEach-Object { $_ * 2 }

実行結果:

2
4
6
8
10

処理の流れ

  1. 1..5 で、数値1から5の配列が生成される
  2. パイプライン | で ForEach-Object に送られる
  3. ForEach-Object は各数値(1,2,3,4,5)を順番に $_ に格納
  4. { $_ * 2 } のスクリプトブロックが各要素に対して実行される
  5. 結果が順番に出力される

$_の意味と役割

$_は、パイプラインで流れてきた”現在のアイテム”を指す特殊変数です。PowerShell 7からは$PSItemも同じ意味で使えますが、一般的には$_が広く使われています。

例:

"apple","banana","orange" | ForEach-Object { Write-Host "果物は $_ です" }

出力:

果物は apple です
果物は banana です
果物は orange です

オブジェクトのプロパティやメソッドへのアクセス

$_を通じて、オブジェクトのプロパティやメソッドにもアクセスできます:

Get-Process | ForEach-Object { 
    "$($_.Name) は $($_.WorkingSet64 / 1MB) MB のメモリを使用中"
}

ここで$( )は式を評価し、文字列に埋め込むための構文です。

よくある使い方パターン

ファイル名のリストを表示:

Get-ChildItem *.txt | ForEach-Object { $_.Name }

条件付きで処理:

1..10 | ForEach-Object {
    if ($_ % 2 -eq 0) {
        "$_ は偶数です"
    }
}

出力:

2 は偶数です
4 は偶数です
6 は偶数です
8 は偶数です
10 は偶数です

オブジェクトの変更:

Get-Service | ForEach-Object {
    $_.DisplayName = $_.DisplayName.ToUpper()
    $_  # 変更したオブジェクトを出力
}

複数のコマンドを実行:

Get-ChildItem *.log | ForEach-Object {
    Write-Host "処理中: $($_.Name)" -ForegroundColor Green
    $content = Get-Content $_.FullName
    "ファイル「$($_.Name)」には $($content.Count) 行あります"
}

Begin / Process / End の3つのブロック

ForEach-Objectは、3つのスクリプトブロックを指定することもできます。

これにより処理の前後でも特別な操作が可能になります。

Get-Process | ForEach-Object -Begin {
    "開始"
    $total = 0
} -Process {
    "プロセス名: $($_.Name)"
    $total++
} -End {
    "終了 - 合計 $total 個のプロセスがありました"
}
  • -Begin:パイプライン処理の前に1回だけ実行される
  • -Process:オブジェクト1件ごとに実行される(省略時の{ }はこれと同じ)
  • -End:すべての処理が終わった後に1回だけ実行される

応用例:合計値の計算

Get-Process | ForEach-Object -Begin {
    $totalMem = 0
} -Process {
    $totalMem += $_.WorkingSet64
} -End {
    "全プロセスの合計メモリ使用量: $($totalMem / 1MB) MB"
}

foreachとの違いは?

PowerShellにはForEach-Objectとは別に、foreachキーワードも存在します。

この2つは似ていますが、用途が異なります。

# ForEach-Object(パイプラインで使用)
Get-Process | ForEach-Object { $_.Name }

# foreach(スクリプトブロック内でコレクション全体に対して使用)
$processes = Get-Process
foreach ($process in $processes) {
    $process.Name
}

主な違い

機能ForEach-Objectforeach(キーワード)
パイプライン対応◎(得意)×(使えない)
一括処理△(1つずつ)◎(配列全体を一度に取得)
変数$_自分で指定($process など)
処理速度大量データで遅い一般的に高速
メモリ使用少ない(ストリーム処理)多い(全データをメモリに保持)

使い分けポイント

  • パイプラインの中で使いたい → ForEach-Object
  • 配列全体に対して繰り返したい → foreach
  • メモリが限られている → ForEach-Object
  • 処理速度重視 → foreach

応用例:ファイル処理・リモート操作など

複数ファイルを一括リネーム:

Get-ChildItem *.log | ForEach-Object {
    $newName = "Archive_" + $_.Name
    Rename-Item $_ -NewName $newName
    "リネーム: $($_.Name) → $newName"
}

複数サーバーにPing:

"192.168.0.1","8.8.8.8","example.com" | ForEach-Object {
    $result = Test-Connection $_ -Count 1 -Quiet
    [PSCustomObject]@{
        Target = $_
        Online = $result
    }
}

CSVファイルの処理:

Import-Csv users.csv | ForEach-Object {
    # 各ユーザー(行)に対する処理
    $_.Department = $_.Department.ToUpper()
    if ([int]$_.Age -gt 30) {
        $_.IsExperienced = "Yes"
    } else {
        $_.IsExperienced = "No"
    }
    $_  # 修正したオブジェクトを出力
} | Export-Csv users_modified.csv -NoTypeInformation

並列処理(PowerShell 7以降):

# -Parallelパラメータを使用した並列処理
Get-ChildItem -Path C:\Logs\*.log | ForEach-Object -Parallel {
    # 各ファイルを別々のスレッドで処理
    $content = Get-Content $_.FullName
    "ファイル $($_.Name) 処理完了: $($content.Count) 行"
} -ThrottleLimit 5  # 同時に実行するスレッド数を5に制限

まとめ

ForEach-Objectは、PowerShellらしい「パイプライン的思考」での反復処理に非常に役立つコマンドレットです。

ポイントまとめ:

  • $_は現在のオブジェクトを指す特殊変数
  • -Begin, -Process, -Endの3段階で制御可能
  • foreachキーワードとは用途や特性が異なる
  • ファイル処理・ネットワーク操作など実践的な場面で活躍
  • PowerShell 7では並列処理もサポート

ベストプラクティス:

  1. 複雑なスクリプトブロックは見やすく整形する
  2. 大量のオブジェクトを処理する場合はメモリ消費に注意
  3. 必要に応じてForEach-Objectforeachを使い分ける
  4. 処理の進捗状況を表示すると長時間の処理も安心

最初は難しそうに見えても、使い慣れると柔軟で強力なスクリプトが書けるようになります

日常業務や自動化スクリプトに、ぜひ活用してみてください!

PowerShellでの効率的なデータ処理の鍵は、このパイプラインとForEach-Objectの組み合わせにあります。

基本を押さえて、ぜひあなたのスクリプトをパワーアップしましょう!

コメント

タイトルとURLをコピーしました