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

この間PowerShellからWatiNを使おうとして一番問題になったのがWatiNをPowerShell上でSTAモードで実行しなければならなかったことだ。前回の記事でも紹介したようにV1のPowerShellではSTAにするにはC#のカスタムコマンドレットをコンパイルしてそれの助けを得て初めてWatiNをSTA(シングルスレッドアパートメント)モードで実行できたのだが、なんとV2を使うとPowerShellを簡単にSTAモードでスタート出来てしまうことを発見。これがあればこの間苦労したことなんて一気に解決だ。

コンソール上でpowershell /?と打ってやるとpowershell.exeの起動時のオプションが表示される。その中に・・・

-Sta
    Start the shell using a single-threaded apartment.

PowerShellを起動するショートカットのプロパティのターゲットに-Staを追加して更新し、ショートカットをダブルクリックするとPowerShellがSTAモードで起動してくれるのだ。あとはWatiNスクリプトが入ったファイルを普通に実行すると見事に成功。今までの苦労はなんだったんだろう・・・

というわけでWatiN+PowerShellがかなり現実味を帯びてきた。これからもっとWatiN用のPowerShellスクリプトを書いていきたいと思っている。


が催される予定だそうです。下の画像からその催しの情報ページへ飛ぶことができます。

INETA & techbank.jp & PowerShell from Japan!! & HIRO's.NET 合同勉強会 in 仙台

実家の秋田にいたら行くんだけどなあ・・・


ずっと前にPowerShellでテキストファイルに含まれる文字列を検索して検索する文字があったらそれを画面上に表示するというのを紹介したことがあったが、もうちょっと踏み込んで条件に合ったファイルを一つのディレクトリにコピーするところまでやってみよう。

