フォーマットストリングと配列 Lengthの副作用? [PowerShell]
実用上困るかというと、そうでもなさそうな細かな話ですが・・・
配列の長さを知るための Length や Count を使うと不思議な副作用があるようなのです。
まず配列を用意します。たとえば文字列の配列。
なぜでしょう。
配列ではなくなったかのように見えます。
とはいえ [] での要素へのアクセスは可能で、たとえば
さらに不思議なことにここで
でアクセスできるようになります。
配列の長さを知るための 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のようにインデックス0番目を指定したところで全要素が出力され、1番目2番目はエラーになってしまいます。
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}" -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
PowerShellのバックグラウンドジョブ [PowerShell]
unix系のシェルだと & (ampersand) で簡単に作れるバックグラウンドジョブですが、
PowerShell v1 ではそれに相当する機能はありません(よね?)
v2 からは実現可能になっています。CTP2 では runspace、CTP3 では PSSession を用いて、こんな感じで書けます。
さらにこの方法には CTP2 から CTP3 になって、できるようになるかと思っていたけどまだそのままの制限があります。
バックグラウンドジョブを実行しているセッションの中からはたとえば
Enter-PSSessionn の二段重ねが出来ないのも同じ理由かもしれません。
認証とか権限とかの問題のような気がするので、クレデンシャルをうまく渡すとかhttpsでつなぐとかすればどうにかなるのかもしれませんが、winrm 周りの設定が複雑でよくわかりません。(^_^;
どうにかならないものですかねえ。。。
というフィードバックをしようと思いつつ英語で書くのが面倒で・・・
PowerShell v1 ではそれに相当する機能はありません(よね?)
v2 からは実現可能になっています。CTP2 では runspace、CTP3 では PSSession を用いて、こんな感じで書けます。
$session01 = New-PSSession -ComputerName $ComputerNameなんだか面倒ですよね。なぜなんでしょう。
$job = Invoke-Command `
-AsJob -ScriptBlock $blockTest01 `
-Session $session01
さらにこの方法には CTP2 から CTP3 になって、できるようになるかと思っていたけどまだそのままの制限があります。
バックグラウンドジョブを実行しているセッションの中からはたとえば
Get-WmiObject -Class Win32_BIOS -ComputerName $OtherComputerのように他のコンピュータにアクセスができないのです。
Enter-PSSessionn の二段重ねが出来ないのも同じ理由かもしれません。
認証とか権限とかの問題のような気がするので、クレデンシャルをうまく渡すとかhttpsでつなぐとかすればどうにかなるのかもしれませんが、winrm 周りの設定が複雑でよくわかりません。(^_^;
どうにかならないものですかねえ。。。
というフィードバックをしようと思いつつ英語で書くのが面倒で・・・
タグ:powershell
タイマーを使ってフォームの定期更新 [PowerShell]
PowerShellでWindowsフォームによるGUIを使ってみています。表示内容の定期的な自動更新を行うために、タイマーを利用した例を書いておきます。
PowerShellでのGUIとはいえ独自の世界があるわけではなく、Windowsフォームの知識があれば書けるということになっているようです。
今回試してみたいタイマーについても、MSDNの次のページに説明はあるのですが、残念ながら使用例としては- Visual Basic
- C#
- J#
- Visual C++
「Windows フォームの Timer コンポーネントを使用して一定間隔でプロシージャを実行する」
http://msdn.microsoft.com/ja-jp/library/3tszykws.aspx
ということで原理についてはわかったつもりでも、実際にPowerShellで書くには、コールバックの書き方などの文法の細かい部分を理解するのに少し試行錯誤が必要でしたので、忘れないためにもここに記録しておきます。いや、わかってしまえば単純なんですけどね。
空っぽのフォームを作って、そのタイトルに現在時刻と更新回数を表示するだけのとても単純化した例です。
[void][reflection.assembly]::LoadWithPartialName("System.Windows.Forms")
$timerTest = New-Object Windows.Forms.Timer
$counter = 0
$timerTestTick = {
$formInfo.text = "{0} ({1})" -f (Get-Date), $counter++
}
function ShowInfoMain
{
#=== タイマーの初期化
$timerTest.Add_Tick($timerTestTick)
$timerTest.Interval = 200
$timerTest.Enabled = $TRUE
$timerTest.Start()
#=== フォームを作って表示
$formInfo = CreateFormInfo
[void]$formInfo.ShowDialog()
}
function CreateFormInfo
{ # フォームの定義
$form = New-Object Windows.Forms.Form
# ここでその他の要素を定義する
$form
}
. ShowInfoMain