Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
This topic applies to Windows Workflow Foundation 4 (WF4).
The InvokePowerShell sample demonstrates how to invoke Windows PowerShell commands using the InvokePowerShell activity.
Demonstrates
Simple innovation of Windows PowerShell commands.
Retrieve values from the Windows PowerShell output pipeline and store them in workflow variables.
Pass data into windows PowerShell as input pipeline for an executing command.
Discussion
This sample contains the following three projects.
| Project Name | Description | Main Files |
|---|---|---|
CodedClient |
A sample client application that uses the PowerShell activity. |
|
DesignerClient |
A set of custom activities that contain the |
|
PowerShell |
The |
Activity Files
Designer files:
|
The client projects are discussed first, as it is easier to understand the internal functionality of the PowerShell activity once its use is understood.
Using This Sample
The following sections describe how to use the three projects in the sample.
Using the Coded Client Project
The sample client programmatically creates a sequence activity, which contains examples of several different methods of using the InvokePowerShell activity. The first invocation launches Notepad.
new InvokePowerShell()
{
CommandText = "notepad"
},
The second invocation gets a list of the processes running on the local machine.
new InvokePowerShell<Process>()
{
CommandText = "Get-Process",
Output = processes1,
},
Output is the variable used to store the output of the command.
The next call demonstrates how to run a post-processing step on each individual output of the PowerShell invocation. InitializationAction is set to the function that outputs a string representation for each process. The collection of these strings is returned in the Output variable by the InvokePowerShell<string> activity.
The succeeding InvokePowerShell calls demonstrate passing data into the activity and getting outputs and errors out.
Using the Designer Client Project
The DesignerClient project consists of a set of custom activities, almost all of which are built containing the InvokePowerShell activity. Most of the activities call the non-generic version of the InvokePowerShell activity, and do not expect a return value. Other activities use the generic version of the InvokePowerShell activity, and use the InitializationAction argument to post-process the results.
Using the PowerShell Project
The main action of the activity takes place in the ExecutePowerShell class. Because the execution of PowerShell commands should not block the main workflow thread, the activity is created to be an asynchronous activity by inheriting from the AsyncCodeActivity class.
The BeginExecute method is called by the workflow runtime to begin running the activity. It starts by calling PowerShell APIs to create a PowerShell pipeline.
runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
pipeline = runspace.CreatePipeline();
It then creates a PowerShell command and populates it with parameters and variables.
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);
The inputs piped in are also sent to the pipeline at this point. Finally, the pipeline is wrapped in a PipelineInvokerAsyncResult object and returned. The PipelineInvokerAsyncResult object registers a listener and invokes the pipeline.
pipeline.InvokeAsync();
When execution finishes, output and errors are stored within the same PipelineInvokerAsyncResult object, and control is handed back to the workflow runtime by calling the callback method originally passed to BeginExecute.
At the end of the method's execution, the workflow runtime calls the activity’s EndExecute method.
The InvokePowerShell class wraps the ExecutePowerShellCommand class and creates two versions of the activity; a generic version and a non-generic version. The non-generic version returns the output of the PowerShell execution directly, whereas the generic version transforms the individual results to the generic type.
The generic version of the activity is implemented as a sequential workflow that calls ExecutePowerShellCommand and post-processes its results. For each element in the result collection, the post-processing step calls InitializationAction if it is set. Otherwise, it does a simple cast.
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
},
}
}
}
},
For each of the two InvokePowerShell activities (generic, and non-generic), a designer was created. InvokePowerShellDesigner.xaml and its associated .cs file define the appearance in Workflow Designer for the non-generic version of the InvokePowerShell activity. Inside InvokePowerShellDesigner.xaml, a DockPanel is used to represent the graphical interface.
<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>
Note that the Text property of the text box is a two-way binding that ensures that the value of the activity’s CommandText property is equivalent to the value input into the designer.
GenericInvokePowerShellDesigner.xaml and its associated .cs file define the graphical interface for the generic InvokePowerShell activity. The designer is slightly more complicated because it allows users to set an InitializationAction. The key element is the usage of WorkflowItemPresenter to allow drag and drop of child activities onto the InvokePowerShell designer surface.
<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" />
The designer customization does not stop with the .xaml files that define the appearance of the activity on the design canvas. The dialog boxes used to display the parameters of the activity can also be customized. These parameters and PowerShell variables affect the behavior of PowerShell commands. The activity exposes them as Dictionary types. ArgumentDictionaryEditor.cs, PropertyEditorResources.xaml and PropertyEditorResources.cs define the dialog box that allows you to edit these types.
To set up, build, and run the sample
You must install Windows PowerShell to run this sample. Windows PowerShell can be installed from this location: Windows PowerShell.
To run the coded client
Open PowerShell.sln using Visual Studio 2010.
Right-click the solution and build it.
Right-click the CodedClient project and select Set as Startup Project.
Press CTRL+F5 to run the application.
To run the designer client
Open PowerShell.sln using Visual Studio 2010.
Right-click the solution and build it.
Right-click the DesignerClient project and select Set as Startup Project.
Press CTRL+F5 to run the application.
Known Issues
If referencing the
InvokePowerShellactivity assembly or project from another project results in a build error, you may need to manually add the<SpecificVersion>True</SpecificVersion>element to the .csproj file of the new project under the line that referencesInvokePowerShell.If Windows PowerShell is not installed, the following error message is displayed in Visual Studio as soon as you add an
InvokePowerShellactivity onto a workflow:Workflow Designer encountered problems with your document. Could not load file or assembly ‘System.Management.Automation’ ... or one of its dependencies. The system cannot find the file specified.In Windows PowerShell 2.0, programmatically calling
$input.MoveNext()fails and scripts using$input.MoveNext()produce unintended errors and results. To work around this issue, consider using the PowerShell verbforeachinstead of callingMoveNext()when iterating an array.
Note: |
|---|
The samples may already be installed on your computer. Check for the following (default) directory before continuing.
<InstallDrive>:\WF_WCF_Samples
If this directory does not exist, go to Windows Communication Foundation (WCF) and Windows Workflow Foundation (WF) Samples for .NET Framework 4 to download all Windows Communication Foundation (WCF) and WF samples. This sample is located in the following directory.
<InstallDrive>:\WF_WCF_Samples\WF\Scenario\ActivityLibrary\PowerShell
|
Note: