2009-07-18 16 views
8

CONTESTO

  • Sto usando PowerShell 2.0 su Windows 7.
  • Sto scrivendo un cmdlet in un modulo PowerShell ("modulo "è nuovo di Powershell 2.0).
  • Per testare il cmdlet, sto scrivendo i test delle unità in Visual Studio 2008 che richiamano a livello di codice il cmdlet.

RIFERIMENTO

  • This Article on MSDN chiamato "come richiamare un cmdlet dall'interno di un Cmdlet" mostra come chiamare un cmdlet da C#.

IL CODICE SORGENTE

  • Questa è una versione distillata del mio codice attuale — Ho fatto il più piccolo possibile in modo che si può vedere il problema che sto avendo chiaramente:Come catturare output dettagliato di un cmdlet PowerShell quando il cmdlet è a livello di codice richiamato da C#

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

COMMENTI

  • Capisco come abilitare e catturare l'output dettagliato dalla riga di comando di Powershell; non è questo il problema
  • In questo caso sto richiamando a livello di codice il cmdlet da C#.
  • Nulla di ciò che ho trovato riguarda il mio specifico scenario. Alcuni articoli suggeriscono che dovrei implementare il mio PSHost, ma sembra costoso e sembra anche dover chiamare il cmdlet come testo, che vorrei evitare perché non è così fortemente digitato.

AGGIORNAMENTO SULLA 2009-07-20

Ecco è il codice sorgente in base alla risposta qui sotto.

Alcune cose non sono ancora chiaro per me: * Come chiamare i "Get-Colors" cmdlet (idealmente senza dover passare come una stringa al ps objet) * Come ottenere l'output dettagliato come viene generato invece di ricevere una raccolta alla fine.

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

      } 

     } 
    } 

Il codice precedente genera questo output:

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

AGGIORNAMENTO SULLA 2010-01-16

utilizzando la classe PowerShell (trovato in System.Management.Automation, ma solo nella versione dell'assembly fornito con l'SDK di PowerShell 2.0, non quello che viene fornito in Windows 7) Posso chiamare a livello di programmazione il cmdlet e ottenere l'output dettagliato. La parte rimanente è di aggiungere effettivamente un cmdlet personalizzato all'istanza di PowerShell, poiché questo era il mio obiettivo originale: testare i miei cmdlet non quelli forniti con 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"); 
    } 
} 
+1

c'era un "backtick mancante" nella mia risposta - questo impedisce alla variabile $ verbosepreference di essere valutata prima del tempo. – x0n

+0

Perché non hai contrassegnato la mia risposta come risposta? – x0n

+0

Se si desiderano record dettagliati in tempo reale, sottoscrivere l'evento datachanged nella proprietà di streaming dell'istanza di PowerShell. – x0n

risposta

10
  • Output dettagliato in realtà non è uscita a meno che $VerbosePreference è impostato almeno su "Continua".
  • Utilizzare il tipo PowerShell per eseguire il vostro cmdlet, e leggere VerboseRecord istanze dal Streams.Verbose propery

esempio nello script 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} 

Questo dovrebbe essere facile da tradurre in C#.

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.  } 

linee importanti sono la linea 5 e 6. Questo fondamentalmente impostare il $ VerbosePreference per la sessione e per le prossime nuovi comandi e script.

Problemi correlati