Hey, Scripting Guy!カップホルダーはどこえ消えた?

Microsoft Scripting Guy

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

一般的に新しいテクノロジが導入されると、ユーザーが新しいテクノロジとその前身のテクノロジを差別化できるようになるには時間がかかります。たとえば、初期の自動車を例にお話をしましょう。初期の自動車は、馬がない馬車として認識されていましたが、他に特徴がなかったので、このように考えられていたのは仕方がないことでした。突き詰めると、初期の自動車と馬車の違いは、馬を使用するかしないかという 1 点だけでした。それ以外に、これらの 2 つのものを区別する要素はありませんでした。

今日、自動車と馬車を間違える人は、まずいないでしょう。これは、時間の経過とともに、自動車メーカーが、自動車と馬車の的確な差別化を図ることに成功した証です。たとえば、現在、工場で作られたばかりの自動車には、CD プレーヤー、エアコン、カーナビが備え付けられていますが、そのような装置がある馬車はほとんどないでしょう。1880 年代の馬車に乗っているところを想像してみてください。少しの間、フラペチーノを横に置おいておきたいと思っても、残念ながら、当時の馬車にはそのような場所はありません。これに対して、スポーツ多目的車 (SUV) には、標準で 17 個ものカップホルダーが備え付けられていたり、ドライバー専用のカップホルダーが 3 個備え付けられている車種もあります。また、最新モデルでは、飲み物を冷やしたり、温めたりできるカップホルダーが備え付けられているものもあります。

注 : ドライブ中、一度に 3 種類の飲み物を飲めないという状態に耐えなければならない時代があったのは信じ難いことです。1 ~ 2 種類の好きな飲み物だけでドライブするなんて、到底不可能です。

新しいテクノロジが成功を収めるには、既存の信頼できるテクノロジの代わりに新しい未知のテクノロジを採用する然るべき根拠が必要です。当初 DVD は、自宅で映画を楽しめるようにすることを目的とし、ビデオデッキと何ら変わりありませんでした。しかし、DVD はビデオデッキよりもかなり高価で、DVD プレーヤーを使用して番組を録画することはできませんでした。ご存知のとおり、DVD は、一世を風靡したわけではありませんでした。実際、DVD が VHS の地位を脅かすようになったのは、DVD メーカーが、未公開シーン、出演者のインタビューなど、カセット テープで提供されていなかったものを DVD ディスクに収録するようになってからです。DVD が普及するには、ただ自宅で映画を見れるという機能だけでは不十分で、DVD メーカーは、既存の機能を上回る機能を提供する必要がありました。

注 : この DVD の特典を実際に見ているのかというのは、また別の話です。既にあるものは、あって当然と思うのが人情です。偶然にも、Scripting Guys は、TechNet Magazine で紹介していないコラムとシステム管理スクリプトの別の結末を収録した DVD を発売することを検討しているところでした。**

Windows PowerShell を使用する

Windows PowerShell™ は、マイクロソフトによってリリースされた新しいコマンド シェルおよびスクリプト テクノロジです。このテクノロジは、既に紹介したシナリオの一例です。Windows PowerShell という用語を初めて聞くときには、一般的に、次のようなことも同時に耳にすると思います。

  • Windows PowerShell を使用すると、プロセスやサービスを管理できる。
  • Windows PowerShell を使用すると、イベント ログからイベントを取得できる。
  • Windows PowerShell を使用すると、WMI を使用してコンピュータを管理できる。

この情報は、すべて事実です。また、これらは有益かつ重要なタスクです。しかし、ここで問題となるのは、これらのタスクは、VBScript や Windows スクリプト ホストを使用して既に実現できていることです。旧バージョンとの互換性は重要で、VBScript で実現できることができなければ、Windows PowerShell はたいした革新ではないと見なされます (たとえば、仮に映画を見ることができない DVD プレーヤーが実在することを想像してみてください。そのような DVD プレーヤーを持っている Scripting Guy がいるので、実際は仮の話ではありませんが、とにかく、映画を見ることができない DVD プレーヤーを欲しいと思う人はいないでしょう。)

