Windows PowerShell簡単なコマンド、強力な管理機能

Don Jones

このコラムは、Windows PowerShell のプレリリース版を基にしています。ここに記載されているすべての情報は変更される可能性があります。

実現するまで時間がかかりましたが、Windows PowerShell はもうすぐ起動できるようになります。つまり、Windows 管理者が注目するときがやってきました。Windows PowerShell は、さまざまな管理作業を自動化するためのおそらく最も簡単で柔軟性のある方法となるものを提供するので、これを使えば作業をより効率的かつ効果的に進められるようになります。

でももっと重要なのは、マイクロソフトが Windows PowerShell™ を基に Exchange Server 2007 や System Center 2007 などの製品のグラフィカルな管理コンソールを構築していることです。つまり、Windows PowerShell 内からほとんどの管理作業を実行できるようになります。マイクロソフトは長い年月をかけて、より多くの製品の管理機能で同じことを行えるようにするつもりです。したがって、Windows PowerShell は最終的にはマイクロソフトのほとんどすべてのサーバー製品を管理するための最初の万能ツールになります。まずは、この新しいコラムで Windows PowerShell について定期的にお話します。ソフトウェアのコピーをダウンロードしてください。

強力さと容易さ

Windows PowerShell は、その名前のとおりシェルであり、Windows NT® 3.1 以降のコマンド プロンプト (Cmd.exe) とよく似ています。Cmd.exe が消えたわけではなく、Windows PowerShell の可用性を備えたうえで、Cmd.exe を引き続き使用する理由がいくつかあります。

Windows PowerShell の使用と Cmd.exe の使用にはそれほど違いはありません。唯一の違いは、Windows PowerShell の方が強力だということです。Cmd.exe と同様、Windows PowerShell には組み込みのスクリプト言語がありますが、Cmd.exe の基本バッチ言語よりもはるかに柔軟性があります。どれくらい柔軟なのでしょうか。Windows PowerShell では、6 個前後の組み込みのキーワードだけを含む言語を使用して、非常に複雑な作業を自動化できます。

スクリプトについては既に説明したので、セキュリティについても触れておいた方がよいでしょう。Windows PowerShell では、マイクロソフトが過去 10 年余りの間、セキュリティについて学習してきたことを生かしています。既定では、Windows PowerShell はスクリプトを実行しません。個別のコマンドを対話的に実行するためにのみ使用できます。スクリプトを有効にすると、デジタル署名付きのスクリプトのみを実行するよう Windows PowerShell に指示できます。このすべてによって、Windows PowerShell が次の VBScript になることはないということを確信できます。VBScript は悪意のあるスクリプトを作成するために悪用されることが多かった、ある意味偉大な言語です。VBScript も消滅してはいませんが、Windows PowerShell の方が多くの異なる作業に簡単に使用できることがおわかりでしょう。

Cmd.exe でできることは、Windows PowerShell でもほとんどすべて実現できます。たとえば、ipconfig を実行すると、おなじみの出力が表示されます。しかし、Windows PowerShell は外部の実行可能ファイルではない、まったく新しいコマンド セットを導入しています。これらのコマンドレットは Windows PowerShell に組み込まれています (Windows PowerShell の使用を開始するときに最も役立つコマンドレットの一部を見てみるには、「すぐに使用できる 10 個の主なコマンドレット」を参照してください)。

すぐに使用できる 10 個の主なコマンドレット

  • Get-Command は利用可能なすべてのコマンドレットの一覧を取得します。
  • Get-Help はコマンドレットと概念に関するヘルプ情報を表示します。
  • Get-WMIObject は WMI を使用して管理情報を取得します。
  • Get-EventLog は Windows イベント ログを取得します。
  • Get-Process はアクティブなプロセスを 1 つ取得するか、その一覧を取得します。
  • Get-Service は Windows サービスを取得します。
  • Get-Content はテキスト ファイルを読み取ります。読み取るとき、各行を 1 つの子オブジェクトと見なします。
  • Add-Content は内容をテキスト ファイルに追加します。
  • Copy-Item はファイル、フォルダ、その他のオブジェクトをコピーします。
  • Get-Acl はアクセス制御リスト (ACL) を取得します。

