PowerShellは強力な言語です。しかし、このスクリプト言語を強力にするのは何でしょうか?それはPowerShellオブジェクトです。これらの魔法のようなオブジェクトとPowerShellの連携方法についてお伝えします。
PowerShellはオブジェクト指向言語でありシェルです。これは、cmdやBashなどの従来のシェルとは異なるものです。これらの従来のシェルはテキスト、つまり文字列に焦点を当てており、依然として有用ですが、機能に制限があります。PowerShellではほとんどのものがオブジェクトです。
この記事では、PowerShellにおけるオブジェクトのキーコンセプトを学びます。記事の最後までには、この知識を実際のスクリプティングに適用する方法を具体的な例コードとビジュアライゼーションを通じて学ぶことができるでしょう。
もしも視覚的な学習者であれば、以下の記事に付属するビデオをご覧ください。
さあ、準備はいいですか?PowerShellにおけるオブジェクトの概念を習得するための思い出に残る体験が待っています!
前提条件
この記事では、実践的なアプローチを通じてPowerShellのオブジェクトについて学びます。コードの例を試す場合、Windows PowerShell 5.1またはPowerShell 6以降のバージョンが必要です。ただし、ここで示す例はWindows 10ビルド1903とWindows PowerShell 5.1で実行されます。
オブジェクトの解剖学を理解する
PowerShellでは、オブジェクトはどこにでも存在します。おそらく「オブジェクトはどのようなものですか?」と自問しているかもしれません。この最初のセクションでは、オブジェクトの構成について概要を把握します。オブジェクトがオブジェクトであるための要素を広く理解した後は、いくつかのコード例に深く入り込むことができます!
Get-Memberを使ってオブジェクトのメンバを発見する
オブジェクトには、さまざまなタイプの情報が関連付けられています。PowerShellでは、この情報はメンバと呼ばれることがあります。オブジェクトのメンバは、オブジェクトに関連するすべての情報を指す一般的な用語です。
オブジェクトの情報(メンバ)を発見するために、Get-Member
コマンドレットを使用することができます。Get-Member
コマンドレットは便利なコマンドであり、PowerShell内の任意のオブジェクトに対して利用可能なプロパティやメソッドなどを見つけることができます。
例えば、Get-Service
コマンドレットで返された特定のオブジェクトのメンバを表示したい場合、以下のようにGet-Service
コマンドの出力をGet-Member
コマンドにパイプで渡すことができます。
Get-Member
コマンドレットに慣れてください。この記事では頻繁に使用することになります。
PowerShellのすべての出力を生成するコマンドは
Get-Member
にパイプできます。ただし、このコマンドレットは自身の出力で出力を上書きするため、パイプラインの非常に最後に配置することを覚えておいてください。
オブジェクトのタイプとクラス
オブジェクト指向プログラミングに詳しくは触れずに、すべてのオブジェクトには「スキーマ」があります。オブジェクトの「スキーマ」とは、オブジェクトを作成するためのブループリントのようなものです。そのブループリントは型と呼ばれます。
PowerShellのすべてのオブジェクトには特定の型があります。各オブジェクトは作成される際のブループリントを持っています。オブジェクトの型はクラスによって定義されます。次の例を考えてみましょう。9は数値、ブルーギルは魚、ラブラドールは犬などです。
オブジェクトは、特定の型を持つクラスのインスタンスです。
このトピックに深く立ち入る必要はありません。ソフトウェア開発者でない限り、この時点ではセマンティクスについてあまり心配する必要はありません。ただし、基本レベルでこの重要な概念を知っておくことは重要です。
プロパティ
オブジェクトについて理解しておくべき最も重要な概念は、プロパティです。プロパティはオブジェクトを説明する属性です。オブジェクトにはさまざまな属性を表す多くの異なるプロパティが付属していることがあります。
オブジェクトに存在するプロパティを発見する最も簡単な方法の1つは、Get-Member
コマンドレットを使用することです。以下の例では、MemberType
パラメータを使用することで、Get-Member
がオブジェクトのみを返すように出力を制限します。また、System.ServiceProcess.ServiceControllerのオブジェクト型も表示されます。

