この記事は、「PowerShell Advent Calender 2011」に参加しています。
コンピューターの管理をしていて、多い作業の一つに「遠隔地のコンピューターに直接プログラムの実行を指示したい」「ある設定をたくさんのコンピュータに一括して実施したい」というものがあります。
こういった要望に応えることができる、PowerShellの便利な機能に、リモーティング機能があります。リモーティング機能は、コマンドレット単体で用意されているもの、いわゆる「リモートシェル」として機能するものなど、様々なかたちで実行することができます。
たとえば、Windows Management Instrumentation(WMI)の機能を使うようなコマンドレット群では、一般に-ComputerNameオプションが実装されていて、他のコンピューターにアクセスして情報を取得することができます。たとえばGet-Processコマンドレットなどは、その代表格となります。
一見高度な「動作中のプロセスが停止(終了)したことを検出する」というようなものも、Register-WMIEventコマンドレットとWin32_ProcessStopTraceクラスを使うことで簡単に実現できます。たとえばこんな感じです。
ところで、こういったコマンドレットは、あくまでコマンドレットが持つ特定の機能をリモートで実行するだけです。任意のプログラムをリモートで実行する方法はあるのでしょうか?実はあります。
Invoke-WMIMethodコマンドレットでWin32_Processクラスを呼び出すことで、リモートコンピュータ上でWMIインスタンスとしてプロセスを起動することができます。このプロセスにシェルプログラムを指定すれば、そのシェル上で任意のコマンドを実行できます。オーソドックスなコマンドプロンプト(cmd.exe)を使うと、こんな風になるでしょう。
シェルプログラムでpowershell.exeを選択すれば、PowerShellスクリプトもリモートで実行できるのです。(後で説明する方法を使えばいいので、残念ながら実質的な意味はありませんけれどね)
Invoke-WMIMethodコマンドレットには、メリットとデメリットがあります。最大のメリットは「PowerShellがインストールされていないWindowsにリモート実行できる」という点です。(とても古いOSでなければ)基本的にリモートコンピュータに制約はありません。一方のデメリットは「複雑な作業ができない」点や「コマンドの実行結果を標準出力で戻せない」という点です(コマンドレットの実行結果自体はちゃんと戻ってきますよ)。これを補うのが、つぎにご紹介する方法になります。
Windowsリモート管理(WinRM)機能は、Windowsのシステム管理上強力なインフラですが、PowerShellにも恩恵をもたらせてくれます。Invoke-ComandコマンドレットはWinRMの機能を必要としますが、リモートコンピュータに対して「リモートシェル」的な振る舞いを行うことができます。つまり、リモートコンピュータ上で任意のコマンドレットを実行することができ、その結果がすべて標準出力で戻ってきます。たとえばこんな感じです。
複数のコマンドレットを実行したい場合、複数行のコマンドレットをヒア文字列(@'や'@)を使って変数に代入することで、簡単に実行できます。こんな感じでしょうか?
通常のコマンドも使うことができ、出力結果は標準出力から戻ります。ただし「dir」のようにPowerShellのエイリアスがあるコマンドについては、そのまま使うとPowerShellのコマンドとして解釈されてしまうので、コマンドプロンプト経由で実行するのがいいでしょう。
なお、Invoke-Commandコマンドレットを実行する際には、必要なPowerShell用のセッションが自動的に張られますが(コマンドが完了すると切れます)、このセッションを手動で張っておく(New-PSSessionコマンドレットを使います)ことで、接続を維持することができます。Invoke-Commandコマンドレットの-Sessionオプションに手動で作ったセッションを指定することで、リモートコマンドを実行することができます。
よくあるケースで、ドメイン環境で作業しながら、システム管理者の管理用端末がワークグループ環境であることがあります。この状態では、そのままではコマンドレットを実行できないので、2つの追加項目が必要です。
まず、リモートに対してドメインアカウント(ドメインのAdministratorなど)での認証が必要です。これを実行するには資格情報についてのオブジェクトを作り、この認証情報を使ってInvoke-Commandコマンドレットを実行します。資格情報を作成するにはGet-Credentialコマンドレットを使います。
うえのコマンドレットを実行すると、認証ダイアログが現れ(ユーザー名には指定したユーザーが記入されています)ますので、パスワードを入力して[OK]をクリックすれば、資格情報の作成は完了ですが、もう1つの作業があります。
それはWinRMのTrustedHosts構成を行う、という作業です。WinRMは強力な管理機能があるため、セキュリティ上コンピュータレベルでの認証が必要(Kerberos)ですが、この構成がとれない場合、操作側の信頼リストに宛先コンピューターのホスト名(あるいはIPアドレス)を登録します。したのような感じです。
この作業が完了したら、つぎのようにコマンドレットを実行すれば、ワークグループ環境からでも実行ができるはずです。
なお、TrustedHosts構成を行う場合、宛先ホスト名は実際に接続可能な名前の登録が必要です。たとえばdc00で(NetBIOSの)名前解決ができ、(FQDNの)dc00.example.comと両方使いたいのであれば、両方登録しなければならないでしょう。