如何从C#以编程方式调用CmdLet时捕获Powershell CmdLet的详细输出

nam*_*los 9 c# powershell cmdlet powershell-2.0

背景

  • 我在Windows 7上使用Powershell 2.0.
  • 我在Powershell模块中编写了一个cmdlet("模块"是Powershell 2.0的新增功能).
  • 为了测试cmdlet,我在Visual Studio 2008中编写单元测试,以编程方式调用cmdlet.

参考

来源代码

  • 这是我实际代码的简化版本 - 我尽可能小,以便您可以清楚地看到问题:

    using System;
    using System.Management.Automation;   
    
    namespace DemoCmdLet1
    {
        class Program
        {
            static void Main(string[] args)
            {
                var cmd = new GetColorsCommand();
    
                    foreach ( var i in cmd.Invoke<string>())
                    {
                       Console.WriteLine("- " + i );   
                    } 
               } 
           } 
    
        [Cmdlet("Get", "Colors")]
        public class GetColorsCommand : Cmdlet
        {
            protected override void ProcessRecord()
            {
                this.WriteObject("Hello");
                this.WriteVerbose("World");
            }
    
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

评论

  • 我了解如何从Powershell命令行启用和捕获详细输出; 那不是问题.
  • 在这种情况下,我以编程方式从C#调用cmdlet.
  • 我找到的任何内容都没有解决我的具体情况.一些文章建议我应该实现我自己的PSHost,但似乎很昂贵,而且似乎必须将cmdlet称为文本,我想避免,因为它不是那么强类型.

更新于2009-07-20

以下是基于以下答案的源代码.

有些事情对我来说仍然不清楚:*如何调用"Get-Colors"cmdlet(理想情况下无需将其作为字符串传递给ps对象)*如何获取详细输出,因为它生成而不是获取最后收集它们.

    using System;
    using System.Management.Automation;   

    namespace DemoCmdLet1
    {
        class Program
        {
            static void Main(string[] args)
            {
                var ps = System.Management.Automation.PowerShell.Create();

                ps.Commands.AddScript("$verbosepreference='continue'; write-verbose 42");

                foreach ( var i in ps.Invoke<string>())
                {
                   Console.WriteLine("normal output: {0}" , i );   
                }
                foreach (var i in ps.Streams.Verbose)
                {
                    Console.WriteLine("verbose output: {0}" , i);
                }

            }
        }

        [Cmdlet("Get", "Colors")]
        public class GetColorsCommand : Cmdlet
        {
            protected override void ProcessRecord()
            {
                this.WriteObject("Red");
                this.WriteVerbose("r");
                this.WriteObject("Green");
                this.WriteVerbose("g");
                this.WriteObject("Blue");
                this.WriteVerbose("b");

            }

        }
    }
Run Code Online (Sandbox Code Playgroud)

上面的代码生成了这个输出:

d:\DemoCmdLet1\DemoCmdLet1>bin\Debug\DemoCmdLet1.exe
verbose output: 42
Run Code Online (Sandbox Code Playgroud)

更新2010-01-16

通过使用Powershell类(在System.Management.Automation中找到但仅在powershell 2.0 SDK附带的程序集版本中,而不是Windows 7上开箱即用的版本),我可以通过编程方式调用cmdlet和得到详细的输出.剩下的部分是实际向该PowerShell实例添加一个自定义cmdlet - 因为这是我最初的目标 - 单元测试我的cmdlet而不是PowerShell附带的cmdlet.

class Program
{
    static void Main(string[] args)
    {
        var ps = System.Management.Automation.PowerShell.Create();
        ps.AddCommand("Get-Process");
        ps.AddParameter("Verbose");
        ps.Streams.Verbose.DataAdded += Verbose_DataAdded;
        foreach (PSObject result in ps.Invoke())
        {
            Console.WriteLine(
                    "output: {0,-24}{1}",
                    result.Members["ProcessName"].Value,
                    result.Members["Id"].Value);
        } 
        Console.ReadKey();
    }

    static void Verbose_DataAdded(object sender, DataAddedEventArgs e)
    {
        Console.WriteLine( "verbose output: {0}", e.Index);
    }
}


[Cmdlet("Get", "Colors")]
public class GetColorsCommand : Cmdlet
{
    protected override void ProcessRecord()
    {
        this.WriteObject("Hello");
        this.WriteVerbose("World");
    }
}
Run Code Online (Sandbox Code Playgroud)

x0n*_*x0n 10

  • 除非$VerbosePreference至少设置为"继续",否则实际上不会输出详细输出.
  • 使用PowerShell类型运行您的cmdlet,并VerboseRecordStreams.Verbose属性中读取实例

powershell脚本中的示例:

ps> $ps = [powershell]::create()
ps> $ps.Commands.AddScript("`$verbosepreference='continue'; write-verbose 42")
ps> $ps.invoke()
ps> $ps.streams.verbose
Message   InvocationInfo                          PipelineIterationInfo
-------   --------------                          ---------------------
42        System.Management.Automation.Invocat... {0, 0}
Run Code Online (Sandbox Code Playgroud)

这应该很容易转换为C#.