InvokePowerShell アクティビティの使用

このトピックの内容は、Windows Workflow Foundation 4 に該当します。

InvokePowerShell サンプルでは、InvokePowerShell アクティビティを使用して Windows PowerShell コマンドを呼び出す方法を示します。

使用例

  • Windows PowerShell コマンドの簡便さと革新性。

  • Windows PowerShell の出力パイプラインから値を取得してワークフロー変数に格納する。

  • 実行するコマンドのための入力パイプラインとして Windows PowerShell にデータを渡す。

Dd797586.Important(ja-jp,VS.100).gif 注 :
サンプルは、既にコンピューターにインストールされている場合があります。続行する前に、次の (既定の) ディレクトリを確認してください。

<InstallDrive>:\WF_WCF_Samples

このディレクトリが存在しない場合は、「.NET Framework 4 向けの Windows Communication Foundation (WCF) および Windows Workflow Foundation (WF) のサンプル」にアクセスして、Windows Communication Foundation (WCF) および WF のサンプルをすべてダウンロードしてください。このサンプルは、次のディレクトリに格納されます。

<InstallDrive>:\WF_WCF_Samples\WF\Scenario\ActivityLibrary\PowerShell

説明

このサンプルには次の 3 つのプロジェクトが含まれています。

プロジェクト名 説明 メイン ファイル

CodedClient

PowerShell アクティビティを使用するサンプル クライアント アプリケーション。

  • Program.cs: InvokePowerShell アクティビティを呼び出すシーケンス ベースのワークフローをプログラムで作成します。

DesignerClient

InvokePowerShell カスタム アクティビティや他のさまざまなカスタム アクティビティを含むカスタム アクティビティのセットと、それらを使用するワークフロー。

  • アクティビティ:

    • PrintCollection.cs: コレクション内のすべての項目をコンソールに出力するヘルパー アクティビティ。

    • ReadLine.cs: コンソールからの入力を読み取るためのヘルパー アクティビティ。

  • ファイル システム:

    • Copy.xaml: ファイルをコピーするアクティビティ。

    • CreateFile.xaml: ファイルを作成するアクティビティ。

    • DeleteFile.xaml: ファイルを削除するアクティビティ。

    • MakeDir.xaml: ディレクトリを作成するアクティビティ。

    • Move.xaml: ファイルを移動するアクティビティ。

    • ReadFile.xaml: ファイルを読み取ってその内容を返すアクティビティ。

    • TestPath.xaml: パスが存在するかどうかを調べるアクティビティ。

  • プロセス:

    • GetProcess.xaml: 実行中のプロセスのリストを取得するアクティビティ。

    • StopProcess.xaml: 特定のプロセスを停止するアクティビティ。

  • Program.cs: Sequence1 ワークフローを呼び出します。

  • Sequence1.xaml: シーケンス ベースのワークフロー。

PowerShell

InvokePowerShell アクティビティと、それに関連付けられたデザイナー。

アクティビティのファイル

  • ExecutePowerShell.cs: アクティビティのメインの実行ロジック。

  • InvokePowerShell.cs: メインの実行ロジックのラッパー。ジェネリック (値を返す) バージョンと非ジェネリック (値を返さない) バージョンが含まれています。これは、アクティビティのパブリック インターフェイスです。

  • NoPersistZone.cs: このアクティビティは、子アクティビティが永続化されるのを防ぎます。このクラスは、InvokePowerShell アクティビティの実装の中で、アクティビティが実行の途中で永続化されるのを防ぐために使用されます。

デザイナーのファイル:

  1. ArgumentDictionaryEditor.cs: InvokePowerShell アクティビティの引数を編集できる Windows ダイアログ。

  2. GenericInvokePowerShellDesigner.xaml および GenericInvokePowerShellDesigner.xaml.cs: ワークフロー デザイナーでのジェネリック InvokePowerShell アクティビティの外観を定義します。

  3. InvokePowerShellDesigner.xaml および InvokePowerShellDesigner.cs: ワークフロー デザイナーでの非ジェネリック InvokePowerShell アクティビティの外観を定義します。

PowerShell アクティビティの使用方法を把握しているとその内部機能を理解しやすくなるため、クライアント プロジェクトから先に説明します。

このサンプルの使用

以降では、このサンプルの 3 つのプロジェクトの使用方法について説明します。

CodedClient プロジェクトの使用

このサンプル クライアントは、InvokePowerShell アクティビティのさまざまな使用方法の例を含むシーケンス アクティビティをプログラムで作成します。最初の呼び出しでは、メモ帳を起動します。

new InvokePowerShell()
{
    CommandText = "notepad"
},

2 番目の呼び出しでは、ローカル コンピューターで実行されているプロセスのリストを取得します。