Windows PowerShell に含まれているコマンドレットの完全な一覧については、windowssdk.msdn.microsoft.com/en-us/library/ms714408.aspx (英語) を参照してください。

すべてのコマンドレットの名前は、理解しやすく覚えやすいように、動詞と名詞を組み合わせた標準の形式になっています。たとえば、Get-Command コマンドレットを実行すると、使用できるすべてのコマンドレットが一覧表示されます。おそらく管理者にとって最も役立つコマンドレットは Get-WMIObject です。たとえば、Server2 がどの Service Pack を実行しているのかを知りたい場合は、以下のコードを実行するだけです。

Get-WMIObject Win32_OperatingSystem –Property ServicePackMajorVersion
 –Computer Server2

VBScript を使用してこれと同じ情報を取得するには、数行のコードを記述する必要があります。他のコマンドレットではサービス (Start-Service、Stop-Service など)、プロセス (Stop-Process など)、ファイル (Rename-Item、Copy-Item、Remove-Item、Move-Item、など) や、その他の項目を操作できます。これらのコマンドレットの多くは、エイリアスと呼ばれるショートカット名を持っています。Get-WMIObject の場合は、gwmi と入力するだけ済みます。Get-Alias を実行すると、これらのショートカット名の一覧が表示されます。

オブジェクト指向の理由

Microsoft® .NET Framework を基に構築された Windows PowerShell は、完全にオブジェクト指向です。通常それについて興奮するのはソフトウェア開発者だけですが、この場合、オブジェクト指向によって管理者の時間を大幅に節約できます。これは、管理者がテキストベースのシェルで豊富なオブジェクトを直接操作できるようになったためです。次の例について考えてみましょう。

Get-Process | Sort-Object pm –desc | Select-Object –first 10

上記のコードはたった 1 行ですが、パイプ記号で区切られた 3 つの異なるコマンドレットを含んでいます (コマンドレットは瞬時に増やすことができます)。最初のコマンドレットは実行中のすべてのプロセスを取得して、それらのオブジェクトを Sort-Object に渡します (つまり、パイプします)。2 番目のコマンドレットは各プロセス オブジェクトの pm (物理メモリ) プロパティを降順に並べ替えます。並べ替えられたプロセス オブジェクトのコレクションは Select-Object にパイプされ、最初の 10 個が選択され表示されます。では、表示結果を見てみましょう。この単純な行によって、図 1 のように、コンピュータ上の上位 10 個の物理メモリ コンシューマが表示されます。これは、何らかのトラブルシューティングを行うときにさっと調べることができる非常に効率的な方法と言えます。

図 1 単純なコマンドレットを使用したトラブルシューティング

図 1** 単純なコマンドレットを使用したトラブルシューティング **(画像を拡大するには、ここをクリックします)

パイプ (通常は日本語キーボードの円記号キーにある縦線文字) の使用は、Windows PowerShell を非常に高性能にするのに不可欠です。この文字を使用して、あるコマンドレットから別のコマンドレットにオブジェクトを渡す (パイプする) ことができ、さらに結果の精度を上げたり、表示用に書式設定したりすることができます。このメカニズムが動作するのは、各コマンドレットが純粋なテキストではなく 1 つ以上のオブジェクトを返し、後続のコマンドレットに、動作する完全なオブジェクトを提供するためです。

Windows PowerShell のオブジェクトはその変数まで幅広く使用されています。そして事前に変数を宣言しておく必要はありません。変数名の前にドル記号 ($) を付けるだけで変数の使用を開始できます。必須ではありませんが、変数に格納するデータの型を Windows PowerShell に通知することもできます。Windows PowerShell で変数を非常に強力な .NET Framework 型の 1 つにマップして、多数の追加の組み込み機能を提供することができます。たとえば、コンピュータ名の入力を求めて、コンピュータから Service Pack のバージョンを取得したいのですが、コンピュータ名を入力するユーザーが (\\Server2 のように) 2 個の円記号を含めるかどうかがわからないとします。Get-WMIObject コマンドレットが円記号を必要としないことはわかっているので、コンピュータ名を String 変数に保存し、Replace メソッドを使用して円記号を空の文字列に置き換えることができます。その例を次に示します。

