2011-03-03 13 views
6

Mój program wykonuje określone przez użytkownika bloki skryptów i chcę, aby zwracał swoje dane wyjściowe przyrostowo (np. W przypadku, gdy skryptblok działa przez dłuższy czas).Jak przesyłać strumieniowo dane wyjściowe z programowo wykonanej ScriptBlock?

Jednak interfejs API ScriptBlock nie wydaje żadnych informacji związanych z potokiem!

Ma kilka funkcji, które wyglądają tak, jak są one potrzebne (InvokeWithPipe), ale są wewnętrzne, a ich argumenty są typu wewnętrznego. Nie chciałbym uciekać się do włamywania do refleksji.

Czy istnieje sposób dostępu do potoku skryptu skryptowego? Może jakiś solidny sposób obejścia tego problemu?

Odpowiedz

8

Oto kod, który doda metodę rozszerzenia do ScriptBlock, aby przesyłać strumieniowo dane wyjściowe, wywołując delegata dla każdego obiektu wyjściowego. To jest prawdziwe strumieniowanie, ponieważ obiekty nie mają kopii zapasowej w kolekcji. Dotyczy to programu PowerShell 2.0 lub nowszego.

public static class ScriptBlockStreamingExtensions { 
     public static void ForEachObject<T>(
      this ScriptBlock script, 
      Action<T> action, 
      IDictionary parameters) { 

      using (var ps = PowerShell.Create()) { 

       ps.AddScript(script.ToString()); 

       if (parameters != null) { 
        ps.AddParameters(parameters); 
       } 

       ps.Invoke(Enumerable.Empty<object>(), // input 
          new ForwardingNullList<T>(action)); // output 
      } 
     } 

     private class ForwardingNullList<T> : IList<T> { 
      private readonly Action<T> _elementAction; 

      internal ForwardingNullList(Action<T> elementAction) { 
       _elementAction = elementAction; 
      } 

      #region Implementation of IEnumerable 
      // members throw NotImplementedException 
      #endregion 

      #region Implementation of ICollection<T> 
      // other members throw NotImplementedException 

      public int Count { 
       get { 
        return 0; 
       } 
      } 
      #endregion 

      #region Implementation of IList<T> 
      // other members throw NotImplementedException 

      public void Insert(int index, T item) { 
        _elementAction(item); 
      } 
      #endregion 
     } 
} 

Przykład:

// execute a scriptblock with parameters 
ScriptBlock script = ScriptBlock.Create("param($x, $y); $x+$y"); 
script.ForEachObject<int>(Console.WriteLine, 
    new Dictionary<string,object> {{"x", 2},{"y", 3}}); 

(zaktualizowany 07.03.2011 wsparcie parametrów)

Nadzieja to pomaga.

+0

Sneaky! Lubię to. – Josh

+0

Fajne, ale nie do końca potrzebne - potrzebuję skryptu blokującego nie tylko jako fragment tekstu, ale jako prawdziwą instancję ScriptBlock z ArgumentList. To ściska ArgumentList wewnątrz tego, o co walczyłem. W końcu musiałem po prostu uciekać się do programistycznego wywołania "Invoke-Command". – jkff

+0

@jkff - musisz spędzać więcej czasu z API - mój kod jest dobry. Jeśli chcesz dodać parametry/argumenty do bloku skryptów, po prostu musisz użyć AddArgument (pozycyjny) lub AddParameter (nazwany), aby je dodać. Zaktualizuję próbkę kodu. – x0n

Powiązane problemy