PowerShellはオブジェクト指向の言語です。コマンドを実行すると、その出力はオブジェクトとして表示されます。オブジェクトは空気から生じるものではありません。開発者が作成し、具体的にはクラスを使用してインスタンス化します。PowerShellのクラスは、それらのオブジェクトの定義またはスキーマを表します。
おそらく、New-Object
のようなコマンドを使用してオブジェクトを作成し、pscustomobject
タイプ アクセラレータを使用する方法には馴染みがあるかもしれませんが、これらは「新しい」オブジェクトではありません。これらのメソッドが生成するオブジェクトの種類は特定のタイプです。PowerShellのクラスはタイプを定義します。
このチュートリアルでは、PowerShellのクラスの基本を学びます。コンストラクタを持つ最初のクラスを作成し、そのクラスからオブジェクトを作成し、プロパティやメソッドでクラスをカスタマイズします。
オブジェクト、プロパティ、メソッドなどの用語については、ブログ投稿「基礎に戻る:PowerShellオブジェクトの理解」を参照してください。
前提条件
最初のクラスとオブジェクトの作成
PowerShellのクラスの詳細を学ぶ前に、まずはシンプルなクラスの作成を進めてみましょう。より高度なトピックについては後で学びます。
最初のクラスを作成すると、関数を作成する感じになります。基本的な構文は同じです。クラスは、関数と同様に定義から作成されます。ただし、最初の行はfunction
ではなく、class
で始まり、オブジェクトの型の名前が続きます。
以下には、studentというクラスの基本的な構造が示されています。
クラスには、そのクラスを説明する属性であるパラメータのようなプロパティがあります。以下の例では、studentというクラスにはFirstName
とLastName
という2つのプロパティがあります。
プロパティを定義する際には、プロパティの値が保持できる具体的な「スキーマ」を設定する型を常に定義するべきです。以下の例では、両方のプロパティを文字列として定義しています。
プロパティの型を常に定義するべきです。後でその理由がわかります。
クラスを定義したら、それからオブジェクトを作成するか、インスタンス化します。クラスからオブジェクトを作成する方法は複数ありますが、よく使われる方法の一つは、クラスを表すタイプアクセラレータ(例:[student]
)を使用し、それに続くクラスに付属するデフォルトのメソッドであるnew()
を使用することです。
タイプアクセラレータのショートカットを使用することは、New-Object
コマンドを使用してオブジェクトを作成することと同じです。
そのクラスからオブジェクトを作成したら、プロパティに値を割り当てます。以下の例では、Tyler
とMuir
をFirstName
とLastName
のプロパティに割り当てています。
オブジェクトを作成し、プロパティに値を割り当てたら、以下のように割り当てた変数を呼び出してオブジェクトを検査します。

クラスからオブジェクトを作成したので、PowerShellの他のオブジェクトと同様に、そのオブジェクトをGet-Member
コマンドレットにパイプで渡して検査します。以下の例では、$student1
変数に保持されているオブジェクトの型はstudentです。
クラス名は常にオブジェクトの型と関連しています。
Get-Member
が4つのメソッドと2つのプロパティを返すことに注目してください。プロパティはおそらく馴染みがあるかもしれませんが、メソッドはそうではないでしょう。PowerShellはデフォルトで特定のメソッドを追加しますが、独自のメソッドを追加したり、デフォルトのメソッドを変更したりすることもできます。

メソッドの作成
前述の例では、オブジェクトにいくつかのデフォルトのメソッドがあることがわかりましたが、おそらく独自のメソッドを作成したいと思うでしょう。そのためには、クラス定義の内部に1つ以上のメソッドを定義する必要があります。
A method definition looks like below with an output type that defines what type of object is returned from this method, the name of the method, and the code to execute inside of a scriptblock.
名前の後ろにあるかっこ()
に注目してください。ここで、メソッドパラメータ(後述)を定義することができます。メソッドパラメータを使用すると、関数パラメータと同様にメソッドの機能を変更することができます。
PowerShell関数を以前に書いたり実行したことがある場合、メソッドのスクリプトブロックは馴染みがあるはずですが、メソッドにはいくつかの特別なルールがあります。
return
は必須です。
PowerShell関数では、オブジェクトを単に関数内の任意の場所に配置するだけで返されます(以下の例を参照)。
ただし、関数とは異なり、メソッドがオブジェクトを返す場合、以下に示すようにreturn
構文を使用する必要があります。
$this
変数の使用
メソッドには、関数とは異なり、$this
変数があります。メソッド内で定義された$this
変数は、現在のオブジェクトのプロパティや他のメソッドを参照します。
以下は、student
クラスに追加されたGetName()
メソッドの例で、FirstName
とLastName
の値を連結して返します。
これで、以下のようにドット表記を使用してGetName()
メソッドを呼び出すことができます。以前にFirstName
とLastName
に値を割り当てた場合、GetName()
はそれらを返します。

