SSブログ
QLOOKアクセス解析

PowerGUI での Read-Host の戻り値の問題 [PowerShell]

$myInvocation の値が正しく設定されていない以外に、
PowerGUI に問題点がもうひとつありました。

PowerGUI で Read-Host が実行されると普通のコンソールのようにコマンドラインで値を受け付けるのではなく、ダイアログボックスが出てきて入力をうながします。
ここで入力欄に値をなにも入れずにそのままOKをクリックすると戻り値が $null になってしまいます。
普通にコンソールで実行している際には $null ではなく長さ0の文字列が帰ってきます。
したがって
$str1 = 'abcde'
$userinput = Read-Host '[' $str1 ']'
if ($userinput -eq '')
{
    $input = $userinput
}
のような判定ではうまく動かなくなってしまい $null かどうかの判定も付け加えなくてはいけません。

どちらの問題も
http://powergui.org/
の Discussion で話題に出てはいるけれど、まだ直っていないようです。

[Winform] フォーム上のコントロールへのアクセス [PowerShell]

Winformで、フォーム上に配置されたコントロールは、
フォームの Controls プロパティ(Control.ControlCollection)に格納されています。
この中の目的のコントロールに名前を指定してアクセスするために PowerShell では次のように書きます。
コントロール名を連想配列のキーとして扱うような記述方法ですね。
(フォーム $this の中の tableLayoutPanelBase という名前(Name プロパティ値)を持つ
コントロールを変数 panel に格納する例です。)
$panel = $this.Controls['tableLayoutPanelBase']
入れ子になったパネルの上のコントロールへのアクセスは次のように続けて書くこともできます。長いですけど。
$checkBoxMonitor =
$this.Controls['tableLayoutPanelBase'].Controls['tableLayoutPanelData'].
Controls['checkBoxMonitor']
Controls の要素には、名前ではなく配列のインデックス番号で Controls[0] のようにしてアクセスすることも可能です。
また、たとえばイベントハンドラー(関数やスクリプトブロック)からアクセスしたいようなコントロールは、フォームから順にたどってアクセスするのではなく、作成時などに script スコープの変数に入れておけば、その変数を使ってアクセスすることも可能です。
コントロールを作成する関数内にイベントハンドラースクリプトブロックを記述すれば、local スコープの変数でも見えるのかと思いましたが、そうではないようです。たとえば次のようなスクリプトで、イベントハンドラー($OnShowDialog1)の《記述場所》はコントロールを作成したスコープの内側だとしても、実行時にはそうではないといういうことなのでしょう、おそらく。
$script:checkBox1 = New-Object System.Windows.Forms.CheckBox
$script:checkBox2 = New-Object System.Windows.Forms.CheckBox

$OnShowDialog1 =
{
     $checkBox1.Checked = $This.Tag.prop1
     $checkBox1.Checked = $This.Tag.prop2
}

$FormSetting.Add_Shown($OnShowDialog1)

ISE か PowerGUI か [PowerShell]

PowerShell のスクリプト作成時の環境として ISE(Integrated Scripting Environment) を使うか、PowerGUI を使うかを迷っています。

ISE と PowerGUI を比較すると後者の方がスクリプトエディターは使いやすいように思います。
ISE では
  • タブキーによる字下げが空白文字で行われる
  • タブ文字による字下げ幅がフォントによっては、ずれる場合がある。たとえば MS ゴシックの場合3文字分の幅になってしまう。
などの点が気に入りません。設定の余地があるのかもしれませんが、わかっていません。また、以前書いたように日本語入力のON/OFFの切り替えが少しうまくいかない問題もあります。(これは将来は修正されるものと期待していますが)
逆にデバッグ実行環境については ISE の方が素直なようです。
PowerGUI では
& { $myInvocation }
を実行すると、次のようになり ScriptName のところに実行しているスクリプトファイルの情報が入りません。
MyCommand         :  $myInvocation
BoundParameters : {}
UnboundArguments : {}
ScriptLineNumber : 2
OffsetInLine : 2
ScriptName :
Line : & { $myInvocation }
PositionMessage :
                     At line:2 char:2
                   + & <<<< { $myInvocation }
