Skip to main content

Activity Editor

You can create PowerShell activities using the Activity Editor. These activities are executed on the Pia Orchestrator platform by default however they can also be executed via a Pia agent. Refer to the [YAML - Activities/Steps] section regarding the executionEnvironment and executionEnvironmentKey properties.

To create a PowerShell activity:

  1. Ensure you are in Sandbox mode with a sandbox selected.
  2. Navigate to the Activity Editor where you will be presented with the new activity form.
  3. Fill out the required fields as such:
    • Name: The display name of the activity.
    • Static Name: The static name is how the activity will be referenced in the package YAML definition. This property can only be set on creation and cannot be changed once it is set. The typical naming convention for activities consists of words separated by underscores for example my_test_activity.
    • Description: This is where you can give a brief description of what the activity does.

PowerShell Activities

When you first create a new activity from the activity editor, you will see the following PowerShell templated code with two pre-defined functions VerifyActivity and ExecuteActivity:

Activity Template:​

     Function VerifyActivity()
{
# Put code here to verify the command will work given the variables
return $true;
}

Function ExecuteActivity()
{
# Do stuff here

# Set output variables
$activityOutput.out.Variable1 = "something";
$activityOutput.out.Variable2 = "something else";

# Set execution status
$activityOutput.success = $true;

return $activityOutput;
}

Default Functions:​

  • VerifyActivity - If there are any checks which need to be performed to verify that this activity can be safely executed, you can put these checks inside this function. At the current time, this function is not used so you may safely ignore it.
  • ExecuteActivity - This is the business end of the activity, where all the business logic which your activity needs to perform will be invoked.
info

Note: These functions are called by the Orchestrator platform, if you remove or rename either of these two functions the activity will not work.

You can configure input/output variables in the editor by clicking on the 'Variables' menu item at the top of the code editor. Input variables allow you to pass information into the activity from the calling package. Output variables allow you to return information from an activity to the calling package.

In the code editor you can access the input variables by name for example if you configure a variable called "upn" then you can access this variable by $upn.

The output variables are returned by the activity via the $activityOutput object, you can see an example of this in the above activity template where 'Variable1' and 'Variable2' properties are being set on the $activityOutput.out child object i.e. $activityOutput.out.Variable1 = "something"; and $activityOutput.out.Variable2 = "something else";

There is an additional section of the PowerShell template which is initially hidden from view, you can view this section by clicking on the 'Show Test Code' checkbox in the menu at the top of the editor. This section shows how the input and output variables are initialized in the script.

Hidden Test Code Section:​

    #read_only
####################################################
########## INPUT
#####################################################

$my_input = "";

####################################################
########## OUTPUT
#####################################################

$variableProps = @{
my_output = $null;
}

$outputProps = @{
out = $(New-Object psobject - Property $variableProps);
success = $false;
}

$activityOutput = New-Object psobject -Property $outputProps;

#/read_only

So in the above read only section you can see that the input variables are just a plain old variable in the script, and the output variable are properties in the 'out' object which is a property of the $activityOutput variable.

Calling Activities in Packages

To call a PowerShell activity from a package you need to reference its static name, any input arguments are provided via the inputs element in the YAML task definition, see below example:

Calling an activity:​

    #Calling an activity with a static name of my_test_activity
- task: my_test_activity
inputs:
my_input: 'some value'

Retrieving output from an activity:​

    #Calling an activity with a static name of my_test_activity
- task: my_test_activity
inputs:
my_input: 'some value'

#Passing out of previous activity to next activity
- task: inline_powershell
inputs:
my_activities_output: =my_test_activity.my_output
script: 'Write-Host "This is my output: $my_activities_output"'

The above example of retrieving output from an activity will work for a simple scalar output variable, however you will often need to return lists of objects, and in this case you will need to deserialize the output before you can work with it.

Deserializing activity output:​

    #Calling an activity with a static name of my_test_activity
- task: my_test_activity
inputs:
my_input: 'some value'

#Deserializing the output variable
- task: inline_powershell
inputs:
my_activities_output: =my_test_activity.my_output
script: |
$my_activities_output = [Array]$(ConvertFrom-Json $my_activities_output)
foreach($output in $my_activities_output){
Write-Host "Object property value: $($output.my_property)"
}

Calling the meta property to get activity name or description:​

The meta property has the following 2 values:

  • name - This is the display name of the activity.
  • description - This is where you can give a brief description of what the activity does.
      #Calling the meta property to get activity name or description
- task: my_test_activity
document: 'This {=my_test_activity.meta.name} will {=my_test_activity.meta.description}'
inputs:
my_input: 'some value'

Best Practices

When developing a PowerShell activity it is recommended to breakup your logic into separate functions rather then writing everything in the ExecuteActivity function, however if the activity is only performing a very simple action for example calling a single function and returning its result then this can just go in the ExecuteActivity function.

It is important that when you call a function or perform any action within the script which returns any output you must assign the output to a variable, if you do not assign the output to a variable it will cause the activity to fail because the Orchestrator platform will not be able to distinguish between the multiple returns.

For example, if we define an activity which makes the following function call Get-ADGroupMember -Identity 'Domain Users' and do not assign the output to a variable the activity will fail. Additionally, the objects you return from your activities must be serialized, and to ensure that the objects you are returning will be serialized properly you should return them as basic powershell objects which you create yourself from the more complex objects you may be working with (i.e. do not simply return the output of Get-ADUser).

Example activity returning a list of users in an AD group:​

Function GetGroupMembers() 
{
# a list to collect our basic powershell objects in
$users = @();

# assigning the output of function call to a local variable
$adUsers = Get-ADGroupMember -Identity $groupName | get-aduser -Properties mail | Select samaccountname, mail

# constructing basic powershell objects to be serialized and return in output variable
foreach($user in $adUsers)
{
$users += @{
accountName = $user.SamAccountName;
email = $user.mail;
};
}

return $adUsers;
}

Function ExecuteActivity()
{
try
{
# Get users using our function above
$users = GetGroupMembers

# Serialise the list and assign it to an output variable
$activityOutput.out.users = $(ConvertTo-Json -Depth 5 $users);

# Set execution status
$activityOutput.success = $true;
}
catch
{
Write-Error $_.Exception.Message
# set the success property to false so Pia knows something went wrong
$activityOutput.success = $false;
}

return $activityOutput;
}

In the above example we have put most of the logic in the GetGroupMembers function which is called within the ExecuteActivity function, we are assigning the output of the GetGroupMembers function to a variable which is this serialized and assigned the the $activityOutput.out.users output variable, we are wrapping this in a try catch if an exception is caught then we are setting the $activityOutput.success to false which lets the Orchestrator platform know that something went wrong and it should stop execution of the package.