So-net無料ブログ作成
QLOOKアクセス解析

ふたたび Live Mesh Remote Desktop の話 [PowerShell]

また PowerShell 以外の話になってしまうのですが、
昨日書いた Live Mesh Remote Desktop がつながるかどうかの話。
やはりだめだったマシンはだめでした。

Live Mesh Remote Desktop の proxy 経由での利用 (2)
http://kawasaki-shingo-ps.blog.so-net.ne.jp/2009-01-10
では、切り分けできないと書きましたが、
今のところわかる範囲では、おそらく・・・
OSの種類には関係なく(XPだからだめというわけではない)
プロキシー経由で接続しなければいけない環境の問題です。
そのようなマシンだと、そこから他につなぎに行くのはできますが、
つながれるのはだめなようです。


式モードとコマンドモード [PowerShell]

式モード(expression mode)とコマンドモード(command mode)の違いに注意せず失敗したので、まとめておきます。

まず基本の確認から。

PowerShellでの構文解析には式モードとコマンドモードの二種類があります。おおざっぱに言うと、

式モード: (PowerShell での通常の解釈を行うモード)
    数字は数字、文字列には引用符が必要、など
    
コマンドモード:(コマンドにそのままパラメターとして引き渡すためのモード)
    数字は数字、引用符なしでも文字列は文字列。
    ただし $ と @ と ' と " ( で始める場合は別。
    

行頭からいきなり書き始めると式モードで解析されるので、
PS> abc
用語 'abc' は、コマンドレット、関数、操作可能なプログラム、またはスクリプト ファイルとして認識されません。用語を確認し
、再試行してください。
発生場所 行:1 文字:3
+ abc <<<<
のように引用符のない文字列は単なる文字列ではなく、何か呼び出し可能なものの名前として探されます。
PS> 'abc'
abc
引用符をつければ文字列と扱われます。
数字の場合には、
PS> 11+22
33
のように式モードで数値として評価されます。

代入の右辺でもやはり式モードであり、おなじく、
PS> $str = abc
用語 'abc' は、コマンドレット、関数、操作可能なプログラム、またはスクリプト ファイルとして認識されません。用語を確認し
、再試行してください。
発生場所 行:1 文字:10
+ $str = abc <<<<
PS> $str = 'abc'
PS> $str
abc
のようになります。

これがコマンドレットのパラメターとして扱われる場所ではコマンドモードとなります。
PS> $y = Write-Output abc ; $y
abc
PS> $y = Write-Output 11+22 ; $y
11+22
引用符をつけなくても文字列と解釈され、数字も数値として計算されません。

さてここで私が起こしたミスの話です。

New-Object コマンドレットで .NET Framework のオブジェクトを作成するときに、そのコンストラクターに引数を渡す場面です。
望ましい書き方は次のようになります。
$m = New-Object System.Threading.Mutex ($false, "MyMutex")
ミューテックスのコンストラクターに論理値の偽と名前の文字列を渡しています。
二つのパラメターは () で囲まれているので式モードで解釈され、要素数2の配列が渡されることになります。
そのようすはたとえば次のように確認できます。
PS> $x = Write-Output ($false, "MyMutex")
PS> $x
False
MyMutex
PS> $x.GetType()

IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array


PS> $x[0].gettype()

IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Boolean System.ValueType


PS> $x[1].gettype()

IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
ところが、私はこれを最初 () なしで書いていました。
さらに次のように $false の $ を書き洩らしていました。
$m = New-Object System.Threading.Mutex false, "MyMutex"
するとどうなるでしょう。
まず $ を書き洩らしていない場合を考えます。
$m = New-Object System.Threading.Mutex $false, "MyMutex"
実はこの場合には問題なく動作するのです。
先ほどと同じように確認すると次のようになります。
PS> $x = Write-Output $false, "MyMutex"
PS> $x
False
MyMutex
PS> $x.GetType()

IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array


PS> $x[0].gettype()

IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Boolean System.ValueType


PS> $x[1].gettype()

IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
おなじように論理値と文字列の配列が渡されているのがわかります。
今度は$を抜かしてしまった場合の動作です。
PS> $x = Write-Output false, "MyMutex"
PS> $x
false
MyMutex
PS> $x.GetType()

IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array


PS> $x[0].gettype()

IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object


PS> $x[1].gettype()

IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object

