PowerShell Where-Objectのマスタリング:包括的なガイド

PowerShellのオブジェクトのコレクションでプロパティの値を操作する際には、必要のないものをフィルタリングする方法が必要になることがあります。PowerShellのWhere-Objectコマンドレットの使用方法を知っておくことは、PowerShellのツールボックスにおいて重要なスキルです。

Where-Objectコマンドレットは、オブジェクトをフィルタリングする便利な方法です。このチュートリアルでは、Where-Objectコマンドの構築方法、利用可能なパラメータ、構文、および複数の条件を使った効果的な使用方法について学びます。

前提条件

この記事の前提条件は1つだけです。PowerShellのコマンドと構文について基本的な理解がある必要があります。

この記事のすべての例は、現行の安定版のPowerShell(執筆時点でのバージョン7.1.0)を基にしています。ただし、Windows PowerShell 4.0以降があれば、コマンドは同じように動作します。

PowerShellのWhere-Objectの動作の理解

PowerShellのWhere-Objectコマンドの唯一の目的は、コマンドの出力をフィルタリングして必要な情報のみを返すことです。

要するに、Where-Objectコマンドレットはフィルターです。条件を構築し、TrueまたはFalseを返すことができます。その条件の結果に応じて、コマンドレットは出力を返すかどうかを決定します。

その条件は2つの方法のいずれかで作成できます。「古い」方法では、スクリプトブロックを使用し、「新しい」方法ではパラメータや比較文を使用します。

スクリプトブロックを使用したフィルタ条件の作成

スクリプトブロックは、PowerShellの重要なコンポーネントです。スクリプトブロックは、言語全体で何百もの場所で使用されます。スクリプトブロックは無名の関数です。コードを区分して異なる場所で実行する方法です。スクリプトブロックを使用して、Where-Object のフィルタを作成することができます。

フィルタとしてスクリプトブロックを使用するには、FilterScript パラメータを使用します。このパラメータを使用して、FilterScript パラメータにスクリプトブロックを作成して渡すことができます。

スクリプトブロックがブール値のFalseまたはnull以外の値を返す場合、Trueと見なされます。それ以外の場合はFalseと見なされます。

例えば、現在の起動タイプがAutomaticのWindowsサービスをすべて検索する必要があるとします。まずGet-Serviceを使用して現在のすべてのサービスを取得します。Get-Serviceは、さまざまなプロパティを持つさまざまなサービスオブジェクトを返します。

PowerShell パイプラインを使用すると、オブジェクトを Where-Object コマンドレットにパイプすることができます。その際、FilterScript パラメータにスクリプトブロックを指定することができます。以下のように、各オブジェクトの StartType プロパティが Automatic と等しいかどうかを確認する条件を作成できます。

{$_.StartType -EQ 'Automatic'}

フィルタリングのスクリプトブロックを作成したら、そのスクリプトブロックを FilterScript パラメータに指定します。Where-Object はパイプラインで渡されるすべてのオブジェクトに対してそのスクリプトブロックを実行し、各 StartType プロパティを評価します。プロパティが Automatic と等しい場合、Where-Object はオブジェクトを通過させます。そうでない場合、オブジェクトは破棄されます。

以下に、この方法の簡単な例を示します。

Get-Service | Where-Object -FilterScript {$_.StartType -EQ 'Automatic'}
Script Block construct

多くの人々は、Where-Object コマンドレットで位置パラメータを使用し、FilterScript パラメータ名を含めません。代わりに、スクリプトブロックだけを提供します。例:Where-Object {$_.StartType -eq 'Automatic'}

このような構成は、この特定のシナリオでは機能しますが、スクリプトブロックの中括弧や パイプライン変数 $_ は、コードの可読性を低下させ、経験の浅い PowerShell ユーザーにとっても理解しにくくなります。この可読性の問題が、PowerShell チームがパラメータや比較文を導入した理由です。

比較文

Windows PowerShell 3.0で導入された比較文は、構築方法によりより自然なフローを持っています。前の例と同じシナリオを使用して、比較文の構文を使用して、自動起動タイプのすべてのWindowsサービスを検索しましょう。

Get-Service | Where-Object -Property StartType -EQ 'Automatic'

上記の例では、スクリプトブロックの代わりに、コマンドはオブジェクトのプロパティをPropertyパラメータの値として指定しています。eq演算子もパラメータとして使用され、Automaticの値を渡すことができます。

このようにパラメータを使用することで、スクリプトブロックの必要性が完全になくなります。

A scriptblock is a better choice when defining more complex filtering conditions. The Property parameter may not always be the best choice. If using a scriptblock, just remember to document your code using comments!

次のセクションでは、Where-Objectで使用できる利用可能な比較演算子の種類について学びます。

フィルタリングの基本

パラメータを使用して、Where-Objectは一般的な比較演算子を使用してオブジェクトのコレクションをフィルタリングします。いくつかの例を見てみましょう。

包含演算子

包含演算子は、コレクションを扱う際に便利です。包含演算子を使用すると、コレクションが特定の項目を含んでいるかどうかを条件として定義できます。

例えば、コレクション内の特定のプロパティ値をフィルタリングしたい場合、包含演算子を使用することができます。

PowerShellでは、いくつかの異なる包含演算子が用意されています:

  • -contains / -ccontains – プロパティ値を含むコレクションをフィルタリングします。
  • -notcontains / -cnotcontains – プロパティの値を含まないコレクションをフィルタリングします。
  • -in / -cin – 値がコレクション内にある場合、一致するプロパティの値を返します。
  • -notin / -cnotin – 値がコレクション内にない場合、プロパティの値がない場合はnull/$falseを返します。