メソッドにパラメータを追加する
上記の例では、$student1.GetName()
という行を実行すると、GetName()
メソッドがそのまま呼び出されます。カッコ内では、関数と同様にパラメータを定義することができます。
GetName()
メソッドは、FirstName
とLastName
プロパティに設定された値を返します。しかし、GetName()
が取得できるプロパティを設定するメソッドがあればどうでしょうか?その場合、メソッドのパラメータを定義する必要があります。
メソッドのパラメータは、メソッドのパラメータの括弧内に、コンマで区切られた1つ以上のパラメータを含めることで定義します。以下に示すように。
[void]
という出力タイプに注目してください。メソッドが何も出力しない場合、return
構造を使用する必要はなく、出力タイプを[void]
として定義することで、PowerShellにメソッドが何も返さないことを伝えます。
例えば、SetName()
メソッドがフルネーム(名前と姓)を受け入れる場合、スクリプトブロック内でこの文字列を分割し、それによって名前と姓を割り当てることができます。
SetName()
メソッドをstudent
クラスに挿入すると、以下のようになります。
これで、パラメータとしてフルネームをSetName()
メソッドに渡すことができ、現在のオブジェクトのFirstName
とLastName
プロパティが設定されます。

メソッドのオーバーロード
おそらく、メソッドに異なるパラメータセットを定義したいと思うかもしれません。関数やコマンドレットでパラメータセットが機能する方法と似ていますが、異なるパラメータの「コンテキスト」またはメソッドのシグネチャを定義することができます。
おそらく、FirstName
とLastName
のパラメーターをSetName()
メソッドにフルネームで渡すか、名前を個別に渡すことができるでしょう。選ぶ必要はありません。両方をメソッドのシグネチャで定義することができます。
クラス内で複数のメソッドシグネチャを定義することをオーバーロードと呼びます。
前のセクションの例を再利用して、SetName()
メソッドに1つではなく2つの文字列を受け入れるオーバーロードを作成することができます。1つではなく2つの文字列を渡すと、SetName()
メソッドは最初の文字列をFirstName
とし、2番目の文字列をLastName
とします。そのオーバーロードを使用すると、クラスは以下のようになります。

クラスのコンストラクタ
new()
メソッドまたは他の方法でオブジェクトをインスタンス化するときに、PowerShellにユーザー定義のコードであるコンストラクタを実行するように指示することができます。コンストラクタはメソッドのようなものですが、PowerShellがオブジェクトをインスタンス化する際に自動的に実行されます。
すべてのクラスにはデフォルトのコンストラクタがあります。このデフォルトのコンストラクタはあまり多くのことを行いません。オブジェクトのインスタンス化を担当するだけです。New
メソッドの出力を表示することでデフォルトのコンストラクタを確認できます。以下の行は単一のnew()
メソッドを返します。

コンストラクタのオーバーロード
おそらく、オブジェクトを作成するときに、通常のドット表記ではなく、FirstName
とLastName
のプロパティに値を設定したいと思うかもしれません。その場合、SetName()
を呼び出すパラメータを持つコンストラクタを作成することができます。
以下はstudent
クラスのコンストラクタの例です。コンストラクタには特定の名前や出力タイプの前置詞はありません。コンストラクタは常にクラスと同じ名前を使用します。
コンストラクタ内で既存のメソッドを呼び出すことで、既に書かれた変数の設定を再利用することができます。
そして、student
クラスにそのコンストラクタを追加したのが以下です。
新しいstudent
オブジェクトをインスタンス化し、文字列パラメータを渡すと、オブジェクトのプロパティにはすぐに予想される値が設定されます。

また、[student]::New
でオーバーロードされたコンストラクタを再度確認することができます。この場合、Name
パラメータで定義された新しいオーバーロードされたコンストラクタに注目してください。

デフォルトとオーバーロードされたコンストラクタの定義
これでstudent
クラスにオーバーロードされたコンストラクタがあるので、PowerShellはデフォルトのコンストラクタを上書きします。ただし、パラメータのないコンストラクタを手動で作成することで、デフォルトのコンストラクタを取り戻すことができます。
以下はstudent
クラスのデフォルトコンストラクタの例です。
コンストラクタを再度確認してください。今度は両方のコンストラクタが表示されます。

