Actions

PRO

Note 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 a ActionSet. An ActionSet can contain several actions of several types. You can specify a Condition for an action to be executed conditionally. As you can also specify a Condition for a set, 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 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.

To specify the action type, fill the required key Type. You can also specify a condition under which the action is executed

Key Type Possible values Explanation Is Required
Type String SendRequest, SaveInputs, Log, ExecuteCommand, ExecuteScript, ExecuteJamfPolicy, DisplayAlert, RestartComputer, ShutdownComputer, AsleepComputer, LogoutUser, PlaySound Specify the action type ⚠️
Condition String - Conditionally execute the action. More information on conditions

Here are the current available actions:

Action Sets

You will use an ActionSet to group actions together, and execute them when the set is triggered. Note 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.

Key Type Possible values Explanation Is Required
Type String Parallel,Chained With Parallel, all the actions of the set will be executed without waiting for the previous one to be executed. With Chained, you specify that you want to wait for each action to be executed before to execute the next one. It is useful for SendRequests or ExecuteScripts action for example which run asynchronously and can populate some variables inside Octory when they complete. Thus, by specifying Chained, you can wait for an action to populate a variable and then execute an other action which needs this variable ⚠️
Triggers Triggers array - 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.
Condition String - Conditionally execute the actions in the set. More information on conditions
Actions Actions Array - The actions that the set will execute when triggered, and if the condition is verified (if present) ⚠️
ContinueAfterFailure Boolean - If set to true, when using a Chained set, the next action will be executed even if the current one did not terminate successfully (e.g. an error occured). Default is false

Triggers

There are several ways to trigger an ActionSet. Here are the available triggers:

Key Explanation
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

Action types

Log

Write text and variables in Octory log. Useful when debugging

Key Type Possible values Explanation Is Required
Message String - The message to write ⚠️

    <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


    <dict>
        <key>Type</key>
        <string>SaveInputs</string>
    </dict>
    

SendRequest

Key Type Possible values Explanation Is Required
Request Request - The request to send ⚠️

Example


    <key>Type</key>
    <string>SendRequest</string>
    <key>Request</key>
    <dict>
        <key>Endpoint</key>
        <string>https://evalamaris.jamfcloud.com/JSSResource/computers/id/20</string>
        <key>MDMApi</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:

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 UserDefaults key 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 retrieve a 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

Requests

You can specify a request directly in the action or in the APIRequests as models, and then use them in the action.

Key Type Possible values Explanation Is Required
Endpoint String - Request endpoint URL. Is added to the base URL you provide in the APIRequests section
Method  String POST, GET, PUT, DELETE The HTTP method. Default is GET
Headers Dictionary - HTTP headers if necessary
Parameters Dictionary - Request URL parameters if necessary
Body Dictionary - Key/Values Data you want to send with the request.
ParentRequest String - The parent request fields to use if the field in the request are not specified
MDMApi String Jamf, JamfPro, AirWatch MDM Api to target. This provide the heavy lifting to directly use those APIs
VariableReadingPaths Dictionary - Allow 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 the [Index] to indicate that you want to target the value in an array at the index

Examples

Request to Jamf API with full information.


    <dict>
        <key>Endpoint</key>
        <string>https://evalamaris.jamfcloud.com/JSSResource/computers/id/20</string>
      <key>MDMApi</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 DefaultMDMApi 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.

Key Type Possible values Explanation Is Required
Title String - The main text of the alert ⚠️
Message String - The sub-text of the alert ⚠️
Style String Informational, Warning, Critical By setting this value, the alert will change its appearance accordingly. Note that there is now visual difference between Informational and Warning currently in Apple's library. ⚠️
ButtonsText String array - 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 String - 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.
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.

Key Type Explanation Is Required
Command String The command to execute ⚠️
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.

Key Type Explanation Is Required
ScriptPath String The path to the script to execute ⚠️
Arguments String Array 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
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.

Key Type Explanation Is Required
Name String 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:

Examples

So 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/.

Key Type Explanation Is Required
SoundNameOrFilePath String 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>