最初にPowerShellスクリプトの作成を始めると、コレクションから複数のアイテムを処理する必要がある場面に遭遇することがあります。その時には、PowerShellのforeachループについて深く掘り下げて学ぶ必要があります。
ほとんどのプログラミング言語には、ループと呼ばれる構造がありますが、PowerShellも例外ではありません。PowerShellで最も人気のあるループの一つは、foreachループです。基本的に、foreachループはコレクション全体を読み込み、それぞれのアイテムごとにコードを実行します。
PowerShellのforeachループについて、初心者にとって最も混乱するのは、利用可能なオプションの多さです。コレクション内の各アイテムを処理するための方法は一つだけではありません。実際には、3つの方法があります!
本記事では、各タイプのforeachループの動作方法と、どのタイプを使うべきかについて学びます。この記事を読み終える頃には、各タイプのforeachループについて理解が深まるでしょう。
PowerShellのForEachループの基本
PowerShellでよく使用するループの一つは、foreach
ループです。foreach
ループは、オブジェクトのセット(イテレーション)を読み込み、最後のオブジェクトで処理が完了するまで続きます。読み込まれるオブジェクトのコレクションは通常、配列やハッシュテーブルで表されます。
注意:イテレーションという用語は、ループの各実行を指すプログラミング用語です。ループが1サイクル完了するたびに、これはイテレーションと呼ばれます。オブジェクトのセット上でループを実行する行為は、一般にセットをイテレートすると言われます。
おそらく、ファイルシステム上に広がるいくつかのフォルダにテキストファイルを作成する必要があるかもしれません。たとえば、フォルダのパスはC:\Folder
、C:\Program Files\Folder2
、C:\Folder3
とします。ループを使用しない場合、Add-Content
コマンドレットを3回参照する必要があります。
これらのコマンド参照の唯一の違いは何ですか?それはPath
の値です。各参照間で変化するのはPath
の値だけです。
コードを多重化しています。入力するための時間を無駄にしており、将来の問題を引き起こす可能性があります。代わりに、変化しているすべてのアイテムを含む「セット」を作成するべきです。この例では、配列を使用します。
これで各パスが単一の「セット」または配列に格納されました。これで、各要素を繰り返し処理するためのループを使用できる状態になりました。ただし、その前に、PowerShellを初めて使う人々が通常つまづくトピックについて説明するのが良いタイミングです。他の種類のループとは異なり、foreach
ループは同じものではありません。
厳密に言えば、PowerShellには3つの異なるforeach
ループのタイプがあります。使用方法は似ていますが、違いを理解することが重要です。
foreachステートメント
最初のタイプのforeach
ループはステートメントです。 foreach
は、コマンドレットでも関数でもない内部のPowerShellのキーワードです。 foreach
ステートメントは常にforeach ($i in $array)
の形式で使用されます。
上記の例では、$i
変数はイテレータを表し、$path
の各要素を反復処理する際の各アイテムの値を表します。
イテレータ変数の名前は
$i
である必要はありません。変数名は任意のものにすることができます。
以下の例では、Add-Content
の参照を繰り返すという同じタスクを次のように実行することができます:
foreach
ステートメントは、ForEach-Object
コマンドレットを使用するよりも高速な代替手段であることが知られています。
ForEach-Objectコマンドレット
foreach
はステートメントであり、単一の方法で使用することしかできませんが、ForEach-Object
はパラメータを持つコマンドレットであり、さまざまな方法で使用することができます。 foreach
ステートメントと同様に、ForEach-Object
コマンドレットは、オブジェクトのセットを反復処理します。ただし、この場合は、そのオブジェクトのセットと各オブジェクトに対して実行するアクションをパラメータとして渡します。
注意:混乱を招くため、
ForEach-Object
コマンドレットにはforeach
というエイリアスがあります。用語「foreach」がどのように呼ばれるかによって、foreach
ステートメントが実行されるか、ForEach-Object
が実行されます。A good way to differentiate these situations is to notice if the term “foreach” is followed by
($someVariable in $someSet)
. Otherwise, in any other context, the code author is probably using the alias forForEach-Object
.
foreach()
メソッド
最新のPowerShell v4で導入されたforeach
ループの一つは、foreach()
メソッドと呼ばれます。このメソッドは、配列やコレクションオブジェクトに存在します。foreach()
メソッドには、他のメソッドと同様に、各イテレーションで実行するアクションを含む標準のスクリプトブロックパラメータがあります。
foreach()
メソッドの最も重要な違いは、内部での動作方法です。
大規模なデータセットの場合、
foreach()
メソッドを使用するとかなり高速で、明らかな差があります。可能な場合は、他の2つの方法よりもこのメソッドを使用することが推奨されます。
ミニプロジェクト:サーバー名のセットに対するループ処理
PowerShellでループを使用する最も一般的な用途の一つは、あるソースからサーバー名のセットを読み取り、それぞれのサーバーに対して何らかのアクションを実行することです。最初のミニプロジェクトでは、テキストファイルから1行ずつサーバー名を読み取り、各サーバーにpingを実行してオンラインかどうかを判定するコードを作成します。

