title: How to capture a Powershell CmdLet's verbose output when the CmdLet is programmatically Invoked from C#
body: <h1>BACKGROUND</h1>
  
  <ul>
  <li>I am using Powershell 2.0 on Windows 7.</li>
  <li>I am writing a cmdlet in a Powershell module ("module" is new to Powershell 2.0).</li>
  <li>To test the cmdlet I am writing Unit tests in Visual Studio 2008 that programmatically invoke the cmdlet.</li>
  </ul>
  
  <h1>REFERENCE</h1>
  
  <ul>
  <li><a href="http://msdn.microsoft.com/en-us/library/ms714876%28VS.85%29.aspx" rel="nofollow noreferrer" title="How to Invoke a Cmdlet from Within a Cmdlet">This Article on MSDN</a> called "How to Invoke a Cmdlet from Within a Cmdlet" shows how to call a cmdlet from C#.</li>
  </ul>
  
  <h1>THE SOURCE CODE</h1>
  
  <ul>
  <li><p>This is a distilled version of my actual code &mdash; I've made it as small as possible so that you can see the problem I am having clearly:</p>
  
  <pre><code>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&lt;string&gt;())
                  {
                     Console.WriteLine("- " + i );   
                  } 
             } 
         } 
  
      [Cmdlet("Get", "Colors")]
      public class GetColorsCommand : Cmdlet
      {
          protected override void ProcessRecord()
          {
              this.WriteObject("Hello");
              this.WriteVerbose("World");
          }
  
      }
  }
  </code></pre></li>
  </ul>
  
  <h1>COMMENTS</h1>
  
  <ul>
  <li>I understand how to enable and capture verbose output from the Powershell command line; that's not the problem.</li>
  <li>In this case I am programmatically invoking the cmdlet from C#.</li>
  <li>Nothing I've found addresses my specific scenario. Some articles suggest I should implement my own PSHost, but seems expensive and also it seems like a have to call the cmdlet as text, which I would like to avoid because that is not as strongly typed.</li>
  </ul>
  
  <h1>UPDATE ON 2009-07-20</h1>
  
  <p>Here is is the source code based on the answer below.</p>
  
  <p>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 <em>as it is generated</em> instead of getting an collection of them at the end. </p>
  
  <pre><code>    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&lt;string&gt;())
                  {
                     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");
  
              }
  
          }
      }
  </code></pre>
  
  <p>The code above generates this output:</p>
  
  <pre><code>d:\DemoCmdLet1\DemoCmdLet1&gt;bin\Debug\DemoCmdLet1.exe
  verbose output: 42
  </code></pre>
  
  <h1>UPDATE ON 2010-01-16</h1>
  
  <p>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.</p>
  
  <pre><code>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");
      }
  }
  </code></pre>