Summary: Honorary Scripting Guy and Microsoft PowerShell MVP Richard Siddaway continues his Windows PowerShell workflow series with a discussion on parameters.
Microsoft Scripting Guy, Ed Wilson, is here. Today, we have the sixth in a series of guest blog posts written by Windows PowerShell MVP and Honorary Scripting Guy Richard Siddaway dealing with Windows PowerShell workflow.
Note The first article, PowerShell Workflows: The Basics, introduced the basic concepts of Windows PowerShell workflow. The second article, PowerShell Workflows: Restrictions, discussed the restrictions encountered with working with Windows PowerShell workflows. The third article was PowerShell Workflows: Nesting. The fourth article talked about PowerShell Workflows: Job Engine. The fifth article talked about PowerShell Workflows: Restarting the Computer. You should read those articles prior to reading today’s article.
Richard has written a number of guest Hey, Scripting Guy! Blog posts, and he has also written two books on Windows PowerShell. His most recent book, PowerShell in Depth, is co-written with fellow MVPs Don Jones and Jeffrey Hicks.
Now, take it away, Richard …
In this installment, we’ll look at the parameters that are available to workflows and activities, the options for connecting to remote computers and the workflow cmdlets. Let’s start with the parameters.
There are a good number of parameters available to use with your workflows and activities that are summarized in the following table.
Parameter | Workflow | Activity |
AppendOutput |
| Y |
AsJob | Y |
|
JobName | Y |
|
Debug |
| Y |
DisplayName |
| Y |
ErrorAction |
| Y |
Input |
| Y |
MergeErrorToOutput |
| Y |
PSActionRetryCount |
| Y |
PSActionRetryIntervalSec |
| Y |
PSActionRunningTimeoutSec |
| Y |
PSAllowRedirection | Y | Y |
PSApplicationName | Y | Y |
PSAuthentication | Y | Y |
PSAuthenticationLevel | Y |
|
PSCertificateThumbprint | Y | Y |
PSComputerName | Y | Y |
PSConfigurationName | Y | Y |
PSConnectionRetryCount ** | Y | Y |
PSConnectionRetryIntervalSec ** | Y | Y |
PSConnectionURI | Y | Y |
PSCredential | Y | Y |
PSDebug |
| Y |
PSDisableSerialization |
| Y |
PSElapsedTimeOutSec | Y |
|
PSError |
| Y |
PSParameterCollection | Y |
|
PSPersist | Y | Y |
PSPort | Y | Y |
PSPrivateMetaData | Y |
|
PSProgress |
| Y |
PSProgressMessage |
| Y |
PSRemotingBehavior |
| Y |
PSRequiredModules |
| Y |
PSRunningTimeOutSec | Y |
|
PSSessionOption | Y | Y |
PSUseSSL | Y | Y |
PSVerbose |
| Y |
PSWarning |
| Y |
Result |
| Y |
UseDefaultInput |
| Y |
Verbose |
| Y |
WarningAction |
| Y |
** The documentation implies these parameters can be used on activities but the activities I tested don’t support them. I suspect they are workflow level parameters.
I don’t propose to discuss each one as they are mostly self-explanatory and more details on the individual parameters can be found in two Help files:
about_WorkflowCommonParameters
about_ActivityCommonParameters
Some of the parameters you’ve already seen in action, such as those related to running the workflow as a job.
Remote access in workflows
One of the more interesting parameters is PSComputerName, which is used for connecting to a remote computer. You get a number of options. First option is to access the remote computer at the workflow level.
workflow test-remoteaccess {
Get-WmiObject -Class Win32_ComputerSystem
}
Notice in this workflow that there is no obvious reference to a computer name. You can then do this:
PS> test-remoteaccess -PSComputerName server02, win732 | select Name, Manufacturer, Model
Name Manufacturer Model
---- ------------ -----
SERVER02 LENOVO 4318CTO
WIN732 Microsoft Corporation Virtual Machine
Using –PSComputerName at the workflow level passes the remote computer names automatically to the activities in the workflow. This is great if you have a simple workflow where you want all of the activities to access a remote computer; however, if you are returning data from multiple computers, it can get a bit messy. Consider this:
workflow test-remoteaccess {
Get-WmiObject -Class Win32_ComputerSystem |
Select-Object -Property Name, Manufacturer, Model
Get-Process
Get-Service
}
test-remoteaccess -PSComputerName server02, win732
I received the data in this order.
Data item | First | Second |
WMI | Server02 | Win732 |
Process | Server02 | Win732 |
Service | Server02 and Win732 intermingled |
The order in which data is returned is not guaranteed, as with any workflow running activities in parallel.
Using the –PSComputerName at the workflow level is probably best kept for situations where you have simple data return requirements, or you are predominantly performing actions against the remote computer with minimal, or no, data returned.
When you use the –PSComputerName parameter, it effectively replaces the –ComputerName on the cmdlet. You don’t get free connectivity! You will also find that you are connecting over the native mechanism used by the cmdlet. If the remote computer doesn’t support that particular mode of connectivity, your workflow will fail for that computer. You can see an example of this by changing the workflow to use Get-CimInstance instead of Get-WmiObject. You will also need to change the parameter from –Classto –ClassName.
workflow test-remoteaccess {
Get-CimInstance -ClassName Win32_ComputerSystem
}
Let’s run it against the same two computers.
PS> test-remoteaccess -PSComputerName server02, win732
Name PrimaryOwnerName Domain TotalPhysicalMemory Model Manufacture PSComputerName
---- ----------- ------ ----------- ----- ----------- -----------
SERVER02 Windows ... Manticor... 17108062208 4318CTO LENOVO server02
The WS-Management service cannot process the request. A DMTF resource URI was used to
access a non-DMTF class. Try again using a non-DMTF resource URI.
+ CategoryInfo : NotSpecified: (root\cimv2:Win32_ComputerSystem:String) []
, CimException
+ FullyQualifiedErrorId : HRESULT 0x80338139,Microsoft.Management.Infrastructure.Ci
mCmdlets.GetCimInstanceCommand
+ PSComputerName : [localhost]
Server02 works fine, but Win732 fails with a message showing that there is a problem with connectivity through WSMan (WnRM). The WMI cmdlets use DCOM to access remote computers, but the CIM cmdlets use WSMan and it has to be WSMan 3.0 that ships with Windows PowerShell 3.0. Win732 is a computer running Windows 7 with Windows PowerShell 2.0. The resolution is to upgrade the remote computer to Windows PowerShell 3.0, use the WMI cmdlets, or create a CIM session using DCOM (but that’s a subject for another day).
Returning to how you can access a remote computer … you can move the –PSComputerName parameter on to the activity:
workflow test-remoteaccess {
param(
[string[]]$computername
)
foreach -parallel ($computer in $computername) {
Get-WmiObject -Class Win32_ComputerSystem -PSComputerName $computer
}
}
This workflow defines a parameter that takes a list of computer names. The foreach –parallel construct is used to iterate over the computer names. If you remember back to article one in the series, the computers in the list are processed in parallel and the commands within the foreach –parallel block are processed sequentially for each computer. You are back to using the native connectivity (DCOM in this case), so it works like this:
PS> test-remoteaccess -computername server02, win732 | select Name, Manufacturer, Model
Name Manufacturer Model
---- ------------ -----
SERVER02 LENOVO 4318CTO
WIN732 Microsoft Corporation Virtual Machine
You need to consider one last scenario—running a workflow with an InlineScript block where the cmdlets in the block need to connect to remote computers. The big thing for you to remember in this scenario is that you are running cmdlets not workflow activities, so you need to use the cmdlet’s native parameter -ComputerName.
workflow test-remoteaccess {
param(
[string[]]$computername
)
inlinescript {
foreach ($computer in $using:computername) {
Get-WmiObject -Class Win32_ComputerSystem -ComputerName $computer
}
}
}
The workflow has a computername parameter that takes a list of computer names. Within the InlineScript block, a foreach loop iterates over the list of computers. You have to define the foreach loop like this:
foreach ($computer in $using:computername)
The $using modifier enables the loop to access the variable that was defined in a higher scope within the workflow (refer to the second article in the series for more details on variable scope in workflows). The workflow is used in the same as previously.
PS> test-remoteaccess -computername server02, win732 | select Name, Manufacturer, Model
Name Manufacturer Model
---- ------------ -----
SERVER02 LENOVO 4318CTO
WIN732 Microsoft Corporation Virtual Machine
You have seen that there are a number of ways of working with computer names in workflows. There is one more way of doing this, but before looking at that you need to know a bit about the workflow cmdlets.
Workflow cmdlets
The PSWorkflow module has been mentioned a number of times already. It installs two cmdlets in addition to the workflow about* files and the ability to run workflows. There is a second module PSWorkflowUtility that installs a single cmdlet—Invoke-AsWorkflow—which you will see in action in a while. The cmdlets and modules are summarized in the following table.
Module | Cmdlet/Function |
PSWorkflow | New-PSWorkflowExecutionOption New-PSWorkflowSession |
PSWorkflowUtility | Invoke-AsWorkflow |
The cmdlets in the PSWorkflow module are concerned with workflow sessions. You can think of workflow sessions as being analogous to remoting sessions that you’ve known and loved since Windows PowerShell 2.0. If you are running one or two commands against a remote computer, it is probably as efficient to create individual connections and tear them down each time you want to connect. If you are performing many actions against the remote computer each of which would need to create and then destroy a connection you will find it more efficient to create a session to the remote computer.
The Help file for New-PSWorkflowSession states: “The New-PSWorkflowSession cmdlet creates a user-managed session ("PSSession") that is especially designed for running Windows PowerShell workflows. It uses the Microsoft.PowerShell.Workflow session configuration, which includes scripts, type and formatting files, and options that are required for workflows.” The New-PSWorkflowExecutionOption allows you to further configure and constrain the workflow session, if you require.
If you have ever created a session for Windows PowerShell remoting, you will not have any surprises when it comes to creating a workflow session.
$wkfsess1 = New-PSWorkflowSession -ComputerName server02, win732
$wkfsess1
$sb ={
Import-Module PSWorkflow
workflow test-remoteaccess {
Get-WmiObject -Class Win32_ComputerSystem |
select -Property Name, Manufacturer, Model
}
test-remoteaccess
}
Invoke-Command -Session $wkfsess1 -ScriptBlock $sb
The commands you want to run over the session are put into a script block and Invoke-Command is used to run the commands over the session.
Invoke-Command -Session $wkfsess1 -ScriptBlock $sb
New-PSSession : [win732] Connecting to remote server win732 failed with the following error
message : The WS-Management service cannot process the request. Cannot find the
Microsoft.PowerShell.Workflow session configuration in the WSMan: drive on the win732 computer.
For more information, see the about_Remote_Troubleshooting Help topic.
At C:\Windows\system32\WindowsPowerShell\v1.0\Modules\PSWorkflow\PSWorkflow.psm1:58 char:9
+ New-PSSession -ConfigurationName Microsoft.PowerShell.Workflow @PSBoundP ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OpenError: (System.Manageme....RemoteRunspace:RemoteRunspace) [New-
PSSession], PSRemotingTransportException
+ FullyQualifiedErrorId : InvalidResourceUri,PSSessionOpenFailed
Id Name ComputerName State ConfigurationName Availability
-- ---- ------------ ----- ----------------- ------------
5 Session5 server02 Opened Microsoft.PowerSh... Available
WARNING: [localhost]:This workflow job cannot be suspended because there are no persistence points
in the workflow. To make the workflow job suspendable, add persistence points to the workflow.
For more information, see the Help topics for Windows PowerShell Workflows.
Name : SERVER02
Manufacturer : LENOVO
Model : 4318CTO
PSSourceJobInstanceId : 78ab3c45-a8f6-428d-a4a4-92aff9df257d
PSComputerName : server02
RunspaceId : 6595de20-5cc3-41fa-9cb7-da0f40f1f0e0
Oops. This is the one drawback to using workflow sessions—they are only available if you have Windows PowerShell 3.0 on the remote computer. If you examine the remoting endpoints on a computer running Windows Server 2012 … it has Windows PowerShell 3.0 (WSMAN v3) installed and you will see this:
PS> ls WSMan:\localhost\Plugin | select name
Name
----
Event Forwarding Plugin
microsoft.powershell
microsoft.powershell.workflow
microsoft.powershell32
microsoft.windows.servermanagerworkflows
SEL Plugin
WMI Provider
By contrast, a computer running Windows 7 with Windows PowerShell 2.0 (WSMAN v2) will show this list of endpoints:
PS> ls WSMan:\localhost\Plugin | select name
Name
----
Event Forwarding Plugin
microsoft.powershell
WMI Provider
You can’t get around this, unfortunately. You have to revert to using the ComputerName or PSComputerName parameters, as discussed earlier.
The last cmdlet is Invoke-AsWorkflow. This is great for testing existing code through a workflow. Start with a simple script:
$exp = "Get-WmiObject -Class Win32_ComputerSystem |
select -Property Name, Manufacturer, Model"
You can run it as workflow like this:
Invoke-AsWorkflow -Expression $exp -PSComputerName server02, win732
Before you start thinking this is a shortcut to converting everything to workflows, you need to be aware that it’s not a full answer as Invoke-AsWorkflow takes the expression and runs it as an InlineScript block. You don’t get any of the parallelism—that is one of the great benefits of workflows.
Summary
This article has shown you the range of parameters available to workflows and how they can be used at the workflow or activity level. You have seen that computer names can be supplied to the workflow, an activity, or a workflow session. There is also a way to start testing code in a workflow scenario by using Invoke-AsWorkflow.
The next article in the series will look at some best practices around using workflows and some of the things you need to consider when designing workflows.
Until then, enjoy!
Thank you, Richard.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy