tech.guitarrapc.cóm

Technical updates

パイプラインの処理を途中で打ち切る方法のPowerShell版

PowerShellの最大の特徴と言われた時に、おそらく掲げるべきはパイプラインだと思います。

それが、cmdやLinux/UNIXシェルにおけるパイプラインと異なる挙動だったり、オブジェクトを伝搬するという性質も含めて良くも悪くもPowerShellをPowerShell足らしめているのはパイプラインかなと。

さて、パイプラインが特徴のPowerShellですが、問題がいくつかあります。その1つが、以下の記事にあるパイプラインの中断処理。

https://d.hatena.ne.jp/anon_193/20121214/1355495660

https://winscript.jp/powershell/308

今回は少しその辺をみてみましょう。

StopUpstreamCommandsException

先に結論だけ書くと、InternalなクラスであってもSystem.Management.Automation.StopUpstreamCommandsExceptionが一番楽ちんでしょう。

ということで、PowerShell版で書くなら雑にこんな感じで。あえてNew-ObjectではなくNew-Objectしています。

https://gist.github.com/guitarrapc/9507f44125dc97c89fdf

中でSystem.Collections.Queueを使ってるのはそれほどの意味はありません。入力されたオブジェクトをいいように扱うためです。なので、カウンタ変数を用意してでもお好きなようにやればいいと思います。

この方式なら、Cmdletでも同様なので好きなように扱えるのもいいでしょう。

はじめは、ReferenceSource見て自分で実装するのでいいんじゃないかなと思いましたが、当然ながら面倒さが上回ったのでやめました。

仕様変更あったらどうしよう

そもそもその場合は、Select-Objectも仕様変わります。もはやその時点で一緒かなと。

Select -Fist 1のGetSteppablePipeline()でもPowerShellスクリプトならいいのですが、CmdletからPowerShell関数呼ぶの悲しさしかないですし仕方ないのかなという妥協もあります。

Connect

ちなみにこのInternal ClassなやつをPublicにしてというリクエストはあります。ワークアラウンドにdo{}while()do{}while()の例もあります。

https://connect.microsoft.com/PowerShell/feedback/details/768650/enable-users-to-stop-pipeline-making-stopupstreamcommandsexception-public

すでにPowerShellのフィードバックは、UserVoiceに移っており、同フィードバックも転載されています。

https://Windowsserver.uservoice.com/forums/301869-powershell/suggestions/11087865-enable-users-to-stop-pipeline-making-stopupstreamc

なので、Stop-Pipeline CmdletやStop-Pipelineのパブリック化がこれに基づきされてほしいですね。Voteしましょう。

Endが実行されないのも、フィードバックすればいいと思います。Endで何かしらするのはリソース破棄以外にもあり得るので、実際あってほしいでしょう。PowerShell Teamの書くスクリプトの中にもProcess{} 句で配列にまとめてEnd{} 句で出力するパターンもあるので。

余談

こういったパイプラインの制限というか、まだまだいけてないシーンはあって、たとえばforeach(){} | ....もそれです。

https://Windowsserver.uservoice.com/forums/301869-powershell/suggestions/11087667-make-the-foreach-statement-work-with-a-pipeline

パイプラインの中断エラーをWrite-Errorで出せるようにとかもあります。

https://Windowsserver.uservoice.com/forums/301869-powershell/suggestions/11088492-option-to-output-a-pipeline-terminating-error-via

昔記事にした| Out-Nullの遅さなども。

https://Windowsserver.uservoice.com/forums/301869-powershell/suggestions/11088471-performance-of-out-null-drastically-worse-then-usi

https://tech.guitarrapc.com/entry/2013/03/12/080349

あとは、Where-ObjectなどでWhere-Object抜きで自動変数 $_ にアクセスしたいという例など。実際これほしいですよね。

https://Windowsserver.uservoice.com/forums/301869-powershell/suggestions/11088306--should-be-accessible-without-curly-brackets-wit

まとめ

リフレクション最高 (