title: How can I read the verbose output from a Cmdlet in C# using Exchange Powershell
body: <p>Environment: Exchange 2007 sp3 (2003 sp2 mixed mode)</p>
  
  <p>Visual Studio 2008, .Net 3.5</p>
  
  <hr>
  
  <p>I'm working with an Exchange powershell move-mailbox cmdlet and have noted when I do so from the Exchange Management shell (using the Verbose switch) there is a ton of real-time information provided.</p>
  
  <p>To provide a little context, I'm attempting to create a UI application that moves mailboxes similarly to the Exchange Management Console but desire to support an input file and specific server/database destinations for each entry (and threading).</p>
  
  <p>Here's roughly what I have at present but I'm not sure if there is an event I need to register for or what...  And to be clear, I desire to get this information in real-time so I may update my UI to reflect what's occurring in the move sequence for the appropriate user (pretty much like the native functionality offered in the Management Console).  And in case you are wondering, the reason why I'm not content with the Management Console functionality is, I have an algorithm which I'm using to balance users depending on storage limit, Blackberry use, journaling, exception mailbox size etc which demands user be mapped to specific locations... and I do not desire to create many/several move groups for each common destination or to hunt for lists of users individually through the management console UI. </p>
  
  <p>I can not seem to find any good documentation or examples of how to tie into reading the verbose messages that are provided within the console using C# (I see value in being able to read this kind of information in many different scenarios).</p>
  
  <p>I've explored the Invoke and InvokeAsync methods and the StateChanged &amp; DataReady events but none of these seem to provide the information (verbose comments) that I'm after.</p>
  
  <p>Any direction or examples that can be provided will be very appreciated!</p>
  
  <p>A code sample which is little more than how I would ordinarily call any other powershell command follows:</p>
  
  <pre><code>// config to use ExMgmt shell, create runspace and open it
  RunspaceConfiguration rsConfig = RunspaceConfiguration.Create();
  
  PSSnapInException snapInException = null;
  PSSnapInInfo info = rsConfig.AddPSSnapIn("Microsoft.Exchange.Management.PowerShell.Admin", out snapInException);
  
  if (snapInException != null) throw snapInException;
  
  Runspace runspace = RunspaceFactory.CreateRunspace(rsConfig);
  
  try
  {
    runspace.Open();
  
    // create a pipeline and feed script text
    Pipeline pipeline = runspace.CreatePipeline();
  
    string targetDatabase = @"myServer\myStorageGroup\myDB";
    string mbxOwner = "user@company.com";
  
    Command myMoveMailbox = new Command("Move-Mailbox", false, false);
    myMoveMailbox.Parameters.Add("Identity", mbxOwner);
    myMoveMailbox.Parameters.Add("TargetDatabase", targetDatabase);
    myMoveMailbox.Parameters.Add("Verbose");
    myMoveMailbox.Parameters.Add("ValidateOnly");
    myMoveMailbox.Parameters.Add("Confirm", false);
    pipeline.Commands.Add(myMoveMailbox);
  
    System.Collections.ObjectModel.Collection&lt;PSObject&gt; output = null;
  
    // these next few lines that are commented out are where I've tried
    // registering for events and calling asynchronously but this doesn't 
    // seem to get me anywhere closer
    //
    //pipeline.StateChanged += new EventHandler&lt;PipelineStateEventArgs&gt;(pipeline_StateChanged);
    //pipeline.Output.DataReady += new EventHandler(Output_DataReady);
    //pipeline.InvokeAsync();
    //pipeline.Input.Close();
    //return; tried these variations that are commented out but none seem to be useful
  
    output = pipeline.Invoke();
  
    // Check for errors in the pipeline and throw an exception if necessary
    if (pipeline.Error != null &amp;&amp; pipeline.Error.Count &gt; 0)
    {
       StringBuilder pipelineError = new StringBuilder();
       pipelineError.AppendFormat("Error calling Test() Cmdlet.  ");
       foreach (object item in pipeline.Error.ReadToEnd())
         pipelineError.AppendFormat("{0}\n", item.ToString());
  
       throw new Exception(pipelineError.ToString());
     }
  
     foreach (PSObject psObject in output)
     {
       // blah, blah, blah
       // this is normally where I would read details about a particular PS command
       // but really pertains to a command once it finishes and has nothing to do with
       // the verbose messages that I'm after... since this part of the methods pertains
       // to the after-effects of a command having run, I'm suspecting I need to look to
       // the asynch invoke method but am not certain or knowing how.
     }
  }
  finally
  {
    runspace.Close();
  }
  </code></pre>