Cmdlet详细信息流

时间:2016-11-10 21:07:41

标签: c# powershell cmdlets cmdlet pscmdlet

我目前正在使用PowerShell 5.0 SDK编写C#cmdlet。

我试图将第三方可执行文件的StandardError传递给cmdlet输出,当时从PowerShell运行实时"。

我目前正在使用MedallionShell库来处理运行过程。我用普通的C#win表单尝试了这个,并使用Command.StandardError.PipeToAsync(Console.OpenStandardOutput())将输出打印为可执行文件生成它到控制台中"实时&# 34。

我尝试创建自己的Stream对象,该对象调用WriteVerbose,但它似乎没有向powershell屏幕打印任何东西(我在运行时传递-Verbose到cmdlet)。

我目前的流程看起来像这样:

  1. Open Powershell ISE
  2. 加载我的模块(C#dll)
  3. 使用参数调用我的cmdlet
    • Command.Run
    • Command.StandardError.PipeToAsync(???)
    • Command.Wait(在此步骤中,输出应该流向powershell窗口)
    • 检查Command.Result.Success。
  4. 有人能指出我正确的方向吗?

2 个答案:

答案 0 :(得分:1)

您不能从任意线程调用Cmdlet的{​​{1}}方法(如Write)。您需要将对此方法的调用封送回管道线程。一种方法是实现消息循环,当其他线程想要在管道线程中调用某些东西时,它会处理来自其他线程的消息。

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

答案 1 :(得分:0)

如果您来自PSCmdlet的{​​{1}} instrad,则可以访问Cmdlet,可以从任何线程调用{{1>,后果自负(我认为它不会以任何方式防止输出的字符串以错误的方式混合) 无论如何,以我的经验,到目前为止,它一直运行良好,如果只有您会使用cmdlet,我认为这种风险可能是可以接受的。

同样,如果在控制台中使用它会很好地工作,如果您稍后将详细流重定向到控制台以外的其他地方或没有“ UI”的地方,我不知道它是否按照预期的方式运行< / p>

如果您还有更多时间实施@PetSerAl解决方案,请确保它更合适