2011/05/05

仕様みたいです。以下、検証コード。

$def = @"
public static string TestMethod(string str)
{
    if(str==null)
    {
        return "null";
    }
    else if(str==string.Empty)
    {
        return "empty";
    }
    else
    {
        return "other";
    }
}
"@
$test = Add-Type -memberDefinition $def -name "TestClass" -passThru
$test::TestMethod($null)

結果は「null」ではなく「empty」になってしまいます。

Windows Phone 7 エミュレーターをビルド後アクティブにする « LiveSpac.esのコメント欄でも書いたのですが、回避策はリフレクション経由でメソッドを呼ぶしかなさそうです。

$test.GetMethod("TestMethod").Invoke($null, @($null))

このように、Invokeメソッドの第一引数はスタティックメソッドの実行なのでインスタンスを指定しないので$null、第二引数はメソッドに与える引数の配列を指定します。ここでは引数は一つ、その値は$nullなので、@($null)を指定します。このようにすると結果は「null」となり意図した結果が得られます。

元記事:http://blogs.wankuma.com/mutaguchi/archive/2011/05/05/198785.aspx

2011/05/04

PSプロバイダをC#で実装する場合、NavigationCmdletProviderクラスなんかを継承させたクラスを作ってCmdletProvider属性をつけてやりますが、今回はその辺の話は省略して、このクラスからPowerShell変数を読み書きする方法について述べます。

たとえばそのPSプロバイダを含むモジュールを読み込んだPowerShellコンソールに変数$valを書き出すには、

this.SessionState.PSVariable.Set("val", 1);

のようにします。

逆にコンソールで読み込まれている変数$valの値を読み込むには、

PSVariable ret = this.SessionState.PSVariable.Get("val");

のようにします。

と、それだけなら話は簡単なのですが、実はPowerShellの仕組み上、そう単純には行きません。書き出しの方はさほど問題はないのですが、問題は読み込み。ここでretに格納されたオブジェクトから$valの実際の値を取得するにはどうすればいいでしょうか。

このコードを上から順に実行したら、ret.Valueにその値が入っているので、これを単にintにキャストすればOKです。

しかし$valがPowerShell側でその値が変更されていた場合は、ret.ValueにはPSObjectという、元の値をラッピングしたオブジェクトが格納されています。実際の値はPSObject.BaseObjectに格納されています。よって、(int)((PSObject)ret.Value).BaseObjectのように取得する必要があります。

めんどくさいのでメソッドにしてしまいました。

private T GetPSVariableValue<T>(string name)
{
    PSVariable variable = this.SessionState.PSVariable.Get(name);
    if (variable != null)
    {
        T obj;
        if (variable.Value is PSObject)
        {
            obj = (T)((PSObject)variable.Value).BaseObject;
        }
        else
        {
            obj = (T)variable.Value;
        }
        return obj;
    }
    else
    {
        return default(T);
    }
}

使い方は

int ret = GetPSVariableValue<int>("val");

みたいな感じです。

元記事:http://blogs.wankuma.com/mutaguchi/archive/2011/05/04/198782.aspx

配列変数がnullかそうでないかを調べることはたまにあるかと思います。しかし、

if($array -eq $null)
{
	'$arrayはnull!'
}
else
{
	'$arrayはnullじゃない!'
}

とするのはダメです。たとえば$array=@($null,$null,121,123)というような配列を渡すと「$arrayはnull!」と表示されてしまいます。

なぜこんなことが起きてしまうかというと、-eq演算子は比較演算子であると同時に、配列をフィルタする演算子でもあるからです。たとえば、1,2,2,3,3,3,4,5という要素を持つ配列のうち、2と一致する要素を持つ配列だけを抽出するのはこんな感じです。

PS > $array=@(1,2,2,3,3,3,4,5)
PS > $array -eq 2
2
2