Windows PowerShell を使用しても VBScript が実現できることと同じことしか実現できないなら、そもそも、このコラムでこのテクノロジを取り上げたりすることはありません。正直なところ、VBScript にはカップホルダーはありません。また、Windows PowerShell にもカップホルダーはありません。では、どちらのスクリプト テクノロジを使用するかという判断は、何を基準にしたらよいのでしょうか。

正直なところ、どちらのスクリプト テクノロジを使用しても、それほど大きな違いはないかもしれません。けれども、カップホルダーがないことを除けば、Windows PowerShell には、VBScript にない機能が用意されています。必要な処理がプロセスとサービスの管理だけであれば、「壊れていないものを修理するな」(If it ain't broke, don't fix it) という諺があるように、Windows PowerShell を採用すべき大きな理由はありません (Scripting Guys に言わせると、この諺は、"修正すると壊れるから止めておきなさい" という意味になります)。Windows PowerShell が非常に魅力的なテクノロジとなるのは、VBScript では実現できないことに使用できるときです。たとえば、Windows PowerShell を使用するとファイルの最終書き込み時刻を変更することができます。

最終書き込み時刻を変更する

空耳ではありません。Windows PowerShell を使用すると、ファイルの最終書き込み時刻を変更することができます。バージョン管理の簡略化など、さまざまな理由により、スクリプト作成者は、ファイルの最終書き込み時刻 (または作成時刻) を変更できるようになる日を待ち望んでいました。残念ながら、このような機能は Windows Management Instrumentation (WMI) にも FileSystemObject にもありませんでした。どちらのテクノロジを使用した場合も、ファイルの日付や時刻は読み取り専用の属性でした。

しかし、Windows PowerShell では、次のコマンドを実行するだけで、ファイルの最終書き込み時刻を現在の日付と時刻に変更することができます。

$a = Get-Item c:\scripts\test.txt; $a.LastWriteTime = Date

このコマンドの動作について説明する前に、多くの読者が抱いていると思われる疑問にお答えしておきましょう。Windows PowerShell では WMI で変更できない最終書き込み時刻をなぜ変更できるのでしょうか。これは Windows PowerShell によくある誤解なので、他のことについて説明する前に、まずこの点について説明することにしました。Windows PowerShell は、単に WMI を使用する新しい方法であると思われがちです。もちろん、Windows PowerShell を使用して WMI のデータにアクセスできるのは事実です。また、追加のコマンドレット (ネイティブな Windows PowerShell コマンド) が構築されるまで、多くのシステム管理スクリプトは、依然として WMI に依存しています。しかし、基本的に、Windows PowerShell は .NET Framework に基づいており、Windows PowerShell のコマンドレットでは、一般的に WMI オブジェクトではなく .NET オブジェクトを処理します。.NET Framework で利用できるプロパティは WMI で利用できるプロパティと同一であるとは限らないので、この点は重要です。

たとえば、Get-Item コマンドレットを使用してファイルをバインドすると、WMI の CIM_Datafile クラスのインスタンスではなく、.NET オブジェクトが返されます。たいした問題ではないと思うかも知れませんが、これは大きな問題です。.NET オブジェクトで公開されるファイルの管理に関するプロパティやメソッドは、WMI オブジェクトで公開されるものと若干異なります。しかし、既に説明したように、プロパティが読み取り専用であるのか、または読み取り/書き込みであるのか、という小さな違いが重要になってきます。

Get-Item コマンドレットから返されたのが .NET オブジェクトであることを、どのように判別しているのかについて説明しましょう。この場合 (また、多くの場合)、処理しているオブジェクトの種類 (または、利用できるプロパティとメソッド) を特定するには、オブジェクトをファイルにバインドし、そのオブジェクトを Get-Member コマンドレットに渡すのが最も簡単な方法です。次に例を示します。