今度は最初の要素は論理値ではなく文字列になっています。
これがSystem.Threading.Mutexのコンストラクターに渡された時に、型の違いでエラーが出たりするわけではなく、最初のパラメターが論理値の真と解釈されて動作してしまいます。
書いたつもりと反対になってしまうわけですね。

このような場所では () で囲ってPowerShellの式モードでの構文チェックを通して、エラーを見つけて貰った方が安心であるという教訓を得たのでした。

囲っておけば次のようにエラーになります。
PS> $x = Write-Output (false, "MyMutex")
用語 'false' は、コマンドレット、関数、操作可能なプログラム、またはスクリプト ファイルとして認
識されません。用語を確認
し、再試行してください。
発生場所 行:1 文字:25
+ $x = Write-Output (false, <<<< "MyMutex")
PS>


どこがコマンドモードとして扱われるのか、にも注意が必要ですね。
それをわかりやすくまとめたところはどこかに無いかなあ。。。
タグ:powershell

Windows Server 2008 SP2 での PowerShell のバージョン [PowerShell]

Windows Server 2008 SP2 の RC 版に入っている
PowerShell のバージョンを確認してみました。
インストールして機能を有効にしただけの状態です。
Get-ItemProperty HKLM:\SOFTWARE\Microsoft\PowerShell\1\PowerShellEngine
で調べたら、今までの1.0と変わっていないようです。
PowerShellVersion : 1.0
RuntimeVersion : v2.0.50727

R2 ではなく Service Pack なので機能追加を伴うような更新はないと
思っていましたが、バージョン番号から見て細かな修正・変更などもないようです。


PowerShell のバージョン判別方法 [PowerShell]

忘れそうなので PowerShell のバージョン判別方法を整理しておくことにします。
(以下 Version 2 と書いてますが現時点では CTP 3 での確認のみ)

Version 2 からは PSVersionTable という変数が追加されており、
PS > $PSVersionTable

Name                           Value
----                           -----
CLRVersion                     2.0.50727.3053
BuildVersion                   6.1.6949.0
PSVersion                      2.0
PSCompatibleVersions           {1.0, 2.0}
のように確認可能です。

Version 1 にはこの変数は存在していなかったので、
Get-Variable で変数の存在を見分ければ Version 1 か
それより新しいのかを判別できます。
if (Get-Variable PSVersionTable -ErrorAction SilentlyContinue)
{
    # ある時:Version 2 ~
}
else
{
    # ない時:Version 1
}

他に、次のようにレジストリを見て PowerShellVersion の値を調べる方法もあります。
(Get-ItemProperty HKLM:\SOFTWARE\Microsoft\PowerShell\1\PowerShellEngine).PowerShellVersion
文字列として 1.0 もしくは 2.0 が戻ってきます。数値ではないので比較には注意しましょう。

どちらの方法がいいのでしょうね?
不存在を調べるのも、レジストリパスを書くのもどちらもあまり美しくないような気はします。

なお、Get-Host で PowerShell ホストのバージョンを取得可能で、
これも参考にはなるのですが、Hostの種類・バージョンと PowerShell の
バージョンは異なるので単純に判別できるわけではありません。

たとえば、標準コンソールの場合であれば
Name : ConsoleHost
Version : 1.0.0.0

あるいは
Name : ConsoleHost
Version : 2.0

になるのですが、PowerGUI の中だと
Name : PowerGUIScriptEditorHost
Version : 1.5.2.550
だったりします。





Get-Content の Wait パラメターを使うときには encoding 指定が必要 [PowerShell]

2月23日にGet-Content の Wait パラメターの説明が無いと書いて、そのあと「動作がおかしい」と書き足していました。
その後調べていたら Microsoft Connect で情報を発見。
Get-Content test.log -wait -encoding unicode
とエンコーディングを明示的に指定すれば正しく動きますね。
指定しないと空白が余計に入ったり、日本語文字が化けたりしてしまいます。

とはいえ tail -f のようには使えないのは残念なまま・・・

Get-Content の Wait パラメターの説明が無い [PowerShell]

Get-Content コマンドレットの Wait スイッチパラメターの説明が
Version 1 の Get-Help では書かれていないことに、いまさらながら気づきました。
V2 CTP3 の Get-Help には一応登場します。
しかし PARAMETERS のところにも意味は記載されていません。
-Wait [<SwitchParameter>]
    Not Specified