クラスの継承
すべての他のオブジェクト指向言語と同様に、複数のクラスで階層的にPowerShellクラスを構築することができます。各クラスには「親」クラスと「子」クラスがあり、具体的でない、より一般的な目的から始まり、特化度を高めていきます。
例えば、私たちのstudent
クラスは大学生(子/具体的)を表しています。その大学生は人(親/一般的)です。これらの2つの概念は関連しており、階層を形成しています。
A child class can inherit a parent class which means it can hold all properties and methods (members) defined via a parent class. We know that a person
class may have properties like eye_color
, height
, and weight
and perhaps a method called SetHeight()
.
学生が人である場合、その学生には依然としてそのプロパティとメソッドがあります。すでにperson
クラスに存在するこれらのメンバーをstudent
クラスにも実装すると、重複した作業になります。クラスの継承を定義することで、student
クラスにperson
クラスのすべてのメンバーを自動的に定義することができます。
これが現時点では理解できない場合は、デモを実施する過程で理解できるようになります。
クラスの継承デモ
まず、以前に作成したstudent
クラスのコピーを作成し、コンストラクタを削除してperson
クラスに名前を変更します。以下のようにperson
クラスが表示されるはずです。
A student, of course, has a first name and last name, but the class can be described more accurately by labeling it as a person. When creating a more “generic” class like this, you can create more specific “child” classes from it.
次に、人を表すいくつかのクラスを作成しますが、より具体的な役割を持ちます。たとえば、以下のコードスニペットでは、teacher
クラスとstudent
クラスが作成されます。
現状では、teacher
クラスとstudent
クラスはperson
クラスとは相関関係がなく、person
クラスのクラスメンバーを継承することはできません。それを変更しましょう。
今、teacher
とstudent
クラスをperson
クラスの「子」クラスとして、継承によって階層を定義します。以下のように、クラス名の後にコロン(:
)を追加し、親クラスの名前を続けて記述することで継承を定義できます。
以下は、クラスのスクリプト全体です。
この時点で、teacher
クラスまたはstudent
クラスからオブジェクトをインスタンス化すると、どちらのクラスもperson
クラスと同じメンバーを持ちます。

コンストラクタを継承する
先ほど見たように、クラスメソッドはクラス継承によって継承されますが、コンストラクタは継承されないため、子クラスごとに個別に定義する必要があります。
たとえば、以下のようにperson
クラスにオーバーロードされたコンストラクタを定義したが、teacher
クラスにはコンストラクタを定義していない場合を考えてみます。
次に、teacher
クラスのような子クラスを定義し、パラメータを持たないオブジェクトを作成しようとすると、以下のようにエラーが返されます。なぜなら、teacher
クラス内にパラメータなしのコンストラクタが定義されていないからです。

A constructor is not necessary in a child class if you’re only using it as a template. Alternatively, if you want to use the parent class as its own standalone class and as a parent class you can include constructors. But you have to make sure that the parent class has a constructor that matches the ones in the child classes.
クラスメンバー属性
PowerShellのコマンドパラメータと同様に、クラスにはメンバー属性を持つことができます。これらの属性は、各メンバーの動作を変更します。
非表示メンバー
クラスメンバーを内部でのみ使用し、ユーザーが読み取ったり書き込んだりできないようにする場合は、メンバーを非表示に設定します。たとえば、他のメソッドによってのみ使用されるメソッドがあるかもしれません。そのメソッドをユーザーに公開する必要はありません。
非表示メンバーを定義するには、次に示すようにhidden
属性を使用します。
これにより、Get-Member
を使用してすべてのオブジェクトメンバーを検査すると、そのプロパティは表示されません。

クラスメンバーを非表示に設定することは、値へのアクセスを制限するものではありません。値を表示から非表示にするだけです。機密データを保存するためにプロパティを非表示にするべきではありません。
静的メンバー
以前に説明したように、このチュートリアルでは「インスタンス化」という用語を使用してクラスからオブジェクトを作成することを説明しました。オブジェクトをインスタンス化すると、そのオブジェクトはクラスが定義するすべてのプロパティとメソッドを継承します。しかし、常にそのような場合ばかりではありません。
場合によっては、オブジェクト全体をインスタンス化するオーバーヘッドは不要で、代わりに単一のクラスメンバーを迅速に参照する必要があります。その場合、クラスメンバーを静的に設定できます。
hidden
属性と同様に、次に示すようにstatic
キーワードを使用してクラスメンバーを静的に定義します。
通常のクラスメンバーとは異なり、PowerShellは静的クラスメンバーからプロパティとメソッドを作成しません。クラスメンバーを静的に定義すると、非表示メンバーと同様にGet-Member
を使用しても表示されません。

例えば、student
クラスに大学のクラス名を関連付け、学生が参加できる大学のクラスの最大数を定義したいとします。そのために、Classes
の配列メンバーとMaxClassCount
メンバーを作成します。
ユーザーはほとんどMaxClassCount
メンバーを変更する必要がないため、それを静的に定義することにしました。
最後に、AddClass()
メソッドを作成し、それがMaxClassCount
より少ない場合にのみ、学生のスケジュールにクラスを追加します。
これで、新しいstudent
オブジェクトを作成し、それに多すぎる大学のクラスを割り当てようとすると、PowerShellは最大数の7つだけを割り当てます。

静的メンバーの値はいつでも変更できます。例えば、
MaxClassCount
メンバーを7ではなく5にしたい場合は、[student]::MaxClassCount = 5
というコードを使用して値を変更します。この例では、値の変更は制限を超えるクラスを逆に取り除くわけではありません。
結論
PowerShellのクラスは、スクリプト言語とプログラミング言語の境界を曖昧にします。クラスはオブジェクトの関係を定義し、通常は特殊な関数を書くことしかできないオブジェクトとの対話やフォーマットの方法を追加するための素晴らしい方法です。