[string]$c = Read-Host "Enter computer name"
$c = $c.Replace("\","")
    Get-WMIObject Win32_OperatingSystem
    –Property  ServicePackMajorVersion
    –Computer $c

–Computer パラメータの値は $c 変数に格納されています。その変数は最初は文字列として作成されたので、.NET Framework の String 型のすべての機能 (Replace メソッドを含む) を選択しました。もちろん、これらの機能をすべて理解するにはしばらくかかりますが、例を通してそれらの機能を簡単に選択できるようにします。Windows PowerShell 自体が学習を簡略化するのに役立ちます。たとえば、「$c = $c.」(ピリオドを忘れないでください) と入力し、Tab キーを押すと、Windows PowerShell が Clone() という String 型の最初のメソッドを表示します。Tab キーを押し続けると、Windows PowerShell は使用できるすべてのメソッドを繰り返し表示します。基本的には、これを行うと、Windows PowerShell が String 型をどのように処理するのかがわかります。

以下はもっと厄介な作業です。ファイルからコンピュータ名の一覧を読み取り、1 行に 1 つのコンピュータ名を表示します。また、各コンピュータの Service Pack 番号も表示します。VBScript では、この作業は 10 行以上のコードが必要です。Cmd.exe では、複雑なバッチ ファイルを使用する必要があります。Windows PowerShell では、この作業はたった 1 行で済みます。

Get-Content "c:\computers.txt" | foreach  
{ $_; gwmi Win32_OperatingSystem -prop 
ServicePackMajorVersion -comp $_ }

Get-Content コマンドレットは C:\Computers.txt のコンテンツを読み取ります。ファイルの各行はそれ自体でオブジェクトになります。このオブジェクト (つまりコンピュータ名) のコレクションは、foreach コマンドにパイプされます。foreach は ForEach-Object コマンドレットの単なるエイリアスに過ぎません。中かっこの中のコマンドは、パイプされる各オブジェクトに 1 回ずつ繰り返されます。この例では、各コンピュータ名に対して 1 回ずつ実行されます。特殊な変数 $_ は、現在のオブジェクト (つまり、現在のコンピュータ名) を格納します。

中かっこの中には実際には 2 つのコマンドがあります。最初のコマンドは $_ の内容を出力することによって、現在のコンピュータ名を表示するだけです。2 番目のコマンドは今ではおなじみの gwmi です。このコマンドは、ファイルに一覧表示されているすべてのコンピュータの Service Pack のバージョンの一覧を返します。このすべてが比較的わかりやすい 1 行のコードで完了しました。

–Property パラメータと –Computer パラメータの名前が略されていることに注意してください。Windows PowerShell ではパラメータ名を一意に識別できればいいのです。

読みやすさと再利用

コマンドとパラメータを 1 行で記述すると、読みやすさは得られません。Windows PowerShell ではこの行をもっと読みやすいように分割でき、スクリプトを記述することなく、シェルに直接入力できます。コードは、次のようになります。

PS C:\> $names = get-content "c:\computers.txt"
PS C:\> foreach ($name in $names) {
>> $name
>> gwmi Win32_OperatingSystem -prop ServicePackMajorVersion -comp $name
>> }
>>

今回はファイルの内容は変数 $names に格納されます。この例では依然として foreach を使用していますが、パイプラインを使用して入力されていないので、ループするオブジェクトのコレクションと、各オブジェクトに格納する変数、つまり、”($name in $names)” 部分を指定する必要があります。それ以外はまったく同じで、Enter キーを押すとすぐに、コードが実行され、結果が表示されます。

これと同じコードを繰り返し使用する場合は、そのコードから関数を作成するだけです。もう一度言いますが、これは直接シェルに入力できます。

PS C:\> function Get-ServicePacks ($file) {
>> $names = get-content $file
>> foreach ($name in $names) {
>> $name
>> gwmi win32_operatingsystem -prop servicepackmajorversion -comp $name
>> }
>> }
>>

ご覧のとおり、それほど変更された箇所はありません。これは前の例を Get-ServicePacks という関数で囲んでいるだけです (この関数の名前は Windows PowerShell の動詞と名前で構成される名前付け規則に従っています)。関数には $file という入力パラメータが付いていて、Get-Content コマンドレットで置き換えられるので、関数の実行時に別のファイルを指定することができます。関数は既に定義されているので、コマンドレットのような関数名を呼び出して、入力パラメータを渡すことによって、コードを単純に実行できます。

PS C:\> Get-ServicePacks c:\computers.txt

図 2 は結果を示しています。

ここでの弱点は、この関数が存在するのは Windows PowerShell のインスタンスが実行中の場合のみに限られることです。シェルを終了すると、関数は消滅します。この関数は Windows PowerShell プロファイルにコピーできます。これは、Windows PowerShell が起動するたびに実行される、一種の自動実行スクリプトです。これにより、開くすべての Windows PowerShell ウィンドウでその関数を利用できるようになります。または、必要に応じて、関数を単独のスクリプトに作成することができます。そうすると、スクリプトのパスとファイル名を入力するだけでスクリプトを実行できます。

図 2 Get-ServicePacks 関数の 実行結果

図 2** Get-ServicePacks 関数の 実行結果 **

まるでファイル (またはフォルダ)

Windows PowerShell は関数とコマンドレットだけではありません。どんなものがあるのかを示す簡単な例として、ファイル管理を見てみましょう。Cmd.exe でドライブやフォルダを移動する操作はよくご存知でしょう。たとえば、「C:」と入力すると、C ドライブに切り替わり、「cd \test」と入力すると、C:\Test フォルダに移動します。Windows PowerShell はまったく同じ動作をしますが、cd は Set-Location コマンドレットの単なるエイリアスです。

使用できるドライバをすべて一覧表示するコマンドレットである Get-PSDrive を実行してみます。通常の C: ドライブ、D: ドライブ、およびおそらく A: ドライブに加えて、Cert という名前のドライブ、Env という名前のドライブ、HKCU や HKLM という名前のドライブも見つかります。Windows PowerShell は実際にはストレージ リソースの多くの異なる種類を "ドライブ" として公開しており、ファイルのようなおなじみのナビゲーション インターフェイスを使用して利用できるローカル証明書ストア、環境変数、レジストリ変数のようなものを作成します。

「Set-Location HKLM:」(またはショートカットを好む場合は「cd hklm:」) と入力して Enter キーを押すことにより、HKEY_LOCAL_MACHINE レジストリ ハイブに変更します。その後、cd software\microsoft を実行して SOFTWARE\Microsoft キーに変更します。Get-ChildItem コマンドレットのエイリアスである dir を使用して、レジストリのこの部分にあるサブキーを一覧表示できます。キーを削除する場合は、del を使用して、キーがファイルやフォルダであるかのように削除できます (ただし、必要なキーを削除したりレジストリを誤って変更すると、重大な問題が発生する可能性があるのでご注意ください)。

この柔軟性はすべてプロバイダから提供されており、リソース (レジストリや証明書ストアなど) をファイル システムのような形式にマップします。マイクロソフトは追加のプロバイダを通して Windows PowerShell を拡張する計画を立てています。たとえば、ファイル システムであるかのように Exchange Server ストアを移動する機能を提供します。Windows で使用されている多様なリポジトリを採用して、すべてが同様に見えるようにするだけでなく、既によく知っているコマンドや技法を使用してそれらのリポジトリをすべて管理可能にするという点で、これは非常に重要な技法です。

安全な設計

Windows PowerShell がセキュリティと安全性を念頭に置いて設計されたということは既にお話しました。Windows PowerShell の主要なセキュリティ機能はその実行ポリシーです。既定では、このポリシーは Restricted に設定されています。この設定は、Get-ExecutionPolicy コマンドレットを実行することによって確認できます。Restricted モードでは、スクリプトは実行されません。これで以上です。それが既定のモードなので、Windows PowerShell を使用して特別な構成を行わずにスクリプトを実行することはできません。

他のモードを指定するには、Set-ExecutionPolicy コマンドレットを使用します。個人的には RemoteSigned モードが気に入っています。このモードでは、ローカル スクリプト (リモート スクリプトではない) を、デジタル署名なしで実行できるので、スクリプトを開発してテストする最も簡単な方法が提供されます。AllSigned モードは、スクリプトが信頼されている発行元から発行された証明書を使用してデジタル署名されていない限り、スクリプトは実行されません。最後に、Unrestricted ポリシーの場合は、何でも実行されます。Windows PowerShell を起動して、コンピュータを侵害する可能性のある悪意のあるスクリプトを実行する場合、このポリシーは使わないことをお勧めします。また、実行ポリシーはグループ ポリシーでも管理されるので、ローカルの設定は上書きされることに注意してください (Set-ExecutionPolicy は、グループ ポリシーの設定でローカルの設定が上書きされる場合に、警告を通知します)。

さらに、Windows PowerShell はパスを指定しない限り、現在のディレクトリからスクリプトを実行しません。コマンドの乗っ取りを防ぐように設計されているのです。IPConfig.ps1 というスクリプトを作成した人がいるとします (PS1 は Windows PowerShell スクリプト ファイルのファイル名子拡張子です)。現在のフォルダに含まれていないファイルを実行できるとしたら、実際には Windows プログラム Ipconfig.exe を実行するつもりだったのに、「ipconfig」と入力すると、このユーザーが作成したスクリプトを実行してしまうという危険性があります Windows PowerShell は現在のフォルダに含まれていないスクリプトは実行しないので、この間違いは起こりません。現在のフォルダ以外の場所にあるスクリプトを実行する場合は、パスを指定するだけです。.たとえば、「\myscript」と指定します。現在のフォルダを明示的に参照することによって、スクリプトを実行しているのであって、シェル コマンドを実行しているのではないことがわかります。

Windows PowerShell には、実験を安全に行う機能も備わっています。たとえば、この恐ろしい組み合わせを考えてみてください (ただし、決して試さないでください)。**

Get-Process | Stop-Process

Get-Process コマンドレットはプロセス オブジェクトのコレクションを作成して Stop-Process コマンドレットにパイプします。これにより、本当にプロセスが停止します。その結果、重要な Windows プロセスが強制終了されてから約 5 秒後にブルー スクリーンが表示され、STOP エラーが発生します。しかし、次のように非常に便利な –Whatif パラメータを追加することによって、何が起きるのかを実際に発生させることなく見ることができます。

Get-process | Stop-Process -Whatif

これを Windows PowerShell で実行すると、コマンドレットによって何が行われたのか (実際には行われていません) を通知するステートメントの集まりが返されます。Windows PowerShell のオンライン ヘルプ システム (help エイリアスを使用してアクセスできます) では、–Whatif パラメータについてはまだ文書化されていませんが、覚えておいてください。–Whatif パラメータはスクリプトとコマンドレットをテストするための優れたツールで、悪影響を与えたり混乱を招くような操作を実際には一切行わずに結果を確認できます。

まとめ

このバージョンの Windows PowerShell には含まれていない機能の中で、おそらく最も重要なのは、Active Directory® サービス インターフェイス (ADSI) のサポートです。Windows PowerShell では Active Directory で動作する非常に堅牢な .NET クラスを使用できますが、便利な Get-ADSIObject コマンドレットはまだ備わっていません。そのため、ディレクトリ オブジェクトを操作するのが少し困難です。

また、Windows PowerShell は 1 つの作業の実行に対し、多数の異なる方法を提供しています。それはすばらしいことですが、特定の作業について理解するときに、各作業を行う方法について 6 個の異なる例を見ていくことになるので、Windows PowerShell を学習するうえで混乱が生じることがあります。

そのすべてを長い期間をかけて解決する予定です。また、Windows PowerShell チームは引き続き製品に機能を追加していきます。最新情報を入手するには、チームのブログ (英語) を参照してください。

Don JonesScriptingAnswers.com の創立者で、『Windows PowerShell: TFM』 (英語、2006 年、SAPIEN Press 発行) の共著者でもあります。Don の連絡先は don@scriptinganswers.com です。

© 2008 Microsoft Corporation and CMP Media, LLC. All rights reserved; 許可なしに一部または全体を複製することは禁止されています.