2011-03-03 4 views
6

私のプログラムはユーザ指定のスクリプトブロックを実行し、その出力を徐々に返すようにします(例えば、スクリプトブロックが長時間実行される場合)。プログラムで実行されるScriptBlockの出力をストリーミングする方法は?

しかし、ScriptBlockのAPIはパイプライン関連のものを公開していないようです。

私は必要なもの(InvokeWithPipe)のようないくつかの機能を持っていますが、それらは内部であり、引数は内部型です。私はここで反射にハッキングに頼ることを嫌いだ。

したがって、スクリプトブロックのパイプラインにアクセスする方法はありますか?たぶん何らかの堅牢な回避策ですか?

答えて

8

ここでは、各出力オブジェクトのデリゲートを呼び出して、出力をストリームするためにScriptBlockに拡張メソッドを追加するコードを示します。オブジェクトがコレクションにバックアップされないので、ストリーミングは真実です。これは、PowerShell 2.0以降用です。

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

例:

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

(パラメータのサポートを2011年3月7日更新)このことができます

希望。

+0

卑劣なことだ!私はそれが好きです。 – Josh

+0

クールではありますが、必要なものではありません - 私はスクリプトブロックだけをテキストとしてではなく、ArgumentListを持つ実際のScriptBlockインスタンスとして必要としています。私が苦労していたArgumentListを握っています。結局私は単にInvoke-Commandをプログラム的に呼び出すことに頼らざるを得ませんでした。 – jkff

+0

@jkff - APIでもっと時間を費やす必要があります - 私のコードは良いです。スクリプトブロックにパラメータ/引数を追加するには、AddArgument(位置指定)またはAddParameter(名前付き)を使用して追加する必要があります。コードサンプルを更新します。 – x0n

関連する問題