-eq以外にも各種比較演算子が同様に使えます。3以上の要素のみ返すなら$array -ge 3となります。

つまり最初に挙げた例の場合、左辺の$arrayが配列であれば、TrueかFalseを返すのではなく、右辺の値(ここでは$null)と一致するものを抽出して配列として返すのです。よってもし$arrayに複数の$nullが要素として含まれていると、

if($array -eq $null)

if(@($null,$null))

と解釈され、2要素を持つ配列なのでこれは条件文中でTrueに評価されて結果、ifステートメントの中が実行されてしまうわけです。

$nullが一要素しか含まれない配列、すなわち$array=@($null,121,123)のような配列ではまた挙動が変わり、「$arrayはnullじゃない!」と表示されます。これはなぜかというと、

if($array -eq $null)

if(@($null))

と解釈されるためです。@($null)はFalseと解釈されるので、結果elseが実行されるわけです。

$nullを要素に含まない配列$array=@(1,2,3)とかだと問題が起きないのは、$array -eq $nullが長さ0の配列@()を返し、これはFalseと評価されるからです。(これも良く考えると理由がよくわかりませんが)

このように-eq演算子が配列フィルタとして働いてしまうのを防ぎつつ、配列変数が$nullではないかを確認するには次のようにすると良いでしょう

if($null -eq $array)
{
	'$arrayはnull!'
}
else
{
	'$arrayはnullじゃない!'
}

右辺と左辺を入れ替えただけですが、問題なく動きます。

これが気持ち悪いならば

if($array -isnot [array] -and $array -eq $null)

のようにして変数が配列かどうかまず判断するのでもいいかもです。

これ、案外ハマりどころだと思います。「配列要素に二つ以上nullが含まれるときだけ結果がおかしくなる」のも気づきにくい原因。ぜひ気を付けてください。

ちなみに

if($array)
{
    '$arrayはnullじゃない!'
}
else
{
    '$arrayはnull!'
}

なんてのも駄目です。$array=@($false)や$array=@(0)など、要するに、要素数1でその要素がFalseと解釈される配列が来ると「$arrayはnull!」と表示されてしまいます。

元記事:http://blogs.wankuma.com/mutaguchi/archive/2011/05/04/198780.aspx

2011/04/26

PowerShell 2.0ではAdd-Typeコマンドレットを用いてC#など他言語のコードをコンパイルし実行することが可能です。(P/Invokeも可能です)

ほとんど使っている方はいないと思われますが、JScript.NETのコードもコンパイルして実行できます。以下、コード例です。

$code=@"
static function writeHello()
{
    System.Console.WriteLine("Hello JScript.NET World!");
}
"@

$c = Add-Type -Language JScript -MemberDefinition $code -Name "JSTest" -PassThru
$c[1]::writeHello()

JScript.NETのスタティックメソッドを用意してやると、Add-Typeコマンドレットによりそのメソッドを持ったクラス(ここではMicrosoft.PowerShell.Commands.AddType.AutoGeneratedTypes.JSTest)が生成されます。-passThruパラメータを指定することでその型情報が変数に代入できます。あとはJSTestクラスのスタティックメソッドを::演算子で呼び出すのですが、なぜかAdd-Typeが目的のクラスの型以外にJScript.NETのグローバルクラス?の型情報も一緒に出力するので、型情報が配列になっています。よってインデックスを指定してからスタティックメソッドを呼ぶようにします。

ここではスタティックメソッドを実行する例を挙げましたが、インスタンスメソッドも実行できるか試してみました。

$code=@"
import System;
public class JSTest
{
    public function writeHello()
    {
        Console.WriteLine("Hello JScript.NET World!");
    }
}
"@

Add-Type -Language JScript -TypeDefinition $code
$o = new-object JSTest
$o.writeHello()