BITS サービスの例を取り上げ、以下のコードを使用してそのオブジェクトのプロパティの具体的な値を確認します。 Get-Member
コマンドレットを使用すると、プロパティ名を検索できますが、値は表示されません。ただし、PowerShell の Select-Object
コマンドレットを使用すると、プロパティの値を調べることができます。
以下の例では、StartType
がオブジェクトのプロパティであることがわかります。返されるオブジェクトにはさまざまなメンバーがありますが、Select-Object
コマンドレットを使用することで、出力をそのプロパティのみに制限しています。

プロパティは、PowerShell で作業する際に最も一般的なオブジェクトのコンポーネントです。
エイリアス
一部のプロパティは、MemberType
が Alias
である場合があります。エイリアスはプロパティ名の別名です。エイリアスは、プロパティにより直感的な名前を与えることがあります。
以下の例では、再び Get-Service
コマンドレットを使用してエイリアスを持つオブジェクトの例を示しています。プロパティ Name
は ServiceName
にエイリアスが付けられ、RequiredServices
は ServicesDependedOn
プロパティにエイリアスが付けられています。

プロパティにエイリアスがある場合、実際のプロパティ名ではなく、エイリアス名を使用してそのプロパティの値を参照することができます。この例では、Name
や RequiredServices
のような説明的な属性の方が直感的で入力しやすいです。
以下に、これらのエイリアスを参照する例を示します。
次の出力が表示されます。コードを短く、きれいで簡潔に保つことに注意してください。エイリアスを使用するかどうかにかかわらず、情報は同じです:

メソッド
プロパティはオブジェクトを作成する要素の一部にすぎません。メソッドも重要な概念です。メソッドはオブジェクト上で実行できるアクションです。プロパティと同様に、Get-Member
コマンドレットを使用してオブジェクトのメソッドを発見できます。
Get-Member
の出力をメソッドのみに制限するには、MemberType
パラメータの値をMethod
に設定します。以下に示すように設定します。

初心者の場合、プロパティと比べてメソッドはずっと少なく使用します。
その他のMemberTypes
プロパティ、メソッド、エイリアスは、オブジェクトが持つことができる唯一のメンバータイプではありません。ただし、これらが最も一般的なメンバータイプであることに間違いありません。
完全性のために、以下にいくつかの他のメンバータイプを示します。
- スクリプトプロパティ – これらはプロパティの値を計算するために使用されます。
- ノートプロパティ – これらは静的なプロパティ名に使用されます。
- プロパティセット – これらは、その名前が示すように、プロパティのセットを含むエイリアスのようなものです。たとえば、
Get-CompInfo
関数のためにSpecs
というカスタムプロパティを作成しました。実際には、Specs
は Cpu、Mem、Hdd、IP というプロパティのサブセットです。プロパティセットの主な目的は、グループのプロパティを連結するための単一のプロパティ名を提供することです。
また、オブジェクトのイベントの概念についても言及することが重要です。イベントはこの記事の範囲外です。
PowerShell でオブジェクトを操作する
オブジェクトの構造について基本的な理解を得たので、さっそくコードを書いてみましょう。
多くの PowerShell コマンドは出力を生成しますが、すべての出力を表示する必要はありません。出力を制限したり操作したりする必要があります。幸いにも、PowerShell にはこれを行うためのいくつかの異なるコマンドがあります。
以下に示すように、Get-Service
コマンドレットを使用してローカルコンピュータ上のすべてのサービスを列挙する例から始めましょう。出力から、多くの異なるサービス(オブジェクト)が返されていることがわかります。

