def _fn_sep_quarantine_endpoints_function(self, event, *args, **kwargs): """Function: Quarantine/unquarantine Symantec Endpoint Protection endpoints.""" try: params = transform_kwargs(kwargs) if kwargs else {} # Instantiate result payload object. rp = ResultPayload(CONFIG_DATA_SECTION, **kwargs) # Get the function parameters: sep_group_ids = kwargs.get("sep_group_ids") # text sep_computer_ids = kwargs.get("sep_computer_ids") # text sep_undo = kwargs.get("sep_undo") # boolean LOG.info("sep_group_ids: %s", sep_group_ids) LOG.info("sep_computer_ids: %s", sep_computer_ids) LOG.info("sep_undo: %s", sep_undo) validate_fields(["sep_undo"], kwargs) yield StatusMessage("Running Symantec SEP Quarantine Endpoint or group...") sep = Sepclient(self.options, params) rtn = sep.quarantine_endpoints(**params) results = rp.done(True, rtn) yield StatusMessage("Returning 'Symantec SEP Quarantine Endpoint' or group results") LOG.debug(json.dumps(results["content"])) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: LOG.exception("Exception in Resilient Function for Symantec SEP.") yield FunctionError()
def _fn_sep_move_endpoint_function(self, event, *args, **kwargs): """Function: Checks and moves a client computer to a specified group.""" try: params = transform_kwargs(kwargs) if kwargs else {} # Instantiate result payload object. rp = ResultPayload(CONFIG_DATA_SECTION, **kwargs) # Get the function parameters: sep_groupid = kwargs.get("sep_groupid") # text sep_hardwarekey = kwargs.get("sep_hardwarekey") # text LOG.info("sep_groupid: %s", sep_groupid) LOG.info("sep_hardwarekey: %s", sep_hardwarekey) validate_fields(["sep_groupid", "sep_hardwarekey"], kwargs) yield StatusMessage("Running Symantec SEP Move Endpoint action...") sep = Sepclient(self.options, params) rtn = sep.move_endpoint(**params) results = rp.done(True, rtn) yield StatusMessage( "Returning 'Symantec SEP Move Endpoint' results") LOG.debug(json.dumps(results["content"])) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: LOG.exception("Exception in Resilient Function for Symantec SEP.") yield FunctionError()
def _fn_sep_get_file_content_as_base64_function(self, event, *args, **kwargs): """Function: Get the contents of an uploaded binary file, in base64 format.""" try: params = transform_kwargs(kwargs) if kwargs else {} # Instantiate result payload object. rp = ResultPayload(CONFIG_DATA_SECTION, **kwargs) # Get the function parameters: sep_file_id = kwargs.get("sep_file_id") # text LOG.info("sep_file_id: %s", sep_file_id) validate_fields(["sep_file_id"], kwargs) yield StatusMessage("Running Symantec SEP Get File Content as Base64 ...") sep = Sepclient(self.options, params) rtn = base64.b64encode(sep.get_file_content(**params)).decode("utf-8") results = rp.done(True, rtn) yield StatusMessage("Returning 'Symantec SEP Get File Content as Base64' results") LOG.debug(json.dumps(results["content"])) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: LOG.exception("Exception in Resilient Function for Symantec SEP.") yield FunctionError()
def _fn_sep_get_domains_function(self, event, *args, **kwargs): """Function: Gets a list of all accessible domains.""" try: params = transform_kwargs(kwargs) if kwargs else {} # Instantiate result payload object. rp = ResultPayload(CONFIG_DATA_SECTION, **kwargs) # Get the function parameters: yield StatusMessage("Running Symantec SEP Get Domains query...") sep = Sepclient(self.options, params) rtn = sep.get_domains(**params) results = rp.done(True, rtn) yield StatusMessage("Returning 'Get Domains' results") LOG.debug(json.dumps(results["content"])) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: LOG.exception("Exception in Resilient Function for Symantec SEP.") yield FunctionError()
def _fn_sep_scan_endpoints_function(self, event, *args, **kwargs): """Function: Run a Evidence of Compromise (EOC) scan on Symantec Endpoint Protection endpoints.""" try: params = transform_kwargs(kwargs) if kwargs else {} # Instantiate result payload object. rp = ResultPayload(CONFIG_DATA_SECTION, **kwargs) # Get the function parameters: sep_group_ids = kwargs.get("sep_group_ids") # text sep_computer_ids = kwargs.get("sep_computer_ids") # text sep_scan_type = self.get_select_param(kwargs.get( "sep_scan_type")) # select, values: "QUICK_SCAN", "FULL_SCAN" sep_file_name = kwargs.get("sep_file_path") # text sep_sha256 = kwargs.get("sep_sha256") # text sep_sha1 = kwargs.get("sep_sha1") # text sep_md5 = kwargs.get("sep_md5") # text sep_description = kwargs.get("sep_description") # text sep_scan_action = self.get_select_param( kwargs.get( "sep_scan_action")) # select, values: "scan", "remediate" LOG.info("sep_group_ids: %s", sep_group_ids) LOG.info("sep_computer_ids: %s", sep_computer_ids) LOG.info("sep_scan_type: %s", sep_scan_type) LOG.info("sep_file_path: %s", sep_file_name) LOG.info("sep_sha256: %s", sep_sha256) LOG.info("sep_sha1: %s", sep_sha1) LOG.info("sep_md5: %s", sep_md5) LOG.info("sep_description: %s", sep_description) LOG.info("sep_scan_action: %s", sep_scan_action) validate_fields( ["sep_scan_type", "sep_description", "sep_scan_action"], kwargs) yield StatusMessage( "Running Symantec SEP Scan Endpoints command...") sep = Sepclient(self.options, params) rtn = sep.scan_endpoints(**params) results = rp.done(True, rtn) yield StatusMessage( "Returning 'Symantec SEP Scan Endpoints' results") LOG.debug(json.dumps(results["content"])) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: LOG.exception("Exception in Resilient Function for Symantec SEP.") yield FunctionError()
def _fn_sep_add_fingerprint_list_function(self, event, *args, **kwargs): """Function: Add a hash to a new fingerprint list.""" try: params = transform_kwargs(kwargs) if kwargs else {} # Instantiate result payload object rp = ResultPayload(CONFIG_DATA_SECTION, **kwargs) # Get the function parameters: sep_fingerprintlist_name = kwargs.get( "sep_fingerprintlist_name") # text sep_description = kwargs.get("sep_description") # text sep_domainid = kwargs.get("sep_domainid") # text sep_hash_value = kwargs.get("sep_hash_value") # text LOG.info("sep_fingerprintlist_name: %s", sep_fingerprintlist_name) LOG.info("sep_description: %s", sep_description) LOG.info("sep_domainid: %s", sep_domainid) LOG.info("sep_hash_value: %s", sep_hash_value) validate_fields([ "sep_fingerprintlist_name", "sep_description", "sep_domainid", "sep_hash_value" ], kwargs) yield StatusMessage( "Running Symantec SEP Add Fingerprint List action ...") sep = Sepclient(self.options, params) rtn = sep.add_fingerprint_list(**params) if "errors" in rtn and rtn["errors"][0]["error_code"] == 409: # If this error was trapped user probably tried to re-add a hash to a fingerprint list. yield StatusMessage( u"Got a 409 error while attempting to get a fingerprint list for fingerprint name '{0}' " "because of a possible invalid or deleted id.".format( sep_fingerprintlist_name)) else: yield StatusMessage( u"Returning 'Symantec SEP Add Fingerprint List' results for fingerprint name '{}'." .format(sep_fingerprintlist_name)) results = rp.done(True, rtn) LOG.debug(json.dumps(results["content"])) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: LOG.exception("Exception in Resilient Function for Symantec SEP.") yield FunctionError()
def _fn_sep_assign_fingerprint_list_to_group_function( self, event, *args, **kwargs): """Function: Assign a fingerprint list to a group for lock-down.""" try: params = transform_kwargs(kwargs) if kwargs else {} # Instantiate result payload object rp = ResultPayload(CONFIG_DATA_SECTION, **kwargs) # Get the function parameters: sep_fingerprintlist_id = kwargs.get( "sep_fingerprintlist_id") # text sep_groupid = kwargs.get("sep_groupid") # text LOG.info("sep_fingerprintlist_id: %s", sep_fingerprintlist_id) LOG.info("sep_groupid: %s", sep_groupid) validate_fields(["sep_fingerprintlist_id", "sep_groupid"], kwargs) yield StatusMessage( "Running Symantec SEP Assign Fingerprint List to Group for Lock-down action ..." ) sep = Sepclient(self.options, params) rtn = sep.assign_fingerprint_list_to_group(**params) results = rp.done(True, rtn) if "errorCode" in rtn and int(rtn["errorCode"]) == 400: # If this error was trapped user probably tried to get an invalid fingerprint list. yield StatusMessage( "Symantec SEP Assign Fingerprint List to Group for Lock-down: Got a 400 error " "while attempting to assign a fingerprint list for fingerprint id '{0}' because of a " "possible invalid or deleted fingerprintlist id.".format( sep_fingerprintlist_id)) else: yield StatusMessage( "Returning 'Symantec SEP Assign Fingerprint List to Group for Lock-down' results for " "fingerprintlist_id '{0}' and groupid '{1}'".format( sep_fingerprintlist_id, sep_groupid)) LOG.debug(json.dumps(results["content"])) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: LOG.exception("Exception in Resilient Function for Symantec SEP.") yield FunctionError()
def selftest_function(opts): """ Simple test to confirm access to Cisco AMP for endpoint API connectivity. """ options = opts.get("fn_sep", {}) try: sep = Sepclient(options, None) r = sep.test_connectivity() if r == '': return {"state": "success"} else: return {"state": "failure"} except Exception as e: return {"state": "failure", "status_code": e}
def _fn_sep_delete_fingerprint_list_function(self, event, *args, **kwargs): """Function: Delete a file fingerprint list.""" try: params = transform_kwargs(kwargs) if kwargs else {} # Instantiate result payload object rp = ResultPayload(CONFIG_DATA_SECTION, **kwargs) # Get the function parameters: sep_fingerprintlist_id = kwargs.get( "sep_fingerprintlist_id") # text LOG.info("sep_fingerprintlist_id: %s", sep_fingerprintlist_id) validate_fields(["sep_fingerprintlist_id"], kwargs) yield StatusMessage( "Running Symantec SEP Delete Fingerprint List action ...") sep = Sepclient(self.options, params) rtn = sep.delete_fingerprint_list(**params) results = rp.done(True, rtn) if "errors" in rtn and rtn["errors"][0]["error_code"] == 410: # If this error was trapped user probably tried to get information on invalid connector guid. yield StatusMessage( "Got a 410 error while attempting to delete fingerprint list fingerprint id '{0}' " "because of a possible deleted id.".format( params["sep_fingerprintlist_id"])) else: yield StatusMessage( "Returning 'Symantec SEP Delete Fingerprint List' results for fingerprint id '{}'." .format(sep_fingerprintlist_id)) LOG.debug(json.dumps(results["content"])) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: LOG.exception("Exception in Resilient Function for Symantec SEP.") yield FunctionError()
def _fn_sep_upload_file_to_sepm_function(self, event, *args, **kwargs): """Function: Upload suspicious file from endpoint back to SEPM server.""" try: params = transform_kwargs(kwargs) if kwargs else {} # Instantiate result payload object. rp = ResultPayload(CONFIG_DATA_SECTION, **kwargs) # Get the function parameters: sep_file_path = kwargs.get("sep_file_path") # text sep_computer_ids = kwargs.get("sep_computer_ids") # text sep_sha256 = kwargs.get("sep_sha256") # text sep_sha1 = kwargs.get("sep_sha1") # text sep_md5 = kwargs.get("sep_md5") # text sep_source = kwargs.get("sep_source") # text LOG.info("sep_file_path: %s", sep_file_path) LOG.info("sep_computer_ids: %s", sep_computer_ids) LOG.info("sep_sha256: %s", sep_sha256) LOG.info("sep_sha1: %s", sep_sha1) LOG.info("sep_md5: %s", sep_md5) LOG.info("sep_source: %s", sep_source) validate_fields( ["sep_file_path", "sep_computer_ids", "sep_source"], kwargs) yield StatusMessage("Running Symantec SEP Upload File to SEPM ...") sep = Sepclient(self.options, params) rtn = sep.upload_file(**params) results = rp.done(True, rtn) yield StatusMessage( "Returning 'Symantec SEP Upload File to SEPM' results") LOG.debug(json.dumps(results["content"])) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: LOG.exception("Exception in Resilient Function for Symantec SEP.") yield FunctionError()
def _fn_sep_get_fingerprint_list_function(self, event, *args, **kwargs): """Function: Get the file fingerprint list for a specified name or id as a set of hash values.""" try: params = transform_kwargs(kwargs) if kwargs else {} # Instantiate result payload object. rp = ResultPayload(CONFIG_DATA_SECTION, **kwargs) # Get the function parameters: sep_domainid = kwargs.get("sep_domainid") # text sep_fingerprintlist_name = kwargs.get("sep_fingerprintlist_name") # text sep_fingerprintlist_id = kwargs.get("sep_fingerprintlist_id") # text LOG.info("sep_domainid: %s", sep_domainid) LOG.info("sep_fingerprintlist_name: %s", sep_fingerprintlist_name) LOG.info("sep_fingerprintlist_id: %s", sep_fingerprintlist_id) validate_fields(["sep_domainid"], kwargs) yield StatusMessage("Running Symantec SEP Get File Fingerprint List query...") sep = Sepclient(self.options, params) rtn = sep.get_fingerprint_list(**params) results = rp.done(True, rtn) if "errorCode" in rtn and int(rtn["errorCode"]) == 410: # If this error was trapped user probably tried to get an invalid fingerprint list. yield StatusMessage( u"Got a 410 error while attempting to get a fingerprint list for fingerprint name '{0}' and " "domain id '{1}' because of a possible invalid or deleted id.".format(sep_fingerprintlist_name, sep_domainid)) else: yield StatusMessage(u"Returning 'Symantec SEP Get File Fingerprint List' results for fingerprint name " "'{0}' and domain id '{1}' .".format(sep_fingerprintlist_name, sep_domainid)) LOG.debug(json.dumps(results["content"])) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: LOG.exception("Exception in Resilient Function for Symantec SEP.") yield FunctionError()
def _fn_sep_get_groups_function(self, event, *args, **kwargs): """Function: Gets a group list.""" try: params = transform_kwargs(kwargs) if kwargs else {} # Instantiate result payload object. rp = ResultPayload(CONFIG_DATA_SECTION, **kwargs) # Get the function parameters: sep_domain = kwargs.get("sep_domain") # text sep_fullpathname = kwargs.get("sep_fullpathname") # text sep_mode = kwargs.get("sep_mode") # text sep_order = kwargs.get("sep_order") # text sep_pageindex = kwargs.get("sep_pageindex") # number sep_pagesize = kwargs.get("sep_pagesize") # number sep_sort = kwargs.get("sep_sort") # text LOG.info("sep_domain: %s", sep_domain) LOG.info("sep_fullpathname: %s", sep_fullpathname) LOG.info("sep_mode: %s", sep_mode) LOG.info("sep_order: %s", sep_order) LOG.info("sep_pageindex: %s", sep_pageindex) LOG.info("sep_pagesize: %s", sep_pagesize) LOG.info("sep_sort: %s", sep_sort) yield StatusMessage("Running Symantec SEP Get Groups query...") sep = Sepclient(self.options, params) rtn = sep.get_paginated_results(sep.get_groups, **params) results = rp.done(True, rtn) yield StatusMessage("Returning 'Symantec SEP Get Groups' results") LOG.debug(json.dumps(results["content"])) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: LOG.exception("Exception in Resilient Function for Symantec SEP.") yield FunctionError()
def _fn_sep_update_fingerprint_list_function(self, event, *args, **kwargs): """Function: Updates an existing fingerprint list.""" try: params = transform_kwargs(kwargs) if kwargs else {} # Instantiate result payload object rp = ResultPayload(CONFIG_DATA_SECTION, **kwargs) # Get the function parameters: sep_fingerprintlist_id = kwargs.get("sep_fingerprintlist_id") # text sep_fingerprintlist_name = kwargs.get("sep_fingerprintlist_name") # text sep_description = kwargs.get("sep_description") # text sep_domainid = kwargs.get("sep_domainid") # text sep_hash_value = kwargs.get("sep_hash_value") # text LOG.info("sep_fingerprintlist_id: %s", sep_fingerprintlist_id) LOG.info("sep_fingerprintlist_name: %s", sep_fingerprintlist_name) LOG.info("sep_description: %s", sep_description) LOG.info("sep_domainid: %s", sep_domainid) LOG.info("sep_hash_value: %s", sep_hash_value) validate_fields(["sep_fingerprintlist_id", "sep_fingerprintlist_name", "sep_description", "sep_domainid", "sep_hash_value"], kwargs) yield StatusMessage("Running Symantec SEP Update Fingerprint List action ...") sep = Sepclient(self.options, params) rtn = sep.update_fingerprint_list(**params) results = rp.done(True, rtn) yield StatusMessage("Returning 'Symantec SEP Update Fingerprint List' results") LOG.debug(json.dumps(results["content"])) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: LOG.exception("Exception in Resilient Function for Symantec SEP.") yield FunctionError()
def _fn_sep_get_command_status_function(self, event, *args, **kwargs): """Function: Gets the details of a command status from a command id.""" try: params = transform_kwargs(kwargs) if kwargs else {} # Instantiate result payload object. rp = ResultPayload(CONFIG_DATA_SECTION, **kwargs) # Get the function parameters: sep_incident_id = kwargs.get("sep_incident_id") # number sep_commandid = kwargs.get("sep_commandid") # text sep_order = kwargs.get("sep_order") # text sep_pageindex = kwargs.get("sep_pageindex") # number sep_pagesize = kwargs.get("sep_pagesize") # number sep_sort = kwargs.get("sep_sort") # text sep_status_type = kwargs.get("sep_status_type") # text sep_matching_endpoint_ids = kwargs.get( "sep_matching_endpoint_ids") # boolean sep_scan_date = kwargs.get("sep_scan_date") # text LOG.info("sep_incident_id: %s", sep_incident_id) LOG.info("sep_commandid: %s", sep_commandid) LOG.info("sep_order: %s", sep_order) LOG.info("sep_pageindex: %s", sep_pageindex) LOG.info("sep_pagesize: %s", sep_pagesize) LOG.info("sep_sort: %s", sep_sort) LOG.info("sep_status_type: %s", sep_status_type) LOG.info("sep_matching_endpoint_ids: %s", sep_matching_endpoint_ids) LOG.info("sep_scan_date: %s", sep_scan_date) validate_fields(["sep_commandid", "sep_status_type"], kwargs) yield StatusMessage( "Running Symantec SEP Get Command Status query...") sep = Sepclient(self.options, params) rtn = process_results( sep.get_paginated_results(sep.get_command_status, **params), self.options, sep_status_type, sep_scan_date) if sep_status_type.lower( ) == "remediation" and rtn["total_remediation_count"] > 0: # Artifact may be remediated in multiple locations on multiple endpoints so send # back remediation details as an incident attachment # Get csv attachment file name and content. (file_name, file_content) = generate_remediate_result_csv( rtn, sep_commandid) yield StatusMessage( "Adding remediation data for command id {} as an incident attachment {}" .format(sep_commandid, file_name)) # Create an attachment att_report = create_attachment(self.rest_client(), file_name, file_content, params["incident_id"]) # Add attachment name to result rtn["att_name"] = att_report["name"] elif sep_status_type.lower( ) == "scan" and sep_matching_endpoint_ids: # Return only endpoint ids for artifact matches. content_copy = rtn.get("content", []) if not content_copy: raise ValueError( "Expected remediation result 'content' is empty") rtn = {"endpoints_matching_ids": []} for i in range(len(content_copy)): rtn["endpoints_matching_ids"].append( content_copy[i]["computerId"]) del content_copy elif sep_status_type.lower( ) == "scan" and rtn["total_match_count"] > int( self.options.get("sep_results_limit", RESULTS_LIMIT_DEF)): # Over results limit. Send full result back as an attachment and also return an actual # result truncated to the results limit. results_limit = int( self.options.get("sep_results_limit", RESULTS_LIMIT_DEF)) result_limit_complete = False total_match_count = 0 match_types = [ "HASH_MATCHES", "FULL_MATCHES", "PARTIAL_MATCHES" ] yield StatusMessage( "Adding EOC scan data for command id {} as an incident attachment" .format(sep_commandid)) # Get csv attachment file name and content. (file_name, file_content) = generate_scan_result_csv(rtn, sep_commandid) # Create an attachment att_report = create_attachment(self.rest_client(), file_name, file_content, params["incident_id"]) # Truncate the result to 'results_limit'. content_copy = copy.deepcopy(rtn["content"]) for i in range(len(content_copy)): if result_limit_complete: rtn["content"] = rtn["content"][:i] break else: if total_match_count <= results_limit: match_count = content_copy[i]["scan_result"][ "match_count"] if total_match_count + match_count <= results_limit: total_match_count += content_copy[i][ "scan_result"]["match_count"] else: for match_type in match_types: if content_copy[i]["scan_result"][ match_type]: # Truncate matches to limit value. rtn["content"][i]["scan_result"][match_type] = \ content_copy[i]["scan_result"][match_type][:results_limit - total_match_count] rtn["content"][i]["scan_result"][ "match_count"] = results_limit - total_match_count result_limit_complete = True rtn["scan_eoc_hits_over_limit"] = True rtn["att_name"] = att_report["name"] rtn["truncated_count"] = results_limit del content_copy else: yield StatusMessage( "Returning 'Symantec SEP Get Command Status' results for command id {}" .format(sep_commandid)) results = rp.done(True, rtn) LOG.debug(json.dumps(results["content"])) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: LOG.exception("Exception in Resilient Function for Symantec SEP.") yield FunctionError()
def _fn_sep_get_computers_function(self, event, *args, **kwargs): """Function: Returns a list of computers with agents deployed on them. You can use parameters to narrow the search by IP address or hostname.""" try: params = transform_kwargs(kwargs) if kwargs else {} # Instantiate result payload object. rp = ResultPayload(CONFIG_DATA_SECTION, **kwargs) # Get the function parameters: sep_computername = kwargs.get("sep_computername") # text sep_status = kwargs.get("sep_status") # boolean sep_status_details = kwargs.get("sep_status_details") # boolean sep_domain = kwargs.get("sep_domain") # text sep_lastupdate = kwargs.get("sep_lastupdate") # text sep_order = kwargs.get("sep_order") # text sep_os = kwargs.get("sep_os") # text sep_pageindex = kwargs.get("sep_pageindex") # number sep_pagesize = kwargs.get("sep_pagesize") # number sep_sort = kwargs.get("sep_sort") # text sep_matching_endpoint_ids = kwargs.get("sep_matching_endpoint_ids") # boolean LOG.info("sep_computername: %s", sep_computername) LOG.info("sep_status: %s", sep_status) LOG.info("sep_status_details: %s", sep_status_details) LOG.info("sep_domain: %s", sep_domain) LOG.info("sep_lastupdate: %s", sep_lastupdate) LOG.info("sep_order: %s", sep_order) LOG.info("sep_os: %s", sep_os) LOG.info("sep_pageindex: %s", sep_pageindex) LOG.info("sep_pagesize: %s", sep_pagesize) LOG.info("sep_sort: %s", sep_sort) LOG.info("sep_matching_endpoint_ids: %s", sep_matching_endpoint_ids) yield StatusMessage("Running Symantec SEP Get Computers query...") sep = Sepclient(self.options, params) rtn = sep.get_computers(**params) now = time.time() if "content" in rtn and rtn["content"]: # Add a human readable date stamp dict entry for timestamps for each computer. for i in range(len(rtn["content"])): for f in ["lastScanTime", "lastUpdateTime", "lastVirusTime"]: try: secs = int(rtn["content"][i][f]) / 1000 timediff = now - secs ts_readable = datetime.fromtimestamp(secs).strftime('%Y-%m-%d %H:%M:%S') # New keys will be "readableLastScanTime", "readableLastUpdateTime", "readableLastVirusTime" rtn["content"][i]["readable"+f[0].capitalize()+f[1:]] = ts_readable rtn["content"][i]["timediff" + f[0].capitalize() + f[1:]] = timediff except ValueError: yield FunctionError('A timestamp value was incorrectly specified.') if sep_matching_endpoint_ids: # Return only endpoint ids since post-processing may timeout processing large number of ids. content_copy = rtn.get("content", []) if not content_copy: raise ValueError("Expected remediation result 'content' is empty") rtn = {"endpoints_matching_ids": []} for i in range(len(content_copy)): rtn["endpoints_matching_ids"].append(content_copy[i]["uniqueId"]) del content_copy elif sep_status: rtn = get_endpoints_status(rtn) elif sep_status_details: rtn = get_endpoints_status_details(rtn) results = rp.done(True, rtn) yield StatusMessage("Returning 'Get Computers' results") LOG.debug(json.dumps(results["content"])) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception: LOG.exception("Exception in Resilient Function for Symantec SEP.") yield FunctionError()