1

現在、PowerShell 5.0 SDK を使用して C# コマンドレットを作成しています。

「リアルタイム」でpowershellから実行したときに、サードパーティの実行可能ファイルのStandardErrorをコマンドレット出力にパイプしようとしています。

現在、プロセスの実行を処理するために MedallionShell ライブラリを使用しています。私はこれを通常の C# win フォームで試し、 Command.StandardError.PipeToAsync(Console.OpenStandardOutput()) を使用して出力を取得し、実行可能ファイルが「リアルタイム」でコンソールに生成したときに出力を取得しました。

WriteVerbose を呼び出す独自の Stream オブジェクトを作成しようとしましたが、powershell 画面に何も出力されていないようです (実行時にコマンドレットに -Verbose を渡しています)。

私の現在の流れは次のようになります。

  1. Powershell ISE を開く
  2. モジュールをロードする (C# dll)
  3. パラメーターを指定してコマンドレットを呼び出す
    • Command.Run
    • Command.StandardError.PipeToAsync(???)
    • Command.Wait (このステップの間、出力は powershell ウィンドウに流れているはずです)
    • Command.Result.Success を確認してください。

誰かがこれについて正しい方向に私を向けることができますか?

4

2 に答える 2

2

CmdletWriteメソッド ( などWriteVerbose) を任意のスレッドから呼び出すことはできません。このメソッドへの呼び出しをパイプライン スレッドにマーシャリングする必要があります。これを行う方法は、他のスレッドがパイプライン スレッドで何かを呼び出したいときに、他のスレッドからのメッセージを処理するメッセージ ループを実装することです。

Add-Type @‘
    using System;
    using System.Collections.Concurrent;
    using System.Diagnostics;
    using System.Management.Automation;
    using System.Threading;
    [Cmdlet(VerbsLifecycle.Invoke, "Process")]
    public class InvokeProcessCmdlet : Cmdlet {
        [Parameter(Position = 1)]
        public string FileName { get; set; }
        [Parameter(Position = 2)]
        public string Arguments { get; set; }
        protected override void EndProcessing() {
            using(BlockingCollection<Action> messageQueue = new BlockingCollection<Action>()) {
                using(Process process = new Process {
                    StartInfo=new ProcessStartInfo(FileName, Arguments) {
                        UseShellExecute=false,
                        RedirectStandardOutput=true,
                        RedirectStandardError=true
                    },
                    EnableRaisingEvents=true
                }) {
                    int numberOfCompleteRequests = 0;
                    Action complete = () => {
                        if(Interlocked.Increment(ref numberOfCompleteRequests)==3) {
                            messageQueue.CompleteAdding();
                        }
                    };
                    process.OutputDataReceived+=(sender, args) => {
                        if(args.Data==null) {
                            complete();
                        } else {
                            messageQueue.Add(() => WriteObject(args.Data));
                        }
                    };
                    process.ErrorDataReceived+=(sender, args) => {
                        if(args.Data==null) {
                            complete();
                        } else {
                            messageQueue.Add(() => WriteVerbose(args.Data));
                        }
                    };
                    process.Exited+=(sender, args) => complete();
                    process.Start();
                    process.BeginOutputReadLine();
                    process.BeginErrorReadLine();
                    foreach(Action action in messageQueue.GetConsumingEnumerable()) {
                        action();
                    }
                }
            }
        }
    }
’@ -PassThru | Select-Object -First 1 -ExpandProperty Assembly | Import-Module

そして、次のようなものでテストできます:

Invoke-Process icacls 'C:\* /c' -Verbose
于 2016-11-11T20:16:19.913 に答える
0

PSCmdletあなたがinstradから派生した場合、あなた自身の責任で任意のスレッドから呼び出すことができるCmdletアクセス権があります(出力された文字列が間違った方法で混合されることを決して防げないと思います)とにかく、私の経験ではこれまでのところ、常にうまく機能しており、コマンドレットがあなただけが使用するものであれば、リスクは許容できると思います.this.Host.UI.WriteVerboseLine

繰り返しますが、コンソールで使用するとうまく機能します。後で詳細ストリームをコンソール以外の場所または「UI」を持たないものにリダイレクトした場合、意図したとおりに動作するかどうかはわかりません

確かに @PetSerAl ソリューションを実装する時間があれば、より適切です

于 2018-06-20T08:47:20.683 に答える