Actions PRO
About Pro features: All the features described here are available only in the PRO version,
except for simple ActionSet
on a button click with no triggers or conditions, SaveInputs
and Log
actions.
You can execute an action in Octory by inserting them in an ActionSet
. An ActionSet
can contain several actions of several types.
You can specify a Condition
for an action to be executed conditionally.
To specify the action type, fill the required key Type
. You can also specify a condition under which the action is executed.
The current available actions list is on the left
In the tutorial An Octory Pro tour, you can learn how to deal with some actions.
Action Set
An ActionSet
is a dictionary. It has an Actions
array key which holds the action you want to execute.
They will be executed depending on the triggers and the condition you specify.
Triggers are specified in the Triggers
array key. You can also use a Button Component
to trigger an ActionSet
.
In this case, you will not need to specify triggers for the set to be executed.
You can specify all your sets in the ActionSets section of the configuration file.
Keys
Summary
Name | Type | Possible values | Required |
---|---|---|---|
Type | String | Chained , Parallel |
Required |
Condition | String | - | |
Triggers | Array(Triggers) | - | Required |
Actions | Array(Actions) | - | Required |
ContinueAfterFailure | Boolean | - |
Detail
Type Required
- Type: String
-
Possible values:
Parallel
,Chained
- Explanation: With
Parallel
, all the actions of the set will be executed without waiting for the previous one to be executed. WithChained
, you specify that you want to wait for each action to be executed before to execute the next one. It is useful forSendRequests
orExecuteScripts
actions for example which run asynchronously and can populate some variables inside Octory when they complete. Thus, by specifyingChained
, you can wait for an action to populate a variable and then execute an other action which needs this variable.
Condition
- Type: String
- Explanation: Conditionally execute the actions in the set. More information on conditions.
Triggers Required
- Type: Array(Triggers)
- Explanation: Let Octory know when to execute the actions in the set. Whenever a trigger in the array is met, the application will try to execute the set, accordingly to its condition if present.
Actions Required
- Type: Array(Actions)
- Explanation: The actions that the set will execute when triggered, and if the condition is verified (if present).
ContinueAfterFailure
- Type: Boolean
- Explanation: If set to
true
, when using aChained
set, the next action will be executed even if the current one did not terminate successfully (e.g. an error occured). Default isfalse
.
Condition of the ActionSet
Vs. conditions of the Action
s in the set
As you can specify a Condition
for an ActionSet
, and a condition for each Action
the set holds, be aware that if the condition of the set is evaluated as true
the action will not be executed if its own condition is evaluated as false
. The priority is put to the action condition, as it is more specific.
That said, if the condition of the set is false
, none of its actions will be executed.
This process is summarised in the following chart for a chained ActionSet
.

