Loop Activity
Overviewβ
The Loop Activity is one of the features available in Pia Package Editor that you can use to execute the same activity multiple times in a single package execution. This activity makes your package more dynamic and is one of the ways to control the flow of your automation.
One scenario where the Loop Activity may be used is to ask the user of Pia a question and upon checking the answer, you may decide to ask the same question again if the answer was not sufficient. For example, you may ask the user to select a machine where exchange server is installed. If the user selects a machine and clicks proceed, you may check their selection and loop back to the question if the selection was invalid.
Another scenario where this activity is used today is in the printer troubleshooting package. The package contains multiple troubleshooting steps to resolve printer issues. In this case, the user may want to try the first option and if that does not work, try the second option or the third depending upon how many options there are. Here, with the loop feature, Pia can perform the first option the user selects, ask the user if it has resolved their issue and if not, prompt the user to select the next troubleshooting option. In this scenario, Pia is simply looping back to the main option selection question each time.
The Loop activity can be located by searching for "Loop" in the list of activities in the package editor:
Here is a working sample of the activity in a basic package where the package loops back to 'first_activity' activity every time user selects 'Yes' in the chat interaction.
# Orchestrator package
conditions:
- name: 'client_filter'
optMode: 'OptOut'
category: 'Testing'
- name: 'chat'
option_button: 'Loop Test'
option_text: 'This is a Test Package'
option_category: 'Test Category'
steps:
- task: chat_interaction
alias: 'first_activity'
inputs:
text: 'Hi! What would you like to do?'
form_name: 'loop_test'
form_display_mode: 'Embed'
- task: inline_powershell
alias: selection_processor
inputs:
selection: =first_activity.form.Options
script: |
$message = "$selection has been completed."
return @{Message = $message;}
- task: chat_interaction
inputs:
text: =selection_processor.Message
# The form below contains a radio field with two options.
# The options are 'Yes' and 'No'.
# The 'Yes' option has a value of true and the 'No' option has a value of false.
- task: chat_interaction
alias: 'loop_option'
inputs:
text: 'Would you like to try again?'
form_name: 'yes_no_form'
form_display_mode: 'Embed'
- task: loop
inputs:
condition: =loop_option.form.Option
activity: 'first_activity'
In the above example, user will be redirected to the first chat interaction (first_activity) every time they select 'Yes' in the third chat interaction (loop_option).
Activity Behaviourβ
The primary behaviour of the Loop activity is to allow the users to perform the same action multiple times until they want to stop. By doing so, the same activity is executed multiple times until the desired result is achieved.
The loop activity in the Package Editor closely resembles a do/while loop as it will execute the activity once, check if the condition is true and repeat the same activity in a loop as long as the condition remains true.
Note: In scenarios where the loop activity stop condition is always true (i.e. the activity continuously loops until the user cancels the package manually), your package is limited to 500 activity executions per execution.
The Loop Activity can be used in all package executions (i.e. packages that are initiated via Schedule or Ticketing System Event or the Chatbot).
Input Propertiesβ
Below are the properties to modify the behaviour of the activity.
Property Name: condition
Property Required: Yes
Property Description: If the condition is 'true', it will continue with the looping. If the condition is set to 'false', looping behaviour will be stopped.
Property Name: activity
Property Required: No
Property Description: This is the name of the property or alias to loop back to.
Output Propertiesβ
There is no output property for this activity.
Examplesβ
The loop activity in Pia can be implemented in three ways:
Loop based on chat interaction
The first example above shows a loop based on chat interaction where the input by the user determines if the loop condition is triggered in the package or not.
Loop based on error handling and validation
The example below shows a loop where the user is reverted back to the first question until the package receives desired input.
# Orchestrator package
conditions:
- name: 'client_filter'
optMode: 'OptOut'
category: 'Testing'
- name: 'chat'
option_button: 'Loop Test 3'
option_text: 'This is a Loop Test'
option_category: 'Test Category'
steps:
- task: chat_interaction
alias: 'first_activity'
inputs:
text: |
Hi, your selection must contain 'Option A' to continue:
form_name: 'select_an_option'
form_display_mode: 'Embed'
- task: inline_powershell
alias: loop_condition_processor
inputs:
selected_option: =first_activity.form.SelectOption
script: |
$loop = $true
Write-Host "$selected_option"
$optionsColl = $selected_option -split ","
if($optionsColl.length -gt 0)
{
foreach($arrayOpt in $optionsColl)
{
if($arrayOpt -eq "OptionA")
{
$loop = $false
break;
}
}
}
return @{Loop = $loop; Skip = -not $loop;}
- task: chat_interaction
skip: =loop_condition_processor.Skip
inputs:
text: |
Your selection does not contain 'Option A' as one of the options. Please Try again.
- task: loop
inputs:
condition: =loop_condition_processor.Loop
activity: 'first_activity'
- task: chat_interaction
inputs:
text: 'Hello Again!'
Loop based on deterministic behaviour
Below is the example where the package loops until the defined action is performed for all the selected machines.
For this package, a custom activity has been created in Activity Editor as below:
Function VerifyActivity()
{
# Put code here to verify the command will work given the variables
return $true;
}
Function ExecuteActivity()
{
# Do stuff here
# Set output variables
$currentLoggedInUser = whoami
$activityOutput.out.currentLoggedInUser = $currentLoggedInUser
# Set execution status
$activityOutput.success = $true;
return $activityOutput;
}
This activity retrieves the current logged in user for all the selected machines in the below package:
# Orchestrator package
conditions:
- name: 'client_filter'
optMode: 'OptOut'
category: 'Testing'
- name: 'chat'
option_button: 'Get Machines Test2'
option_text: 'This is a test package'
option_category: 'Test Category'
steps:
- task: get_machines
alias: agents_for_client
- task: inline_powershell
alias: prepare_data
inputs:
agents_for_client: =agents_for_client.machines
script: |
write-host 'agents for user' $agents_for_user
If(![string]::IsNullOrEmpty($agents_for_client) ){
$agents_for_client = [Array]$(ConvertFrom-Json $agents_for_client)
$agents_for_client = $agents_for_client | Where {$_.Status -eq "Online"}
#Write-Host "=====agents_for_client: $(ConvertTo-Json -Depth 5 $agents_for_client)"
$allMachines += $agents_for_client | Select @{N='text';E={"$($_.ComputerName) `(User: $($_.LastLoggedInUser)`)"}},@{N='value';E={$($_.QualifiedName)}}
}
Else{
$agents_for_client = @()
}
$allMachines = $allMachines | Where {![string]::IsNullOrEmpty($($_.value))} | Sort -Property text;
$formDefProps = @{
isLastLoggedComputer = ($lastLoggedComputers.Count -gt 0).ToString();
lastLoggedComputer = @($lastLoggedComputers);
computer = @($allMachines);
};
return @{
formDef = $(ConvertTo-Json -Depth 5 $formDefProps);
isNotLoggedComputer = -not [System.Convert]::ToBoolean($formDefProps.isLastLoggedComputer);
}
- task: chat_interaction
alias: selected_machines
inputs:
text: |
Select the machine to continue:
form_name: 'get_machines2'
form_def: =inline_powershell.formDef
form_display_mode: 'Embed'
# Retrieve currently logged in user in the selected machines
- task: inline_powershell
alias: loop_condition_processor
inputs:
selected_machines: =selected_machines.form.computer
script: |
$computers = @()
$selectedMachines = $selected_machines -split ","
$totalMachines = $selectedMachines.Length
$loopData = @{TotalCount =$totalMachines; Machines = $selectedMachines; }
return @{LoopData = @{Count = $totalMachines; Machines = $selectedMachines; SkipLoopProcesses = $totalMachines -lt 1}}
#Start
- task: inline_powershell
alias: loop_start_checker
skip: =loop_condition_processor.LoopData.SkipLoopProcesses
inputs:
machines: =loop_condition_processor.LoopData.Machines
last_run_index: =loop_end_checker.Index
script: |
$index = $last_run_index
if($index -eq $null)
{
$index = 0
}
else
{
[int]$index += 1
}
$currentSelectedMachines = $machines[$index]
return @{CurrentIndex = $index; Machine = $currentSelectedMachines;}
- task: get_logged_in_user
executionEnvironment: 'AsUser'
executionEnvironmentKey: =loop_start_checker.Machine
- task: inline_powershell
alias: 'chat_message_processor'
inputs:
machine: =loop_start_checker.Machine
user: =get_logged_in_user.currentLoggedInUser
script: |
$chatText = "The logged in user in machine $machine is $user"
return @{ChatMessage = $chatText;}
- task: chat_interaction
inputs:
text: =chat_message_processor.ChatMessage
#End
- task: inline_powershell
alias: loop_end_checker
skip: =loop_condition_processor.SkipLoopProcesses
inputs:
total_loops: =loop_condition_processor.LoopData.Count
last_run_index: =loop_start_checker.CurrentIndex
script: |
$continueLoop = $true
if([int]$last_run_index -ge ([int]$total_loops) - 1)
{
$continueLoop = $false
}
return @{Index = [int]$last_run_index; Loop = $continueLoop;}
- task: loop
inputs:
condition: =loop_end_checker.Loop
activity: 'loop_start_checker'
- task: chat_interaction
inputs:
text: 'Task Completed.'
In this package, Pia retrieves the current logged in user for each of the selected machines in a loop and presents them in the chatbot as below:
Additional Example
Here is a traditional loop with a terminating check (i > 5) and position counter (pos). There are three components needed for this setup:
- Counter Activity: The first activity which keeps track of the loop position. I Have used an inline_powershell activity to demonstrate this.
- Activities: Any activities you want to execute multiple times go here
- Loop Activity: The loop activity at the end of the loop
You can use loop_start.pos as an input parameter so your activities know what iteration of the loop they are currently in.
Here is the sample code:
#Keep track of the position in the loop by using a self-referencing input parameter
# Output a property to tell the loop activity whether we should continue executing
- task: inline_powershell
alias: 'loop_start'
inputs:
pos: =loop_start.pos
script: |
$i = If($pos -ne $null) { [int]$pos + 1 } Else { 0 }
$continue = If($i -gt 5) { "False" } Else { "True" }
return @{ pos = $i; continue = $continue }
- task: inline_powershell
inputs:
pos: =loop_start.pos
script: |
Write-Host "This is loop number $pos"
- task: loop
inputs:
condition: =loop_start.continue
activity: 'loop_start'