Get-Item c:\scripts\test.txt | Get-Member

このコマンドの結果は図 1 のようになります。ご覧のように、これは .NET オブジェクトです (Script Guys が、このようなことについて間違えることはありません)。

Figure 1 Get-Item で返されるオブジェクトのメンバ

   
TypeName: System.IO.FileInfo

Name                      MemberType     Definition
----                      ----------     ----------
AppendText                Method         System.IO.StreamWriter AppendText()
CopyTo                    Method         System.IO.FileInfo CopyTo(String destFileName),
                                         System.IO.FileInfo CopyTo(S...
Create                    Method         System.IO.FileStream Create()
CreateObjRef              Method         System.Runtime.Remoting.ObjRef CreateObjRef(
                                         Type requestedType)
CreateText                Method         System.IO.StreamWriter CreateText()

偶然にも、この単純なコマンドは、Windows PowerShell が持つ別の 2 つの興味深く、かつ有益な機能を例示しています。それは、パイプラインとメタ情報です。今回のコラムでは、これらの機能についての技術的な説明は行いませんが、パイプラインの基本的な概念は、コマンドレットを使用してオブジェクトを取得し、そのオブジェクトを別のコマンドレットに渡せるということです。このコマンドでは、Get-Item コマンドレットを使用して、C:\Scripts\Test.txt ファイルを表すオブジェクトを取得し、パイプラインを使用して、このオブジェクトを (オブジェクトとして) Get-Member コマンドレットに渡しています (Windows PowerShell コマンドでは、| 文字はパイプラインを表します)。

その後、Get-Member コマンドでは、受け取ったオブジェクトのプロパティとメソッドを取得します。これは Windows PowerShell の優れた機能の一例で、メタ情報 (情報に関する情報) に間単にアクセスできます。Windows PowerShell では、Get-Member や Get-Command などのコマンドレットを使用することによって、利用できる WMI のクラス、プロパティ、およびメソッドに関する情報を取得する WMI スクリプトを記述するのとほぼ同じ方法で、必要なデータを取得することができます。

Get-Member では、WMI スクリプトよりも、多くの処理を行うことができます。WMI スクリプトでは WMI オブジェクトに関する情報を取得できますが、FileSystemObject など、他の COM オブジェクトに関する情報を取得することはできません。しかし、Windows PowerShell では、それが可能です。Get-Member では、バインドまたは作成できる任意のオブジェクトに関する情報を取得できます。FileSystemObject で使用できるメソッドがわからない場合は、次のコマンドを実行すると、このオブジェクトに関する情報を取得できます。

New-Object -comobject "Scripting.     FileSystemObject" | Get-Member

これは、非常に便利な機能ですが、あまり活用されていません。

なかなか便利ですね。ファイル C:\Scripts\Test.txt で利用できるプロパティとメソッドの一覧をスクロールしていくと、次のような行があると思います。

LastWriteTime             Property       System.DateTime LastWriteTime {get;set;}

興味深いことに、LastWriteTime は、get (読み取り) と set (書き込み) の両方をサポートしているプロパティです。これは、Windows PowerShell を使用して、ファイルの最終書き込み時刻を変更できるということになるのでしょうか。ふむ。

Windows PowerShell の用語集

エイリアス 既存のコマンドレットを表すカスタマイズ可能な名前。Windows PowerShell には、一般的なシェル コマンドを対応するコマンドレットにマップする多数の既定のエイリアスが用意されています。

コマンドレット 他のシェルの組み込みコマンドと類似した、Windows PowerShell における機能の最小単位。

コマンド Windows PowerShell における実行単位。コマンドには、パイプラインを使用した複数の操作を含めたり、; 文字を使用して 1 行に複数のコマンドを含めたりすることができます。

フラペチーノ スターバックスで販売しているアイス コーヒー。

Monad/MSH/Microsoft Command Shell Windows PowerShell のコード ネーム。

オブジェクト システムまたはコマンドから取得する構造化されたデータ。Windows PowerShell では、データを .NET オブジェクトとして操作するので、ユーザーはテキスト ベースのコマンド出力を解析する必要なく、名前でオブジェクトのプロパティを操作できます。

パラメータ コマンド ラインでコマンドレットに設定するオプション。Windows PowerShell では、パラメータの指定にハイフン (-) を使用します。

パイプライン あるコマンドの出力を別のコマンドの入力として送信できるようにします。パイプと呼ばれることもあり、コマンドでは | 文字で表されます。

プロファイル Windows PowerShell の起動時に読み込まれる設定で、シェルの動作を指定できます。

スクリプト ファイルとして保存され、またファイルから実行できる 1 つ以上のコマンド。Windows PowerShell では、スクリプト ファイルの拡張子に .ps1 を使用します。

シェル コマンドとコマンドレットの両方を実行できるコマンド ライン環境。

変数 コマンドの実行中にその値を設定、変更、または取得できるオブジェクトまたはパラメータ。

Test.txt の最終書き込み時刻を現在の日付と時刻に設定するコマンドの説明に戻りましょう。以下にこのコードを示します。

$a = Get-Item c:\scripts\test.txt; $a.LastWriteTime = Date

ご覧のとおり、このコマンドではたいした処理は行っていません。まず、$a という名前の変数を定義します。次に、Get-Item コマンドレットを使用してファイル C:\Scripts\Test.txt に接続します。このコマンドにより、このオブジェクトを変数 $a に格納します。セミコロンを入力した後に、LastWriteTime プロパティの値を現在の日付と時刻に設定します (セミコロンを使用すると 1 行で複数のコマンドを実行できます)。これは、カップホルダーの埋め合わせになりますよね。

少し高度な処理を実行する

もちろん、最終書き込み時刻を現在の日付と時刻以外の日時に変更することは可能です。たとえば、次のコマンドについて考えてみましょう。

$b = Get-Date "5/22/2006 8:15 PM";
$a = Get-Item c:\scripts\test.txt; $a.LastWriteTime = $b

今度は、3 つのコマンドを使用します。まず、Get-Date コマンドレットを使用して、5/22/2006, 8:15 PM に一致する DateTime オブジェクトを作成しました。最終書き込み時刻を現在の日付と時刻に設定したスクリプトでは、Get-Date を使用して DateTime オブジェクトを作成しませんでしたが、その理由は単に、Date コマンドでは DateTime オブジェクトが自動的に返されるからです (このことを確認するには、Windows PowerShell コンソールで「Date | Get-Member」コマンドを実行してみてください)。

必要な日付と時刻を設定した DateTime オブジェクトを作成したら、次は、Get-Item コマンドを使用してファイル Test.txt を表すオブジェクトを取得します (このオブジェクトは、変数 $a に格納します)。最後に、変数 $b が表す値を LastWriteTime プロパティに設定します (この処理は次のコマンドで行っています)。

$a.LastWriteTime = $b

信じられないかもしれませんが、最終書き込み時刻の変更については、まだ半分もお見せしていません。次の何の変哲もないコマンドを見てみてください。

$b = Get-Date "5/22/2006 8:15 PM";
Get-ChildItem c:\scripts | ForEach-Object {$_.LastWriteTime = $b}

このコマンドの興味深い点は何だと思いますか。このコマンドで行われる処理を見てみましょう。前半部分は簡単です。ここでも、5/22/2006, 8:15 PM に一致する DateTime オブジェクトを作成していますが、後半部分では Get-Item コマンドレットではなく、次のコマンドを使用しています。

Get-ChildItem c:\scripts

このコマンドには、どのような意味があるのでしょうか。Get-ChildItem コマンドレットをフォルダに適用すると、そのフォルダに含まれているすべてのファイルが返されます。このファイル コレクションを取得し、パイプラインを使用して、このコレクションに含まれるすべてのアイテムを ForEach-Object コマンドレットに渡します (ここでも | 文字を使用しています)。

ForEach-Object は、これらのファイルをどのように処理するのでしょうか。もちろん、このコマンドレットでは、各ファイルの LastWirteTime プロパティの値を変更します。

ForEach-Object {$_.LastWriteTime = $b}

注 : 今月のコラムは、Windows PowerShell の初心者を対象としているわけではありませんが、$_ は For Each ループの現在の項目を表す特別な変数であることはお知らせしておきましょう。これは、次のような VBScript ループの objItem に相当するものです。

For Each objItem in colItems
    Wscript.Echo objItem.Name
Next

Windows PowerShell コマンドの実行が完了すると、C:\Scripts フォルダにあるすべてのファイルの最終書き込み時刻は同じになります。ぜひ、新しいテクノロジである Windows PowerShell を使用して、ファイルの最終書き込み時刻を変更してみてください。**

このコマンドの変化形は一晩かけて紹介することもできます。たとえば、フォルダ C:\Scripts にある .txt ファイルについてのみ最終書き込み時刻を変更する場合は、次のコマンドを実行します。

$b = Get-Date "5/22/2006 8:15 PM"; Get-ChildItem c:\scripts\*.txt | ForEach-Object {$_.LastWriteTime = $b}

食欲を刺激する

Windows PowerShell は非常に優れています。しかし、このコラムの目的は、Windows PowerShell の販促活動でもなく、VBScript スクリプトを廃止して、Windows PowerShell に移行するのを推奨することでもありません。VBScript スクリプトで必要な処理を行え、その処理が必要な場合は、現状のままにしておくべきです。バッチ ファイル、コマンド ライン ツール、おまじない、コンピュータの管理に使用するツールについても同様です。「壊れていないものを修理するな」という諺をお忘れなく。

このコラムで説明したのは、Windows PowerShell を使用して、既に実現できている処理を行えるということではありません。Windows PowerShell を使用すると、.NET Framework にアクセスすることが可能になるので、これまでに実現できなかった処理が行えるようになるということです。その一例が、ファイル (または一連のファイル) の最終書き込み時刻の変更です。このようなニーズに対応できる処理は、他にもあります。Windows PowerShell には、このような優れた機能があるため、このテクノロジの導入を検討してみる価値はあると思います。

多くの読者にとって、このコラムは異色な Windows PowerShell の紹介だったと思います。このコラムでは "Hello, world" のような単純なサンプルを使用する代わりに、パイプラインやコマンドレットなどの専門用語の知識があることを前提に、Windows PowerShell のマルチパート コマンドを紹介するサンプルを使用しました。これは意図的に行いました。Windows PowerShell を試したユーザーは少ないという状況を把握していたので、コンピュータで実行しているサービスの一覧を取得する方法を紹介したら、読者の皆さんをがっかりさせ、皆さんがこのコラムを読まずに、その前に行っていた作業に戻ってしまうのではないかということを懸念していました。

注 : このコラムを読む前に行っていた作業が車の運転でなければよいのですが。多くの人にとって、運転しながら 3 種類の飲み物を飲む、DVD を見る、携帯電話で話をするという 3 つの作業を同時に行うのは、十分に困難だと思います。それに "TechNet Magazine を読む" という作業を加えるのはあまりにも過酷な作業だと思いますから。**

おっと、多くの人にとってとは言いましたが、すべての人にとってとは言っていませんよ。

Microsoft Scripting Guy Microsoft の仕事をしています、というよりも Microsoft に雇われています。野球をプレイしたり監督したり観戦したり (または他のさまざまな活動を) しているのでない限り、彼らは TechNet Script Center を運営しています。詳細については、https://www.microsoft.com/japan/technet/scriptcenter/default.mspx を参照してください。

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