Triggers
There are several ways to trigger an ActionSet
. Here are the available triggers.
Name | Event |
---|---|
Launch | The set will be executed when the application is just launched |
Termination | The set will be executed when the application is about to be terminated |
NextButtonClick | The set will be triggered when the Next button of the navigation view is clicked. The set is executed regardless of the validity of the slide. You can conditionally execute the set with a condition on the current slide validity by using the CURRENT_SLIDE_VALID placeholder. |
PreviousButtonClick | The set will be triggered when the Previous button of the navigation view is clicked |
Update(VariableName) | The set will be triggered when the variable defined as VariableName is updated. You can then conditionally execute the set by setting a condition on the VariableName variable. |
Examples
The following set will be triggered when the placeholder INSTALLATION_COMPLETE
is updated,
and executed only if the installation of all monitors (apps, mandatory files) is complete (i.e. INSTALLATION_COMPLETE
is true
).
It holds an action to display an alert to the user, and one to play a custom sound.
Note: INSTALLATION_COMPLETE
and OCTORY_DIRECTORY
are placeholders offered by the application.
<dict>
<key>Type</key>
<string>Parallel</string>
<key>Condition</key>
<string>Update(INSTALLATION_COMPLETE)</string>
<key>Triggers</key>
<array>
<string>Termination</string>
</array>
<key>Actions</key>
<array>
<dict>
<key>Type</key>
<string>DisplayAlert</string>
<key>Title</key>
<string>Your ${DEVICE_MODEL_NAME} is ready</string>
<key>Message</key>
<string>You may now close the window with the "Quit" button</string>
<key>Style</key>
<string>Informational</string>
</dict>
<dict>
<key>Type</key>
<string>PlaySound</string>
<key>SoundNameOrFilePath</key>
<string>${OCTORY_DIRECTORY}/Resources/Sounds/finish.mp3</string>
</dict>
</array>
</dict>
The following set will be triggered when the user clicks on one of the navigation buttons, and will execute a command to retrieve the local IP address.
Then, it will send an API request to the MDM to store this IP address (the request does not appear). As the SendRequest
action uses the variable
LocalIP
updated by the ExecuteCommand
action, the Type
of the set is "Chained".
<dict>
<key>Type</key>
<string>Chained</string>
<key>Condition</key>
<string>INSTALLATION_COMPLETE</string>
<key>Triggers</key>
<array>
<string>PreviousButtonClick</string>
<string>NextButtonClick</string>
</array>
<key>Actions</key>
<array>
<dict>
<key>Type</key>
<string>ExecuteCommand</string>
<key>Command</key>
<string>ifconfig | grep "inet " | head -n 2 | tail -n 1 | cut -d " " -f 2</string>
<key>Variable</key>
<string>LocalIP</string>
</dict>
<dict>
<key>Type</key>
<string>SendRequest</string>
<key>Request</key>
<dict>
<key>ParentRequest</key>
<string>StoreLocalIP</string>
<key>Body</key>
<dict>
<key>LocalIPAddress</key>
<string>${LocalIP}</string>
</dict>
</dict>
</dict>
</array>
</dict>
Actions
The following explains each action in detail.Log
Write text and variables in Octory log. Useful when debugging
Summary
Name | Type | Possible values | Required |
---|---|---|---|
Type | String | Log |
Required |
Message | String | - | Required |
Detail
Message Required
- Type: String
- Explanation: The message to write
Example
<dict>
<key>Type</key>
<string>Log</string>
<key>Message</key>
<string>I'm afraid of no ghost</string>
</dict>
SaveInputs
Save the user inputs into the specified file. More info on user inputs.
Summary
Name | Type | Possible values | Required |
---|---|---|---|
Type | String | SaveInputs |
Required |
Example
<dict>
<key>Type</key>
<string>SaveInputs</string>
</dict>
SendRequest
Send an Api request.
Summary
Name | Type | Possible values | Required |
---|---|---|---|
Type | String | SendRequest |
Required |
Request | Request | - | Required |
Detail
Request Required
- Type: Request
- Explanation: The request to send
Example
Retrieve the name of the computer with the id 20 from a Jamf MDM server, using the classic Jamf API.<key>Type</key>
<string>SendRequest</string>
<key>Request</key>
<dict>
<key>Endpoint</key>
<string>https://mycompany.jamfcloud.com/JSSResource/computers/id/20</string>
<key>MDM</key>
<string>Jamf</string>
<key>VariableReadingPaths</key>
<dict>
<key>ComputerName</key>
<string>computer->general->name</string>
</dict>
</dict>
Authentication
You can ask Octory to execute API requests to the supported APIs. The currently supported APIs are:
- Jamf
- Jamf Pro
- Airwatch (Workspace ONE)
To provide credentials to Octory to let it authenticate when making the request, you have to launch the application providing your base–64 encoded credentials as arguments. The application will then store them securely in the system keychain. This is done through the Helper and thus it has to be running whenever you use API credentials. You can learn here how to manage the Helper installation.
Once you have provided a credential, you will not need to provide it the next time as it will be stored in the system keychain. That said, if you provide the same credential, the previous one will be overwritten. Here are the arguments:
API | Authentication | Option name (long) |
Note |
---|---|---|---|
Jamf | Base–64 Basic Auth | jamfBasicAuth |
Jamf credentials token encoded in base–64 |
JamfPro | Base–64 Basic Auth | jamfProBasicAuth |
Jamf Pro credentials token encoded in base–64. After having retrieved the token, Octory will request a session token (bearer token) to avoid to use your credentials and thus to reduce security risks. |
Airwatch | Base–64 Basic Auth | airwatchBasicAuth |
Airwatch credentials token encoded in base–64 |
Airwatch | Header ‘aw-tenant-code’ | airwatchApiKey |
API key required to make Airwatch API calls. How to get your key |
Examples
For example, to give to the application your Jamf and Jamf Pro credentials, you will run once:
/Library/Application Support/Octory/Octory.app/Contents/MacOS/Octory \
--jamfBasicAuth [YOUR_JAMF_CREDENTIAL_TOKEN] \
--jamfProBasicAuth [YOUR_JAMF_PRO_CREDENTIAL_TOKEN]
Later, if you want to update your credentials, run the application the same way:
/Library/Application Support/Octory/Octory.app/Contents/MacOS/Octory \
--jamfProBasicAuth [NEW_JAMF_PRO_CREDENTIAL_TOKEN]
Get your base–64 encoded credentials
To get your base–64 encoded credentials token, simply run
echo -n username:password | base64
Example (do not use this password in real life)
echo -n jdoe:toto123456789 | base64
Specify a request
You can specify a request directly in the action or in the APIRequests as models, and then use them in the action.
Name | Type | Possible values | Required |
---|---|---|---|
Endpoint | String | - | |
Method | String | POST , GET ,
PUT , DELETE
|
|
Headers | Dictionary | - | |
Parameters | Dictionary | - | |
Body | Dictionary | - | |
ParentRequest | Dictionary or String | - | |
MDM | String | - | |
VariableReadingPaths | Dictionary | - |
Detail
Endpoint
- Type: String
- Explanation: Request endpoint URL. Is added to the base URL you can provide in the APIRequests section
Method
- Type: String
- Possible values:
POST
,GET
,PUT
,DELETE
- Explanation: The HTTP method. Default is
GET
Headers
- Type: Dictionary
- Explanation: Let you specify additional HTTP headers if required by the API
Parameters
- Type: Dictionary
- Explanation: Let you specify additional URL paramters if required by the API
Body
- Type: Dictionary
- Explanation: Key/Values pairs Data you want to send as the body of the request.
ParentRequest
- Type: String
- Explanation: The parent request whose fields are to be reused if the same fields in the request are not specified. If no field has to be modified, the parent request can be specified as a String, with the parent name for value.
MDM
- Type: String
- Explanation: MDM Api to target. This provide the heavy lifting to directly use those APIs
VariableReadingPaths
- Type: Dictionary
- Explanation: Allows you to specify a path in a received data object like computer->general->name
and to associate a variable name that can then be used within Octory.
Use [Index] to indicate that you want to target the value in an array at the index, and [#] to get a dictionary or an array count.
See more examples and explanations (the separator "->" is replaced by a point ".")
Examples
Request to Jamf API with full information.
<dict>
<key>Endpoint</key>
<string>https://mycompany.jamfcloud.com/JSSResource/computers/id/20</string>
<key>MDM</key>
<string>Jamf</string>
<key>VariableReadingPaths</key>
<dict>
<key>ComputerName</key>
<string>computer->general->name</string>
</dict>
</dict>
Get the computer name of the user identifier by the id 20 and store it in the ComputerName variable.
The same request when you have specified a DefaultMDM
and the JamfBaseURL
keys in the APIRequests section.
<dict>
<key>Endpoint</key>
<string>computers/id/20</string>
<key>VariableReadingPaths</key>
<dict>
<key>ComputerName</key>
<string>computer->general->name</string>
</dict>
</dict>
Get the computer name of the user identifier by the id 20 and store it in the ComputerName variable.
By specifying the keys mentioned above, you can easily define other Jamf API requests.
<dict>
<key>Endpoint</key>
<string>accounts</string>
<key>VariableReadingPaths</key>
<dict>
<key>FirstUserName</key>
<string>accounts->users->[0]->name</string>
<key>SecondUserName</key>
<string>accounts->users->[1]->name</string>
</dict>
</dict>
Retrieve first and second users in the users array and store their respective names in FirstUserName and SecondUserName
When defining request in the APIRequests as models, you can reuse them in an action. For example, if you have defined a “GetComputerName” request:
<dict>
<key>Type</key>
<string>SendRequest</string>
<key>Request</key>
<string>GetComputerName</string>
</dict>
Retrieve the departments count and store it in the variable DepartmentsCount.
<dict>
<key>Endpoint</key>
<string>departments</string>
<key>VariableReadingPaths</key>
<dict>
<key>DepartmentsCount</key>
<string>departments->[#]</string>
</dict>
</dict>
You can also override some keys of the parent request “GetComputerName”. Here, we are overriding the Endpoint
key value of the parent request “GetComputerName”.
<dict>
<key>Type</key>
<string>SendRequest</string>
<key>Request</key>
<dict>
<key>ParentRequest</key>
<string>GetComputerName</string>
<key>Endpoint</key>
<string>computers/id/5</string>
</dict>
</dict>
DisplayAlert
Display an alert which can be customized.
Summary
Name | Type | Possible values | Required |
---|---|---|---|
Type | String | DisplayAlert |
Required |
Title | String | - | Required |
Message | String | - | Required |
Style | String | Informational , Warning , Critical |
Required |
ButtonsText | Array(String) | - | |
Variable | String | - | |
IconPath | String | - |
Detail
Title Required
- Type: String
- Explanation: The main text of the alert
Message Required
- Type: String
- Explanation: The sub-text of the alert
Style Required
- Type: String
- Possible values:
Informational
,Warning
,Critical
- Explanation: By setting this value, the alert will change its appearance accordingly.
Note that there is now visual difference between
Informational
andWarning
currently in Apple’s library.
ButtonsText
- Type: Array(String)
- Explanation: You can add up to three buttons to the alert. By adding a string item in the array, you ask to add button with the specified string for text.
Variable
- Type: String
- Explanation: If set, the application will add a variable with the name you specified. The value of the variable will be the text of the button clicked by the user. Note that if you don’t specify any buttons text, the default button has a “OK” value.
IconPath
- Type: String
- Explanation: Lets you specifiy a custom icon file path for the alert. Include the file extension.
Examples
Display an alert to inform the user. No buttons are specified, so the only one displayed is the default one with “OK” text.
<dict>
<key>Type/<key>
<string>DisplayAlert</string>
<key>Title</key>
<string>Kawabunga</string>
<key>Message</key>
<string>Let's defeat Schredder!</string>
<key>Style</key>
<string>Informational</string>
</dict>
Display an alert with two buttons: “You can go” and “Doesn’t work on me, duh!”, an error style, and a variable UserLetPass
<dict>
<key>Type<key>
<string>DisplayAlert</string>
<key>Title</key>
<string>Let us pass</string>
<key>Message</key>
<string>These are not the Droids you are looking for</string>
<key>Style</key>
<string>Error</string>
<key>Variable</key>
<string>UserLetPass</string>
<key>ButtonsText</key>
<array>
<string>You can go</string>
<string>Doesn't work on me, duh!</string>
</array>
</dict>
If the user clicks on “You can go”, Octory will create (or update if it already exists) the variable UserLetPass
with the value You can go
.
ExecuteCommand
This action make the application execute a command like in the terminal. Those commands will be executed with root rights thanks to the Helper. You can learn here how to manage the Helper installation.
Summary
Name | Type | Possible values | Required |
---|---|---|---|
Type | String | ExecuteCommand |
Required |
Command | String | - | Required |
Variable | String | - |
Detail
Command Required
- Type: String
- Explanation: The command to execute
Variable
- Type: String
- Explanation: When specified, the output of the command will be stored inside a variable with the given name.
Examples
This action will read out loud a message to the user.
<dict>
<key>Type<key>
<string>ExecuteCommand</string>
<key>Command</key>
<string>say -v Alex "As always, should you or any of your ${Company} Force be caught or killed, the Secretary will disavow any knowledge of your actions. This disc will self-destruct in ten seconds. Good luck, ${USER_FIRST_NAME}.</string>
</dict>
The next example shows how to save the first configuration profile on the Mac into the variable ProfileIdentifier
. Note that the profile
command requires root rights, which is not a problem since it is executed by the privileged Helper.
<dict>
<key>Type</key>
<string>ExecuteCommand</string>
<key>Command</key>
<string>profiles -P | head -n 1 | cut -d "." -f 3</string>
<key>Variable</key>
<string>ProfileIdentifier</string>
<dict>
ExecuteScript
This actions takes a script path to execute and execute it, passing it arguments if specified. Those script will be executed with root rights thanks to the Helper. You can learn here how to manage the Helper installation.
Summary
Name | Type | Possible values | Required |
---|---|---|---|
Type | String | ExecuteScript |
Required |
ScriptPath | String | - | Required |
Arguments | array(String) | - | |
Variable | String | - |
Detail
ScriptPath Required
- Type: String
- Explanation: The path to the script to execute
Arguments
- Type: Array(String)
- Explanation: Specify here all the arguments needed for the command Note that you can write several arguments in one string. It’s up to your preference. When writing several arguments in one string, you have to respect the classic quoting when specifying paths with spaces. Don’t hesitate to use another string in the array for large arguments
Variable
- Type: String
- Explanation: When specified, the output of the command will be stored inside a variable with the given name.
Examples
The following example will execute a script which takes an argument and rename the computer based on this argument. The variable UserChoiceComputerName
can be asked to the user with a TextInputComponent.
<dict>
<key>Type<key>
<string>ExecuteScript</string>
<key>ScriptPath</key>
<string>${ScriptsFolder}/changeComputerName.sh</string>
<key>Arguments</key>
<array>
<string>${UserChoiceComputerName}</string>
</array>
</dict>
ExecuteJamfPolicy
This action will take the name of a Jamf policy and execute it. Thanks to the Helper, Octory will be able to execute the Jamf policy which requires root rights. You can learn here how to manage the Helper installation.
Summary
Name | Type | Possible values | Required |
---|---|---|---|
Type | String | ExecuteJamfPolicy |
Required |
Name | String | - | Required |
Detail
Name Required
- Type: String
- Explanation: The name of the Jamf policy to execute
Examples
Execute the Jamf policy named StartEnrolling
<dict>
<key>Type<key>
<string>ExecuteJamfPolicy</string>
<key>Name</key>
<string>StartEnrolling</string>
</dict>
Termination action
Send an Apple event to the computers. You just need to specify the action type:
- RestartComputer
- ShutdownComputer
- LogoutUser
- AsleepComputer
Summary
Name | Type | Possible values | Required |
---|---|---|---|
Type | String | RestartComputer , ShutdownComputer LogoutUser , AsleepComputer |
Required |
Examples
For example, to restart the computer:
<dict>
<key>Type<key>
<string>RestartComputer</string>
</dict>
PlaySound
Play a system or a custom sound (MP3, MP4, WAV). You can find the system sounds list at /System/Library/Sounds/.
Summary
Name | Type | Possible values | Required |
---|---|---|---|
Type | String | PlaySound |
Required |
SoundNameOrFilePath | String | - | Required |
Detail
SoundNameOrFilePath Required
- Type: String
- Explanation: The system name of the sound to play, or a path to a sound file to play. Empty value will play system sound “Hero”
Examples
Play a custom sound in the file path {ResourcesFolderPath}/Sounds/welcome-user.mp3. Note the usage of the custom variable “ResourcesFolderPath”
<dict>
<key>Type<key>
<string>PlaySound</string>
<key>SoundNameOrFilePath<key>
<string>${ResourcesFolderPath}/Sounds/welcome-user.mp3</string>
</dict>
Play the system sound named “Bottle”
<dict>
<key>Type<key>
<string>PlaySound</string>
<key>SoundNameOrFilePath<key>
<string>Bottle</string>
</dict>