首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Cmdlet细流

Cmdlet细流
EN

Stack Overflow用户
提问于 2016-11-10 21:07:40
回答 2查看 650关注 0票数 1

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

当从powershell“实时”运行时,我试图将第三方可执行文件的StandardError输送到cmdlet输出。

我目前正在使用MedallionShell库来处理这个进程。我用普通的Command.StandardError.PipeToAsync(Console.OpenStandardOutput()) win表单尝试了这一点,并使用C#将输出作为可执行文件以“实时”方式生成到控制台。

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

我当前的流程如下:

  1. 开放Powershell ISE
  2. 加载我的模块(C# dll)
  3. 使用参数调用cmdlet
    • Command.Run
    • Command.StandardError.PipeToAsync(??)
    • Command.Wait (在这个步骤中,输出应该流向powershell窗口)
    • 检查Command.Result.Success。

有人能为我指出正确的方向吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-11-11 20:16:19

您不能只从任意线程调用CmdletWrite方法(如WriteVerbose)。您需要将对该方法的调用编成回管道线程。实现消息循环的一种方法是实现消息循环,当其他线程希望调用管道线程时,消息循环将处理来自其他线程的消息。

代码语言:javascript
复制
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

你可以用这样的方法来测试:

代码语言:javascript
复制
Invoke-Process icacls 'C:\* /c' -Verbose
票数 2
EN

Stack Overflow用户

发布于 2018-06-20 08:47:20

如果您派生自PSCmdlet instrad of Cmdlet,您将可以访问this.Host.UI.WriteVerboseLine,它可以从任何线程中调用,由您自己承担风险(我认为它不会以任何方式阻止输出的字符串以错误的方式混合),在我的经验中,到目前为止它一直运行良好,而且如果cmdlet是只有您将消耗的东西,我认为这种风险可能是可以接受的。

同样,如果在控制台中使用它,我也不知道它是否按照预期的方式工作,如果您稍后将冗长的流重定向到控制台以外的其他地方,或者没有"UI“的东西,我不知道它是否符合预期的方式。

当然,如果您有更多的时间来实现@PetSerAl解决方案,则更合适。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40537019

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档