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.

When the set is triggered, it will evaluate its condition to know whether it should execute its actions or not. If no condition is specified, the set will execute its actions.

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


Condition


Triggers Required


Actions Required


ContinueAfterFailure



Condition of the ActionSet Vs. conditions of the Actions 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


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


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.

Once you have provided a credential, you will not need to provide it the next time as it will be stored in the 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


Method


Headers


Parameters


Body


ParentRequest


MDM


VariableReadingPaths


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>

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 -

Detail

Title Required


Message Required


Style Required


ButtonsText


Variable


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.

Summary

Name Type Possible values Required
Type String ExecuteCommand Required
Command String - Required

Detail

Command Required


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.

Summary

Name Type Possible values Required
Type String ExecuteScript Required
SciptPath String - Required
Arguments array(String) -

Detail

ScriptPath Required


Arguments


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.

Summary

Name Type Possible values Required
Type String ExecuteJamfPolicy Required
Name String - Required

Detail

Name Required


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


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>