このワークフローでは、どのタイプのループが最適だと思いますか?
「セット」という言葉を使用したことに注目してください。「サーバーのセット」ということです。すでに指定された数のサーバー名があり、それぞれに何らかのアクションを実行したいと考えています。これは、最も一般的に使用されるPowerShellのループであるforeach
ループを試す絶好の機会です。
最初のタスクは、コード内でサーバー名のセットを作成することです。最も一般的な方法は、配列を作成することです。幸運なことに、Get-Content
はデフォルトで、テキストファイルの各行を要素とする配列を返します。
まず、すべてのサーバー名の配列を作成し、$servers
と呼びます。
配列が作成されたので、各サーバーがオンラインかどうかを確認する必要があります。サーバーの接続をテストするための素晴らしいコマンドレットがあります。それはTest-Connection
と呼ばれます。このコマンドレットは、コンピューターのオンライン/オフラインを確認するために、いくつかの接続テストを実行します。
Test-Connection
をforeach
ループの中で実行し、各ファイル行を読み取ることで、$server
変数で表される各サーバー名をTest-Connection
に渡すことができます。これがPowerShellでテキストファイルをループする方法です。以下に、これがどのように機能するかの例を示します。
foreach
ループが実行されると、以下のようになります。

これで、サーバー名が記載されたテキストファイルの接続を正常にテストしました!この時点で、コードを変更することなく、テキストファイル内のサーバー名を自由に追加または削除することができます。
私たちが説いていることを実践することに成功しました、DRYメソッドです。
ForEach PowerShellの例
ForEachループの使い方のいくつかの例を見てみましょう。これらは、コンセプトを示す現実世界のユースケースに基づいており、必要に応じて変更できます。
例1:ForEachステートメントを使用してディレクトリ内の各サブフォルダにファイルを作成する
この例では、PowerShellのforeachフォルダー内の共通の使用方法を示しています。
仮に、C:\ARCHIVE_VOLUMES
フォルダ内に10個のサブフォルダがあるとします。各サブフォルダは、毎日バックアップされるアーカイブボリュームを表します。バックアップが完了すると、BackupState.txt
という名前のファイルが作成され、バックアップされた日付が含まれます。
以下に、これがどのように見えるかの例を示します。

以下のスクリプトは、次の3つのアクションを実行します:
C:\ARCHIVE_VOLUMES
内のすべてのサブフォルダのリストを取得する- 各フォルダをループ処理する
- 現在の日付と時刻の値を含む
BackupState.txt
という名前のテキストファイルを作成する
以下の例では、foreach
ステートメントを使用しています。
Get-ChildItem
コマンドレットを使用して、サブフォルダの各内部にファイルが作成または更新されたかどうかを確認できます。
以下のスクリーンショットは、スクリプトの出力を示しており、それぞれのサブディレクトリで見つかったすべてのBackupState.txt
ファイルを表示しています。

例2:サブディレクトリの各テキストファイルの内容を読み取る
次に、PowerShellのforeachファイルを使用してディレクトリ内の各BackupState.txt
ファイルを読み取るために、以下のスクリプトは、例1で作成された各BackupState.txt
ファイルを読み込みます。
- 各サブディレクトリ内のすべての
BackupState.txt
ファイルを再帰的に検索します。 foreach
ステートメントを使用して、各テキストファイルを読み取り、「最終バックアップ時刻」の値を取得します。- 結果を画面に表示します。
このスクリプトをPowerShellセッションで実行すると、以下のスクリーンショットと似たような出力が表示されます。これにより、PowerShellがファイルをループし、内容を読み取り、出力を表示することが示されます。

例3:ForEach-Object CmdLetを使用してサービスを取得し、起動する
システム管理者は、しばしばサービスの状態を取得し、失敗したサービスを修復するための手動または自動のワークフローをトリガーする必要があります。次に、ForEach-Object
cmdletを使用したサンプルスクリプトを見てみましょう。
この例では、以下のスクリプトが以下の操作を行います:
- 自動起動に設定されているが現在実行されていないサービスのリストを取得します。
- 次に、リスト内のアイテムは
ForEach-Object
cmdletにパイプされ、各サービスの起動を試みます。 - A message of either success or failed is displayed depending on the result of the
Start-Service
command.
スクリプトを実行すると、以下のスクリーンショットのような出力が表示されます。各サービスには起動コマンドが発行されていることがわかります。いくつかは正常に起動されましたが、いくつかは起動に失敗しました。

例4: ForEach()
メソッドを使用してCSVからデータを読み取る
CSVファイルからデータを使用するのはシステム管理者の間で一般的です。CSVファイル内のレコードを使用すると、Import-CSV
とForEach
の組み合わせを使用して一括操作を簡単に実行できます。Active Directoryで複数のユーザーを作成するために、この組み合わせは一般的に使用されます。
次の例では、2つの列(FirstnameとLastname)を持つCSVファイルがあることを前提としています。このCSVファイルには作成する新しいユーザーの名前が記載されているはずです。CSVファイルは以下のようになります。
次のスクリプトブロックに移りましょう。まず、Import-CSV
コマンドレットにコンテンツのパスを渡してCSVファイルをインポートします。その後、foreach()
メソッドを使用して名前をループ処理し、Active Directoryに新しいユーザーを作成します。
実行すると、CSVファイルの各行に対してADユーザーが作成されます!
概要
PowerShellのforeachループのロジックは、他のプログラミング言語とは変わりません。ただし、使用方法や特定のタスクに対してどのバリエーションのforeachループを選択するかは異なります。
この記事では、PowerShellで使用できるforeachループの異なるタイプと、どのタイプを使用するかについて学びました。また、さまざまなサンプルシナリオを使用して3つのforeachループのタイプを実際に見てきました。