返されたオブジェクトのプロパティを制御する
Get-Service
の例を続けると、各プロパティを表示する必要はないかもしれません。代わりに、Status
と DisplayName
のプロパティだけを表示する必要があります。返されるプロパティを制限するには、Select-Object
コマンドレットを使用します。
Select-Object
コマンドレットは、PowerShellパイプラインに返されるプロパティを「フィルタリング」します。返されるオブジェクトのプロパティを「フィルタリング」するには、Property
パラメータを使用し、返される1つ以上のプロパティをカンマ区切りで指定します。
以下に、Status
とDisplayName
プロパティのみを返す例があります。

オブジェクトのソート
おそらく、サービスとそのステータスを表示するレポートを作成しています。情報の理解を容易にするために、Status
プロパティの値で返されるオブジェクトをソートしたいと思います。そのために、Sort-Object
コマンドレットを使用できます。
Sort-Object
コマンドレットを使用すると、返されたすべてのオブジェクトを収集し、定義した順序で出力することができます。
たとえば、Sort-Object
のProperty
パラメータを使用して、Get-Service
からの入力オブジェクトの1つ以上のプロパティを指定してソートすることができます。PowerShellは各オブジェクトをSort-Object
コマンドレットに渡し、プロパティの値でソートされたオブジェクトを返します。
以下に、Sort-Object
のDescending
スイッチパラメータを使用して、Status
プロパティで降順に返されるすべてのサービスオブジェクトの例があります。

PowerShellのパイプ[
|
]は、必要な場合に使用するいくつかの行継続テクニックの1つです。バッククォートではなく、それを使用してください。
オブジェクトのフィルタリング
おそらく、マシン上のすべてのサービスを表示したくないと考えたかもしれません。代わりに、特定の基準で出力を制限する必要があります。オブジェクトの数をフィルタリングする方法の1つは、Where-Object
コマンドレットを使用することです。
Select-Object
コマンドレットは特定のプロパティの出力を制限しますが、Where-Object
コマンドレットはオブジェクト全体の出力を制限します。
Where-Object
コマンドレットは、SQLのWHERE句と似た機能を持っています。特定の基準に一致するオブジェクトのみを元のソースからフィルタリングして返します。
たとえば、Status
プロパティの値がRunning
であり、DisplayName
プロパティの値がA
で始まるオブジェクトのみを返すようにしたいとしましょう。
次のコードスニペットでは、Where-Object
参照がパイプラインの順序でSelect-Object
とSort-Object
の間に挿入されていることがわかります。各オブジェクトが満たす必要のある条件を持つスクリプトブロック値をFilterScript
パラメータで使用することで、任意のクエリを作成できます。
出力をコンソールに返す方法を操作したい場合は、
Format-Table
コマンドレットをチェックしてください。

返されたオブジェクトの数を数えると平均を出す
Get-Service
コマンドはさまざまなオブジェクトを返します。 Where-Object
コマンドレットを使用して、これらのオブジェクトの一部をフィルタリングしましたが、その数はいくつですか? Measure-Object
コマンドレットをご紹介します。
Measure-Object
コマンドレットは、パイプラインを介して受け取ったオブジェクトの数を数えることができるPowerShellコマンドです。
おそらく、結合されたコマンドが実行されるまでに最終的に返されるオブジェクトの数を知りたいと思うかもしれません。以下のように、最終出力をMeasure-Object
コマンドレットにパイプすることで、返されるオブジェクトの総数を求めることができます。
コマンドの処理が完了すると、この場合は、最初にGet-Service
コマンドで作成された21個のオブジェクトが返されたことがわかります。

おそらく、返される総オブジェクトのみを探しているかもしれません。 Measure-Object
コマンドはCount
プロパティを介して見つかったオブジェクトの総数を返すため、再度Select-Object
コマンドレットを参照することができます。ただし、この場合はCount
プロパティのみを返します。