InvocationName : &
PipelineLength : 1
PipelinePosition : 1
ExpectingInput : False
CommandOrigin : Internal
ISEなら
MyCommand        :  $myInvocation
BoundParameters : {}
UnboundArguments : {}
ScriptLineNumber : 1
OffsetInLine : 2
ScriptName : D:\test\test1.ps1
Line : & { $myInvocation }
PositionMessage :
                     At D:\test\test1.ps1:1 char:2
                     + & <<<< { $myInvocation }
InvocationName : &
PipelineLength : 1
PipelinePosition : 1
ExpectingInput : False
CommandOrigin : Internal
のように入っています。
これだけであれば、なんとか回避することもできるのかもしれませんが、こういうレベルで環境が違うとなると、なんとなく気持ちが悪いような。。。

使い慣れたテキストエディター+コンソールにするのがいいのでしょうかね。

PowerShell の連想配列のコピー [PowerShell]

PowerShell の配列変数や連想配列変数のコピーは実体への参照がコピーされるだけなのを忘れないようにしよう。
簡単な確認。次のように連想配列を作って値を入れてからコピーして、
$hashtable1 = @{}
$hashtable2 = @{}

$hashtable1["key1"] = 101
$hashtable1["key2"] = 102

$hashtable2 = $hashtable1
コピーしたほうに別の値を代入すると、
$hashtable2["key1"] = 201
$hashtable2["key3"] = 203
元のhashtabele1の値もかわります。
http://msdn.microsoft.com/en-us/library/system.collections.hashtable.clone(VS.85).aspx
を見ると .NET Framework のハッシュテーブルの Clone メソッドもシャロウコピーと明記されているので、代入はこのメソッドが呼ばれているのかな?
ディープコピーしたい場合にはどうすればいいのだろう。
GetEnumerator メソッドを使って再帰的に全部コピーするように書くのがいいのでしょうか。一段だけなら次のように割と単純に書けますが、
foreach ($item in $hashtable1.GetEnumerator())
{
     $hashtable3[$item.Key] = $item.Value
}
連想配列の要素がさらに連想配列なら再帰的にする必要あるのでちょっと面倒?。


PowerShell で Winform を使う:イメージデータの読み込み [PowerShell]

PowerShell で Windows Form (WinForm) を用いた GUI を作成するときの書き方の例です。
.NET Framework に詳しい人には当たり前の操作だと思いますが、PowerShellでの記述例が見つけにくかった部分を忘れないように書いておきます。
MSDNのこのあたり
http://msdn.microsoft.com/ja-jp/library/haf2a2zb(VS.80).aspx
http://msdn.microsoft.com/ja-jp/library/system.windows.forms.treeview.imagelist(VS.80).aspx
を見ればわかるのですが PowerShell での記述例が無いので、どう書けばいいのか、また少し悩んだところです。

ビットマップファイルを読み込んで TreeView のアイコンとして利用する例
(PowerShell in Action の winform.ps1 内の関数も利用)

# まず ImageList を作成
$imageList1 = new-object System.Windows.Forms.ImageList

# アイコンのサイズを指定
# (winform.ps1 より) function size {new-object System.Drawing.Size $Args} を利用
$imageList1.ImageSize = size 16 16

# ファイルからイメージデータを追加 (フルパスで指定)
# ファイルの場所は $myd に入っているものとする
# スクリプトファイルとと同じ場所なら
# $myd = & { Split-Path $myInvocation.ScriptName }
$imageList1.Images.Add([Drawing.Image]::FromFile((Join-Path $myd "icon-00.bmp")))
$imageList1.Images.Add([Drawing.Image]::FromFile((Join-Path $myd "icon-01.bmp")))
$imageList1.Images.Add([Drawing.Image]::FromFile((Join-Path $myd "icon-02.bmp")))