dir -filter *.sql -recurse | where {[System.IO.File]::ReadAllText($_.FullName) `
-match "DataStatus"} | foreach {$_.CopyTo("D:\Temp\$_")}

上の例では拡張子がsqlのファイルを最初にリストしてDataStatusという文字列が含まれるとD:\Tempにそれぞれのファイルをコピーするというもの。必要に駆られたのでメモ程度に紹介しておきます。

 


PowerShellからウェブアプリテスト用のフレームワークWatiNを読み込んでウェブアプリのテストプログラムを書こうとしているのだが、これが一筋縄ではいかない。二重、三重の問題が立ちはだかる。

まずはWatiNをダウンロードしてWatiN.Core.dllをPowerShellに読み込む。そしてIEを立ち上げてURLに行くという単純な作業をしたいと思い、まずは下のようなコードを書いてみた。ちなみにこのスクリプトはTest.ps1というファイルに保存し、アセンブリが入っているbinフォルダに入れてある。

[System.Reflection.Assembly]::LoadFile((Join-Path (Get-Location) "\WatiN.Core.dll"))
$ie = New-Object WatiN.Core.IE
$ie.GoTo(http://www.devslife.com)

すると次のようなエラーが出る。

New-Object : Exception calling “.ctor” with “0″ argument(s): “Could not load file or assembly ‘Interop.SHDocVw, Version
=1.1.0.0, Culture=neutral, PublicKeyToken=null’ or one of its dependencies. The system cannot find the file specified.”
At D:\Scripts\WatiN\bin\Test.ps1:2 char:17
+ $ie = New-Object <<<<  WatiN.Core.IE
+ CategoryInfo          : InvalidOperation: (:) [New-Object], MethodInvocationException
+ FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand

なるほど。PowerShell.exeが入っているフォルダ内(C:\Windows\System32\WindowsPowerShell\v1.0)にInteropアセンブリが入っていないからなのだ。Interop.SHDocVw.dllをPowerShell.exeと同じフォルダ内にコピーするか、再コンパイルをして厳密名をアセンブリにつけるかだがとりあえずPowerShell.exeと同じフォルダにInteropアセンブリをコピーすることにする。PowerShellコンソールを再起動して再びスクリプトを実行すると・・・

今度は下のようなエラーが・・・

New-Object : Exception calling “.ctor” with “0″ argument(s): “The CurrentThread needs to have it’s ApartmentState set t
o ApartmentState.STA to be able to automate Internet Explorer.”
At D:\Scripts\WatiN\bin\Test.ps1:2 char:17
+ $ie = New-Object <<<<  WatiN.Core.IE
+ CategoryInfo          : InvalidOperation: (:) [New-Object], MethodInvocationException
+ FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand

て、手ごわすぎるぞ。でも上のエラーは完全にWatiNから意図的に投げ出されたものなのでちょっと希望の光が見えてきた。エラーによるとIEの自動化を行うにはスレッドがApartmentState.STAにセットされていなければいけないと。つまりPowerShellをApartment.STAにセットしなければいけないのか。そこでググってみるとPowerShellチームブログに到着。なんとカスタムアセンブリをこしらえてそれによってSTAにセットせよと。おっしゃあ、こうなったら意地でやってやる。

まずはPowerShellチームブログにあったカスタムCmdletをコンパイルしてそれをインストール。インストールの仕方はこのブログで一度紹介しているので参考にしていただきたい。インストールするとInvoke-Apartmentというコマンドレットが利用可能になる。それを使用してTest.ps1ファイル内のPowerShellスクリプトを実行するのだ。

Invoke-Apartment "STA" ([System.IO.File]::ReadAllText("Test.ps1"))

これを実行したらちゃんとIEが立ち上がってURLに行くことができたのだ。これでPowerShellからWatiNを使うことができる。

これは蛇足なのだが、上のコマンドでテキストファイルを読みだしているだけなのにどうしてGet-Contentコマンドを使わなかったというとGet-Contentが行ごとのObject配列を返してくるのでInvoke-Apartmentの二つ目のパラメータのString型と合わないために上のようにした。

あー苦労した。上のことを踏まえてなんとかもっと簡単にWatiNをPowerShellから使えるようにできないものだろうか。

これってどうしてもPowerShellでウェブアプリテストしたいという人には役立ちそうなので英語でも書いてみることにする。


と聞くと「おお!誰かがそんなフレームワークを書いたのか!?」と思われそうだが、そうではない。Watirのような完全なラッパー(Yoのラッパーじゃなくて、包むのほう)は自分が知る範囲では存在しない。というのはうそでこのブログを見直している間にそんなフレームワークを発見した。それは最後に述べるとして、IEはCOM経由で.NETから操ることができるのでWatirのようなフレームワークを作るのは時間がかかるかもしれないが、そんなに難しいことではないような気がする。(気がするだけ)前述のように.NETからIEをCOM経由で操ることができるのでPowerShellからもIEを操ることができるのだ。

$ie = New-Object -COM “InternetExplorer.Application”

をPowerShellで実行すると$ie変数の中にIEが格納される。それを使ってとりあえず何でも出来てしまうのだ。タスクマネジャーを見てみるとiexplorer.exeのプロセスが出現したのがわかる。では$ie変数に格納されたIEを少々操ってみることにしよう。

$ie.Navigate(”http://www.itmedia.co.jp“)
$ie.visible = $true

とするとIEが表れて指定したURLへ行ってくれる。

さらに・・・

$ie | gm

を実行すると$ieに格納されたIEオブジェクトのメンバを見ることができる。HTMLのそれぞれの要素への参照を得るには次のようにすると良い。

$txtNamae = $ie.document.getElementByID(”txtNamae”)
$txtNamae.value = “名無しのごんべい”

そうするとテキストフィールドに「名無しのごんべい」という値が入る。

このようにDOMを直接歩いて取り合えず何でも出来てしまいそうだ。ただ前述のとおりフレームワーク化されていないので、PowerShellを使ってすべて自分でUI用のユニットテストを作ろうとするとかなりガシガシ書かなければいけない部分って多そうである。

そういえばPowerShellチームブログで過去に「ユニットテストのPowerShell用のフレームワークって必要だと思う?」と一般の人々に聞いていたのを思い出す。あれってどうなったんだろう?ググってみるとこんなのもある。面白そう。あれれ?さらにさらに.NET用のWatirでWatiN(ワットイン)というのを発見。これだったらPowerShellで読み込んで出来そう。一番最近の更新が2月12日だから結構最近だ。試してみる価値あるかも。試してみたらまたこのブログで紹介します。


今日仕事をしていてちょっとPowerShellのお力を借りる機会があってスクリプトを書いていた。ディスクの空き容量を調べる本当に単純な4行ぐらいのスクリプトなのだ。それはまた別の機会に紹介することとして、その結果次第でメールを送りたいと思いいつものようにSmptClientを使い始めたが、待てよ・・・もしかしてV2にはそういうCmdletがあるんじゃないのか?と思ってV2上でget-command | where {$_.Name -match “mail”}を実行してやると案の定Send-MailMessageというのが引っ掛かった。パラメータなどな以下のような感じ。

image

早くV2プロダクション環境で使いたいなあ。


どうでもいいことかもしれませんが、PowerShellのV1では129個で、Windows7のPowerShellのV2ではget-command | where {$_CommandType -eq “Cmdlet”}として変数に入れてその結果の数を数えると、235個でした。今のところCmdletが106個も増えたことになります。どうでもいいけどちょっと気になる数字でした。


今このブログを書いている時点ではバージョン2のCTP3が出ている状態です。もし書いたスクリプトがどうしてもV2の機能を必要とするという場合は次のようにコメントをスクリプトの一番最初の行に入れておくといいそうです。元ネタはMSのWindows PowerShell Blogから

#requires -version 2

そうすればスクリプトを実行した時点で「おんどりゃあ、Windows PowerShellの2.0必要なんじゃい!」とお叱り頂けるそうです。w

 


ゲームに夢中になっている間にPowerShellのCTP3がリリースされていました。始めのCTPからもう一年ぐらい経っているのでそろそろV2はリリースかなあと思うのですが。来年にリリースされるWindows Server 2008 R2やWindows 7にはPowerShell V2は含まれるようですね。


PowerShellのスクリプトをPowerGUIで編集していたらコピペができない事態が生じたので、秀丸で編集しようと思ったら強調表示定義ファイルがない・・・ということで作ってみました。キーワードが文字列内で強調されないようにしたかったけど、正規表現がちょっとめんどかったのでそのままにしてしまいました。

ファイルはここからダウンロードできます。

一応秀丸サイトにも投稿しておきます。