コマンドレットのパラメータを列挙してみる。|Tweetというわけで、10年目に突入しました。これも私のアウトプットをインプットしてくださる皆様、私のインプットとなるアウトプットをしていただいている皆様のおかげです。いつもありがとうございます。10周年なので軽く歴史を振り返ります。Scriptingという分野でMSMVPを受賞したのがはじまりです。Lab.を始めたのが1999年のことで、それ以前も1997年頃からWindows系のニュースグループに出入りして、オンラインコミュニティではMVP受賞前も知る人ぞ知る存在ではあったように思います。(なんせ、WSHは相当ニッチな分野だったもので、まともに取り扱おうと思う人は当時はほとんどいなかったもので)当時は私はまだ大学生(しかも分野は化学系でIT関係なし)でして、体調崩したり色々あって卒業後も就職せず迷走してた時期でした。IT系の方々とも交流はなく、オンラインのみで何故かWSHというこれまたあんまり誰も手を付けないマイナー分野で突っ走ってる謎の存在だったんじゃないかなーと思います。MVP受賞後はひょこひょこオフラインにも出没するようになり、謎めいた存在から確かに実在する存在として認識されていったのではないかと思います。2006年にはわんくま同盟に加入し、IT系の方々と交流し、また自らセッションをする機会にも恵まれました。WSH入門という連載をさせていただくことができ、商業デビュー(?)を果たしました。WSHがフェードアウトしていくと同時にPowerShellというものが登場したのも2006年のことでした。当時は.NETのことは全然知らなかったのですが、このままでは取り残される!と思い、それなりに勉強を始めたものでした。Frameworksというよく分からない名前に代わり、開発系からサーバー系への移籍となりました。Serverなんてものもまともに触ったこともなく、今思えばあの頃は色々と憶えることがたくさんあったなーと思いますね。PowerShellとなり、PowerShell専門となりました。ポケットリファレンスという書籍を書かせてもらうことができました。自分が本を書くなんて思ってもいなかったですし、あれはいい経験になったと思っています。それからも体調はずっとよくなくて迷走しまくりで随分多くの方々にご迷惑をかけ続けていましたが、なんとかMVPという繋がりを武器に社会と繋がっていようとあがいた感じです。書籍や記事執筆、スピーカー、そして密かにプログラマーとして会社に勤めたりしてた時期もありました。3.0がリリースされた2012年は全国各地で声がかかって(自分で志願したのもありますが)、計8回もセッションを担当しました。DaysでMicrosoft社員さんに交じってセッションを担当したのは貴重な経験でした。今年はPowerShellポケットリファレンスの改訂版を世に出すことができました。PowerShell周りで要所要所でいろいろやってきたなーという感じですね。R2がリリースされる予定で、PowerShellは今後も着実に発展、浸透していくのだと思います。私も陰ながらと言わず割と表立って、そのお手伝いをしていければいいなーと思っています。余談ですが、結局あがいた結果今はどうなん?という話なんですが、結果としてはITの世界では今まで通り、PowerShellの分野ではこういう感じの活動を続けてますが、メインのおしごとは全然ITとも化学とも違う別なことをやっていたりします。おしごとしてるのでそんな目で見ないでくださいね。あと、体調に関しては2年前くらいからほぼ完全に回復してるので、遠慮せず遊んでやってください。こんなことを書いてると、なんか「お前...消えるのか...?」と思われてしまうかもしれませんがそんなことは全然ない(と思う)ので、これからも変わらず、お付き合いいただければと思います。Vistaの登場で追加されたプログラムで、デスクトップ上にガジェットと呼ばれるミニプログラムを貼り付けることができます。(+VBScript)で記述することができます。Windows7の登場で名称が「Windowsデスクトップガジェット」と変更され、一部仕様に変更が加えられたものの現役でした。Galleryでの公開が中止されました。現在は登録されたガジェットのリストは表示されるものの、ダウンロードができない状態です。まもなくサイト自体が閉鎖されるものと思われます。Windowsというページに飛ばされますが、ここでは(おそらく人気上位であった)ガジェットが数点のみダウンロードできるという状態です。この措置に対するMicrosoftの公式コメントがこちらになります。Appにシフトしてねでもまだガジェットに興味がある人もいるだろうから一応開発ドキュメントは残しておくよまだガジェットを公開したいのならCodePlexでどうぞという感じになるかと思います。Appを移行先に指定するのはかなり無理があるように思いますが、どうもMicrosoftはMetroと技術的にかぶるガジェットをさっさと亡きものにしたいようです。Previewのクラシックデスクトップでは一応、今のところはデスクトップガジェットの機能は削除されていませんが、これからの開発の過程で削除されてしまう可能性も十分にありそうです。ちなみにデスクトップガジェットはたとえIE9をインストールしてもHTML5コンテンツは動きませんし、JavaScriptもチャクラではなくJScript5.8で動きます。この時点でガジェットの未来はなさそうだと踏んでいましたが、思ったより早い終焉を迎えるようです。AppはたしかにWinRT上でJavaScript+HTML5+CSS3で開発することができ、ガジェットで培われたノウハウの一部は流用できる可能性はあるものの、ガジェットから単純に移行というのは難しそうです。Appは一つだけクラシックデスクトップと同時に表示できる)。告知も私の知るかぎりなかったですし、気づけばいきなり消滅していたという感じで、お困りの方も今後増えそうです(たしかにガジェットはいまいち流行ってなかったですがいきなりはヒドイ)。現在追加インストールしているガジェットは、今後入手困難になる可能性が高いので、各自でバックアップを取っておくことをお勧めします。Sidebar\Gadgetsの各サブフォルダがガジェット一つ一つに対応しているので、これをバックアップしておけば問題ありません。再インストールも単にこれらのファイルを同じ場所に書き戻すだけでOKです。.gadgetファイルは単に関連ファイルをzipで固めたものなので、ご自分でこれらの各サブフォルダをzipにして.gadgetにリネームすればインストーラーを復元することもできます。これらの措置は自己責任にてお願いします。各ガジェット作者のアナウンスがある場合はそちらに従ってください。それにしても、WindowsデスクトップにHTML+スクリプトで記述されたミニプログラムを配置するといえば古くは「アクティブデスクトップ」まで遡ることになると思いますが、「ガジェット」で安定するかと思ったら二世代しか持ちませんでしたね。競合するGoogleデスクトップも終了しましたし、あまりウケがよろしくないんでしょうか。|TweetJScriptは言語単体ではSafeArrayを作ることができません。そこでJScriptでSafeArrayが必要な場合、VBScriptを併用しVBScriptの配列(これはSafeArrayです)をJScriptに取り込む方法や、Scripting.DictionaryのItems()メソッドを使う方法などが使われているようです。これらの方法で多次元のSafeArrayを作るサンプルをあまり見かけませんでした。Dictionaryの方法ではそもそも1次元しか無理ですしね。プログラマとSEのあいだこの記事の二つ目の例ではExcelを使用しRegionオブジェクトが二次元配列を返す点を利用しています。これはなかなか盲点というかアイデアものではありますが、実行速度にやや難があるかな?と思いました。この記事の方法は、もともとExcelで二次元配列が必要な場合があったから考案されたもののようで、その用途においてはExcelを起動するコストは考慮しなくてよいのかもしれません。一つ目の方法ではVBScriptを併用していますが、.wsfファイルを使用してJScriptとVBScriptを混在させる形式をとっています。この方法はWSHでは問題ありませんが、複数のスクリプトエンジンを混在できないホスト環境では問題があります。ASPなどほとんどの環境では大丈夫そうです。私が最近はまっているJScript実行環境であるところのAzureaでは無理ですね。WSHでも.jsファイルにこだわるのであれば。そこで考えたのが、ScriptControlを使用してJScriptのコードの中でVBScriptのコードを実行させる方法です。以下のような感じになります。sc.Run("ConvertArray",jsArray2d);}まあやっていることは本当にJScriptの配列をバラしてVBScriptの二次元配列に詰め直しているだけです。いくつかポイントがあって、まずVBScriptからはJScriptのオブジェクトメンバーにドット演算子でアクセスができます。JScriptの配列はオブジェクトと同一であり、配列はオブジェクトに0,1,2...という名前のプロパティが存在することになります。VBScriptで数字のメンバ名はそのままではドット演算子でアクセスできないので、[]でくくる必要があります(これ、予約語なんかもそうですね。あとVB6でもVB.NETでも同じなので覚えておくといいかも)。次元数2の配列の長さを調べるのにjsArray.[0]でまず内側の配列オブジェクトを取得しているわけです。Next構文が使えます。Nextを使ってインデックスアクセスはできません。いうのもjsArray.[3]とかはあくまでjsArrayオブジェクトの3プロパティの値を参照しているにすぎず、jsArray.[I]という書き方ができないからです(これだと単にIプロパティの値を見てることになる)。Eval関数を併用すれば可能ではありますが、コードの中にコードを含ませさらにその中にまたコードを含ませるのも微妙なのでここでは使ってません。あとは紹介した記事の関数部分だけ置き換えればJScriptのVBArrayオブジェクトを用いたテストもできるかと思います。注意点はExcelオブジェクトは配列添え字が1から始まるのに対し、VBScriptの配列は0から始まる点です。LBound関数を使えばその差違は吸収できるかな、と思います。最初は多次元配列というかn次元配列に拡張した関数を書いてやろうと企んでましたが挫折しました。ネストしたループではなく再帰呼び出しである必要がありますし、ReDimは次元数を動的に指定することができないので実行するVBScript自体を動的生成しなければいけません。興味がある方はチャレンジしてみてください。|TweetPowerShellでJSONをパースする方法はいくつかあると思います。3.5から追加されたクラスで、JSONデータを読み書きするXMLReader/Writerを提供します。JSONをパースしてXMLに変換することが可能です。XMLはPowerShellから簡単に扱えるので有用な方法と言えるでしょう。PowerShellからの使用方法についてはこちらの記事が参考になります。3.5が入っていない環境では1の方法が使えないので別の方法を考える必要があります。JSONはテキストデータなので、頑張って自力でパースすることもできなくはないでしょう。PowerShellでやっている例はこちらになります。ScriptControl+JScriptを用いるもう少し簡便な方法はないかなと思っていろいろ考えたんですが、PowerShellではScriptControlを用いるとJScriptやVBScriptを実行することができます。JSONはJavaScriptで扱うことを想定しているだけあって、JScriptではeval()するだけでJSONをオブジェクトに変換することができます。')').toString();}"$sc.AddCode($jscode)$jsobj=$sc.CodeObject.parseJSON($json)$jsobjこのコードを実行すると、確かにJSONがパースされ、結果が$jsobjという変数に格納されるのですが、残念ながらPowerShellはJScriptのオブジェクト(JScriptTypeInfo)を展開することができないようなのです。Array)に変換し、その結果オブジェクトをPowerShellに戻すという方法を考えました。Arrayは扱えるので理屈の上ではうまくいきます。(参考までに、ASPでこの方法を実際にコードにしてる方がいらっしゃいました。ゆるゆると)しかしこの方法は当初の目的「簡便にJSONをパースする」からだいぶ離れてしまっています。JScript.NETを用いるそうだ、JScriptが駄目ならJScript.NETを使えばいいじゃない。JScript.NETなら結果は.NETのオブジェクトで返るしPowerShellでも読めるだろう、ということで、この前このブログで紹介したAdd-Typeコマンドレットを使ってJScript.NETのコードを実行する方法を利用してやってみました。名前が列挙されるという感じでうまくいきました。ここで$jsobjに格納されているのはMicrosoft.JScript.JSObjectクラスのオブジェクトです。このクラスのItemプロパティ(引数付きプロパティ、PowerShellではParameterizedPropertyと呼ばれる)にプロパティ名を引数として渡すと、その値が返却されます。PowerShellでは引数付きの既定プロパティはC#のインデクサと同様の構文で値が参照できるので、$jsobj[“items”]のように[]でアクセス可能です。これは$jsobj.Item(“items”)としても同様の結果が得られます(プロパティなのに()で値を取るところはVB風味?)。配列の列挙ですが、JSObjectと、オブジェクトが配列の場合はその派生クラスであるJSArrayObjectクラスになりますが、これらはIEnumerableインターフェースを実装しているのでforeachで列挙が可能です。ここで列挙されるのはあくまでkey、すなわちプロパティ名の方です。値が列挙されるわけではありません。ご存じのとおり、JavaScriptの配列、連想配列、オブジェクトは同じものであり、配列の場合はkeyが配列インデックスの数字に相当します。そのため配列をforeachしても「0,1,2...」という数字が列挙されるだけです。配列を列挙する場合は、この例のように、一旦JSArrayObjectを変数で受けて、それに対してforeachし、列挙した要素(インデックスの数字)をJSArrayObject.Itemプロパティの引数に与えることで、JS配列要素の値を取得してやる必要があると思います。2.0は入ってる)環境では、それほど手間をかけずJSONを扱えるという点でそれなりに有用ではないでしょうか。JSObjectもXMLみたいに型アダプタがあればプロパティアクセスできるようになるでしょうし、Add-Memberコマンドレットを駆使してJSObjectに動的にプロパティを追加する関数を書くのもいいかもしれません。そこまでいくとやはりお手軽からはかけ離れてしまうので今回はこの辺にとどめておきましょう。|Tweet正規表現は便利なのですが、「ある文字列が存在したときはマッチしない」という正規表現を書くのはちょっと考えないとできないと思います。今回考えてみたので使ってみてください。^(?!.*【文字列】)PowerShellによる使用例。「test」という文字列が含まれているとFalseになる。"^(?!.*test)"Trueこのようにちゃんと動きます。この正規表現の意味は、「文頭があるとマッチする。あとに0文字以上の何かの文字およびtestという文字列が続く場合はマッチしない」となります。評価対象になる文字列には必ず文頭が存在するので^が基本的にはすべてマッチするのですが、後に否定の先読み(?!・・・)をつけてマッチする条件を絞っているのがポイントです。【文字列】の部分は、任意の正規表現も使用可能です。正規表現の否定、論理反転ができるわけですね。正規表現の否定の先読み(?!・・・)は処理系によっては使えないそうです。.NET、VBScript、JavaScript、Perl、PHPなんかの最近のバージョンでは大丈夫みたいです。なんでもかんでも正規表現にしなくても、コードを書いてやれば大抵のことは解決します。この例でも、"test"のマッチ結果を論理否定すれば求める結果は得られます。正規表現でしかプログラムの機能を拡張できないケースというのもよくありますよね。TwitterクライアントのNG処理とか。いうときに使えばいいんじゃないかなと思います。2.0では新しい演算子-splitと-joinがサポートされました。-splitは「文字列を特定の文字で切り分けて配列を作る」演算子、-join演算子は「配列を特定の文字列を使って繋いで一つの文字列にする」演算子です。","$a[1]これは-split演算子を使って、a,b,c,d,eという文字列を、,(カンマ)で切り分けて配列にし、2つ目の要素を取り出す例です。結果は次のようになります。b配列は-joinを使って一つの文字列にすることができます。先ほど作った配列を&という文字で繋げるには次のようにします。"&"結果は以下のようになります。a&b&c&d&eこのように、PowerShellでもVBScriptのSplit関数やJoin関数を使った場合と同様の文字列配列操作が可能になりました。1.0ではこのようにします。-split演算子の代わり。string型のインスタンスに対し、Splitメソッドを実行する。$b="a,b,c,d,e".Split(",")-join演算子の代わり。stringクラスのスタティックメソッドJoin()を使用。|TweetレガシASPでサイトを作ってると、Shift-JISなサイトを作るのが基本になると思います。なんでかというと、FileSystemObjectが基本的にShift-JISの読み書きにしか対応しておらず(UTF-16もいけますが)、いまどきのUTF-8を使うのはちょっと面倒です(FSOの代わりにADODB.Streamを使えば行けますけどどうでしょうねー?私はあんまり好きじゃないです)。UTF-8な他のWebサイト/サービスと連携する場合はどうしても避けて通れません。そこでレガシASPでShift-JISなページを作る際、UTF-8文字列を扱う上で知っておくべきこと。escape関数を使うとShift-JISでURLエンコードがされるASPはだいたいVBScriptで書くと思うんですが、隠し関数であるescape関数を使うとURLエンコードができます。escape関数は呼び出し元のページコードの文字コードでエンコードします。Shift-JISなページで呼び出すとShift-JISのエンコードURLを出力します。(ちなみにWSHで使うとUTF-16のものになる)JScriptのencodeURIComponent関数はどんな場合でもUTF-8文字列を出力するので、これを使うといいでしょう。js.encodeURIComponent("文字列")逆にShift-JISなページでShift-JISなエンコードURL文字列を取得したい場合は単にescape関数を呼び出せばいいです。別なケースですがUTF-8なページでShift-JISなエンコードURLを取得したい場合は、こんな関数を使うといいんじゃないでしょうか。"文字列"このように何も考えずに書いても、勝手にUTF-8でURLエンコードされてPostされるので大丈夫です。標準機能だけでやろうと思うとADODB.Streamを使うしかないと思います。ちなみに読み込むページの文字コードが不明の場合は判定した上で変換する必要がありますが、これはかなり面倒なので、BASP21を使うといいんじゃないでしょうか。Functionこれは引数にURLを与えるとそのHTMLを文字列として取得します。対象の文字コードが何であってもOKなのがミソ。UTF-8のURLエンコードされたクエリ、あるいはPOSTされたデータを受ける際これのやり方が分からない!具体的にはトラックバックpingなんかを受け取る際に困ります(さすがにShift-JISでトラックバックpingを送れ!というのはゴーマンだと思います)。私はここだけASP.NETを使って逃げました。どなたかやり方わかります?追記。Request.BinaryReadしたやつをADODB.Streamにかけたあと&でsplitして=でsplitしてDictionaryに入れてdecodeURIComponentすればいけるかな?ただし、ここだけASP.NETを使う際にも注意が必要です。web.configの<system.web>セクションに<globalizationrequestEncoding="Shift-JIS"responseEncoding="Shift-JIS"fileEncoding="Shift-JIS"/>というのを埋め込んで、まずレスポンスエンコーディングをShift-JISにしておきます。IISの設定でもいいですが。Request.QueryStringやRequest.Formは使えないので、Request.InputStreamを使ってごりごり読まないと駄目じゃないかな・・・。VB.NETですがUTF-8なトラックバックpingをShift-JISなページで受けるサンプルコードを。IfNext↑自分でも謎なコードを書いてたのでちょっとマシなのに修正。コンパイル通るかどうかわかりませんが・・・さらにゴミコードが残ってたのでバッサリ切りました。!これの問題は改行コードが消えることなんです。対処法は見つけていません(勘違いでした)。いい方法があったら教えてください。そもそもInputStreamを使わないでRequest.Formとか使いたいんですが、Shift-JISのところにUTF-8が来るとうまくいかないですねぇー。いうわけで長々と書きましたが、Shift-JISにこだわらなければこんなに苦労することはないです。FileSystemObjectがUTF-8を読み書きできないので私はSJISにこだわってるだけです。|TweetOutlook2007は、メールアドレスに.の連続(hoge...hoge@example.com)や@の前に.がある場合(hoge.hoge.@example.com)にはメールを送信することができません。受信トレイに「システム管理者」から送信不能と通知メッセージが入ります。これは別にOutlook2007が悪いんじゃなくて、RFCに準拠しているためです。Docomoやauなど、このRFCに準拠していないキャリアがあって、結構、よく見ます。その辺の詳しい事情はこちらなどをどうぞ。Outlookユーザーはじゃあこれらのメアドにはメールを送れないのか、と言うとそうではなく、実は裏技があって、@の前の部分を""(ダブルクォーテーション)でくくることで送信可能になります。"hoge...hoge"@example.comや"hoge.hoge."@example.comなどのようにします。これはOKとRFCで規定されてるらしいですね。毎回これを手で入力するのはメンドイ!ということでなんとかしてみました。SubこのようなコードをThisOutlookSessionに埋め込みます。1.0と5.5を参照設定してください。マクロなんで毎回起動時にマクロを有効にするか聞かれます。(以上の意味が分からない方は使わないほうが無難です)すると、問題あるメールアドレスのメールを送信しようとすると、正しくクォーテーションがつけられたメールアドレスに変換します。Cc:やBcc:にも対応してもよかったんですがそれは宿題ということで。Cancel=Trueは要らないと思ったんですが、これを取るとなんかさらに''でクォートされて送信トレイに残骸が残ってしまいます。一度メール編集画面に戻るようにしています。|TweetあまりガジェットをVBScriptで書いてる人はいないと思いますが、System.*で始まるクラスのメンバを使うときは注意が必要です。VBScriptであろうとも、System.*で始まるクラスおよびメンバ名はCasesensitive(大文字小文字を区別する)ですつまり、System.Gadget.Settings.readStringはOKですが、System.Gadget.Settings.ReadStringはNGです。これはハマりますねぇー。皆さんも注意してくださいね。[string]でできるとあるんですがこれは嘘ですね。$a.gettype().fullnameSystem.RuntimeTypeRCとかの段階ではそうだったのかもしれませんが...New-Variableコマンドレットを使っても初期値を-valueパラメータで与えないと駄目です。結論として「PowerShellには(値を初期化しない)変数宣言をする方法はない」となると思います。