カテゴリ「PowerShell」の過去ログ

PowerShellのコンソールを起動すると普通のコマンドラインに比べて起動が遅いなと感じる。これは.NETの性質に由来するもので、MSIL(中間言語)を実行時にJIT(Just in Time)コンパイルするためである。実行時に機械言語へのコンパイルを行っているのだ。このJITコンパイル方式はあらゆるCPUやOSに対応させるためにインタプリタの利点を生かしたまま実行時には機械言語の処理速度を保てるという利点がある。

でも考えても見るとPowerShellが必要な環境では多種のOSで動く必要が今のところはない。速く起動してくれるに越したことはないのだ。それを実現するためにはMSILをすでに機械言語にコンパイルさせていればその実行時にその過程が不必要になるために速くなる。.NET Frameworkにはngenというのがあってこれを使うと事前コンパイルを可能にしてくれる。

ネイティブ イメージ ジェネレータ (Ngen.exe) は、マネージ アプリケーションのパフォーマンスを向上するツールです。Ngen.exe は、コンパイルされたプロセッサ固有のマシン コードを含むファイルであるネイティブ イメージを作成してローカル コンピュータのネイティブイメージ キャッシュにインストールします。ランタイムは、JIT (Just-In-Time) コンパイラを使用してオリジナルのアセンブリをコンパイルする代わりに、キャッシュにあるネイティブ イメージを使用できます。(MSDNより

そのngenを使って実際に起動を速くするスクリプトがPowerShell Team Blogに載っていたので下に抜粋しておく。

Set-Alias ngen @(
dir (join-path ${env:\windir} "Microsoft.NET\Framework") ngen.exe -recurse |
sort -descending lastwritetime
)[0].fullName
[appdomain]::currentdomain.getassemblies() | %{ngen $_.location}

上のスクリプトを.ps1ファイルに保存してPowerShellから実行してPowerShellのコンソールを起動してみると、起動が数倍速くなっている。ぜひ試してみてほしい。


Quest Softwareから無料のPowerShellコマンドレット群が提供されています。それで何ができるかというとActive Directoryの管理のほとんどができてしまうそうです。一度試したことがありますが、かなりOOでいけてます。勤務している会社では私はネットワークの管理者ではありませんので、大層なことはできませんが、基本的なユーザアカウントの情報やネットワーク上にあるコンピュータについて、それを使って検索もできてしまいます。

例えば・・・

Get-QADComputer -DisplayName “vm*”

とすると、vmで始まるコンピュータがコンソール上に表示されます。ユーザカウントを検索したい場合は・・・

Get-QADUser -DisplayName “*John*”

などとするとJohnという文字列を含んだユーザアカウントをリストしてくれます。

上のコマンドレットの結果を変数に格納していろいろすることができるかもしれませんね。ただ実際にやる場合は犠牲者を出さないように気をつけてくださいね。w


PowerShellを通して知り合いましたHIROさんが日本にもっとPowerShellを広めるべくPowerShell from Japan!!というサイトを立ち上げました。このサイトはPowerShell専用のブログでありWikiであり、とにかくそこに行けばPowerShellについて分かるというサイトにしたいとのこと。私もお誘いを受けまして徐々にこのサイトとクロスポストですがそちらにも記事を書いていこうと思っています。

少しでも日本のプログラミングコミュニティに貢献し、そこから自分も学べればと思います。


何となくいろいろなブログを読んでいた。PowerShellチームのブログにv2はいつリリースされるかについて書いてあったので読んでみると、今の時点では機能に関してはすべて決まったようだ。しかしここから1年以上かかるとのこと。既にCTPが出てるのにそこから1年って結構長いですな。


MSDN側からもPowerShellフォーラムにアクセスできるようになったようです。


今回はカスタムコマンドレットのインストール方法について書くことにします。(現在カリフォルニアに向かう途中の飛行機の中。)

簡潔に言うとInstallerクラスをカスタムコマンドレットのプロジェクトに追加し、InstallUtilでアセンブリ(DLL)をインストールしてからAdd-PSSnapinを実行すると初めてカスタムコマンドレットが使えるようになります。

まずはInstallerクラスをカスタムコマンドレットのプロジェクトに追加します。

image

追加したらそのコードを開いてクラスをSystem.Management.Automation.PSSnapInというクラスから継承します。

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Linq;
 
using System.Management.Automation;
 
 
namespace PSIIS
{
    [RunInstaller(true)]
    public partial class PSSnapinInstaller : PSSnapIn
    {
        public PSSnapinInstaller()
        {
            InitializeComponent();
        }
 
        public override string Name
        {
            get { return "PSIIS"; }
        }
        public override string Vendor
        {
            get { return "www.devslife.com"; }
        }
        public override string VendorResource
        {
            get { return "PSIIS6,"; }
        }
        public override string Description
        {
            get { return "PowerShell Cmdlets to Manage IIS6"; }
        }
        public override string DescriptionResource
        {
            get { return "PowerShell Cmdlets to Manage IIS6"; }
        }
    }
}

個人的な目的で使うならこれらのプロパティはあまり重要ではありませんが、後で見て分かりやすい情報を入れておくといいでしょう。上のInstallerクラスの準備ができたらコンパイルしましょう。

次にInstallUtilを使ってカスタムコマンドレットのAssembly(DLL)をインストールします。Visual Studio 2008 Command Prompt(またはVisual Studio 2005 Command Prompt)を立ち上げてアセンブリが存在するディレクトリに移動してInstalUtil PSIIS.dllと入力して実行します。

image

ここでPowerShellに戻ってGet-PSSnapin -Registeredと入力するとそのアセンブリがPowerShellによって認識されたことが分かります。しかし認識されてはいるのですが、まだ使える状態にはなっていません。最後にAdd-PSSnapin PSIISと入力して実行すると初めて自作コマンドレットが使えるようになります。

PowerShellコンソールを一度閉じてしまうと自作コマンドは再びAdd-PSSnapinを実行してやらないと使えるようになりません。どうしてAdd-PSSnapinを実行した時点でPowerShellに登録されないのかは定かではないです。それが面倒な場合は$profileにあるMicrosoft.PowerShell_profile.ps1(ない場合は作りましょう。set-executionpolicy unrestrictedを忘れないように。)にAdd-PSSnapin PSIISというコマンドを入れて保存してやると自作コマンドレットがPowerShell起動後すぐに使えるようになります。


PowerShellをインストールした時点で結構な数のコマンドが存在します。それをいろいろ組み合わせれば多くの作業が済んでしまうのですが、拡張またはPowerShellで全く提供されていない機能を持ち合わせたコマンドレットを自作することができます。今回はその基本をおさらいしましょう。

この間床に着く前ににIIS6の管理コマンドレットを作りたいと思ってメモしました。多分マイクロソフトからそういうコマンドレットは近い将来提供されるだろうと予想しながらも自作でがんばってこのブログの場で考えながら作っていきたいなあと思っているところです。

開発環境はWindowsXPとVS2008(C#)でやります。

さて、ではどうやったら自作(カスタム)コマンドレットを作ることができるのか。まずはWindowsのクラスライブラリのプロジェクトを作って参照を追加してしまいましょう。C:\Program Files\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0\System.Management.Automation.dllにあります、System.Management.Automationを追加しましょう。これがなくては始まりません。またIISを管理する核の部分は別のプロジェクト(IIS6Mgr)に書くことにします。というのはPowerShellだけでなくてそれにWindowsのGUIものせることも考えられるからです。すると下のような感じになります。

image

ここではすべて手作業でやっていきますが、PowerShell用のVisual StudioプロジェクトをダウンロードしてインストールしてやるとPowerShellカスタムコマンドのプロジェクトをプロジェクトの新規追加のダイアログボックスから選択できるようになります。なぜかChannel9からダウンロードが可能になっています。

まだIIS6を管理するコマンドを書いていませんが、とりあえず今回はカスタムコマンドレット書く方法を紹介したいのでそちらから先にやることにしましょう。

IISには複数のSiteが存在する可能性があるのでGet-IISSiteというコマンドレットを用意することにしましょう。PSIISのコマンドレットプロジェクトにGet-IISSiteというクラスを追加します。カスタムコマンドレットを作成するときは一つのコマンドレットにつき一つのクラスを用意することになります。それでは実際にGet-IISSiteのクラスを作成しコードを書くことにしましょう。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management.Automation;
 
namespace PSIIS
{
    [Cmdlet(VerbsCommon.Get, "IISSite")]
    public class Get_IISSite : Cmdlet
    {
        protected override void BeginProcessing()
        {
           WriteDebug("BeginProcessing");
        }
 
        protected override void ProcessRecord()
        {
            WriteDebug("ProcessRecord");
        }
 
        protected override void EndProcessing()
        {
            WriteDebug("EndProcessing");
        }
    }
}

上のコードを説明します。

まず初めにコマンドレットのクラスをCmdletクラスから継承します。classにはCmdletAttributeをつけます。 これで初めてPowerShellがこのクラスをコマンドレットと認識します。このCmdletAttributeにはVerbsCommonというstaticなクラスがありまして、よく使われる動詞がメンバーとして存在しています。別にVerbsCommonを使う必要はなく、自分の好きな動詞をstringとして使ってもかまいません。そしてその次に名詞をそのAttributeに渡してやります。これでGet-IISSiteというコマンドレットを宣言できたわけです。ちなみにこれが日本語でできるか現在興味ありな感じです。

後はoverrideできるメソッドを使ってそこにコードを書いてやります。今回はBeginProcessingとProcessRecordとEndProcessingにそれぞれWriteDebugメソッドを使って文字列をコンソールに書き出してみます。これをコンパイルしてインストールしてGet-IISSite -Debugとして実行してやると・・・

image

のように順番に実行されているのが分かります。BeginProcessingには初期化的なコードを書き、ProcessRecordにはメインのコードを書き、そしてEndProcessingには後始末のコードを書くのが適当だと言うことは想像できます。

今回はWriteDebugを使いました。WriteDebugの内容を表示するには-DebugのパラメータをコマンドレットにつけなければならないのとWriteDebugのコードが実行された直後に必ず「継続しますか?」と聞いてきますのでそれが面倒な場合には単にConsole.Write(Line)を使うとサクっとコンソールに文字列を表示してくれます。

基本編ではインストールの部分を端折りました。近日中にそれについてブログしようと思います。


PowerShellにはEnvというドライブがある。EnvというのはEnvironmentの初めの三つ文字で「環境」という意味だ。つまり環境変数をEnvドライブでリストすることができる。

image

これらの環境変数は普段のアプリケーション開発においてもよく使うものである。

ではどうやって値をPowerShell上で使うかというと$envという変数を使って・・・

image

これで少しでもハードコードを減らせるといいですね。w


この例はテキストファイルにしか有効ではないことを初めに断っておく。当たり前といえば当たり前なのだが。ある文字列を含むファイルを探すことはPowerShellだと一行で済んでしまう。二通り試してみたのでどちらも紹介することにしよう。

【例1】

dir -filter *.cs -recurse | where {(Get-Content $_.FullName) -match "検索文字"}

この後にさらにパイプを追加してやればコピーしたり、削除したり、リストにしたりいろいろ加工できる。例えば| foreach {notepad $_.FullName}とするとそのファイルをメモ帳で開いてくれるのだ。結果が多い場合には多分notepadのプロセスが何十個いや何百個にもなってしまいそうなので注意。

【例2】

dir -filter *.cs -recurse | where {$fs = $_.OpenRead(); `
$sr = New-Object System.IO.StreamReader($fs);$sr.ReadToEnd() -match "検索文字"}

この例はより長く読みにくいけど、例1よりずっと早かった。どうしてだろう?解明するにはGet-Contentの仕組みを理解する必要があるようだ。後で見てみることにしよう。


この間PowerShellのプレゼンを同僚にした。プレゼンの仕方もあまりよくなかったのかも知れないが反応が今ひとつだ。そうなると逆に燃える。異端児、はぐれもの、新撰組(一人だけど)、明治維新前夜(?)みたいな感じで面白いじゃないか。5月の初めに南カリフォルニアのIrvineという都市にあるオフィスに「参勤交代」する予定なのだがそのときにはPowerShell帽をかぶっていこう。(笑)

反応があまりよくないのはどうしてかをちょっと考えた。もちろん自分のプレゼンの力不足もあるのだが、Windows上での今までのシェルの地位も影響しているのではないか?ということも考えた。何せ今までWindowsのコマンドプロンプトはUnix使いにはバカにされ、Windowsから入った人はGUIが主流だろうからどうして今頃苦労してそんなだるいコマンドベースのものを覚えなければいけないんだ?という疑問があるのだと思う。それを払拭できなかった自分にも責任はあるのだが、今までのそのイメージを変えるのは並大抵な努力ではない。ヤンクミも第一話では生徒の心はつかみきれないのだ。(はい、ごくせん見てます。最近仲間由紀恵のまねに凝ってる・・・)

しかしである。PowerShellのはっきり言ってUnixのシェルを超えた。パイプでテキストじゃなくてオブジェクトを渡すって革命的だよ。しかもカスタムコマンドまで作ることができるフレームワークまで用意されている。単なるコンソールアプリとは訳が違うのだ。PowerShellは.NET Frameworkをベースにしたもう一つ上の層の更なるプラットフォームなのだ。このすごさを伝えるにはどうしたらいいんだろう。結局すごいすごいって言ってても意味がないので徐々に実際に見せていくしかないのか。ヤンクミみたいに広告作って渡してみようか。(んなアホな・・・)

PowerShellはやればやるほど発見がある。それと同時に.NET Frameworkの発見もあるのだ。宗教が政治や戦争で使われると危険なのと同じく、PowerShellだって使い方を間違えると大変なことになることだってある。何事もバランスの問題なのだ。

PowerShellがどんなにすごいかというのを今までのように自分のブログとそして会社で「布教活動」していこうかと思う。

決していかがわしい壺を売ることはありませんので、ご心配なく。

明日はまた忙しくなりそうだ。寝よっと。