基本に戻る: PowerShell オブジェクトの理解

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コマンドにパイプで渡すことができます。

language-powershell
Get-Service -ServiceName 'BITS' | Get-Member

Get-Memberコマンドレットに慣れてください。この記事では頻繁に使用することになります。

PowerShellのすべての出力を生成するコマンドはGet-Memberにパイプできます。ただし、このコマンドレットは自身の出力で出力を上書きするため、パイプラインの非常に最後に配置することを覚えておいてください。

オブジェクトのタイプとクラス

オブジェクト指向プログラミングに詳しくは触れずに、すべてのオブジェクトには「スキーマ」があります。オブジェクトの「スキーマ」とは、オブジェクトを作成するためのブループリントのようなものです。そのブループリントはと呼ばれます。

PowerShellのすべてのオブジェクトには特定の型があります。各オブジェクトは作成される際のブループリントを持っています。オブジェクトの型はクラスによって定義されます。次の例を考えてみましょう。9は数値ブルーギル、ラブラドールはなどです。

オブジェクトは、特定の型を持つクラスのインスタンスです。

このトピックに深く立ち入る必要はありません。ソフトウェア開発者でない限り、この時点ではセマンティクスについてあまり心配する必要はありません。ただし、基本レベルでこの重要な概念を知っておくことは重要です。

プロパティ

オブジェクトについて理解しておくべき最も重要な概念は、プロパティです。プロパティはオブジェクトを説明する属性です。オブジェクトにはさまざまな属性を表す多くの異なるプロパティが付属していることがあります。

オブジェクトに存在するプロパティを発見する最も簡単な方法の1つは、Get-Memberコマンドレットを使用することです。以下の例では、MemberTypeパラメータを使用することで、Get-Memberがオブジェクトのみを返すように出力を制限します。また、System.ServiceProcess.ServiceControllerのオブジェクト型も表示されます。

PS51> Get-Service | Get-Member -MemberType Property
Get-Service object properties

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

以下の例では、StartType がオブジェクトのプロパティであることがわかります。返されるオブジェクトにはさまざまなメンバーがありますが、Select-Object コマンドレットを使用することで、出力をそのプロパティのみに制限しています。

PS51> Get-Service -ServiceName 'BITS' | Select-Object -Property 'StartType'
BITS service start type

プロパティは、PowerShell で作業する際に最も一般的なオブジェクトのコンポーネントです。

エイリアス

一部のプロパティは、MemberTypeAlias である場合があります。エイリアスはプロパティ名の別名です。エイリアスは、プロパティにより直感的な名前を与えることがあります。

以下の例では、再び Get-Service コマンドレットを使用してエイリアスを持つオブジェクトの例を示しています。プロパティ NameServiceName にエイリアスが付けられ、RequiredServicesServicesDependedOn プロパティにエイリアスが付けられています。

PS51> Get-Service | Get-Member -MemberType 'AliasProperty'
AliasProperty members on service objects

プロパティにエイリアスがある場合、実際のプロパティ名ではなく、エイリアス名を使用してそのプロパティの値を参照することができます。この例では、NameRequiredServices のような説明的な属性の方が直感的で入力しやすいです。

以下に、これらのエイリアスを参照する例を示します。

# 実際のプロパティ名の代わりにAliasPropertyを使用する
PS51> $Svc = Get-Service -ServiceName 'BITS' # 作業中のオブジェクト
PS51> $Svc.Name
BITS
PS51> $Svc.RequiredServices

次の出力が表示されます。コードを短く、きれいで簡潔に保つことに注意してください。エイリアスを使用するかどうかにかかわらず、情報は同じです:

Properties on the BITS service object

メソッド

プロパティはオブジェクトを作成する要素の一部にすぎません。メソッドも重要な概念です。メソッドはオブジェクト上で実行できるアクションです。プロパティと同様に、Get-Memberコマンドレットを使用してオブジェクトのメソッドを発見できます。

Get-Memberの出力をメソッドのみに制限するには、MemberTypeパラメータの値をMethodに設定します。以下に示すように設定します。

PS51> Get-Service | Get-Member -MemberType 'Method'
Methods on service objects

初心者の場合、プロパティと比べてメソッドはずっと少なく使用します。

その他のMemberTypes