# TreeView を作成
# (winform.ps1 より)
#function Form ($control,$properties)
#{
# $c = new-object "Windows.Forms.$control"
# if ($properties)
# {
# foreach ($prop in $properties.keys)
# {
# $c.$prop = $properties[$prop]
# }
# }
# $c
#}
# を利用
$TV = Form TreeView @{
Anchor = "top, left, right, bottom"
}

# イメージリストを指定
$TV.ImageList = $imageList1



[CTP3] PowerShell の WindowStyle オプションで Hidden を指定してコンソールを隠す [PowerShell]

V2 CTP3 から PowerShell.exe に WindowStyle オプションが追加され、起動時のコンソール画面の状態を指定できるようになりました。
これはうれしい。
指定できるのは Normal, Minimized, Maximized, Hidden のいずれか。(通常、最小化、最大化、非表示)

画面は不要で動かし続けたいスクリプトの場合なら powershell -windowstyle hidden で起動すればよくなります。
また、Winform で GUI を持たせたスクリプトも、コンソール画面は見せずに GUI のみを表示させられます。
ショートカットを作成して [リンク先] を、たとえば
C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe -windowstyle hidden "C:\honya\rara.ps1"
としておくといいのですね。
コンソール画面がいったん表示されてから消えるところが見えてしまうのが少し残念ですが・・・


タグ:powershell

[CTP3] PowerShell ウィンドウ内 IME 状態表示 [PowerShell]

CTP3として配布されている PowerShell v2 と Windows 7、Windows Server 2008 R2 のベータに含まれている版の違いにもう一つ気がつきました。ベータのほうは PowerShell ウィンドウの右下隅に
全あ般ローマ

という IME の状態を表示する文字列が表示されます。コマンド プロンプトにも出てます。
わかりやすいといえばわかりやすいかな?
リモートデスクトップ接続でどっち側のIMEが動くのとかいう問題と絡んでる?
ただし、まだ正確に条件など把握できていないのですが、一部動作がおかしいような気もします。

1. キーボードで入力モードを切り替えると一部追従しない。マウスだと問題なし。
2. テキスト サービスとして英語と日本語が入っている場合に、日本語から英語に切り替えると”全あ”の部分だけ消え残る。これはコマンド プロンプトではおこらない。

PowerShell の中身の問題ではなく コンソール ホストの問題でしょう。
いずれにせよ他の機能を試すのに問題のあるような動作ではなさそうです。表示がずれて混乱しやすいですけどね。

[CTP3] Windows Server 2008 R2 とか Windows 7 のベータ版の PowerShell [PowerShell]

Windows Server 2008 R2 とか Windows 7 のベータ版に PowerShell V2 が入っていますが、
これは CTP3 と完全に同じものというわけではないようですね。
http://blogs.msdn.com/powershell/archive/2009/01/12/please-give-us-feedback.aspx
に「they are essentially the same bits」 とありますし、
Get-ItemProperty HKLM:\Software\Microsoft\PowerShell\1\PowerShellEngine
を見ても RuntimeVersion は同じく v2.0.50727 なので中身は同じなのでしょうが PSCompatibleVersion の値はCTP3 では 1.0,2.0 で、ベータ版に入っている方では 2.0 になっています。CTP3 には CTPVersion :10 という値も入っています。

細かい話ですが、起動したときに表示される文字列にも Community Technology Preview うんぬんという文字列の有無の差があります。スタートメニューなどでの表記にも CTP と書かれていませんね。
管理ツールではなくアクセサリに入っていますね。コマンド プロンプトと同じ場所と考えればそうるのか・・・

Windows 7 はまだ触っていなくて R2 でしか見ていないのですが。。。

タグ:powershell

デバッグ出力の文字色指定とISE [PowerShell]

