tech.guitarrapc.cóm

Technical updates

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

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

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

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

d.hatena.ne.jp

winscript.jp

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

目次

StopUpstreamCommandsException

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

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

gist.github.com

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

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

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

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

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

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

Connect

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

Bing

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

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

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

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

余談

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

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

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

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

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

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

tech.guitarrapc.com

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

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

まとめ

リフレクション最高 (