Automation Scripts are a powerful feature of Palo Alto’s Cortex XSOAR product. This post reviews how to utilize the executeCommand
method to run other existing integration commands, scripts, or built-ins from within a custom automation script of your creation.
Disclaimer
This tutorial assumes you have a fundamental understanding of Python and at least some prior experience working with XSOAR.
Table of contents
Open Table of contents
executeCommand
Automation scripts automatically import the Demisto class. This makes the executeCommand
method available for use without having to import anything in the script ourselves.
You can use executeCommand
to call just about any other commands available within XSOAR. This includes integration commands, built-in system commands, and even other custom automation scripts. Pretty Cool!
Example:
##Simple Ping Example
ping_args = {
"address" : "google.com"
}
ping_result = demisto.executeCommand("Ping", ping_args)
executeCommand requires two positional arguments:
- cmd - The name of the command you want to run as a string (must match exactly as it appears in XSOAR)
- args - A python dictionary containing the key/value pairs of the arguments required by the specified command
The Script Helper is a great way to determine what arguments need to be specified for a given command:
You can optionally specify what integration instance executeCommand uses by specifying the instance name with key name "using"
. This is very handy when you have multiple instances configured for a single integration.
Example:
send_mail_args = {
"to" : "jim@example.com",
"subject" : "Need Coffee",
"body" : "Please make more coffee, the pot is empty."
"using" : "MicrosoftGraphMail_instance_1"
}
send_mail_result = demisto.executeCommand("send-mail", send_mail_args)
Walkthrough
Let’s expand upon the simple ping example above to demonstrate how we could capture just the destination IP address from pinging a specified address.
Create a new automation script and then copy/paste the snippet below. Save the script and then execute to the script in the playground to view the results:
import json
ping_args = {
"address" : "google.com"
}
ping_result = demisto.executeCommand("Ping", ping_args)
print(json.dumps(ping_result,indent=4))
Results:
As you can see, running Ping via executeCommand returns a large amount of data in the form of a JSON object. Since we’re only after the destination ip, we’ll have to parse this data.
Response JSON:
[
{
"ModuleName": "CustomScripts",
"Brand": "Scripts",
"Category": "automation",
"ID": "",
"Version": 0,
"Type": 1,
"Contents": {
"avg_rtt": "15.350",
"destination": "google.com",
"destination_ip": "142.250.191.174",
"max_rtt": "15.568",
"mdev_rtt": "0.154",
"min_rtt": "15.236",
"ret_code": "0"
},
"HumanReadable": "### Ping Results\n|avg_rtt|destination|destination_ip|max_rtt|mdev_rtt|min_rtt|ret_code|\n|---|---|---|---|---|---|---|\n| 15.350 | google.com | 142.250.191.174 | 15.568 | 0.154 | 15.236 | 0 |\n",
"ImportantEntryContext": null,
"EntryContext": {
"Ping": {
"avg_rtt": "15.350",
"destination": "google.com",
"destination_ip": "142.250.191.174",
"max_rtt": "15.568",
"mdev_rtt": "0.154",
"min_rtt": "15.236",
"ret_code": "0"
}
},
"IgnoreAutoExtract": false,
"ReadableContentsFormat": "",
"ContentsFormat": "json",
"File": "",
"FileID": "",
"FileMetadata": null,
"System": "",
"Note": false,
"Evidence": false,
"EvidenceID": "",
"Tags": null,
"Metadata": {
"id": "",
"version": 0,
"cacheVersn": 0,
"modified": "0001-01-01T00:00:00Z",
"created": "2024-06-07T15:18:03.810948074-04:00",
"sizeInBytes": 0,
"type": 1,
"incidentCreationTime": "0001-01-01T00:00:00Z",
"retryTime": "0001-01-01T00:00:00Z",
"user": "",
"errorSource": "",
"contents": "",
"format": "json",
"investigationId": "63f5e7ca-2ffa-4a0c-8871-94d28fd90d2e",
"file": "",
"fileID": "",
"parentId": "7@63f5e7ca-2ffa-4a0c-8871-94d28fd90d2e",
"pinned": false,
"fileMetadata": null,
"parentContent": "!Ping address=\"google.com\"",
"parentEntryTruncated": false,
"system": "",
"reputations": null,
"category": "",
"note": false,
"isTodo": false,
"tags": null,
"tagsRaw": null,
"startDate": "0001-01-01T00:00:00Z",
"times": 0,
"recurrent": false,
"endingDate": "0001-01-01T00:00:00Z",
"timezoneOffset": 0,
"cronView": false,
"scheduled": false,
"entryTask": null,
"taskId": "",
"playbookId": "",
"reputationSize": 0,
"contentsSize": 0,
"brand": "Scripts",
"instance": "Scripts",
"InstanceID": "ScriptServicesModule",
"IndicatorTimeline": [],
"Relationships": null,
"mirrored": false
},
"IndicatorTimeline": null,
"NextRun": "",
"Timeout": "",
"PollingCommand": "",
"PollingArgs": null,
"PollingItemsRemaining": 0,
"Relationships": null,
"APIExecutionMetrics": null
}
]
It looks like the bit we’re after is the key destination_ip
. It’s a bit buried in the JSON response object but still obtainable. Add the following snippet to your script to capture just the destination ip:
import json
ping_args = {
"address" : "google.com"
}
ping_result = demisto.executeCommand("Ping", ping_args)
#print(json.dumps(ping_result,indent=4))
ip = ping_result[0]["Contents"]["destination_ip"]
print(ip)
Now if we run the script again in the playground we should print just the destination ip:
Excellent, now you are free to expand upon the automation script using the results of the executeCommand in an infinite number of ways! :)
Summary
The executeCommand
method allows us to run existing automation scripts, integration commands, and built-ins directly from another automation script. This post gave a brief example of how to use the executeCommand
method to extract a single desired attribute from the Ping
command. This feature within XSOAR completely expands the limited capabilities within the playbook designer since we can now write custom Python scripts but still leverage the same commands available to us within the tool.
See my full example code on my github:
https://github.com/JPSOAR/XSOAR-Sample-Scripts/blob/main/Scripts/executeCommand_example.py