-
Notifications
You must be signed in to change notification settings - Fork 36
Run PowerShell Script Activity
The Run PowerShell Script activity allows you to run a PowerShell 2.0 script and optionally return the script output to the executing workflow for consumption in the subsequent activities.
Optional. Name of the activity to be displayed on the MIM / FIM workflow designer.
Optional. The condition which must be satisfied for execution of this activity's core task (i.e. run the PowerShell script). This can be any WAL function expression resolving to a boolean value.
Optional.The username of the user account to use while constructing a PowerShell Credential object to pass the script. The credential object is passed as a $Credential session variable to the script. The username must be in the Domain\UserName format if "Impersonate PowerShell User" setting is selected.
Required when "PowerShell Script User" is specified. The password of the user account to use while constructing a PowerShell Credential objects to pass the script. The password value specified is an encrypted value using a certificate, DPAPI or RSA Machine Keys. Using a self-signed certificate is recommended due to ease of deployment. Please see EncryptedData.ps1
in the "SolutionOutput" folder that demonstrates how the password can be encrypted in the RunPowerShellScript Activity.
Optional. If this setting is selected, the PowerShell script is executed in the context of the specified RunAs user account. This option should be avoided, if the command-lets used in the script support a Credential parameter.
By default the script runs under the context of FIMService service account. This option should be used as a last resort, but if impersonation cannot be avoided, to configure the user's permissions follow the section Additional Configuration for Impersonation of "PowerShell Connector for FIM 2010 R2" Technical Reference.
This feature should not be mistaken as the ability to impersonate requestor in during Workflow execution. It is simply not possible to impersonate requestor during workflow execution to access external systems. Only the specified
PowerShell Script User
could be impersonated.
Optional. If this setting is selected, the user profile of the RunAs user is loaded during impersonation.
Optional. Logon type to use during impersonation. For more information, refer to the dwLogonType documentation. The default value is "Log on as a batch job".
Required. Specifies how the activity will locate the script for execution. The available options are:
- Include in the Workflow Definition
- Read from File
- Resolve from Lookup
Required when "Include in the Workflow Definition" option is selected for Script Location. In this case, the PowerShell script is stored as part of the workflow XOML.
Required when "Read from File" option is selected for Script Location. In this case, the full path of the script located on a network share accessible by all FIMService instances is specified.
Required when "Resolve from Lookup" option is selected for Script Location. In this case, a WAL Lookup expression which represents the script to be executed by the activity is specified.
Required when "Resolve from Lookup" option is selected for Script Location. Specifies whether or not the activity should generate an error when the script lookup resolves to a null value.
Optional. Specifies how the input should be provided to the PowerShell script. The available options are:
- None
- Named Parameters
- Arguments
Required when "Named Parameters" option is selected for script Input Type. When this option is selected, you can then define a list of parameter names expected by the script and corresponding WAL value expressions to be supplied to the script as the values of those parameters.
Required when "Arguments" option is selected for script Input Type. When this option is selected, you can define a list of WAL value expressions to be passed as unnamed arguments to the script. The arguments are passed in the order they are listed.
Optional. Specifies how the script output should be processed. The available options are:
- None
- Single Value
- Table of Values
The activity can capture a return value from the PowerShell script and publish it to a lookup. Alternatively, the PowerShell script may return a Hashtable
of key-value pairs which can be published to the workflow data dictionary WorkflowData
using corresponding key names.
It should be noted that, in contrast to a "return statement" in a C# function, the return value from a PowerShell script / function is not necessarily what is returned by a return statement. Hence, output from any command or function that is not the intended return value from the script should be ignored (void
ed) or thrown away (Out-Null
ed) so that it does not get piped to the output stream that is what is "returned" by the script.
Required when "Single Value" option is selected for Script Return Type. When this option is selected, the script return value is published to the specified WAL Lookup expression.
The RunPowerShellScript activity is a "catch_all" activity in WAL as anything can be scripted and executed when other native WAL activities fall short. But remember, with great power comes great responsibility :). Due to the obvious performance implications and the possibility of failures due to session throttling implemented by the remote systems such as Exchange, Lync/Skype as well as memory leaks that may be present in the PowerShell scripts and get accumulated over each run of the workflow, use of this activity should be avoided in production environments and particularly so in large scale, high-transaction implementations. Instead you should look at exploiting other native WAL activities or take a Management Agent based approach as much as possible. If you think you can avoid the use of RunPowerShellScript activity if a feature were added to WAL, please post the feedback on the WAL project forum.
Workflow Thread pool is a precious system resource. The default configuration for maxSimultaneousAuthorizationAndActionWorkflows is ~4 (yes, four!) workflow threads per CPU core. So optimise your scripts to the fullest possible extent so that they complete as quickly as possible. Load only those command that you need from a remote module. Never introduce any Sleep
in your script even for a minute. Use Add Delay activity if there is such a need. Every second will count in production environment!
The RunPowerShellScript activity has no way of knowing which errors in your script are terminating errors and which ones can simply be ignored. To be safe than sorry, the activity will treat any errors as fatal errors and abort the workflow. Hence when developing your script take a "pessimistic" approach to the script development and test for the success of a command before issuing the command in your script. While you could use try/catch or trap statements in your code for error handling, the many command-lets from the PowerShell modules that you may be importing are going to use simply ignore the -ErrorAction SilentlyContinue
parameter. So don't count on it to handle errors for you.
The RunPowerShellScript activity passes the activity execution context as session variables AECWorkflowInstanceId, AECRequestId, AECActorId, AECTargetId and AECWorkflowDefinitionId). It also set ProgressPreference, DebugPreference and VerbosePreference as per trace levels in the app.config file of FIMService. It is recommended that you instrument your scripts using this information in conjuction with standard Write-*
cmdlets such as a Write-Debug
cmdlet so that the workflow can be traced end-to-end. This is demonstrated in the sample script RunPSLoggingSample.ps1
that gets copied to the "SolutionOutput" folder.
Without the use of AEC* variables, the event will still get logged with standard
Write-*
statements at appropriate trace levels, but they'll not have the request / workflow details and may be hard to correlate in a production environment.
All MIM/FIM workflows run in a .NET Framework 3.5 runtime. This is a product limitation. This .NET runtime environment cannot execute scripts and command-lets that need PowerShell 3.0 or above runtime. If there is a need to execute a script containing PowerShell 3.0+ command-lets (e.g. ActiveDirectory module on Windows Server 2012), they can be made to run in a separate process to avoid the product limitation. e.g. using PowerShell Remoting or launching a new "powershell.exe" session using Start-Process
command-let. Examples of these two techniques are given below:
<#
This script uses PowerShell.exe to execute ActiveDirectory PowerShell 3.0 cmdlets
#>
param
(
[parameter(mandatory = $true)] $AccountName
)
function InvokeImmediateTermination
{
$stdOutFile = Join-Path $env:TEMP -ChildPath "StdOut_$AECRequestId.log"
$stdErrFile = Join-Path $env:TEMP -ChildPath "StdErr_$AECRequestId.log"
$command = @"
& {
if (!(Get-Module -Name "ActiveDirectory"))
{
Import-Module ActiveDirectory
}
Set-ADUser -Identity '$AccountName' -Enabled:`$false
if (`$Error.Count -eq 0)
{
"!!Success!!"
}
else
{
# Can't easily use stdErrFile as it comes as CLIXML and includes Warning/Verbose/Debug streams as well. So we'll simply use stdOutFile
"!!Error!!"
`$Error
}
}
"@
Write-Debug $command
$commandBytes = [System.Text.Encoding]::Unicode.GetBytes($command)
$encodedCommand = [Convert]::ToBase64String($commandBytes)
Start-Process 'PowerShell.exe' `
-ArgumentList "-Version 3.0 -NonInteractive -OutputFormat Text -EncodedCommand $encodedCommand" `
-RedirectStandardOutput $stdOutFile `
-RedirectStandardError $stdErrFile `
-Wait
$statusLine = Get-Content $stdOutFile| Select-Object -Last 2 | ? {
$_.Contains("!!Success!!")
}
if ([string]::IsNullOrEmpty($statusLine))
{
Write-Error ((Get-Content $stdOutFile) -join "`r`n") # TODO: Only get the lines after !!Error!! marker
}
else
{
Write-Debug "Script executed successfully."
}
Remove-Item $stdOutFile -Force
Remove-Item $stdErrFile -Force
}
InvokeImmediateTermination
<#
This script uses Remote PowerShell to execute ActiveDirectory PowerShell 3.0 cmdlets
This script needs Remote PowerShell enabled on each FIMService server.
It also needs FIMService service account permissions to execute remote commands.
This can be configured using
1. Enable-PSRemoting -Force
2. Set-PSSessionConfiguration -Name Microsoft.PowerShell -ShowSecurityDescriptorUI
#>
param
(
[parameter(mandatory = $true)] $AccountName
)
function InvokeImmediateTermination
{
# Any errors during execution of the script or the script block are bubbled up automatically.
# Comment out -ComputerName parameter when running interactively
Invoke-Command -ScriptBlock {
param($AccountName)
if (!(Get-Module -Name "ActiveDirectory"))
{
Import-Module ActiveDirectory
}
Set-ADUser -Identity $AccountName -Enabled:$false
} -ArgumentList $AccountName -ComputerName localhost
}
InvokeImmediateTermination
The following Run PowerShell Script activity invokes InvokeImmediateTermination script described earlier that used PowerShell 3.0 command-lets from ActiveDirectory module installed on the server:
Activity Display Name | Execute Immediate Termination |
Script Location | Include in Workflow Definition |
Script | {Copy & Paste of one of the previous examples of InvokeImmediateTermination script} |
Input Type | Named Parameters |
Parameter | Value Expression |
AccountName | [//Target/AccountName] |
- MIMWAL Site - http://aka.ms/MIMWAL
- MIMWAL Releases - http://aka.ms/MIMWAL/Releases
- MIMWAL Documentation Wiki - http://aka.ms/MIMWAL/Wiki
- MIMWAL FAQ - http://aka.ms/mimwal/faq
- MIMWAL GitHub Code Repo - http://aka.ms/MIMWAL/Repo
- MIMWAL TechNet Q&A Forum (now read-only) - http://aka.ms/MIMWAL/Forum