ループを使用してオブジェクトに対してアクションを実行する
パイプラインを介して各オブジェクトが処理されるたびに、ループで各オブジェクトにアクションを実行することができます。PowerShellにはさまざまな種類のループがありますが、パイプラインの例を使って、ForEach-Object
コマンドレットについて見てみましょう。
ForEach-Object
コマンドレットを使用すると、流れ込む各オブジェクトに対してアクションを実行することができます。この動作は、例を使って説明するのが最適です。
Get-Service
の例を引き続き使用すると、おそらく「Windows」で始まる名前のすべてのサービスを検索し、実行中のWindowsコンピュータ上のすべてのサービスを見つけたいと思うかもしれません。 Where-Object
コマンドレットを使用して、これまでと同じように条件を作成できます。
ただし、今回はオブジェクト全体またはいくつかのプロパティを返すのではなく、各オブジェクトに対して文字列<ServiceName> is runningを返したいと思います。そのためには、コード**Write-Host -ForegroundColor 'Yellow' <ServiceName> "is running"
を使用する必要があります。
これにより、出力を操作し、独自の文字列を作成することができます。そのためには、以下に示すようにForEach-Object
コマンドレットを使用する必要があります。以下のコードでは、Where-Objectを介して返される各オブジェクトに対して、PowerShellがコードWrite-Host -ForegroundColor 'Yellow' $_.DisplayName "is running"
を実行することがわかります。

ForEach-Object
コマンドレットは、さまざまな方法で便利です。例えば、見つかったすべてのサービスオブジェクトを列挙し、プロパティの値に基づいて出力文字列の色や文言を変更したり、停止したサービスの開始などの追加のアクションを実行したりするための追加のロジックを組み込むことができます。
これにより、可能性が広がります!少し考えと計画を立てることで、1つのコマンドを複数のオブジェクトに簡単に実行するスクリプトを作成することができます。
オブジェクトの比較
時には、2つのオブジェクトを見て、プロパティの値を比較する必要があります。
おそらく、ネットワーク上にはほぼ同じシステムが2つあります。ただし、2つのシステムのうち1つのサービスに設定の問題が発生していると予想されます。
これらのシステムがネットワークの異なる場所にあるため、PowerShellセッションで情報を収集するためにリモートコマンドを使用する必要があると結論付けます。お気に入りのエディタを開き、スクリプトを作成します。以下に示すように、このスクリプトは2つの異なるサーバーに接続し、それぞれのサーバー上のすべてのプロセスを列挙します。
これにより、各コンピュータのすべてのプロセスが$ProcA
と$ProcB
の変数に保存されます。これらを比較する必要があります。各セットのプロセスを手動で確認することもできますが、Compare-Object
というコマンドレットを使用して簡単な方法で行うこともできます。
Compare-Object
を使用すると、2つの異なるオブジェクトのプロパティ値を比較できます。このコマンドレットは、各オブジェクトの各プロパティを読み取り、その値を比較し、デフォルトで異なるものと同じものを返します。
Compare-Object
を使用するには、以下に示すように、ReferenceObject
とDifferenceObject
パラメーターを指定し、各オブジェクトをパラメーター値として提供します。
デフォルトでは、Compare-Object
はSideIndicator
プロパティで示されるオブジェクトの違いのみを返します。使用されるサイドインジケータの記号は、比較されるオブジェクトの一致を示すために>
、<
、および=
です。

Compare-Object
を使用して、スイッチパラメーターIncludeEqual
を使うと、同じプロパティを持つオブジェクトを返すことができます。その場合、サイドインジケーターとして==
が表示されます。同様に、ExcludeDifferent
を使用すると、差異を除外することができます。
Compare-Object
コマンドレットは非常に便利なコマンドレットです。もっと詳しく学びたい場合は、オンラインドキュメントを参照してください。
カスタムオブジェクトの操作
オブジェクトの概念と操作方法について十分に理解したので、自分自身のオブジェクトを作成する時間です!
ハッシュテーブルを使用したカスタムオブジェクトの作成
自分自身のオブジェクトを作成する方法の1つは、ハッシュテーブルを使用することです。ハッシュテーブルは、オブジェクトのプロパティを作成するのに必要なキー/値の組み合わせです。
以下の例では、ハッシュテーブルを使用していくつかのキー/値を持つカスタムPowerShellオブジェクトを作成します。ハッシュテーブル$CarHashtable
が定義されたら、PsCustomObject
タイプ アクセラレータを使用します。
pscustomobjectタイプアクセラレータは、pscustomobjectクラスのインスタンスを素早く作成する方法です。この動作はキャストと呼ばれます。
以下のコードスニペットの終わりまでに、$CarObject
という名前のオブジェクトが作成され、それには5つのプロパティが割り当てられます。
また、New-Object
コマンドレットを使用することもできます。同じハッシュテーブルを使用して、pscustomobjectタイプアクセラレータではなく、New-Object
を使用して長い形式で行うこともできます。以下にその例を示します。
$CarObject
が作成されると、以下のように、Get-Service
などの組み込みのPowerShellコマンドレットから取得したかのように、各プロパティを参照することができます。

