PowerShellは、システム管理やタスク自動化において中心的な役割を果たすスクリプト言語として、年々その重要性を増しています。
大量のサーバー設定やユーザー情報、ログファイルなどを効率よく処理するためには、繰り返し処理(ループ)を適切に使い分けるスキルが不可欠です。
本記事では、PowerShellで頻繁に使用される「foreach」と「for」の2つのステートメントに焦点を当て、それぞれの特徴や実戦的な活用方法について詳しく解説します。
PowerShellにおける繰り返し処理の基本
プログラミングやスクリプト作成において、同じような処理を何度も実行したい場合に用いられるのが「繰り返し処理」です。
PowerShellでは、データの集合である「コレクション」や「配列」を扱う機会が非常に多いため、これらの要素を一つずつ取り出して操作する技術は必須と言えます。
繰り返し処理を正しく実装することで、コードの記述量を劇的に減らし、メンテナンス性を向上させることが可能です。
なぜ繰り返し処理が必要なのか
例えば、100個のファイル名を一括で変更する場合や、複数のサービスの状態を順番に確認する場合、手動でコマンドを100回入力するのは現実的ではありません。
繰り返し処理を使えば、数行のコードを記述するだけで、対象が10個であろうと10,000個であろうと、コンピューターが正確に処理を完遂してくれます。
自動化の最大のメリットは、単純作業からの解放とヒューマンエラーの削減にあります。
代表的な2つの構文:foreachとfor
PowerShellで繰り返し処理を行う際、最も一般的に使われるのがforeachステートメントとforステートメントです。
foreachは「中身のすべてに対して処理を行う」という直感的な記述が可能であり、一方でforは「回数を指定して処理を行う」といった制御に適しています。
これら2つの構文を使い分けることが、効率的なスクリプト作成への第一歩となります。
foreachステートメントの使い方と特徴
foreachステートメントは、配列やコレクション内の各要素に対して順番に処理を実行するための構文です。
PowerShellにおいて最も利用頻度が高く、オブジェクト指向の特性を活かしやすいのが特徴です。
基本的な構文と動作
foreachの基本的な書き方は非常にシンプルで、可読性が高いという利点があります。
# 数値の配列を定義します
$numbers = 1, 2, 3, 4, 5
# foreachを使用して各要素を表示します
foreach ($num in $numbers) {
Write-Host "現在の数値は $num です。"
}
現在の数値は 1 です。
現在の数値は 2 です。
現在の数値は 3 です。
現在の数値は 4 です。
現在の数値は 5 です。
この例では、$numbers配列の要素が一つずつ$numという変数に代入され、波括弧内の処理が実行されます。
コレクションの反復処理に最適な理由
foreachが優れている点は、「要素の数を事前に把握していなくても良い」という点にあります。
Get-ChildItemコマンドレットで取得したファイル一覧など、実行時まで数が確定しないデータを扱う際に非常に強力です。
また、インデックス(添え字)を意識する必要がないため、境界値エラー(範囲外参照)を起こす心配がありません。
パイプライン版ForEach-Objectとの違い
PowerShellには、foreachステートメントのほかに、ForEach-Objectというコマンドレット(またはエイリアスの%)が存在します。
これらは似ていますが、動作原理が根本的に異なります。
foreachステートメントは、最初にすべてのデータをメモリに読み込んでから処理を開始するため、高速ですがメモリ消費量が多くなる傾向があります。
一方、ForEach-Objectはパイプラインから渡されるデータを一つずつ逐次処理するため、メモリ効率が良いという特徴があります。
大量のデータを扱う場合はパイプラインを、処理速度を優先する場合はステートメントを選択するのが一般的です。
forステートメントの使い方と特徴
forステートメントは、指定した条件が満たされている間、処理を繰り返すための構文です。
他のプログラミング言語(C言語やJavaなど)を経験したことがある方には、馴染み深い形式でしょう。
インデックスを活用する基本構文
for文では、カウンター変数を使用して、特定の回数だけ処理を実行させます。
# 0から4までカウントアップする例
for ($i = 0; $i -lt 5; $i++) {
Write-Host "ループ回数: $i"
}
ループ回数: 0
ループ回数: 1
ループ回数: 2
ループ回数: 3
ループ回数: 4
この構文は、「初期化」「継続条件」「増分処理」の3つの要素で構成されています。
配列操作や数値計算でのメリット
forステートメントが威力を発揮するのは、インデックス番号を直接操作したい場合です。
例えば、「配列の要素を一つ飛ばしで処理したい」ときや、「現在の要素と次の要素を比較したい」ときなどに便利です。
$fruits = "りんご", "みかん", "バナナ", "ぶどう"
# 2つ飛ばしで要素を表示する
for ($i = 0; $i -lt $fruits.Length; $i += 2) {
Write-Host "取得した果物: $($fruits[$i])"
}
取得した果物: りんご
取得した果物: バナナ
このように、「柔軟なステップ制御」を行いたい場合には、for文が最適です。
foreachとforの使い分けガイド
実務でどちらを使うべきか迷った際のために、主要な比較項目を整理しました。
| 項目 | foreach ステートメント | for ステートメント |
|---|---|---|
| 主な用途 | コレクション内の全要素の処理 | 回数指定、インデックス操作 |
| 可読性 | 非常に高い(直感的) | 標準的(条件式が複雑になりがち) |
| 柔軟性 | 低い(順番に全て処理) | 高い(逆順やスキップが可能) |
| 速度 | 高速 | 高速 |
どちらを使うべきか判断する基準
基本的には、「コレクションの全要素を処理するなら foreach」を第一選択にしてください。
コードが短くなり、他人が読んだ際にも意図が伝わりやすくなります。
逆に、特定のインデックス範囲だけを処理したい場合や、ループの途中でカウンター変数を変更したい特殊なケースでのみ、forを検討するのがベストプラクティスです。
パフォーマンス(処理速度)の観点
PowerShell Core(7.x以降)において、foreachとforの速度差は多くの場合で無視できるレベルです。
しかし、数万件規模の配列をループさせる際、パイプライン版のForEach-Objectは、オーバーヘッドのためにステートメント版よりも遅くなる傾向があります。
速度がシビアに求められるスクリプトでは、パイプラインではなくforeach ($item in $collection)形式を採用することをお勧めします。
実戦で役立つ応用テクニック
基礎を理解したところで、現場で役立つより高度な繰り返し処理の手法を紹介します。
continueとbreakによるループ制御
ループの途中で特定の処理をスキップしたり、ループ自体を終了させたりするために、continueとbreakを使用します。
- continue: 現在の反復処理を中断し、次の要素の処理へ進みます。
- break: ループ全体の処理をその場で強制終了します。
foreach ($num in 1..5) {
if ($num -eq 3) {
# 3の場合はスキップ
continue
}
Write-Host "数値: $num"
}
数値: 1
数値: 2
数値: 4
数値: 5
これにより、複雑な条件分岐を含むループでも、コードのネストを深くせずに記述できます。
多次元配列や複雑なオブジェクトの処理
PowerShellでは、CSVファイルやActive Directoryのユーザーオブジェクトなど、複数のプロパティを持つデータを頻繁に扱います。
foreach内でオブジェクトのプロパティにアクセスすることで、高度なフィルタリングやデータ加工が可能になります。
# オブジェクトのリストを想定
$users = @(
[PSCustomObject]@{Name="Tanaka"; Age=25},
[PSCustomObject]@{Name="Sato"; Age=32},
[PSCustomObject]@{Name="Suzuki"; Age=19}
)
foreach ($user in $users) {
if ($user.Age -ge 20) {
Write-Host "$($user.Name) さんは成人です。"
}
}
2026年現在のモダンな記述スタイル(Parallel処理)
現代のPowerShell環境(PowerShell 7以降)では、マルチコアCPUを有効活用するための並列処理が身近になっています。
ForEach-Object -Parallelを使用すると、ループ内の処理を並列で実行し、大幅な時間短縮が期待できます。
# 複数のWebサイトへの疎通確認を並列で実行
$sites = "google.com", "microsoft.com", "github.com"
$sites | ForEach-Object -Parallel {
Test-Connection $_ -Count 1
} -ThrottleLimit 3
ネットワーク通信やファイルI/Oなど、待ち時間が発生する処理を繰り返す場合には非常に効果的です。
エラーハンドリングとトラブルシューティング
繰り返し処理の中でエラーが発生すると、スクリプト全体が停止してしまうことがあります。
これを防ぐためには、ループの内部にtry...catchブロックを配置することが重要です。
特定の要素でエラーが起きても、他の要素の処理を継続できるように設計するのが実戦的なスクリプトです。
foreach ($file in Get-ChildItem "C:\Logs\*.log") {
try {
# ファイルの読み取りを試行
$content = Get-Content $file.FullName -ErrorAction Stop
Write-Host "$($file.Name) を読み込みました。"
}
catch {
Write-Error "$($file.Name) の読み込みに失敗しました: $($_.Exception.Message)"
}
}
このように記述することで、一つのファイルがロックされていても、残りのファイルの処理を止めることなく最後まで実行できます。
まとめ
PowerShellにおける繰り返し処理は、業務自動化の核となる技術です。
基本となるforeachはコレクションの全件処理に、forはインデックスによる細かな制御に適しています。
これらを用途に合わせて正しく選択することで、コードの可読性と効率を両立させることができます。
また、大規模なデータを扱う際にはパイプラインの特性や並列処理(-Parallel)の活用も検討してみてください。
まずはシンプルな配列操作から始め、徐々にtry...catchを用いたエラーハンドリングなどを組み込んでいくことで、より堅牢なスクリプトが作成できるようになります。
本記事の内容を参考に、ぜひ日々のスクリプト作成に役立ててください。
