Skip to main content
Skip table of contents

Writing scripts for remote actions on Windows

Overview

The payload of remote actions on Windows are PowerShell scripts that run on the devices of the employees. PowerShell is a scripting language from Microsoft that is suited for task automation and configuration management and it is built on top of the .NET Framework in Windows devices. PowerShell is 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 PowerShell scripts for remote actions. This article assumes familiarity of the reader with PowerShell scripting.

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

Applies to platform | Windows |

Encoding

To write your own PowerShell scripts for remote actions, encode the files that hold the text of your scripts in UTF-8 with BOM. The BOM (Byte Order Mark) is a Unicode character that must be present at the beginning of the file and whose representation in UTF-8 documents is the following sequence of three bytes (in hexadecimal): EF BB BF.

End each line in the code with the usual character sequence in Windows systems: CR+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 end-users.

Signing your own scripts

For security reasons, Nexthink strongly recommends that you sign all the scripts that you write. Unsigned scripts are only suitable for testing in pre-production environments.

To sign your PowerShell scripts, use the Set-Authenticode command as follows:

  1. Get your code-signing certificate (assuming you have one), either

$cert = Get-ChildItem -Path Cert:\CurrentUser\My -CodeSigningCert

  • From a PFX file:

$cert = Get-PfxCertificate -FilePath C:\Test\Mysign.pfx

2. Sign your script for remote actions (e.g. remoteaction.ps1) with the code-signing certificate, adding a timestamp to keep it working after certificate expiration (the example code below uses the DigiCert timestamp server):

Set-AuthenticodeSignature -FilePath .\remoteaction.ps1 -Certificate $cert -IncludeChain All -TimestampServer "http://timestamp.digicert.com"

3.Optional: Verify the signature in the script.

Get-AuthenticodeSignature .\remoteaction.ps1 -Verbose | fl

Ensure that you have deployed the appropriate signing certificates to the devices that run the Collector, so they can run your signed scripts as well.

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 PowerShell script. Provide actual values to the parameters in the Finder, when editing the remote action that holds the script.

Genericity is specially 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.

For example, to make a script that reads from a registry key generic, declare a parameter in the script that holds the path to the key in the registry. In this way, several remote actions may use the same script to read from different registry keys by supplying a different path to the parameter in the script.

Declare parameters at the beginning of a script in the usual way for PowerShell scripts: 

CODE
param(
    [string]$filePath,
    [string]$regPath
)

The editor of remote actions recognizes the parameters of any imported PowerShell 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 .NET assembly (nxtremoteactions.dll) that is installed in the device of the end-user at the same time as the Collector. The assembly includes a class called Nxt that provides the methods to write results to the Engine.

To use the Nxt class, add the following line at the beginning of a PowerShell script for remote actions:

Add-Type -Path $env:NEXTHINK\RemoteActions\nxtremoteactions.dll

Use the methods of the class to write the desired outputs. All write methods accept two arguments: the name of the output and the value to write. For instance, to write the size of a file to the Engine:

[Nxt]::WriteOutputSize("FileSize", $fileSize)

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 the output. Find the list of available methods and the corresponding PowerShell type of the value to be written in the table below:

Nxt write method

PowerShell type

Constraints

WriteOutputString

[string]

0 - 1024 characters (output truncated if bigger)

WriteOutputBool

[bool]

true / false

WriteOutputUInt32

[uint32]

  • Min: 0

  • Max: 4 294 967 295

WriteOutputFloat

[float]

  • Min: -3.4E+38

  • Max: 3.4E+38

WriteOutputSize

[float]

  • Min: 0

  • Max: 3.4E+38

WriteOutputRatio

[float]

WriteOutputBitRate

[float]

WriteOutputDateTime

[DateTime]

DD.MM.YYYY@HH:MM

WriteOutputDuration

[TimeSpan]

  • Min: 0 ms

  • Max: 49 days

  • Precision in milliseconds

WriteOutputStringList

[string[]]

Same as string

Interacting with end-users in self-help scenarios

To help end-users solve issues by themselves, combine remote actions with campaigns. In combination with remote actions, campaigns let you inform end-users about the detection of an issue and guide them through its resolution.

Because self-help scenarios make use of remote actions and campaigns, they require the purchase of both the Nexthink Act and the Nexthink Engage products.