new InvokePowerShell<Process>()
{
    CommandText = "Get-Process",
    Output = processes1,
},

Output は、コマンドの出力を格納するための変数です。

その次の呼び出しは、PowerShell の呼び出しの個々の出力に対して後処理のステップを実行する方法を示しています。InitializationAction は、各プロセスの文字列形式を出力する関数に設定されています。それらの文字列のコレクションは、InvokePowerShell<string> アクティビティによって Output 変数で返されます。

その後に続く一連の InvokePowerShell の呼び出しは、アクティビティにデータを渡して出力とエラーを取得する方法を示しています。

DesignerClient プロジェクトの使用

DesignerClient プロジェクトは一連のカスタム アクティビティで構成されていますが、それらのほぼすべてに InvokePowerShell アクティビティが含まれています。ほとんどのアクティビティは、非ジェネリック バージョンの InvokePowerShell アクティビティを呼び出します。したがって、戻り値を受け取りません。ジェネリック バージョンの InvokePowerShell アクティビティを使用するその他のアクティビティは、InitializationAction 引数を使用して結果の後処理を行います。

PowerShell プロジェクトの使用

アクティビティの主要なアクションは ExecutePowerShell クラスで実行されます。PowerShell コマンドの実行によってメインのワークフロー スレッドがブロックされないようにする必要があるため、アクティビティは、AsyncCodeActivity クラスを継承して非同期アクティビティとして作成されています。

ワークフロー ランタイムによって BeginExecute メソッドが呼び出されると、アクティビティの実行が開始されます。このメソッドは、まず最初に、PowerShell API を呼び出して PowerShell パイプラインを作成します。

runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
pipeline = runspace.CreatePipeline();

次に、PowerShell コマンドを作成してパラメーターと変数を設定します。

Command cmd = new Command(this.CommandText, this.IsScript); 
// loop over parameters and run: cmd.Parameters.Add(...)
// loop over variables and run: runspace.SessionStateProxy.SetVariable(...)
pipeline.Commands.Add(cmd);

この時点で、パイプ入力された入力がパイプラインにも送信されます。最後に、パイプラインが PipelineInvokerAsyncResult オブジェクトでラップされて返されます。PipelineInvokerAsyncResult オブジェクトは、リスナーを登録してパイプラインを呼び出します。

pipeline.InvokeAsync();

実行が終了すると、出力とエラーが同じ PipelineInvokerAsyncResult オブジェクトに格納され、最初に BeginExecute に渡されたコールバック メソッドが呼び出されてワークフロー ランタイムに制御が返されます。

メソッドの実行の最後に、ワークフロー ランタイムがアクティビティの EndExecute メソッドを呼び出します。

InvokePowerShell クラスは ExecutePowerShellCommand クラスをラップして、ジェネリック バージョンと非ジェネリック バージョンの 2 つのバージョンのアクティビティを作成します。非ジェネリック バージョンは PowerShell の実行の出力をそのまま返しますが、ジェネリック バージョンは個々の結果をジェネリック型に変換します。

ジェネリック バージョンのアクティビティは、ExecutePowerShellCommand を呼び出してその結果の後処理を行うシーケンシャル ワークフローとして実装されています。後処理のステップでは、結果のコレクションの各要素に対して、InitializationAction が設定されている場合にはそれが呼び出され、設定されていない場合には単純なキャストが行われます。

new ForEach<PSObject>
{
    Values = psObjects,
    Body = new ActivityAction<PSObject>
    {
        Argument = psObject,
        Handler = new Sequence
        {
            Activities =
            {
                new If
                {
                    Condition = // Is InitializationAction set?
                    Then = new InvokeFunc<PSObject, TResult>
                    {
                        Argument = psObject,
                        Result = outputObject,
                        Func = this.InitializationAction
                    },
                    Else = new Assign<TResult>
                    {
                        To = outputObject,
                        Value = new InArgument<TResult>(ctx => (TResult) psObject.Get(ctx).BaseObject),
                    }
                },
                new AddToCollection<TResult>
                {
                    Collection = outputObjects,
                    Item = outputObject
                },
            }
        }
    }
},

2 つの InvokePowerShell アクティビティ (ジェネリックと非ジェネリック) のそれぞれにデザイナーが用意されています。InvokePowerShellDesigner.xaml とその関連 .cs ファイルは、非ジェネリック バージョンの InvokePowerShell アクティビティのワークフロー デザイナーでの外観を定義します。InvokePowerShellDesigner.xaml では、DockPanel を使用してグラフィカル インターフェイスを表しています。