PowerShellのコンソールに Write-Debug と Write-Verbose で出力される文字列の色は初期状態ではどちらも黄色になっています。違う色にしたほうが見分けやすいと思いスクリプト内で
$Host.PrivateData.VerboseForegroundColor = 'DarkGreen' $Host.PrivateData.VerboseBackgroundColor = 'Black'
のように指定して詳細出力はダークグリーンに変更していました。
ところがこれを ISE の中で実行すると次のようなエラーになってしまいます。
Property 'VerboseForegroundColor' cannot be found on this object; make sure it exists and is settable.
ISE内では$host が標準のコンソールとは違うものになっていて PrivateData プロパティが存在しません。
#### ISE内の $host ####
Name : Windows PowerShell ISE Host
Version : 2.0
InstanceId : f80a1692-70bd-498d-96c5-1ba368660197
UI : System.Management.Automation.Internal.Host.InternalHostUserInterface
CurrentCulture : ja-JP
CurrentUICulture : ja-JP
PrivateData :
IsRunspacePushed : False
Runspace : System.Management.Automation.Runspaces.LocalRunspace

#### 標準コンソールの $host ####
Name : ConsoleHost
Version : 2.0
InstanceId : ca20e341-fa77-4860-9499-bb51a84fae11
UI : System.Management.Automation.Internal.Host.InternalHostUserInterface
CurrentCulture : ja-JP
CurrentUICulture : ja-JP
PrivateData : Microsoft.PowerShell.ConsoleHost+ConsoleColorProxy
IsRunspacePushed : False
Runspace : System.Management.Automation.Runspaces.LocalRunspace
ということでWindows PowerShell ISE Host での色指定の方法がわからないので、とりあえずその場合には指定をしないという安易な回避策をとっています。
if ($Host.Name -eq 'ConsoleHost') { $Host.PrivateData.VerboseForegroundColor = 'DarkGreen' $Host.PrivateData.VerboseBackgroundColor = 'Black' }
どうすれば指定できるのだろう。

タグ:powershell

フォーマットストリングと配列 Lengthの副作用? [PowerShell]

実用上困るかというと、そうでもなさそうな細かな話ですが・・・

配列の長さを知るための Length や Count を使うと不思議な副作用があるようなのです。

まず配列を用意します。たとえば文字列の配列。
$a = 'Xx','Yy','Zz'
これを次にようにフォーマットストリングを使って
"{0}" -f $a
"{1}" -f $a
"{2}" -f $a
のように出力してみると、
Xx
Yy
Zz
となります。ここで配列の長さを知るために
$a.Length
とすると、当然
3
と出力されます。さらに先ほどと同じくフォーマットストリングを使って
"{0}" -f $a
"{1}" -f $a
"{2}" -f $a
のように出力してみると、今度は
Xx Yy Zz
Error formatting a string: インデックス (0 ベース) は 0 以上で、引数リストのサイズよりも小さくなければなりません。.
At line:13 char:9
+ "{1}" -f <<<< $a
+ CategoryInfo : InvalidOperation: (Xx Yy Zz:PSObject) [], RuntimeException
+ FullyQualifiedErrorId : FormatError
Error formatting a string: インデックス (0 ベース) は 0 以上で、引数リストのサイズよりも小さくなければなりません。.
At line:14 char:9
+ "{2}" -f <<<< $a
+ CategoryInfo : InvalidOperation: (Xx Yy Zz:PSObject) [], RuntimeException
+ FullyQualifiedErrorId : FormatError
のようにインデックス0番目を指定したところで全要素が出力され、1番目2番目はエラーになってしまいます。
なぜでしょう。
配列ではなくなったかのように見えます。

とはいえ [] での要素へのアクセスは可能で、たとえば
"{0} {1} {2}" -f $a[0],$a[1],$a[2]

"{0}" -f $a[0]
"{0}" -f $a[1]
"{0}" -f $a[2]
のように記述すれば、
Xx Yy Zz
Xx
Yy
Zz
と期待通りの動きをします。

さらに不思議なことにここで
$a += 'Aa'
と追加してやるとまた元に戻って
"{0}" -f $a
"{1}" -f $a
"{2}" -f $a

でアクセスできるようになります。

タグ:powershell
人気ブログランキングへ
 

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。