Files
splunk-security_content/playbooks/ServiceNow_Related_Tickets_Search.json
2026-04-28 10:47:57 -04:00

604 lines
32 KiB
JSON

{
"blockly": false,
"blockly_xml": "<xml></xml>",
"category": "Related Tickets Search",
"coa": {
"data": {
"description": "Accepts a user or device and identifies if related tickets exists in a timeframe of last 30 days. Generates a global report and list of observables.",
"edges": [
{
"id": "port_6_to_port_8",
"sourceNode": "6",
"sourcePort": "6_out",
"targetNode": "8",
"targetPort": "8_in"
},
{
"id": "port_0_to_port_6",
"sourceNode": "0",
"sourcePort": "0_out",
"targetNode": "6",
"targetPort": "6_in"
},
{
"conditions": [
{
"index": 0
}
],
"id": "port_10_to_port_9",
"sourceNode": "10",
"sourcePort": "10_out",
"targetNode": "9",
"targetPort": "9_in"
},
{
"id": "port_8_to_port_17",
"sourceNode": "8",
"sourcePort": "8_out",
"targetNode": "17",
"targetPort": "17_in"
},
{
"id": "port_17_to_port_10",
"sourceNode": "17",
"sourcePort": "17_out",
"targetNode": "10",
"targetPort": "10_in"
},
{
"id": "port_9_to_port_19",
"sourceNode": "9",
"sourcePort": "9_out",
"targetNode": "19",
"targetPort": "19_in"
},
{
"id": "port_19_to_port_14",
"sourceNode": "19",
"sourcePort": "19_out",
"targetNode": "14",
"targetPort": "14_in"
},
{
"id": "port_14_to_port_16",
"sourceNode": "14",
"sourcePort": "14_out",
"targetNode": "16",
"targetPort": "16_in"
},
{
"id": "port_16_to_port_25",
"sourceNode": "16",
"sourcePort": "16_out",
"targetNode": "25",
"targetPort": "25_in"
},
{
"id": "port_25_to_port_1",
"sourceNode": "25",
"sourcePort": "25_out",
"targetNode": "1",
"targetPort": "1_in"
}
],
"hash": "0c56bc09507f0a442ed7f70f357f51ae6d3983fe",
"nodes": {
"0": {
"data": {
"advanced": {
"join": []
},
"functionName": "on_start",
"id": "0",
"type": "start"
},
"errors": {},
"id": "0",
"type": "start",
"warnings": {},
"x": 19.999999999999986,
"y": -1.9184653865522705e-13
},
"1": {
"data": {
"advanced": {
"join": []
},
"functionName": "on_finish",
"id": "1",
"type": "end"
},
"errors": {},
"id": "1",
"type": "end",
"warnings": {},
"x": 19.999999999999986,
"y": 1708
},
"10": {
"data": {
"advanced": {
"customName": "input filter",
"customNameId": 0,
"delimiter": ",",
"delimiter_enabled": true,
"description": "Creates a dataset without None values.",
"join": [],
"note": "Creates a dataset without None values."
},
"conditions": [
{
"comparisons": [
{
"conditionIndex": 0,
"op": "!=",
"param": "playbook_input:search_term",
"value": "None"
}
],
"conditionIndex": 0,
"customName": "search term exists",
"logic": "and"
}
],
"functionId": 1,
"functionName": "input_filter",
"id": "10",
"type": "filter"
},
"errors": {},
"id": "10",
"type": "filter",
"warnings": {},
"x": 60,
"y": 622
},
"14": {
"data": {
"advanced": {
"customName": "process results",
"customNameId": 0,
"description": "Iterates through the results of the run ticket query to link playbook input search term to their associated tickets.",
"join": [],
"note": "Iterates through the results of the run ticket query to link playbook input search term to their associated tickets."
},
"functionId": 3,
"functionName": "process_results",
"id": "14",
"inputParameters": [
"filtered-data:input_filter:condition_1:playbook_input:search_term",
"run_ticket_query:action_result.data",
"run_ticket_query:action_result.parameter.query_table"
],
"outputVariables": [
"output"
],
"type": "code"
},
"errors": {},
"id": "14",
"type": "code",
"userCode": " process_results__output = {}\n for search_term in filtered_input_0_search_term_values:\n process_results__output[search_term] = []\n for result, query_table in zip(run_ticket_query_result_item_0, run_ticket_query_parameter_query_table):\n if not isinstance(result, list):\n list_result = [result]\n else:\n list_result = result\n for result_item in list_result:\n result_item_values = [item.lower() for item in result_item.values() if isinstance(item, str)]\n match = False\n for string_value in result_item_values:\n if search_term.lower() in string_value:\n match = True\n break\n if match:\n process_results__output[search_term].append({**result_item, **{\"ticket_type\": query_table}})\n\n",
"warnings": {},
"x": 1.4210854715202004e-14,
"y": 1158
},
"16": {
"customCode": null,
"data": {
"advanced": {
"customName": "build output",
"customNameId": 0,
"description": "Extract relevant data and add them to an observable array.",
"join": [],
"note": "Extract relevant data and add them to an observable array."
},
"functionId": 5,
"functionName": "build_output",
"id": "16",
"inputParameters": [
"process_results:custom_function:output"
],
"outputVariables": [
"observable_array",
"name",
"number",
"message",
"start_time",
"end_time",
"assignee",
"creator_name",
"state",
"matched_fields",
"source_link",
"source"
],
"type": "code"
},
"errors": {},
"id": "16",
"type": "code",
"userCode": " import re \n \n build_output__observable_array = []\n build_output__name = []\n build_output__number = []\n build_output__message = []\n build_output__start_time = []\n build_output__end_time = []\n build_output__assignee = []\n build_output__creator_name = []\n build_output__state = []\n build_output__matched_fields = []\n build_output__source_link = []\n build_output__source = []\n \n def generate_ticket_link(sample_url, ticket_type, sys_id):\n extract_host = re.search(r\"https*:\\/\\/[^\\/]+\", sample_url).group(0)\n extract_host += f\"/nav_to.do?uri={ticket_type}.do?sys_id={sys_id}\"\n return extract_host\n \n for key in process_results__output.keys():\n \n for value in process_results__output[key]:\n assigned_to = None\n caller_id = None\n matched_fields = []\n if value.get(\"assigned_to\"):\n assigned_to = value[\"assigned_to\"][\"display_value\"]\n if value.get(\"caller_id\"):\n caller_id = value[\"caller_id\"][\"display_value\"]\n \n sample_link = None\n for k, v in value.items():\n # generate matched fields where the searched entity appears\n if isinstance(v, str) and key.lower() in v.lower():\n matched_fields.append(k)\n # search for any link sample:\n if isinstance(v, dict):\n sample_link = v.get('link')\n \n source_link = generate_ticket_link(sample_link, value['ticket_type'], value['sys_id'])\n observable_object = {\n \"value\": key,\n \"ticket\": {\n \"name\": value[\"short_description\"],\n \"id\": value[\"sys_id\"],\n \"number\": value[\"number\"],\n \"message\": json.dumps(value[\"description\"]),\n \"start_time\": value[\"sys_created_on\"],\n \"end_time\": value[\"closed_at\"],\n \"assigned_to\": assigned_to,\n \"creator_name\": caller_id,\n \"state\": value[\"state\"],\n \"notes\": [value[\"work_notes\"]],\n \"comments\": [value[\"comments\"]]\n },\n \"matched_fields\": matched_fields,\n \"source\": \"ServiceNow\",\n \"source_link\": source_link\n }\n build_output__observable_array.append(observable_object)\n build_output__name.append(value[\"short_description\"])\n build_output__number.append(value[\"number\"])\n build_output__message.append(json.dumps(value[\"description\"])) # eliminate new line issues\n build_output__start_time.append(value[\"sys_created_on\"])\n build_output__end_time.append(value[\"closed_at\"])\n build_output__assignee.append(assigned_to)\n build_output__creator_name.append(caller_id)\n build_output__state.append(value[\"state\"])\n build_output__matched_fields.append(matched_fields)\n build_output__source.append(\"ServiceNow\")\n build_output__source_link.append(source_link)\n #phantom.debug(observable_object)\n\n",
"warnings": {},
"x": 1.4210854715202004e-14,
"y": 1352
},
"17": {
"data": {
"advanced": {
"customName": "calculate earliest time",
"customNameId": 0,
"join": [],
"note": "Converts the container create time into a different datetime string compatible with ServiceNow."
},
"customFunction": {
"draftMode": false,
"name": "datetime_modify",
"repoName": "community"
},
"functionId": 2,
"functionName": "calculate_earliest_time",
"id": "17",
"loop": {
"enabled": false,
"exitAfterUnit": "m",
"exitAfterValue": 10,
"exitConditionEnabled": false,
"exitLoopAfter": 2,
"pauseUnit": "m",
"pauseValue": 2
},
"selectMore": false,
"type": "utility",
"utilities": {
"datetime_modify": {
"description": "Change a timestamp by adding or subtracting minutes, hours, or days.",
"fields": [
{
"dataTypes": [
""
],
"description": "The datetime to modify, which should be provided in a string format determined by input_format_string",
"inputType": "item",
"label": "input_datetime",
"name": "input_datetime",
"placeholder": "2020-06-27T14:53:08.219016Z",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [],
"description": "The format string to use for the input according to the Python's datetime.strptime() formatting rules. If none is provided the default will be '%Y-%m-%dT%H:%M:%S.%fZ'. In addition to strptime() formats, the special format \"epoch\" can be used to accept unix epoch timestamps.",
"inputType": "item",
"label": "input_format_string",
"name": "input_format_string",
"placeholder": "%Y-%m-%dT%H:%M:%S.%fZ",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [
""
],
"description": "Choose a unit to modify the date by, which must be either seconds, minutes, hours, or days. If none is provided the default will be 'minutes'",
"inputType": "item",
"label": "modification_unit",
"name": "modification_unit",
"placeholder": "minutes",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [],
"description": "The number of seconds, minutes, hours, or days to add or subtract. Use a negative number such as -1.5 to subtract time. Defaults to zero.",
"inputType": "item",
"label": "amount_to_modify",
"name": "amount_to_modify",
"placeholder": "0",
"renderType": "datapath",
"required": false
},
{
"dataTypes": [],
"description": "The format string to use for the output according to the Python's datetime.strftime() formatting rules. If none is provided the default will be '%Y-%m-%dT%H:%M:%S.%fZ'.",
"inputType": "item",
"label": "output_format_string",
"name": "output_format_string",
"placeholder": "%Y-%m-%dT%H:%M:%S.%fZ",
"renderType": "datapath",
"required": false
}
],
"label": "datetime_modify",
"name": "datetime_modify"
}
},
"utilityType": "custom_function",
"values": {
"datetime_modify": {
"amount_to_modify": "-30",
"input_datetime": "container:create_time",
"input_format_string": "%Y-%m-%d %H:%M:%S.%f+00",
"modification_unit": "days",
"output_format_string": "'%Y-%m-%d','%H:%M:%S'"
}
}
},
"errors": {},
"id": "17",
"type": "utility",
"warnings": {},
"x": 1.4210854715202004e-14,
"y": 474
},
"19": {
"data": {
"action": "run query",
"actionType": "investigate",
"advanced": {
"customName": "run ticket query",
"customNameId": 0,
"description": "Perform a text search match within ServiceNow.",
"join": [],
"note": "Perform a text search match within ServiceNow."
},
"connector": "ServiceNow",
"connectorConfigs": [
"servicenow"
],
"connectorId": "a590c3bc-ca41-4a0e-b063-8066ca868794",
"connectorVersion": "v1",
"functionId": 3,
"functionName": "run_ticket_query",
"id": "19",
"loop": {
"enabled": false,
"exitAfterUnit": "m",
"exitAfterValue": 10,
"exitConditionEnabled": false,
"exitLoopAfter": 2,
"pauseUnit": "m",
"pauseValue": 2
},
"parameters": {
"max_results": "100",
"query": {
"functionId": 3,
"parameters": [
"space_delimiter_input:formatted_data",
"calculate_earliest_time:custom_function_result.data.datetime_string"
],
"template": "sysparm_query=active=true^IR_OR_QUERY={0}^opened_at>javascript:gs.dateGenerate({1})&sysparm_display_value=true \n\n"
},
"query_table": "convert_table_list:custom_function_result.data.output"
},
"requiredParameters": [
{
"data_type": "string",
"field": "query"
},
{
"data_type": "numeric",
"default": 100,
"field": "max_results"
},
{
"data_type": "string",
"field": "query_table"
}
],
"type": "action"
},
"errors": {},
"id": "19",
"type": "action",
"warnings": {},
"x": 0,
"y": 980
},
"25": {
"data": {
"advanced": {
"customName": "format report",
"customNameId": 0,
"description": "Format a summary table with the information gathered from the playbook.",
"join": [],
"note": "Format a summary table with the information gathered from the playbook."
},
"functionId": 3,
"functionName": "format_report",
"id": "25",
"parameters": [
"build_output:custom_function:name",
"build_output:custom_function:number",
"build_output:custom_function:message",
"build_output:custom_function:start_time",
"build_output:custom_function:end_time",
"build_output:custom_function:assignee",
"build_output:custom_function:creator_name",
"build_output:custom_function:state",
"build_output:custom_function:matched_fields",
"build_output:custom_function:source",
"build_output:custom_function:source_link"
],
"template": "SOAR retrieved tickets from Service Now. The table below shows a summary of the information gathered.\n\n| Name | Number | Message | Start Time | End Time | Assignee | Creator Name | State | Matched Fields | Source | Source Link |\n| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |\n%%\n| {0} | {1} | {2} | {3} | {4} | {5} | {6} | {7} | {8} | {9} | {10} |\n%%\n",
"type": "format"
},
"errors": {},
"id": "25",
"type": "format",
"warnings": {},
"x": 1.4210854715202004e-14,
"y": 1530
},
"6": {
"data": {
"advanced": {
"customName": "default table list",
"customNameId": 0,
"description": "Adjust the table list variable to change which tables should be searched.",
"join": [],
"note": "Adjust the table list variable to change which tables should be searched."
},
"functionId": 2,
"functionName": "default_table_list",
"id": "6",
"inputParameters": [],
"outputVariables": [
"output"
],
"type": "code"
},
"errors": {},
"id": "6",
"type": "code",
"userCode": " \n # Default tables list to find related tickets. Adjust as needed.\n default_table_list = [\n 'incident', \n 'change_request', \n 'change_task', \n 'problem',\n 'sc_request', \n 'sc_task', \n 'sc_req_item',\n ]\n default_table_list__output = default_table_list\n \n",
"warnings": {},
"x": 1.4210854715202004e-14,
"y": 148
},
"8": {
"data": {
"advanced": {
"customName": "convert table list",
"customNameId": 0,
"join": [],
"note": "Converts the table into a custom function result that is filterable downstream.",
"refreshNotableData": false
},
"customFunction": {
"draftMode": false,
"name": "list_demux",
"repoName": "community"
},
"functionId": 1,
"functionName": "convert_table_list",
"id": "8",
"loop": {
"enabled": false,
"exitAfterUnit": "m",
"exitAfterValue": 10,
"exitConditionEnabled": false,
"exitLoopAfter": 2,
"pauseUnit": "m",
"pauseValue": 2
},
"selectMore": false,
"type": "utility",
"utilities": {
"list_demux": {
"description": "Accepts a single list and converts it into multiple custom function output results. All output will be placed in the \"output\" datapath. Sub-items and sub-item variable names are dependent on the input.",
"fields": [
{
"dataTypes": [
"*"
],
"description": "A list of objects. Nested lists are not unpacked.",
"inputType": "item",
"label": "input_list",
"name": "input_list",
"placeholder": "[\"list_item_1\", \"list_item_2\", \"list_item_3\"]",
"renderType": "datapath",
"required": false
}
],
"label": "list_demux",
"name": "list_demux"
}
},
"utilityType": "custom_function",
"values": {
"list_demux": {
"input_list": "default_table_list:custom_function:output"
}
}
},
"errors": {},
"id": "8",
"type": "utility",
"userCode": "\n",
"warnings": {},
"x": 1.4210854715202004e-14,
"y": 326
},
"9": {
"data": {
"advanced": {
"customName": "space delimiter input",
"customNameId": 0,
"description": "Convert playbook input into space delimiter string for ServiceNow query.",
"drop_none": true,
"join": [],
"note": "Convert playbook input into space delimiter string for ServiceNow query.",
"separator": " "
},
"functionId": 1,
"functionName": "space_delimiter_input",
"id": "9",
"parameters": [
"filtered-data:input_filter:condition_1:playbook_input:search_term"
],
"template": "{0}\n",
"type": "format"
},
"errors": {},
"id": "9",
"type": "format",
"warnings": {},
"x": 1.4210854715202004e-14,
"y": 802
}
},
"notes": "Inputs: user, device\nInteractions: ServiceNow\nActions: run query\nOutputs: report, observables"
},
"input_spec": [
{
"contains": [
"user name",
"host name"
],
"description": "Find tickets in ServiceNow that have mentioned this search term..",
"name": "search_term"
}
],
"output_spec": [
{
"contains": [],
"datapaths": [
"build_output:custom_function:observable_array"
],
"deduplicate": false,
"description": "An array of observable dictionaries with value, type, score, score_id, and categories.",
"metadata": {},
"name": "observable"
},
{
"contains": [],
"datapaths": [
"format_report:formatted_data"
],
"deduplicate": false,
"description": "An array of reports. One report per reputation category.",
"metadata": {},
"name": "markdown_report"
}
],
"playbook_trigger": "artifact_created",
"playbook_type": "data",
"python_version": "3.13",
"schema": "5.0.15",
"version": "6.3.1.176"
},
"create_time": "2025-01-24T16:39:26.106708+00:00",
"draft_mode": false,
"labels": [
"*"
],
"tags": [
"user",
"device",
"ServiceNow",
"ticket"
]
}