プロパティ、メソッド、エイリアスは、オブジェクトが持つことができる唯一のメンバータイプではありません。ただし、これらが最も一般的なメンバータイプであることに間違いありません。

完全性のために、以下にいくつかの他のメンバータイプを示します。

  • スクリプトプロパティ – これらはプロパティの値を計算するために使用されます。
  • ノートプロパティ – これらは静的なプロパティ名に使用されます。
  • プロパティセット – これらは、その名前が示すように、プロパティのセットを含むエイリアスのようなものです。たとえば、Get-CompInfo 関数のために Specs というカスタムプロパティを作成しました。実際には、Specs は Cpu、Mem、Hdd、IP というプロパティのサブセットです。プロパティセットの主な目的は、グループのプロパティを連結するための単一のプロパティ名を提供することです。

また、オブジェクトのイベントの概念についても言及することが重要です。イベントはこの記事の範囲外です。

PowerShell でオブジェクトを操作する

オブジェクトの構造について基本的な理解を得たので、さっそくコードを書いてみましょう。

多くの PowerShell コマンドは出力を生成しますが、すべての出力を表示する必要はありません。出力を制限したり操作したりする必要があります。幸いにも、PowerShell にはこれを行うためのいくつかの異なるコマンドがあります。

以下に示すように、Get-Service コマンドレットを使用してローカルコンピュータ上のすべてのサービスを列挙する例から始めましょう。出力から、多くの異なるサービス(オブジェクト)が返されていることがわかります。

PS51> Get-Service -ServiceName *
Using a wildcard on ServiceName parameter

返されたオブジェクトのプロパティを制御する

Get-Service の例を続けると、各プロパティを表示する必要はないかもしれません。代わりに、StatusDisplayName のプロパティだけを表示する必要があります。返されるプロパティを制限するには、Select-Object コマンドレットを使用します。

Select-Objectコマンドレットは、PowerShellパイプラインに返されるプロパティを「フィルタリング」します。返されるオブジェクトのプロパティを「フィルタリング」するには、Propertyパラメータを使用し、返される1つ以上のプロパティをカンマ区切りで指定します。

以下に、StatusDisplayNameプロパティのみを返す例があります。

PS51> Get-Service -ServiceName * | Select-Object -Property 'Status','DisplayName'
Showing the Status and DisplayName properties

オブジェクトのソート

おそらく、サービスとそのステータスを表示するレポートを作成しています。情報の理解を容易にするために、Statusプロパティの値で返されるオブジェクトをソートしたいと思います。そのために、Sort-Objectコマンドレットを使用できます。

Sort-Objectコマンドレットを使用すると、返されたすべてのオブジェクトを収集し、定義した順序で出力することができます。

たとえば、Sort-ObjectPropertyパラメータを使用して、Get-Serviceからの入力オブジェクトの1つ以上のプロパティを指定してソートすることができます。PowerShellは各オブジェクトをSort-Objectコマンドレットに渡し、プロパティの値でソートされたオブジェクトを返します。

以下に、Sort-ObjectDescendingスイッチパラメータを使用して、Statusプロパティで降順に返されるすべてのサービスオブジェクトの例があります。

PS51> Get-Service -ServiceName * | Select-Object -Property 'Status','DisplayName' |
	Sort-Object -Property 'Status' -Descending
Using Sort-Object to sort service objects by Status in descending order

PowerShellのパイプ[|]は、必要な場合に使用するいくつかの行継続テクニックの1つです。バッククォートではなく、それを使用してください。

オブジェクトのフィルタリング

おそらく、マシン上のすべてのサービスを表示したくないと考えたかもしれません。代わりに、特定の基準で出力を制限する必要があります。オブジェクトの数をフィルタリングする方法の1つは、Where-Objectコマンドレットを使用することです。

Select-Objectコマンドレットは特定のプロパティの出力を制限しますが、Where-Objectコマンドレットはオブジェクト全体の出力を制限します。

Where-Objectコマンドレットは、SQLのWHERE句と似た機能を持っています。特定の基準に一致するオブジェクトのみを元のソースからフィルタリングして返します。

たとえば、Statusプロパティの値がRunningであり、DisplayNameプロパティの値がAで始まるオブジェクトのみを返すようにしたいとしましょう。