To display a campaign in the desktop of an end-user that is interacting with a device:

  • The campaign must target users with a remote action and be published.

  • The script of the remote action can be executed either:

    • In the context of the end-user, if the action does not need any special privileges.

    • In the context of the local system account, if the action needs administrative privileges.

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 Ctrl+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

To interact with campaigns from a remote action, the script of the remote action requires to load a .NET assembly (nxtcampaignaction.dll) that is installed in the device of the end-user along with the Collector. The assembly includes the class Nxt.CampaignAction that provides the methods to control the execution of a campaign and get the responses from the user.

To load the assembly, add the following line at the beginning of the script:

Add-Type -Path $env:NEXTHINK\RemoteActions\nxtcampaignaction.dll

The methods of Nxt.CampaignAction to control campaigns are the following:

NxTrayResp RunCampaign(string campaignUid)

Run the campaign identified by the campaignUid and block until the user finishes answering. Return the response in an object of type NxTrayResp.

NxTrayResp RunCampaign(string campaignUid, int timeout)

Run the campaign identified by the campaignUid and block until the user finishes answering or after the specified timeout (in seconds) elapses. Return the response in an object of type NxTrayResp.

RunStandAloneCampaign(string campaignUid)

Run the campaign identified by the campaignUid without blocking nor expecting results.

String GetResponseStatus(NxTrayResp response)

Given a response object of type NxTrayResp, the method returns a string that reflects the status of the campaign. Possible values for the status:

  • fully, the user has fully answered the questions of the campaign.

  • declined, the user declined to participate in the campaign.

  • postponed, the user accepted to participate in the campaign.

  • timeout, the campaign was timed out before the user finished answering.

  • 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.

string[] GetResponseAnswer(NxTrayResp response, string questionLabel)

Given a response object of type NxTrayResp and the label that identifies a question in the campaign, the method returns the response given by the user.

  • In the case of a single answer question, the returned string array has only one element.

  • In the case of a multiple answer question, the returned string array has as many elements as answers selected by the user. Optional free text is ignored.

  • If the user has not fully answered the campaign (i.e. status is not fully), the returned string array is empty. Optional free text is ignored.

Note that, for security reasons, remote actions for self-help scenarios ignore the optional free text answers of multiple answer or opinion scale questions. Therefore, it is useless to include optional free text answers in campaigns to be used exclusively in self-help scenarios.

Example code

Find below a simple example of how to run a campaign from a remote action. The example assumes that you have created a single-answer campaign where one of the possible answers is yes:

CODE
Add-Type -Path "$env:NEXTHINK\RemoteActions\nxtcampaignaction.dll"

$CampaignUid  = "<UID of a single-answer campaign>"
$maxWaitTimeinSeconds = 60

$result = [Nxt.CampaignAction]::RunCampaign($CampaignUid, $maxWaitTimeinSeconds)
$status = [Nxt.CampaignAction]::GetResponseStatus($result)

if ($status -eq "fully") {
    $questionName = "question1"
    $choiceName =[Nxt.CampaignAction]::GetResponseAnswer($result, $questionName)
    if ($choiceName -eq "yes") {
        # user has confirmed - let's do some actions:
        Start-Process notepad.exe
    }
}


See a more elaborated example of self-help scenario with two campaigns here.

Error handling

Nexthink detects whether the execution of a remote action was successful or not based on the return value of the PowerShell process that ran the script:

  • An exit code value 0 indicates a successful execution.

  • A non-zero value indicates some kind of error.

However, unhandled exceptions in PowerShell may cause the termination of a script without returning an appropriate exit code. To handle unexpected errors, Nexthink recommends you to begin the body of all your scripts with the following code snippet:

CODE
 trap {
     $host.ui.WriteErrorLine($_.ToString())
     exit 1
 }


Place this default error handler right below the addition of the necessary DLL dependencies, which follow the optional declaration of formal parameters.

Performance measurement

To measure the performance and resource consumption of your scripts, turn on the logs of the Collector in debug mode with the help of the Collector Configuration tool:

nxtcfg.exe /s logmode=2

The output is stored in the nxtcod.log file.

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.


RELATED TASKS

RELATED REFERENCES

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.