Writing scripts for remote actions on Mac

Contents

Writing scripts for remote actions on Mac

Overview

The payload of remote actions on Mac are Bash scripts that run on the devices of the employees. Bash is a command-line shell and scripting language that is supported by many UNIX-like operating systems, such as macOS, and suited for task automation and configuration management. Bash scripts are therefore ideal to get on-demand data from devices, perform self-healing tasks, or modifying the configuration of a device, which are typical use cases for remote actions.

Learn here the specifics of how to write Bash scripts for remote actions. This article assumes familiarity of the reader with Bash scripting.

Find more information about writing scripts for remote actions on Community:

Remote actions group in Community

Encoding

To write your own Bash scripts for remote actions, encode the files that hold the text of your scripts in UTF-8 (without BOM).

End each line in the code with the usual character in UNIX systems: LF.

Failing to provide the right encoding to your script files will result in the inability of remote actions to run on the devices of the employees.

Signing and packaging your own scripts

For security reasons, the Finder requires Bash scripts for remote actions on Mac to be digitally signed with the codesign tool. Additionally, package your signed script as a tar.gz file to preserve its extended attributes. Finder only accepts files with tar.gz extension when importing scripts for remote actions that target macOS.

To sign your script, type in:

codesign -s <your certificate identity> --timestamp --prefix=<code signature identifier prefix> --force <script file name>

Where the options are the following:

-s
The identity of your code signing certificate in the Keychain. Usually, it's a certificate subject common name or a certificate hash. See the codesign manual page for the full description.
--timestamp
Generate a trusted timestamp for a signature.
--prefix
A prefix to a code signature identifier. Attaches your company identity to an identifier and helps to make an identifier unique. See the code signature identifier generation rules in the codesign manual page.
--force
Forces to rewrite a code signature if it already exists.

Package your script and signature as a tar.gz file to preserve the extended attributes before uploading to the Finder:

tar -czvf ./<your script name>.tar.gz ./<script file name>.sh

Writing generic scripts

Scripts may be written in a generic way so they can be adapted to particular use cases. To make your script generic, declare formal parameters at the beginning of the Bash script. Provide actual values to the parameters in the Finder, when editing the remote action that holds the script.

Genericity is especially useful in the case of digitally signed scripts that require some customization. When a script is signed, any modification to its text content breaks the signature. By making a signed script generic, you allow its customization via parameters. With parameters, the text of the script remains unchanged and thus the digital signature remains valid. The values for the parameters that a remote action passes to the script determine its actual behavior.

Declare parameters at the beginning of a script as usual for Bash positional parameters and enclose them between two special comments as follows:

# NXT_PARAMETERS_BEGIN
Parameter1=$1
Parameter2=$2
Parameter3=$3
# NXT_PARAMETERS_END


The editor of remote actions recognizes the parameters between the special Nexthink comments in a Bash script and lists them in the Parameters section, below the script text. Provide actual values to the parameters in the text input boxes displayed to the right of each parameter name. Note that the actual values are always passed to the script as text: if the script declares parameters whose type is other than the string type, ensure that the values that you provide can be properly converted to the type of their corresponding parameter.

Output variables

The execution of a script may generate some outputs that you want to store as on-demand data in the Engine. To that end, Nexthink provides a Bash script (nxt_ra_script_output.sh) that is installed in the device of the employee at the same time as the Collector. The script includes functions to write results to the Engine.

To use the functions in the Nexthink script for remote action output, add the following header at the beginning of your Bash scripts:

#!/bin/bash
. "${NEXTHINK}"/bash/nxt_ra_script_output.sh


All write methods accept two arguments: the name of the output and the value to write. For instance, let us suppose that you want to return the number of files in a directory to the Engine and that the variable nfiles in your script holds that number. To write the value of nfiles through an output with the name FileNumber to the Engine, call the function to write unsigned integers:

nxt_write_output_uint32 'FileNumber' $nfiles


The editor of remote actions recognizes the calls to write outputs in the script and lists the output variables under the Outputs section below the script text. Set the label of the output to indicate how to refer to it in investigations and metrics.

The ending of each write method indicates the type of output. Because Bash is a loosely typed language, the type of the output is interpreted depending on the context. Find the list of available methods in the table below:

nxt write method Constraints
nxt_write_output_string 0 - 1024 characters (output truncated if bigger)
nxt_write_output_bool true / false
nxt_write_output_uint32
  • Min: 0
  • Max: 4 294 967 295
nxt_write_output_float
  • Min: -3.4E+38
  • Max: 3.4E+38
nxt_write_output_string_list Same as string

Interacting with end-users in self-help scenarios

Obtaining the UID of a campaign

The methods to run a campaign from a remote action that are detailed in the section below require the UID of the campaign to be passed as an argument. Thus, to run a campaign from a remote action, first, you need to get the UID of the campaign.