ところがこれはNew-Objectのところで「New-Object : "0" 個の引数を指定して ".ctor" を呼び出し中に例外が発生しました: "アプリケーションでエラーが発生しました。"」というエラーになってしまいます。コンストラクタの実行でしくっているようですが…。ちなみに明示的にfunction JSTest()というコンストラクタを定義してやってもだめでした。なんででしょうね?

元記事:http://blogs.wankuma.com/mutaguchi/archive/2011/04/26/198645.aspx

2011/04/20

PowerShell 2.0の文法、仕様などが詳しく書かれたドキュメント(英文)がMicrosoftから公開されました。

Download details: Windows PowerShell Language Specification Version 2.0
http://www.microsoft.com/downloads/en/details.aspx?FamilyID=509b77d0-5e5f-4194-a2d0-61648abfd093

320ページのWordファイルです。私はさっそくダウンロードしてpdfで保存しました。(定義済みフィールドプロパティのローカライズの関係上、ヘッダの文字列にエラーが出ているので修正すると良いです。「Heading 1」を「見出し 1」にすればOK)

PowerShellの文法については公式ドキュメントが長らく公開されていませんでした。私が知るかぎり、5年前にPowerShell 1.0のbeta版が公開されたときに付属していたのが公式から出された唯一のものだと思います(RC版からは現行ドキュメントに置き換え)。今回ようやく公式ドキュメントが公開されたのには、PowerShell言語に「Community Promise」が適用されたことと関係があります。

PowerShell Language now licensed under the Community Promise - Windows PowerShell Blog - Site Home - MSDN Blogs
http://blogs.msdn.com/b/powershell/archive/2011/04/16/powershell-language-now-licensed-under-the-community-promise.aspx

Community Promiseとは、Microsoftが自社開発のプログラミング言語などの特許権を行使しないという宣言で、すでにC#とCLIに適用されているものです。今回、PowerShell言語でもCommunity Promiseが適用され、サードパーティがPowerShell言語の実装を自由に行うことができるようになります。もちろんWindows以外のプラットフォーム上で動作するPowerShellを合法的に開発することも可能になります。すでにPashというオープンソースでマルチプラットフォーム対応のPowerShell実行環境のプロジェクトが存在しますが、このプロジェクトの進行を後押しする決定になると思われます。

元記事:http://blogs.wankuma.com/mutaguchi/archive/2011/04/20/198525.aspx

2011/03/24

Wake on LANでリモートコンピュータを起動する
http://gallery.technet.microsoft.com/scriptcenter/58ea4272-eb3f-45ff-9ff8-d2a90d03b7c4

前回、リモートコンピュータをシャットダウンするスクリプトを書きましたが、今回はWake on LANを使ってリモートコンピュータを起動するスクリプトを投稿しました。ActiveDirectoryの特定OUに属するPC/サーバーすべてに対してWMIを用いてMACアドレスを収集するスクリプトも付属しています。リモートシャットダウンスクリプトとあわせてご活用ください。

元記事:http://blogs.wankuma.com/mutaguchi/archive/2011/03/24/197834.aspx

2011/03/19

リモートコンピュータをシャットダウンする
http://gallery.technet.microsoft.com/scriptcenter/d578bb1c-380e-4442-b967-4f5f50ca3d49

Technet スクリプトセンターに、リモートコンピュータをシャットダウンするPowerShellスクリプトを投稿しました。このスクリプトを利用すると、ActiveDirectoryドメイン内にある複数のWindows PC/サーバーを一括してシャットダウンすることができます。あらかじめ対象とするコンピュータの一覧とシャットダウンに必要な資格情報を出力して保存しておけば、タスクスケジューラなどで決まった時間に自動的に実行することも可能です。

3/11に東日本で発生した大地震とそれに伴う原発事故の影響で、関東地方および東北地方で計画停電が実施・予定されています。PC/サーバーのシャットダウン操作を行わずに電源供給が絶たれると、データの損失やハードウェアへのダメージが懸念されます。このスクリプトによってこれらの事態を回避する役に立てば幸いです。

