Hey, Scripting Guy!

Hey, Scripting Guy!

TechNet コラムへようこそ。このコラムでは、よく寄せられるシステム管理スクリプトに関する質問に Scripting Guys がお答えします。システム管理スクリプトについて質問がある場合は、scripter@microsoft.com (英語のみ) までお送りください。すべての質問に回答することはできないかもしれませんが、可能な限り対応いたします。

Hey, Scripting Guy! アーカイブも忘れずにチェックしてください。

今日の質問 : Windows PowerShell を使用してリモート コンピュータ上のサービスを起動する方法はありますか


Windows PowerShell を使用してリモート コンピュータ上のサービスを起動する方法はありますか

Q

Scripting Guy さん、よろしくお願いします。Windows PowerShell を使用してリモート コンピュータ上のサービスを起動する方法はありますか。

-- NA

ATechNet Script Center

NA さん、こんにちは。数年前、フランシス・フクヤマという教授が『歴史の終わり』(The End of History and the Last of Man) という本を書きました。この本では、冷戦が終わった今、興味深くエキサイティングなことは二度と起こらないだろうと (いうようなことを) 述べています。Scripting Guy はフクヤマ教授に何と言うべきでしょうか。ただ一言です。はあ!

あらゆる人々の中で、Scripting Guy が現代の第一級の知識人の 1 人に進んで意義を唱えるのはなぜでしょう。まず、フランシス・フクヤマ氏がこのコラムを頻繁に読んでいない方に賭けます。しかし、もっと重要なことは、興味深くエキサイティングなことはまだ "起きる" ということの証拠を私たちが握っているという事実です。なにしろ、私たちは Hey, Scripting Guy! コラム 500 回記念 (英語) の真っ只中にいるだけでなく、はじめて Windows PowerShell の質問に答えているのですから。フランシス・フクヤマ教授、この点を考えてみてください。

注 : Windows PowerShell について聞いたことがないとおっしゃいますか。Windows PowerShell で何を行えるかもご存知ではないのですか。それでしたら、新しいスクリプト センター シリーズ「Windows PowerShell の機能」を参照してください。

NA さん、次のように Start-Service cmdlet を使用してリモート コンピュータ上のサービスを再起動しようとしているのですね (教育的な目的で、スクリプトを少し簡略化しました)。

Get-WmiObject -computer atl-fs-01 Win32_Service -Filter "Name='Alerter'" | Start-Service

つまり、コンピュータ atl-fs-01 上の Alerter サービスに接続し、そのオブジェクトを Start-Service cmdlet に "パイプ" しようとしているのですね。あなたが書いているように、リモート コンピュータ上の Alerter サービスには問題なく接続できます。しかし、Start-Service を呼び出すと、Start-Service cmdlet がローカル コンピュータで正常に動作していてもコマンドが失敗します。

それがここでの問題です。Windows PowerShell は、興味深く強力な新しいテクノロジですが、(このコラムを書いている時点では) まだベータ版であるため、製品のリリース バージョンで期待される機能の一部がまだ準備されていません。残念ながら、このような機能の 1 つに、リモート コンピュータに対して cmdlet を実行する機能があります。"いつか" は、次のようなコマンドを使用してリモート コンピュータ上のサービスを開始できるようになるはずです。

Start-Service alerter –computer atl-fs-01

ただし日を改めて説明します。

では、リモート コンピュータ上の Alerter サービスに関する情報を取得できるのはなぜでしょう。そうです。Get-WMIObject cmdlet は例外なのです。これは WMI に追加されているため、Get-WMIObject は WMI でできることなら何でもできます。そのため、Get-WMIObject はリモート コンピュータに対して動作するのです。Windows PowerShell cmdlet に頼って接続し、タスクを実行するのではなく、Get-WMIObject は WMI を使用してこの作業を行います。

一般的な経験則としては、WMI のプロパティとメソッドを使用していれば、Get-WMIObject を使用してリモート コンピュータを処理できます。そうでない場合、Windows PowerShell を使用するときはローカル コンピュータに対する操作に限定されます (はい。リモート コンピュータ機能が Windows PowerShell にいつ追加されるのかは定かでありませんが、この制限は将来変更されます)。

これは、Get-WMIObject と標準 WMI メソッド (たとえば、StartService など) を使用してリモート コンピュータ上のサービスを起動できることを意味するのでしょうか。実際、ここでは少々工夫が必要ですが、起動できます。リモート コンピュータ上のサービスを起動する Windows PowerShell スクリプト/コマンドをお見せしてから、その動作について説明します。

(Get-WmiObject -computer atl-fs-01 Win32_Service -Filter "Name='Alerter'").InvokeMethod("StartService",$null)