<DockPanel x:Uid="DockPanel_1" LastChildFill="True">
        <TextBlock x:Uid="TextBlock_1" Text="CommandText" />
        <TextBox x:Uid="TextBox_1" Text="{Binding Path=ModelItem.CommandText, Mode=TwoWay}"
                 TextWrapping="WrapWithOverflow"  AcceptsReturn="True" MinLines="4" MaxLines="4"
                 Background="{x:Null}" Margin="3" />
    </DockPanel>

テキスト ボックスの Text プロパティが双方向のバインドになっているため、アクティビティの CommandText プロパティの値がデザイナーに入力された値と同じになります。

GenericInvokePowerShellDesigner.xaml とその関連 .cs ファイルは、ジェネリック InvokePowerShell アクティビティのグラフィカル インターフェイスを定義します。このデザイナーは、InitializationAction を設定できるようになっているため、非ジェネリック バージョンのデザイナーに比べてやや複雑です。ここでのポイントは、WorkflowItemPresenter を使用して、InvokePowerShell のデザイナー画面に子アクティビティをドラッグ アンド ドロップできるようにしていることです。

<sap:WorkflowItemPresenter x:Uid="sap:WorkflowItemPresenter_1" Margin="0,10,0,10"
    HintText="Drop Activities Here"
    AllowedItemType="{x:Type sa:Activity}"
    Item="{Binding Path=ModelItem.InitializationAction.Handler, Mode=TwoWay}"
    Grid.Row="1" Grid.Column="1" />

デザイナーでカスタマイズできるのは、デザイン キャンバスでのアクティビティの外観を定義する .xaml ファイルだけではありません。アクティビティのパラメーターを表示するために使用されるダイアログ ボックスもカスタマイズできます。これらのパラメーターや PowerShell 変数は、PowerShell コマンドの動作に影響します。アクティビティはこれらを Dictionary 型として公開します。これらの型を編集できるダイアログ ボックスは、ArgumentDictionaryEditor.cs、PropertyEditorResources.xaml、および PropertyEditorResources.cs で定義されています。

サンプルを設定、ビルド、および実行するには

このサンプルを実行するには Windows PowerShell をインストールする必要があります。Windows PowerShell は、Windows PowerShell からインストールできます。

コード クライアントを実行するには

  1. Visual Studio 2010 を使用して PowerShell.sln を開きます。

  2. ソリューションを右クリックしてビルドします。

  3. [CodedClient] プロジェクトを右クリックし、[スタートアップ プロジェクトに設定] をクリックします。

  4. Ctrl キーを押しながら F5 キーを押してアプリケーションを実行します。

デザイナー クライアントを実行するには

  1. Visual Studio 2010 を使用して PowerShell.sln を開きます。

  2. ソリューションを右クリックしてビルドします。

  3. [DesignerClient] プロジェクトを右クリックし、[スタートアップ プロジェクトに設定] をクリックします。

  4. Ctrl キーを押しながら F5 キーを押してアプリケーションを実行します。

既知の問題

  1. InvokePowerShell アクティビティのアセンブリやプロジェクトを別のプロジェクトから参照してビルド エラーが発生した場合は、必要に応じて、新しいプロジェクトの .csproj ファイル (InvokePowerShell を参照している行の下) に <SpecificVersion>True</SpecificVersion> 要素を手動で追加してください。

  2. Windows PowerShell がインストールされていない場合は、InvokePowerShell アクティビティをワークフローに追加するとすぐに、Visual Studio で次のエラー メッセージが表示されます。"ワークフロー デザイナーはドキュメントで問題を検出しました。ファイルまたはアセンブリ 'System.Management.Automation'、またはその依存関係の 1 つが読み込めませんでした。指定されたファイルが見つかりません。"

  3. Windows PowerShell 2.0 では、プログラムで $input.MoveNext() を呼び出すと呼び出しが失敗します。そのため、$input.MoveNext() を使用するスクリプトで予想外のエラーと結果が生成されます。この問題を回避するには、配列を反復処理するときに、MoveNext() を呼び出す代わりに PowerShell の動詞 foreach を使用することを検討してください。

Dd797586.Important(ja-jp,VS.100).gif 注 :
サンプルは、既にコンピューターにインストールされている場合があります。続行する前に、次の (既定の) ディレクトリを確認してください。

<InstallDrive>:\WF_WCF_Samples

このディレクトリが存在しない場合は、「.NET Framework 4 向けの Windows Communication Foundation (WCF) および Windows Workflow Foundation (WF) のサンプル」にアクセスして、Windows Communication Foundation (WCF) および WF のサンプルをすべてダウンロードしてください。このサンプルは、次のディレクトリに格納されます。

<InstallDrive>:\WF_WCF_Samples\WF\Scenario\ActivityLibrary\PowerShell