本文介绍了从 C# 以编程方式调用 CmdLet 时,如何捕获 Powershell CmdLet 的详细输出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  • 我在 Windows 7 上使用 Powershell 2.0.
  • 我正在 Powershell 模块中编写 cmdlet(模块"是 Powershell 2.0 的新增功能).
  • 为了测试 cmdlet,我正在 Visual Studio 2008 中编写单元测试,以编程方式调用 cmdlet.
  • This Article on MSDN called "How to Invoke a Cmdlet from Within a Cmdlet" shows how to call a cmdlet from C#.
  • 这是我实际代码的提炼版本—我已经把它做得尽可能小,这样你就可以清楚地看到我遇到的问题:

  • This is a distilled version of my actual code — I've made it as small as possible so that you can see the problem I am having clearly:

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");
        }

    }
}

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

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

Here is is the source code based on the answer below.

有些事情我还是不清楚:* 如何调用Get-Colors"cmdlet(理想情况下不必将其作为字符串传递给 ps 对象)* 如何在生成时获取详细输出,而不是在最后获取它们的集合.

Some things are still not clear to me:* How to call the "Get-Colors" cmdlet (ideally without having to pass it as a string to the ps objet)* How to get the verbose output as it is generated instead of getting an collection of them at the end.

    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");

            }

        }
    }

上面的代码生成此输出:

The code above generates this output:

d:\DemoCmdLet1\DemoCmdLet1>bin\Debug\DemoCmdLet1.exe
verbose output: 42

2010-01-16 更新

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

UPDATE ON 2010-01-16

by using the Powershell class (found in System.Management.Automation but only in the version of the assembly that comes with the powershell 2.0 SDK, not what comes out-of-the-box on Windows 7) I can programmatically call the cmdlet and get the verbose output. The remaining part is to actually add a custom cmdlet to that powershell instance - because that was my original goal - to unit test my cmdlets not those that come with powershell.

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");
    }
}

推荐答案

  • 除非将 $VerbosePreference 至少设置为继续",否则实际上不会输出详细输出.
  • 使用 PowerShell 类型运行您的 cmdlet,并从 Streams.Verbose 属性中读取 VerboseRecord 实例
    • Verbose output is not actually output unless $VerbosePreference is set at least to "Continue."
    • Use the PowerShell type to run your cmdlet, and read VerboseRecord instances from the Streams.Verbose propery
    • powershell 脚本中的示例:

      Example in powershell script:

      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}
      

      这应该很容易翻译成 C#.

      This should be easy to translate into C#.

      这篇关于从 C# 以编程方式调用 CmdLet 时,如何捕获 Powershell CmdLet 的详细输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-30 20:14