如何捕获Powershell CmdLet';以编程方式从C调用CmdLet时的详细输出# 背景 我正在Windows 7上使用Powershell 2.0 我正在Powershell模块中编写cmdlet(“模块”是Powershell 2.0的新版本) 为了测试cmdlet,我正在VisualStudio2008中编写单元测试,以编程方式调用cmdlet 参考文献 名为“如何从Cmdlet中调用Cmdlet”的演示了如何从C#调用Cmdlet 源代码

如何捕获Powershell CmdLet';以编程方式从C调用CmdLet时的详细输出# 背景 我正在Windows 7上使用Powershell 2.0 我正在Powershell模块中编写cmdlet(“模块”是Powershell 2.0的新版本) 为了测试cmdlet,我正在VisualStudio2008中编写单元测试,以编程方式调用cmdlet 参考文献 名为“如何从Cmdlet中调用Cmdlet”的演示了如何从C#调用Cmdlet 源代码,c#,powershell,powershell-2.0,cmdlet,C#,Powershell,Powershell 2.0,Cmdlet,这是我实际代码的一个提炼版本-我将其尽可能小,以便您可以清楚地看到我遇到的问题: using System; using System.Management.Automation; namespace DemoCmdLet1 { class Program { static void Main(string[] args) { var cmd = new GetColorsCommand();

这是我实际代码的一个提炼版本-我将其尽可能小,以便您可以清楚地看到我遇到的问题:

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

    }
}
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");
    }
}
  • 除非至少将
    $VerbosePreference
    设置为“Continue”,否则详细输出不会实际输出
  • 使用PowerShell类型运行
    cmdlet
    ,并从
    Streams.Verbose
    属性中读取
    VerboseRecord
    实例
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}
这应该很容易翻译成C


重要的一行是第5行和第6行。这基本上为会话以及即将发布的新命令和脚本设置了$verbosepreference。

我的答案中缺少了一个backtick`标记-这会阻止$verbosepreference变量提前计算。为什么不将我的回答标记为答案?如果需要实时详细记录,订阅powershell实例的streams属性上的datachanged事件。我已升级该问题以说明您提供的新信息。我仍然无法回答此问题,因为我还不知道如何将“Get-Colors”cmdlet添加到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");
    }
}
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}
1.        string scriptFile = "Test.ps1";
2.        using (PowerShell ps = PowerShell.Create())
3.        {
4.          const string getverbose = "$verbosepreference='continue'"; 
5.          ps.AddScript(string.Format(getverbose));
6.          ps.Invoke();
7.          ps.Commands.Clear();
8.          ps.AddScript(@".\" + scriptFile);
9.          ps.Invoke();
10.         foreach (var v in ps.Streams.Verbose)
11.         {
12.               Console.WriteLine(v.Message);
13.         }
14.       }