PowerShellの最大の特徴と言われた時に、おそらく掲げるべきはパイプラインです。 それが、cmdやLinux/UNIXシェルにおけるパイプラインと異なる挙動だったり、オブジェクトを伝搬するという性質も含めてPowerShellをPowerShell足らしめているのはパイプラインかなと。
さて、パイプラインが特徴のPowerShellですが、問題がいくつかあります。その1つが、以下の記事にあるパイプラインの中断処理。
今回は少しその辺をみてみましょう。
StopUpstreamCommandsException
先に結論だけ書くと、InternalなクラスであってもSystem.Management.Automation.StopUpstreamCommandsExceptionが一番楽ちんでしょう。
ということで、PowerShell版で書くなら雑にこんな感じで。あえてNew-ObjectではなくNew-Objectしています。
中でSystem.Collections.Queueを使ってるのはそれほどの意味はありません。入力されたオブジェクトをいいように扱うためです。なので、カウンタ変数を用意してでもお好きなようにやればいいでしょう。
この方式なら、Cmdletでも同様なので好きなように扱えるのもいいでしょう。
はじめは、ReferenceSource見て自分で実装するのでいいんじゃないかなと思いましたが、当然ながら面倒さが上回ったのでやめました。
仕様変更あったらどうしよう
そもそもその場合は、Select-Objectも仕様変わります。もはやその時点で一緒かなと。
Select -Fist 1のGetSteppablePipeline()でもPowerShellスクリプトならいいのですが、CmdletからPowerShell関数呼ぶの悲しさしかないですし仕方ないのかなという妥協もあります。
Connect
ちなみにこのInternal ClassなやつをPublicにしてというリクエストはあります。ワークアラウンドにdo{}while()やdo{}while()の例もあります。
すでにPowerShellのフィードバックは、UserVoiceに移っており、同フィードバックも転載されています。
なので、Stop-Pipeline CmdletやStop-Pipelineのパブリック化がこれに基づきされてほしいですね。Voteしましょう。
Endが実行されないのも、フィードバックすればいいです。Endで何かしらするのはリソース破棄以外にもあり得るので、実際あってほしいでしょう。PowerShell Teamの書くスクリプトの中にもProcess{} 句で配列にまとめてEnd{} 句で出力するパターンもあるので。
余談
こういったパイプラインの制限というか、まだまだいけてないシーンはあって、たとえばforeach(){} | ....もそれです。
パイプラインの中断エラーをWrite-Errorで出せるようにとかもあります。
昔記事にした| Out-Nullの遅さなども。
あとは、Where-ObjectなどでWhere-Object抜きで自動変数 $_ にアクセスしたいという例など。実際これほしいですよね。
まとめ
リフレクション最高