Microsoftで公開されている他の障害対応・節電情報
マイクロソフト製品群のバックアップ、障害対応および節電に関する情報 | TechNet
停電に備え、節電して Windows PC を使用する方法

震災で亡くなられた方々のご冥福をお祈りするとともに、被害を受けた方々に心よりお見舞い申し上げます。

元記事:http://blogs.wankuma.com/mutaguchi/archive/2011/03/19/197681.aspx

2010/12/15

TechNetスクリプトセンターは以前はMicrosoftが作成したスクリプト(英文解説付き)がメインコンテンツでしたが、最近はコミュニティベース記事としてユーザーがスクリプトを投稿できるようになっています。今回、Microsoft MVPがこのスクリプトギャラリーに投稿したスクリプトを紹介し、スクリプト作成のTipsを取り上げるコンテンツが公開されました。

MVP が伝授するスクリプト作成のヒントとコツ
http://technet.microsoft.com/ja-jp/scriptcenter/gg486878

私も3つスクリプトを紹介させていただきました。PowerShellやWSHスクリプト作成の参考にぜひどうぞ。

元記事:http://blogs.wankuma.com/mutaguchi/archive/2010/12/15/195802.aspx

2010/12/11

記号のみで任意のPowerShellコードを実行 - JPerl advent calendar 2010 sym Track
http://perl-users.jp/articles/advent-calendar/2010/sym/11

最近にわかに流行中(?)の「記号プログラミング」をPowerShellで挑戦してみました。記号プログラミングとは、アルファベットと数字以外の記号のみを使ってプログラムコードを記述する遊戯です。難読化されたコードが書けるという効用はありますがその他には特に意味はなく、パズルや頭の体操に近い遊びだと思っています。ただし言語に対する深い知識が要求されますし、その意味では得るところもあるかもしれません。

Advent Calenderとは、毎年12月に持ち回りで毎日一つずつ記事を公開していく企画だそうで、技術系コミュニティで古くからおこなわれているそうです。http://perl-users.jp/では2008年からおこなわれているようで、今年はhttp://perl-users.jp/articles/advent-calendar/2010/になります。今回私が上げた記事はPerlとは関係ありませんが、Symbolic Programing Trackでは言語を問わないということらしいです。ちなみに今日までは毎日違う言語の記号プログラミング記事が公開されており、11種類の記号プログラミングはなかなか壮観です。

ちなみに、今回の記事においてPowerShellにはeval()に相当する構文がないのでInvoke-Expressionコマンドレットを使わないといけないって書いたんですが、scriptblockクラスの静的メソッドCreate()を使えば文字列からscriptblockを生成し、&演算子で実行可能なことに気づきました。

&$({}."gettype"()::"create"("dir"))

こんな感じで”dir”を実行できます。”gettype”と”create”という文字列を頑張って生成すればできますね。

元記事:http://blogs.wankuma.com/mutaguchi/archive/2010/12/11/195702.aspx

2010/11/04

11/13 プログラミング生放送勉強会 第6回@大阪 [ショートコーディング,PowerShell 他] - Windows Live
http://co9320.spaces.live.com/blog/cns!F8FA3BD6ABDDDB63!314.entry?sa=909959593

PowerShell 基礎文法最速マスター + α

 Windows 7 に標準添付されている PowerShell の基礎文法を解説。PowerShell ならではのワンライナー(1行で書くスクリプト)についても紹介予定。

というわけでぜひどうぞ~

当日はニコニコ生放送でも中継される予定です。

元記事:http://blogs.wankuma.com/mutaguchi/archive/2010/11/04/194456.aspx

古い記事のページへ | 新しい記事のページへ


Copyright © 2005-2018 Daisuke Mutaguchi All rights reserved
mailto: mutaguchi at roy.hi-ho.ne.jp
プライバシーポリシー

Twitter

Books