To pass this UID to a remote action, it is convenient to declare a parameter in the script of the remote action for each campaign that it has to run and use the UID as the actual value for the parameter when editing the remote action.

To get the UID of a campaign and pass it to a remote action as a parameter:

  1. Log in to the Finder as a user with the right to edit campaigns and remote actions.
  2. In the Campaigns section of the left-hand side accordion, right-click the name of a campaign that you wish to launch from a remote action.
  3. Select Export > Campaign Uid to clipboard to copy the UID of the campaign.
  4. In the Remote actions section of the left-hand side accordion, double-click the name of the remote action that should run the campaign to edit it. The remote action should include a script that declares parameters for storing the UID of the campaign.
  5. In the Parameters section under the script, select the parameter that should hold the UID of the campaign.
  6. Press command + v to paste the actual UID of the campaign and assign it to the corresponding parameter.

Running a campaign from the script of a remote action

The following functions extend the scripting capabilities when using remote actions.


nxt_run_campaign( id )
Runs the campaign matching the UID passed as a parameter and saves the answers internally.
  • Returns 0 if the campaign status is received.
  • Returns 1 otherwise, and the error is reported in the logs.
Calling that function pauses the execution of the remote action until the user either completes the campaign or dismisses it.


nxt_run_campaign_with_timeout( id timeout)
Runs the campaign matching the UID with the timeout in seconds (0 < T < 1week) passed as the parameters and saves the answers internally.
  • Returns 0 if the campaign status is received.
  • Returns 1 otherwise, and the error is reported in the logs.
Calling that function pauses the execution of the remote action until the user either completes the campaign, dismisses it, or fails to finalize the campaign before the timeout.


nxt_run_standalone_campaign( id )
Runs the campaign matching the UID passed as a parameter and saves the answers internally.
  • Returns 0 if the campaign status is received.
  • Returns 1 otherwise, and the error is reported in the logs.
Calling that function triggers the start of the campaign and continues the execution of the remote action without waiting for the user's answers.


nxt_get_campaign_status( res_var )
Returns the last campaign status.
  • fully, the user has fully answered the questions of the campaign.
  • timeout, the campaign was timed out before the user finished answering.
  • postponed, the user accepted to participate in the campaign.
  • declined, the user declined to participate in the campaign.
  • connectionfailed, the script was unable to connect to the Collector component that controls campaign notifications.
  • notificationfailed, the script was unable to notify the Collector component that controls campaign notifications.
  • Empty if the last campaign failed


nxt_get_response_answer( res_var question_key)
Query the last campaign using a question label as a string parameter (query_key), extracts the answer as a string value, and returns it into the given variable (res_var).
  • Returns 0 if the campaign status is received.
  • Returns 1 otherwise.

Example codes

Calling for a campaign


 # This is a simple example to demonstrate the basic call for a campaign

if nxt_run_campaign "6c77d4da-e629-4f29-86ee-7ee8955bf123"; then
    nxt_get_campaign_status status
    if [[ status == "fully" ]]; then
        echo "Campaign succeeded"
    else
        echo "Status is $status"
    fi
else
    echo "Campaign failed"
fi 
 


Accessing the answers


# Simple access to the response data
 
nxt_get_campaign_status status
echo "The response status is $status"
nxt_get_response_answer answersArray key1
echo ${answersArray[1]}

# Careful - Bash uses 0 to n-1 whereas Zsh uses 1 to n.

 


Running a campaign with a timeout


# Run a campaign with timeout
# timeout is in seconds (100s or 00:01:40)

if nxt_run_campaign_with_timeout "6c77d4da-e629-4f29-86ee-7ee8955bf123" 100; then
    nxt_get_campaign_status status
    if [[ status == "fully" ]]; then
        echo "Campaign succeeded"
    else
        echo "Status is $status"
    fi
else
    echo "Campaign failed"
fi
 


Running a non-blocking campaign


# Run a non-blocking campaign
 
if nxt_run_standalone_campaign "6c77d4da-e629-4f29-86ee-7ee8955bf123"; then
    nxt_get_campaign_status status
    if [[ status == "fully" ]]; then
        echo "Campaign succeeded"
    else
        echo "Status is $status"
    fi
else
    echo "Campaign failed"
fi
 


Zsh command interpreter

From the Collector version 6.27.2 it is possible to run scripts written for the Zsh Unix shell. You need to add the following line of code at the very beginning of the shell script:

#!/bin/zsh
This is a character sequence known as a shebang (external link).

When a remote action is triggered on a Mac, the Collector checks for that first line of code and then executes the rest of the instructions using the specified interpreter. A script without a shebang will be executed using the Bash command interpreter.

Nexthink recommends to always use a shebang in shell scripts and stick to the standard interpreters.

The operations described in this article should only be performed by a Nexthink Engineer or a Nexthink Certified Partner.

If you need help or assistance, please contact your Nexthink Certified Partner.