次のコードスニペットでは、Where-Object参照がパイプラインの順序でSelect-ObjectSort-Objectの間に挿入されていることがわかります。各オブジェクトが満たす必要のある条件を持つスクリプトブロック値をFilterScriptパラメータで使用することで、任意のクエリを作成できます。

出力をコンソールに返す方法を操作したい場合は、Format-Tableコマンドレットをチェックしてください。

PS51> Get-Service * | Select-Object -Property 'Status','DisplayName' |
	Where-Object -FilterScript {$_.Status -eq 'Running' -and $_.DisplayName -like "Windows*" |
		Sort-Object -Property 'DisplayName' -Descending | Format-Table -AutoSize
Formatting object output

返されたオブジェクトの数を数えると平均を出す

Get-Serviceコマンドはさまざまなオブジェクトを返します。 Where-Objectコマンドレットを使用して、これらのオブジェクトの一部をフィルタリングしましたが、その数はいくつですか? Measure-Objectコマンドレットをご紹介します。

Measure-Objectコマンドレットは、パイプラインを介して受け取ったオブジェクトの数を数えることができるPowerShellコマンドです。

おそらく、結合されたコマンドが実行されるまでに最終的に返されるオブジェクトの数を知りたいと思うかもしれません。以下のように、最終出力をMeasure-Objectコマンドレットにパイプすることで、返されるオブジェクトの総数を求めることができます。

PS51> Get-Service * | Select-Object -Property 'Status','DisplayName' |
	Where-Object {$_.Status -eq 'Running' -and $_.DisplayName -like "Windows*" |
		Sort-Object -Property 'DisplayName' -Descending | Measure-Object

コマンドの処理が完了すると、この場合は、最初にGet-Serviceコマンドで作成された21個のオブジェクトが返されたことがわかります。

Finding the number of objects returned with Measure-Object

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

PS51> Get-Service * | Select-Object -Property 'Status','DisplayName' |
	Where-Object {$_.Status -eq 'Running' -and $_.DisplayName -like "Windows*" |
		Sort-Object -Property 'DisplayName' -Descending |
			Measure-Object |
				# 最初からやり直し、最初にフィルタリングして最後にフォーマット
				Select-Object -Property 'Count'
Only returning the count property

ループを使用してオブジェクトに対してアクションを実行する

パイプラインを介して各オブジェクトが処理されるたびに、ループで各オブジェクトにアクションを実行することができます。PowerShellにはさまざまな種類のループがありますが、パイプラインの例を使って、ForEach-Objectコマンドレットについて見てみましょう。

ForEach-Objectコマンドレットを使用すると、流れ込む各オブジェクトに対してアクションを実行することができます。この動作は、例を使って説明するのが最適です。

Get-Serviceの例を引き続き使用すると、おそらく「Windows」で始まる名前のすべてのサービスを検索し、実行中のWindowsコンピュータ上のすべてのサービスを見つけたいと思うかもしれません。 Where-Objectコマンドレットを使用して、これまでと同じように条件を作成できます。

Where-Object -FilterScript {$_.DisplayName -Like "Windows*" -and $_.Status -eq 'Running'}

ただし、今回はオブジェクト全体またはいくつかのプロパティを返すのではなく、各オブジェクトに対して文字列<ServiceName> is runningを返したいと思います。そのためには、コード**Write-Host -ForegroundColor 'Yellow' <ServiceName> "is running"を使用する必要があります。

これにより、出力を操作し、独自の文字列を作成することができます。そのためには、以下に示すようにForEach-Objectコマンドレットを使用する必要があります。以下のコードでは、Where-Objectを介して返される各オブジェクトに対して、PowerShellがコードWrite-Host -ForegroundColor 'Yellow' $_.DisplayName "is running"を実行することがわかります。

PS51> Get-Service -ServiceName * |
	Where-Object {$_.DisplayName -Like "Windows*" -and $_.Status -eq 'Running'} | 
		Foreach-Object {
			Write-Host -ForegroundColor 'Yellow' $_.DisplayName "is running"
		}
Filtering by property with Where-Object

ForEach-Objectコマンドレットは、さまざまな方法で便利です。例えば、見つかったすべてのサービスオブジェクトを列挙し、プロパティの値に基づいて出力文字列の色や文言を変更したり、停止したサービスの開始などの追加のアクションを実行したりするための追加のロジックを組み込むことができます。

これにより、可能性が広がります!少し考えと計画を立てることで、1つのコマンドを複数のオブジェクトに簡単に実行するスクリプトを作成することができます。

オブジェクトの比較

時には、2つのオブジェクトを見て、プロパティの値を比較する必要があります。

おそらく、ネットワーク上にはほぼ同じシステムが2つあります。ただし、2つのシステムのうち1つのサービスに設定の問題が発生していると予想されます。

これらのシステムがネットワークの異なる場所にあるため、PowerShellセッションで情報を収集するためにリモートコマンドを使用する必要があると結論付けます。お気に入りのエディタを開き、スクリプトを作成します。以下に示すように、このスクリプトは2つの異なるサーバーに接続し、それぞれのサーバー上のすべてのプロセスを列挙します。

$A = 'Svr01a.contoso.com'
$B = 'Svr02b.contoso.com'

$ProcA = Invoke-Command -Computername $A -Scriptblock {Get-Process -Name *}
$ProcB = Invoke-Command -ComputerName $B -Scriptblock {Get-Process -Name *}

これにより、各コンピュータのすべてのプロセスが$ProcA$ProcBの変数に保存されます。これらを比較する必要があります。各セットのプロセスを手動で確認することもできますが、Compare-Objectというコマンドレットを使用して簡単な方法で行うこともできます。

Compare-Objectを使用すると、2つの異なるオブジェクトのプロパティ値を比較できます。このコマンドレットは、各オブジェクトの各プロパティを読み取り、その値を比較し、デフォルトで異なるものと同じものを返します。

Compare-Objectを使用するには、以下に示すように、ReferenceObjectDifferenceObjectパラメーターを指定し、各オブジェクトをパラメーター値として提供します。

Compare-Object -ReferenceObject $ProcA -DifferenceObject $ProcB

デフォルトでは、Compare-ObjectSideIndicatorプロパティで示されるオブジェクトの違いのみを返します。使用されるサイドインジケータの記号は、比較されるオブジェクトの一致を示すために><、および=です。

Running Compare-Object

Compare-Objectを使用して、スイッチパラメーターIncludeEqualを使うと、同じプロパティを持つオブジェクトを返すことができます。その場合、サイドインジケーターとして==が表示されます。同様に、ExcludeDifferentを使用すると、差異を除外することができます。

Compare-Objectコマンドレットは非常に便利なコマンドレットです。もっと詳しく学びたい場合は、オンラインドキュメントを参照してください。

カスタムオブジェクトの操作

オブジェクトの概念と操作方法について十分に理解したので、自分自身のオブジェクトを作成する時間です!

ハッシュテーブルを使用したカスタムオブジェクトの作成

自分自身のオブジェクトを作成する方法の1つは、ハッシュテーブルを使用することです。ハッシュテーブルは、オブジェクトのプロパティを作成するのに必要なキー/値の組み合わせです。

以下の例では、ハッシュテーブルを使用していくつかのキー/値を持つカスタムPowerShellオブジェクトを作成します。ハッシュテーブル$CarHashtableが定義されたら、PsCustomObject タイプ アクセラレータを使用します。

pscustomobjectタイプアクセラレータは、pscustomobjectクラスのインスタンスを素早く作成する方法です。この動作はキャストと呼ばれます。

以下のコードスニペットの終わりまでに、$CarObjectという名前のオブジェクトが作成され、それには5つのプロパティが割り当てられます。

## ハッシュテーブルを定義
$CarHashtable = @{
	Brand      = 'Ford'
	Style      = 'Truck'
	Model      = 'F-150'
	Color      = 'Red'
	Drivetrain = '4x4'
}

## オブジェクトを作成
$CarObject = [PsCustomObject]$CarHashTable

また、New-Objectコマンドレットを使用することもできます。同じハッシュテーブルを使用して、pscustomobjectタイプアクセラレータではなく、New-Objectを使用して長い形式で行うこともできます。以下にその例を示します。

$CarHashtable = @{
	Brand      = 'Ford'
	Style      = 'Truck'
	Model      = 'F-150'
	Color      = 'Red'
	Drivetrain = '4x4'
}
# オブジェクトを作成
$CarObject = New-Object -TypeName PsObject -Properties $CarHashtable

$CarObjectが作成されると、以下のように、Get-Serviceなどの組み込みのPowerShellコマンドレットから取得したかのように、各プロパティを参照することができます。

Inspecting object properties

プロパティの追加と削除

カスタムオブジェクトを作成するだけでなく、追加することもできます。以前に使用したGet-Memberコマンドレットを思い出してください。 Get-Memberには、Add-Memberという相対コマンドがあります。 Add-Memberコマンドレットはメンバーを列挙するのではなく、それらを追加します。

以前に作成したカスタムオブジェクトを例として使用すると、そのオブジェクトにモデル年のプロパティを追加したい場合があるかもしれません。これは、オブジェクトをAdd-Memberにパイプし、次のように指定することで行うことができます:

  • この場合、メンバーのタイプ(単純なNoteProperty
  • プロパティの名前(Year
  • プロパティの値(Value

以下に例が示されています。

PS51> $CarObject | Add-Member -MemberType NoteProperty -Name 'Year' -Value '2010'

以下にも、他のプロパティと同様に表示されます。

Adding and viewing a new property

同様の技術を使用して、さまざまなタイプのメンバーを追加することもできます。独自で詳細を調べる場合は、Add-Memberドキュメントを参照してください。

同様に、オブジェクトからメンバーを削除することも簡単です。 Remove-Memberのコマンドレットは存在しませんが、以下に示すようにオブジェクトのRemove()メソッドを呼び出すことで実現できます。次のセクションでメソッドについて学びます。

PS51> $CarObject.psobject.properties.remove('Drivetrain')

メソッドの簡単な紹介

この記事では、プロパティを扱ってきました。プロパティの値を読み取り、独自のプロパティを作成し、追加および削除しました。ただし、環境にはほとんど変更を加えていません。サーバー上の何も変更していません。では、メソッドで何かアクションを起こしましょう。

メソッドは何らかのアクションを実行します。オブジェクトは情報を格納し、メソッドはアクションを実行します。

たとえば、Stop-Serviceコマンドをご存知かもしれません。このコマンドはWindowsサービスを停止します。これを実現するために、Get-Serviceからオブジェクトを直接Stop-Serviceに送信できます。

以下は、BITSサービスを停止する例があります。この例では、BITSサービスを停止し、その後、停止されていることを確認します。cmdletを使用して2つのアクションを実行しています。サービスを停止し、状態を確認します。

PS51> Get-Service -ServiceName 'BITS' | Stop-Service
PS51> Get-Service -ServiceName 'BITS'

別々のコマンドを実行してGet-Serviceを2回実行する代わりに、サービスオブジェクトに組み込まれているメソッドを活用することができます。多くのオブジェクトにはメソッドがあります。この場合はStop-Serviceメソッドがあり、2回目のGet-Service参照は必要ありません。

Running commands to stop and start a service

サービスオブジェクト自体に対してメソッドを呼び出すことで、1つのオブジェクトを使用して停止して更新された状態を取得することができます。以下では、これが実行されているのがわかります。コマンドと同様に、Stop()メソッドとStart()メソッドを使用することで、サービスを操作することができます。

サービスの状態が変更された後にStatusプロパティの値が最新であることを確認するために、Refresh()メソッドを呼び出すことができます。これは別のGet-Serviceコマンドの呼び出しと同様の機能を持っています。

## ローカルマシン上でBITSを停止します
$Svc = Get-Service -ServiceName 'BITS' #作業しているオブジェクト
$Svc.Stop() #実行しているメソッド/アクション
$Svc.Refresh() #実行しているメソッド/アクション
$Svc.Status #プロパティ

#ローカルマシン上でBITSを開始します
$Svc = Get-Service -ServiceName 'BITS' #作業しているオブジェクト
$Svc.Start() #実行しているメソッド/アクション
$Svc.Refresh() #実行しているメソッド/アクション
$Svc.Status #プロパティ

以下の出力が表示されるはずです:

Executing methods on the service object

詳細なメソッドについては、「about_Methods ヘルプトピック」を参照してください。

結論

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

Source:
https://adamtheautomator.com/powershell-objects/