となっています。

ストップされるまで入力をポーリングし続けるという動作を行います。

タグ:powershell CTP3

日本語の名前 [PowerShell]

PowerShell で変数名や関数名に日本語は使えるのでしょうか。
$あ = 123
PS > Get-Variable あ

Name    Value
----    -----
あ      123

どうやら使えるようです。
実際に使おうとは思いませんが。。。

では、いわゆる全角スペース(和字間隔)はどう扱われるのでしょう、
という重箱の隅をつつくような話を少し。

まず、関数名について確かめてみます。
function a { $myInvocation.MyCommand }
function あ { $myInvocation.MyCommand }
function b  { $myInvocation.MyCommand }
function c d { $myInvocation.MyCommand }

a

b 
c d

というスクリプト(bの後ろとcとdの間は全角スペース)を実行すると
CommandType     Name    Definition
-----------     ----    ----------
Function        a       $myInvocation.MyCommand
Function        あ      $myInvocation.MyCommand
Function        b       $myInvocation.MyCommand
Function        c d    $myInvocation.MyCommand

行頭でなければ全角スペースも関数名の一部として使えます。
空白文字とは解釈されておらず、4番目の例でも
c と d が別のトークンと扱われていないようです。

では変数名ではどうでしょう。
$a = 'abc'
$あ = 'あいう'
$b = 'bcd'
${c d} = 'cde'

こちらは空白文字として扱われるので
4番目のように空白を含む変数名の場合は{}で囲む必要があります。
囲まなければ

Unexpected token 'd' in expression or statement.

とエラーになってしまいます。

関数名の場合とは解釈のされ方が違うのですね。

ちなみに ${ }${ } は別の変数となります。

日本語の名前を使おうとして
間違えて全角スペースが入ってしまうと、
見た目に見分けがつきにくいエディタの場合
わけがわからなくなることでしょう・・・(笑)


PowerShell ISE の名前に込められた意図 [PowerShell]

PowerShell ISE (Integrated Scripting Environment) が
なぜ IDE (Integrated Development Environment)という名前ではないのかについて
Windows PowerShell in Action, Second Edition に書いてありました。

単にアプリケーション開発のための統合環境という位置づけではなく、
PowerShellのインタラクティブな利用のためのベースに使ってほしいということのようです。

最初のバージョンではまだまだやり残していることがあるけど、
ISE自身が PowerShell で scriptable なので、
自分の作るアプリケーションの部品としてemacsが使われるのと
同じように扱えるでしょうと。。。

(Lisp方面の人は「違う違う・・・」と言うかも?)

先日書いた Write-Progress の GUI 表示が行われたりするところで、
なんとなくそんな気がしていたのですが、やはりそうだったのかという感じです。

こうなるともっと使い込んでみたくなります。


タグ:powershell ise

Windows PowerShell in Action, Second Edition [PowerShell]

Windows PowerShell in Action の第2版は9月に出る予定なのですね。
待ち遠しいです。

Manning Early Access Program というので、
できた部分からの先行ダウンロード販売が行われているので買いました。
今のところ4章まで手に入ります。

http://www.manning.com/payette2/


タグ:powershell

[CTP3] ISE での Write-Progress 表示 [PowerShell]

PowerShell ISE だと Write-Progress の表示は、普通のコンソールのように色違いの文字でコンソール上部に表示されるのではなく、ダイアログボックスが出てきて、そこにプログレスバーとして表示されます。
ISE の環境だとその方が見やすいのでうれしいです。

progress.jpg

-ParentID を指定した、子動作状況は、親と同じダイアログ内にインデントされて表示されます。

ところで、ISEでは -Completed スイッチでプログレス表示を消す場合の動作がコンソールの時と異なっています。
コンソールの時は間違えて(親の動作状況に対して) -ParentId に -1 ではない値を指定してしまっていてもプログレス表示が消えていてくれたのですが、ISEでは正しく -1 を指定するか、あるいはそもそも -ParentID を指定しない場合でないとダイアログが消えてくれません。

ISE が悪いのではなく、コンソールでのチェックが甘いために自分のミスに気づいてなかったのですけど、なかなか原因に気づけませんでした。


タグ:powershell ise
メッセージを送る
人気ブログランキングへ
 

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

×

この広告は1年以上新しい記事の更新がないブログに表示されております。