大文字と小文字を区別する場合は、-c[operator]で始まる包含演算子を使用してください。

関連記事: PowerShell比較演算子の理解(例による)

たとえば、BITS Windowsサービスの状態を確認したい場合、以下のようにcontainsパラメータ(演算子)を使用してBITSの値を渡すことができます。

Get-Service | Where-Object -Property Name -Contains 'BITS'

そして、以下が予想される結果です:

Where-Object equivalent to Get-Service -ServiceName ‘BITS’

常に左側をフィルタリングすることを忘れないでください!前の例は、Get-Service -ServiceName 'BITS'を実行するのと同じです。

もっと洗練された方法で、StatusRunningではなく、かつStartTypeinという単一の文字列(または配列)Manualのすべてのサービスを検索したい場合、以下のスクリプトブロックを使用して、コマンドはこれらの条件の両方を評価するためにFilterScriptパラメータを使用しています。

関連記事: 基礎に戻る:PowerShellオブジェクトの理解

Get-Service |
	Where-Object {($_.Status -notcontains 'Running') -and ($_.StartType -in 'Manual')}

上記のコマンドを実行すると、停止しているサービスのみが表示され、StartTypeManualのものが表示されます。

More advanced filtering of a collection of objects

コレクション内の多くのプロパティ値を含むフィルタリングには、含有演算子を組み合わせることで効果的に行うことができます。 Get-Serviceが返すプロパティの数を考慮すると、含有演算子と論理演算子を組み合わせることで、これらのプロパティをフィルタリングすることが容易になります。

マッチング演算子

Where-Objectで含有演算子を使用する方法と同様に、マッチング演算子も使用することができます。マッチング演算子を使用すると、文字列内の文字列を一致させることができます。 例えば、'foofoo' -like '*foo*'はTrueを返し、'foofoo' -match 'foo'もTrueを返します。マッチング演算子は、文字列の一致を確認します。文字列内の

PowerShellでは、Where-Object内で使用できるさまざまなマッチング演算子があります。

  • -like / -clike – 文字列がワイルドカードパターンに一致します。
  • -notlike / -cnotlike – 文字列がワイルドカードパターンに一致しません。
  • -match / -cmatch – 文字列が正規表現パターンに一致します。
  • -notmatch / -cnotmatch – 文字列が正規表現パターンに一致しません。

大文字と小文字を区別する場合は、-c[operator]で始まるマッチング演算子を使用してください。

コンテンツオペレーターとほぼ同じ形式で、以下に示すように、マッチングオペレーターを使用することができます。以下の例では、DisplayNameプロパティの値にWindowsが含まれるすべてのサービスを検索しています。

Get-Service | Where-Object { $_.DisplayName -match 'Windows'}
The match operator uses regular expressions to match on certain values.

関連: PowerShellと正規表現の初め方

また、likeオペレーターを使用して、ワイルドカード(*)を使用して任意の文字に一致させるか、?を使用して1つの文字に一致させるなど、一般的なマッチング技術を使用することもできます。

Get-Service | Where-Object {($_.Name -like 'Win*')}

結果は、最初の3文字が「Win」であるサービス名に絞り込まれます。

service names with ‘Win

ワイルドカードを使用することで、サービスのフルネームを知る必要はありません。文字列のいくつかの文字だけが必要です。これらのオペレーターは、フィルタリングをさらに強化するために、論理演算子と組み合わせることもできます。

等値演算子

コンテンツオペレーターや比較オペレーターの使用方法と同様に、Where-Objectで等値演算子も使用できます。等値演算子は、数値の比較が必要な場合に便利です。

例えば、1 -eq 1はTrueですが、1 -gt 2はFalseです。PowerShellにはさまざまな等値演算子があり、Where-Objectのパラメーターとしてまたは条件のスクリプトブロック内で使用できます。

  • -eq / -ceq – 指定した値に等しい値です。
  • -ne / -cne – 指定された値と等しくない値。
  • -gt / -cgt – 指定された値より大きい値。
  • -ge / -cge – 指定された値以上の値。
  • -lt / -clt – 指定された値より小さい値。
  • -le / -cle – 指定された値以下の値。

たとえば、CPUの使用率が2%から10%の間の実行中のプロセスを検索したい場合、Get-ProcessWhere-ObjectのPowerShellコマンドレットを使用することができます。

スクリプトブロックを使用して、2つの条件をand演算子で組み合わせることができます。両方がTrueを返す場合、Where-Objectはパイプラインに渡されたプロセスオブジェクトを返します。少なくとも1つの条件がFalseを返す場合、Where-Objectはオブジェクトを破棄します。

Get-Process | Where-Object {($_.CPU -gt 2.0) -and ($_.CPU -lt 10)}

以下は期待される結果です:

Filtering with greater than and less than

Where-Objectの等値演算子を使用してフィルタリングすることで、システムレポートの作成や値の比較に役立ちます。

次の手順

PowerShellのWhere-Objectコマンドレットを使用して、さまざまなものをフィルタリングする方法についてより詳しく理解したので、他に何ができるでしょうか? 複数の条件や演算子を使用してコレクションをフィルタリングし、プロパティの値を取り除き、出力を好みの形式に整形するために、より複雑なフィルタリングタスクを試してみてください。

Source:
https://adamtheautomator.com/powershell-where-object/