このコマンドには実際に 2 つの部分があります。Alerter サービスに接続する部分と、サービスを起動する部分です。パート 1 から開始しましょう。これは、WMI サービスに接続する部分です。

(Get-WmiObject -computer atl-fs-01 Win32_Service -Filter "Name='Alerter'")

ここでは、コンピュータ atl-fs-01 上の WMI サービスに接続し、Name プロパティが Alerter と等しい Win32_Service クラスのすべてのインスタンスを取得しています。これは、次の VBScript コードと同等です。

Set objWMIService = GetObject("winmgmts:\\atl-fs-01")

Set colServiceList = objWMIService.ExecQuery _
    ("Select * From Win32_Service Where Name='Alerter'")

Windows PowerShell コマンドでは ExecQuery メソッドを呼び出していないことに注意してください。代わりに、–Filter パラメータを使用しています。このパラメータは、Name が Alerter と等しいサービスのみを返すよう指定します。

良い質問です。Get-WMIObject ステートメントをかっこで囲んだのはなぜでしょうか。それは、Windows PowerShell が返されたオブジェクトを "オブジェクト" として、つまり、メソッドを呼び出すことのできる対象として扱うようにするためです。そして、オブジェクトを入手した後で、VBScript を使用する場合と同様に、閉じるかっこの後にドット (.) を付けることができます。この Windows PowerShell コマンドでは、次のようになります。

(Get-WmiObject -computer atl-fs-01 Win32_Service -Filter "Name='Alerter'").InvokeMethod("StartService",$null)

一方 VBScript では、次のようになります (通常は For Each ループの中で行います)。

objItem.StartService

おわかりでしょうか。よろしいですか。ここからが少し複雑になります。ご覧のとおり、コマンドの後半では、StartService メソッドを直接呼び出しません。代わりに、次のようにします。

InvokeMethod("StartService",$null)

これはどうなっているのでしょう。おわかりのように、Get-WMIObject を呼び出すときにオブジェクトを取得しています。ただし、これは .NET Framework オブジェクト (具体的には System.Management.ManagementObject#root\cimv2\Win32_Service オブジェクト) です。ある単純な理由で、StartService メソッドを呼び出すことができません。それは、この種のオブジェクトが StartService メソッドを持たないためです。代わりに、InvokeMethod を呼び出して次の 2 つのパラメータを渡します。

"StartService" - 呼び出す WMI メソッドの名前です。

$Null - 単純に Null 値を示します。

InvokeMethod は、呼び出すメソッドおよびメソッドに必要な追加の引数の 2 つのパラメータを受け取ります。この場合、メソッド引数はありませんが、InvokeMethod はパラメータが存在するかどうかにかかわらず 2 つのパラメータを必要とします。InvokeMethod を満たすために、第 2 パラメータとして null 値を渡します。

それも良い質問ですね。返されたオブジェクトが System.Management.ManagementObject#root\cimv2\Win32_Service オブジェクトだったこと、またこのオブジェクトが StartService メソッドをサポートしていなかったことはどうしてわかったのでしょうか。私たちは皆本当に賢く、何でも知っているからだと言いたいところですが、それでは誰も納得しないだろうと思いました。ですから、本当のことをお答えします。対象のオブジェクトを入手し、Get-Member cmdlet を実行して、プロパティおよびメソッドの一覧を取得しました。つまり、次のようにしました。

Get-WmiObject Win32_Service -Filter "Name='Alerter'" | Get-Member

ここから、サービスの起動方法を見つけるまで、少々古臭いですが、トライアル アンド エラーに没頭しました。

何点か警告があります。私たちが思い付いたコマンドはうまく機能しますが、この処理を行うのに最適な方法とは言えません。唯一の方法であるとも言えません。Windows PowerShell を使用して同じタスクを実行するもっと良い方法をご存知の方がいらっしゃいましたらお知らせください。この新しいテクノロジは私たちもまだ学習中なのです (フランシス・フクヤマ教授、私たちは特に "あなた" からのお知らせを待っています)。

同様に、比較的表面的なレベルでこの説明を行うために、Windows PowerShell が何をどのような理由で行うかということについての技術的な詳細は省略しました。しかし、それらは今のところ重要ではありません。今は、Windows PowerShell の動作の基本的な概念と、特定の状況下で (少なくとも現時点ではまだ) 動作しない理由のみを示したいと思いました。そうそう、Windows PowerShell を使用してリモート コンピュータ上のサービスを起動する方法も示しました。これこそが本日行おうとしていたことです。

それと、興味深くエキサイティングなことがまだ起きるのだと、世界に証明しましたね。"それ" はうまく行ったと思います。


関連情報

Hey, Scripting Guy! - アーカイブもチェックしてください。

ページのトップへページのトップへ