CreatePlbkDoc
Purpose: This automation will produce docx file detailing the tasks in the given playbook. It can produce a table or paragraph format of the report. Author: Mahmood Azmat Input1: Name of the playbook (Mandatory) Input2: Format type needed. Table or Paragraph. Paragraph is default. Input3: Name of the docx file that will be produced. Give the full name including the ".docx" extension. (Mandatory) Requirements: This automation requires "Core REST API" integration enabled and connected to the XSOAR itself. Automation uses it to read the objects of the playbook.
- Type
- python
- Pack
- CommunityCommonScripts
Source
import demistomock as demisto # noqa: F401
from CommonServerPython import * # noqa: F401
# import json
from docx import Document
from docx.enum.section import WD_ORIENT # pylint: disable=E0611
from docx.shared import Inches
# Purpose: This automation will produce docx file detailing the tasks in the given playbook. It can
# produce a table or paragraph format of the report.
# The automation will create seprate tables (in case of Table format), or separate paragraphs
# (in case of Paragraph format).
# The definition of a section is path starting from a section header type of task, and ends
# when it hits another section header in that path pf traversal.
# Author: Mahmood Azmat
# Input1: Name of the playbook (Mandatory)
# Input2: Format type needed. Table or Paragraph. Paragraph is default.
# Input3: Name of the docx file that will be produced. Give the full name including the ".docx"
# extension. (Mandatory)
# Requirements: This automation requires "Core REST API" integration enabled and connected to the XSOAR itself.
# Automation uses it to read the objects of the playbook.
retVal: dict = {}
DEMISTO_PLAYBOOKS_PATH = "/playbook/search"
document = Document()
SectionID = ""
Table = ""
Paragraph = ""
TaskIDsInLogic = []
TaskIDsInLogic.append("0")
OutPutType = ""
ConditionBranch = ""
PlaybookIndex = -1
NodesVisitedInThisSection = []
NodesVisitedInAllSections = {}
# This is a 2 level associative array. First level is the ID of the section task and
# second level has the IDs visited in that section
def post_api_request(url, body):
api_args = {"uri": url, "body": body}
raw_res = demisto.executeCommand("core-api-post", api_args)
try:
res = raw_res[0]["Contents"]["response"]
return res
except KeyError:
return_error(f"API Request failed, no response from API call to {url}")
except TypeError:
return_error(f"API Request failed, failedto {raw_res}")
def EnterHeader(HeaderStr):
document.add_heading(HeaderStr, level=1)
def StartParagraph(Name, Description):
global Paragraph
document.add_heading(Name, level=2)
if Description == "[Blank]":
Description = ""
Paragraph = document.add_paragraph(Description) # type: ignore[assignment]
Paragraph.paragraph_format.left_indent = Inches(0.25) # type: ignore
def StartTable():
global Table
Table = document.add_table(rows=1, cols=2)
Table.style = "Light Grid Accent 1" # type: ignore
hdr_cells = Table.rows[0].cells # type: ignore
hdr_cells[0].text = "Name"
hdr_cells[1].text = "Description"
def TraverseTasks(TaskID):
global retVal, document, Table, Paragraph, NodesVisitedInAllSections, PlaybookIndex
global OutPutType, ConditionBranch, NodesVisitedInThisSection, SectionID
if TaskID in NodesVisitedInThisSection:
# If this node has already been visited then we will skip it. This avoids putting the same task into the
# document mutiple times.
# You may have mutiple paths ending to the same task within the same section so
# we do not want to make multiple entries of that.
return
else:
NodesVisitedInThisSection.append(TaskID)
NodesVisitedInAllSections[SectionID] = NodesVisitedInThisSection
if TaskID is None:
return
else:
curTask = retVal[PlaybookIndex]["tasks"][str(TaskID)]
taskDescription = curTask["task"].get("description", "[Blank]")
Description = taskDescription
Type = curTask["type"]
if str(TaskID) == "0":
Name = "Playbook Triggered"
else:
Name = curTask["task"]["name"]
if Type == "condition":
Name = Name + " - Conditional Task "
if Type == "playbook":
Name = Name + " - Sub-playbook "
if ConditionBranch != "":
Name = Name + " (Condition branch->" + ConditionBranch + ")"
if Type == "title" or Type == "start":
if Type == "title":
if curTask.get("nextTasks") is not None:
EnterHeader(Name)
if OutPutType == "TABLE":
StartTable()
else:
EnterHeader(Name)
if OutPutType == "TABLE":
StartTable()
else:
if OutPutType == "TABLE":
if Table == "":
StartTable()
row_cells = Table.add_row().cells # type: ignore
row_cells[0].text = Name
row_cells[1].text = Description
else:
StartParagraph(Name, Description)
if curTask.get("nextTasks") is not None:
if curTask["type"] != "condition":
for NextTaskID in curTask["nextTasks"]["#none#"]:
TypeOfNextTask = retVal[PlaybookIndex]["tasks"][str(NextTaskID)]["task"]["type"]
NameOfNextTask = retVal[PlaybookIndex]["tasks"][str(NextTaskID)]["task"]["name"]
if TypeOfNextTask == "title":
NameOfNextTask = NameOfNextTask + " - Section "
if ConditionBranch != "":
NameOfNextTask = NameOfNextTask + " (Condition branch->" + ConditionBranch + ")"
if TypeOfNextTask != "title":
TraverseTasks(NextTaskID)
else:
if OutPutType == "TABLE":
row_cells = Table.add_row().cells # type: ignore
row_cells[0].text = NameOfNextTask
else:
StartParagraph(NameOfNextTask, "")
if str(NextTaskID) not in TaskIDsInLogic:
TaskIDsInLogic.append(str(NextTaskID))
else:
for TempKeys in curTask.get("nextTasks"):
for NextTaskID in curTask["nextTasks"][TempKeys]:
TypeOfNextTask = retVal[PlaybookIndex]["tasks"][str(NextTaskID)]["task"]["type"]
NameOfNextTask = retVal[PlaybookIndex]["tasks"][str(NextTaskID)]["task"]["name"]
ConditionBranch = TempKeys
if TypeOfNextTask == "title":
NameOfNextTask = NameOfNextTask + " - Section "
if ConditionBranch == "#default#":
ConditionBranch = "Else"
NameOfNextTask = NameOfNextTask + " (Condition branch->" + ConditionBranch + ")"
if TypeOfNextTask != "title":
TraverseTasks(NextTaskID)
else:
if OutPutType == "TABLE":
row_cells = Table.add_row().cells # type: ignore
row_cells[0].text = NameOfNextTask
else:
StartParagraph(NameOfNextTask, "")
if str(NextTaskID) not in TaskIDsInLogic:
TaskIDsInLogic.append(str(NextTaskID))
ConditionBranch = ""
return
""" MAIN FUNCTION """
def main():
# print ("Test")
global retVal, TaskIDsInLogic, NodesVisitedInThisSection, PlaybookIndex
global document, SectionID
global OutPutType
global ConditionBranch
args = demisto.args()
DocFileName = args.get("DocFileName")
PlaybookName = args.get("PlaybookName")
OutPutType = args.get("Output_Format")
OutPutType = str(OutPutType).upper()
if OutPutType == "":
OutPutType = "PARAGRAPH"
TempStr = PlaybookName + "- Playbook"
if OutPutType == "TABLE":
sections = document.sections
section = sections[-1]
# Swapping width with height to make the table landscape format
old_width = section.page_width
old_height = section.page_height
section.orientation = WD_ORIENT.LANDSCAPE
section.page_width = old_height
section.page_height = old_width
document.add_heading(TempStr, 0)
retVal = post_api_request(DEMISTO_PLAYBOOKS_PATH, {"query": PlaybookName}).get("playbooks")
if retVal is None:
demisto.results("Playbook not found. Please check the Playbook name.")
return
i = 0
j = 0
while j < len(retVal):
PlaybookNameTempStr = retVal[j].get("nameRaw")
if PlaybookNameTempStr == PlaybookName:
PlaybookIndex = j
j = j + 1
if PlaybookIndex == -1:
demisto.results("Playbook not found. Please check the Playbook name.")
return
while TaskIDsInLogic[i] is not None:
ConditionBranch = ""
NodesVisitedInThisSection.clear()
SectionID = TaskIDsInLogic[i]
TraverseTasks(str(TaskIDsInLogic[i]))
i = i + 1
try:
assert TaskIDsInLogic[i]
except Exception:
break
if OutPutType == "TABLE":
for tb in document.tables:
for cell in tb.columns[0].cells:
cell.width = Inches(3)
for cell in tb.columns[1].cells:
cell.width = Inches(6)
document.save(DocFileName)
with open(DocFileName, "rb") as f:
filedata = f.read()
demisto.results(fileResult(DocFileName, filedata))
return
""" ENTRY POINT """
if __name__ in ("__main__", "__builtin__", "builtins"):
main()
README
Purpose: This automation will produce docx file detailing the tasks in the given playbook. It can produce a table or paragraph format of the report.
Author: Mahmood Azmat
Input1: Name of the playbook (Mandatory)
Input2: Format type needed. Table or Paragraph. Paragraph is default.
Input3: Name of the docx file that will be produced. Give the full name including the “.docx” extension. (Mandatory)
Requirements: This automation requires “Core REST API” integration enabled and connected to the XSOAR itself. Automation uses it to read the objects of the playbook.
Script Data
| Name | Description |
|---|---|
| Script Type | python3 |
| Tags | General, Utility |
Inputs
| Argument Name | Description |
|---|---|
| DocFileName | |
| PlaybookName | |
| Output_Format |
Outputs
There are no outputs for this script.
Troubleshooting
Multi-tenant environments should be configured with the Cortex Rest API instance when using this
automation. Make sure the Use tenant parameter (in the Cortex Rest API integration) is checked
to ensure that API calls are made to the current tenant instead of the master tenant.