プロパティの追加と削除
カスタムオブジェクトを作成するだけでなく、追加することもできます。以前に使用したGet-Member
コマンドレットを思い出してください。 Get-Member
には、Add-Member
という相対コマンドがあります。 Add-Member
コマンドレットはメンバーを列挙するのではなく、それらを追加します。
以前に作成したカスタムオブジェクトを例として使用すると、そのオブジェクトにモデル年のプロパティを追加したい場合があるかもしれません。これは、オブジェクトをAdd-Member
にパイプし、次のように指定することで行うことができます:
- この場合、メンバーのタイプ(単純な
NoteProperty
) - プロパティの名前(
Year
) - プロパティの値(
Value
)
以下に例が示されています。
以下にも、他のプロパティと同様に表示されます。

同様の技術を使用して、さまざまなタイプのメンバーを追加することもできます。独自で詳細を調べる場合は、Add-Member
のドキュメントを参照してください。
同様に、オブジェクトからメンバーを削除することも簡単です。 Remove-Member
のコマンドレットは存在しませんが、以下に示すようにオブジェクトのRemove()
メソッドを呼び出すことで実現できます。次のセクションでメソッドについて学びます。
メソッドの簡単な紹介
この記事では、プロパティを扱ってきました。プロパティの値を読み取り、独自のプロパティを作成し、追加および削除しました。ただし、環境にはほとんど変更を加えていません。サーバー上の何も変更していません。では、メソッドで何かアクションを起こしましょう。
メソッドは何らかのアクションを実行します。オブジェクトは情報を格納し、メソッドはアクションを実行します。
たとえば、Stop-Service
コマンドをご存知かもしれません。このコマンドはWindowsサービスを停止します。これを実現するために、Get-Service
からオブジェクトを直接Stop-Service
に送信できます。
以下は、BITSサービスを停止する例があります。この例では、BITSサービスを停止し、その後、停止されていることを確認します。cmdletを使用して2つのアクションを実行しています。サービスを停止し、状態を確認します。
別々のコマンドを実行してGet-Service
を2回実行する代わりに、サービスオブジェクトに組み込まれているメソッドを活用することができます。多くのオブジェクトにはメソッドがあります。この場合はStop-Service
メソッドがあり、2回目のGet-Service
参照は必要ありません。

サービスオブジェクト自体に対してメソッドを呼び出すことで、1つのオブジェクトを使用して停止して更新された状態を取得することができます。以下では、これが実行されているのがわかります。コマンドと同様に、Stop()
メソッドとStart()
メソッドを使用することで、サービスを操作することができます。
サービスの状態が変更された後にStatus
プロパティの値が最新であることを確認するために、Refresh()
メソッドを呼び出すことができます。これは別のGet-Service
コマンドの呼び出しと同様の機能を持っています。
以下の出力が表示されるはずです:

詳細なメソッドについては、「about_Methods ヘルプトピック」を参照してください。
結論
PowerShellではオブジェクトを使用して多くのことができます。この記事はオブジェクトについて学び始めるための入門的な内容でした。オブジェクトの基本的な概念やアクションの取り方、操作方法、作成方法について学びました。さまざまなシナリオをコードサンプルとともに紹介しました。冷静になり、PowerShellを学んでください。お読みいただきありがとうございました!