epo Deprecated

Deprecated. Use McAfee ePO v2 instead.

Endpoint · McAfee ePO

Details

IDepo
ProviderTrellix
CategoryEndpoint
From Version5.0.0
Supported ModulesAgentix XSIAM EDR Cortex Cloud Cloud Runtime Security

README

This integration was integrated and tested with McAfee ePO v5.3.2.

Configure McAfee ePO in Cortex

  • Name: a textual name for the integration instance.
  • Url: for example: https://****:port
  • Username
  • Password
  • Trust any certificate (not secure) Mark to trust Certificate Authority.
  • Use system proxy settings

Permissions

McAfee ePO has a highly flexible and powerful permissions system. The permissions required for the user that uses this integration depend on which operations they need to perform. The API user should have the same permissions a regular user would have in order to access the data via the UI. It is possible to view the exact permissions needed for a specific command by running the !epo-help command. The !epo-help command’s output will include help information for the specific command including required permissions.
More info about McAfee ePO’s permissions model is available here.

Example !epo-help outputs with permission information:

  • !epo-help command="repository.findPackages":
  • !epo-help command="repository.deletePackage":

Playbooks

  • McAfee ePO Endpoint Connectivity Diagnostics - Perform a check on ePO endpoints to see if any endpoints are unmanaged or lost connectivity with ePO and take steps to return to valid state.
  • McAfee ePO Endpoint Compliance - Discover endpoints that are not using the latest McAfee AV Signatures
  • McAfee ePO Repository Compliance - Ensures that ePO servers are updated to the latest McAfee published AV signatures (DAT file version).
  • Endpoint Enrichment - Generic v2: uses epo-find-systems to enrich an endpoint by hostname.

Commands

You can execute these commands from the CLI, as part of an automation, or in a playbook. After you successfully execute a command, a DBot message appears in the War Room with the command details.

  1. Print help for ePO commands: epo-help
  2. Get the latest DAT file: epo-get-latest-dat
  3. Check the current DAT file version: epo-get-current-dat
  4. Update the DAT file: epo-update-client-dat
  5. Update a repository: epo-update-repository
  6. Get system tree groups: epo-get-system-tree-group
  7. Find systems in the system tree: epo-find-systems
  8. epo-command
  9. epo-advanced-command
  10. Wake up an agent: epo-wakeup-agent
  11. Apply a tag: epo-apply-tag
  12. Clear a tag: epo-clear-tag
  13. Query an ePO table: epo-query-table
  14. Get an ePO table: epo-get-table
  15. Get the ePO version: epo-get-version
  16. Find systems in the system tree: epo-find-system
  17. Move a system to a different group: epo-move-system

1. Print help for ePO commands

Prints help (information) for ePO commands. If no command argument is specified, returns all ePO commands.

Base Command
epo-help
Input
Argument Name Description Required
search String to search for in help. Optional
command Command for which to print help. Optional
Context Output

There is no context output for this command.

Command Example

!epo-help search=”agent”

Human Readable Output

screen shot 2018-08-26 at 10 28 00

2. Get the latest DAT file

Checks for the latest DAT file in the McAfee repository.

Base Command
epo-get-latest-dat
Input

There is no input for this command.

Context Output
Path Type Description
McAfee.ePO.latestDAT Number Latest McAfee DAT file version.
Command Example

!epo-get-latest-dat

Human Readable Output

screen shot 2018-08-26 at 10 15 58

3. Check the current DAT file version

Checks the existing DAT file version in ePO.

Base Command
epo-get-current-dat
Input

There is no input for this command.

Context Output
Path Type Description
McAfee.ePO.epoDAT number Current McAfee DAT file in the ePO repository.
Command Example

!epo-get-current-dat

Human Readable Output

screen shot 2018-08-26 at 10 18 36

4. Update the DAT file

Run client task to update the DAT file.

To run this command, you need to create a task on the ePO server with a specific name.

  1. Log on to the ePO server.
  2. Select System Tree.
  3. Select Assigned Client Tasks > Actions > New Client Task Assignment.
  4. Configure the Select Task section.
Field Value
Product McAfee Agent
Task Type Product Update
Task Name DAT Update
  1. Select Create New Task.
Field Value
Task Name VSEContentUpdateDemisto
Package Selection Selected packages
Signatures and Engines DAT
Base Command
epo-update-client-dat
Input
Argument Name Description Required
systems A CSV list of IP addresses or system names. Required
retryAttempts Number of times the server will attempt to send the task to the client. Default is 1 retry. Optional
retryIntervalInSeconds Retry interval in seconds. Default is 30 seconds. Optional
abortAfterMinutes The threshold (in minutes) after which attempts to send the task to the client are aborted. Default is 5. Optional
stopAfterMinutes The threshold (in minutes) that the client task is allowed to run. Defaults to 20. Optional
randomizationInterval Duration (in minutes) over which to randomly spread task execution. Default is 0 (executes on all clients immediately). Optional
Context Output

There is no context output for this command.

Command Example

!epo-update-client-dat systems=ADMIN-PC

Human Readable Output

screen shot 2018-08-26 at 10 41 04

5. Update a repository

Triggers a server task in specific ePO servers to retrieve the latest signatures from the update server.

Base Command
epo-update-repository
Input

There is no input for this command.

Context Output

There is no context output for this command.

Command Example

!epo-update-repository

Human Readable Output

screen shot 2018-08-26 at 10 00 40

6. Get system tree groups

Returns system tree groups.

Base Command

epo-get-system-tree-group

Input
Argument Name Description Required
search String to search for in the system tree group. Optional
Context Output
Path Type Description
McAfee.ePO.SystemTreeGroups.groupId number System tree group ID.
McAfee.ePO.SystemTreeGroups.groupPath string System tree group path.
Human Readable Output

screen shot 2018-08-26 at 9 59 49

7. Find systems in the system tree

Find systems in the System Tree - by group ID or by search

Base Command

epo-find-systems

Input
Argument Name Description Required
groupId System tree group ID. Required
verbose Whether to return all system data. Optional
Context Output
Path Type Description
Endpoint.Name string Endpoint name.
Endpoint.Domain string Endpoint domain.
Endpoint.Hostname string Endpoint hostname.
Endpoint.IPAddress string Endpoint IP address.
Endpoint.OS string Endpoint OS.
Endpoint.OSVersion string Endpoint OS version.
Endpoint.Processor string Processor model.
Endpoint.Processors number Number of processors.
Endpoint.Memory number Endpoint memory.
McAfee.ePO.Endpoint.ComputerName string Endpoint name.
McAfee.ePO.Endpoint.Domain string Endpoint domain.
McAfee.ePO.Endpoint.Hostname string Endpoint hostname.
McAfee.ePO.Endpoint.IPAddress string Endpoint IP address.
McAfee.ePO.Endpoint.OS string Endpoint OS.
McAfee.ePO.Endpoint.OSVersion string Endpoint OS version.
McAfee.ePO.Endpoint.Processor string Processor model.
McAfee.ePO.Endpoint.Processors number Number of processors
McAfee.ePO.Endpoint.Memory number Endpoint memory.

8. epo-command

Executes the ePO command. Receives the mandatory ‘‘command’’ argument, and other optional arguments.

To get a list of available commands, run the ‘‘epo-help’’ command to get a list of available commands. You can also specify the ‘‘headers’’ argument to filter table headers. Example/:/ !epo-command command=system.find searchText=10.0.0.1 headers=EPOBranchNode.AutoID,EPOComputerProperties.ComputerName

Base Command

epo-command

Command Example

!epo-command command=system.find searchText=10.0.0.1

screen shot 2018-10-02 at 9 44 34

!epo-command command=agentmgmt.listAgentHandlers

screen shot 2018-10-02 at 9 46 00

9. epo-advanced-command

Executes the ePO command.

To get a list of available commands, run the ‘‘epo-help’’ command. For example/:/ !epo-advanced-command command=clienttask.find commandArgs=searchText:On-demand. You can also specify the ‘‘headers’’ argument to filter table headers, for example/:/ !epo-command command=system.find searchText=10.0.0.1 headers=EPOBranchNode.AutoID,EPOComputerProperties.ComputerName.

Base Command
epo-advanced-command
Input
Argument Name Description Required
command The command to execute. Run either the core.help command or the !epo-help to get all available commands. Required
commandArgs CSV list of key value pairs as additional arguments to pass, for example, “argName1:argValue1,argName2:argValue2”. Required
Context Output

 There is no context output for this command.

Command Example

!epo-advanced-command command=”clienttask.find” commandArgs=”searchText:On-demand”

screen shot 2018-10-29 at 13 31 53

10. Wake up an agent

Wakes up an agent.

Input
Argument Name Description Required
names Agent hostname. Required

11. Apply a tag

Applies a tag to hostnames.

Input
Argument Name Description Required
names Hostnames on which to apply tags. Required
tagName Tag name. Required

Command Example

!epo-apply-tag names=”ADMIN-PC” tagName=”Compromised”

12. Clear a tag

Clears a tag from hostnames.

Input
Argument Name Description Required
names Hostnames from which to clear tags. Required
tagName Tag name. Required

Command Example

!epo-clear-tag names=”ADMIN-PC” tagName=”Compromised”

13. Query an ePO table

Queries an ePO table.

Base Command
epo-query-table
Input
Argument Name Description Required
target Table name. Required
select The columns to select, in SQUID syntax. Example: “(select EPOEvents.AutoID EPOEvents.DetectedUTC EPOEvents.ReceivedUTC)”. Optional
where Filter results, in SQUID syntax. Example: “(where ( eq ( OrionTaskLogTask .UserName “ga” )))”. Optional
order Order in which to return the results, in SQUID syntax. Example: “(order (asc OrionTaskLogTask.StartDate) )”). Optional
group Group the results, in SQUID Syntax. Example: “(group EPOBranchNode.NodeName)”. Optional
joinTables Perform join, in SQUID syntax. Optional
query_name Name for the query to appear in the context. Optional
Context Output
Path Description
McAfee.ePO.Query Query result.
Human Readable Output

!epo-query-table target=EPOLeafNode select="(select EPOLeafNode.NodeName EPOLeafNode.Tags EPOBranchNode.NodeName)" where="(hasTag EPOLeafNode.AppliedTags 4)"

screen shot 2018-10-29 at 15 17 18

!epo-query-table target=EPOLeafNode select="(select (top 3) EPOLeafNode.NodeName EPOLeafNode.Tags EPOBranchNode.NodeName)"

screen shot 2018-10-29 at 15 17 43

!epo-query-table target="EPOEvents" select="(select EPOEvents.AutoID EPOEvents.DetectedUTC EPOEvents.ReceivedUTC)" order="(order(desc EPOEvents.DetectedUTC))"

screen shot 2018-10-29 at 16 35 41

!epo-query-table target="EPExtendedEvent" select="(select (top 250) EPOEvents.ThreatName EPOEvents.AutoID EPExtendedEvent.EventAutoID EPExtendedEvent.TargetHash EPExtendedEvent.TargetPath EPOEvents.SourceHostName)" order="(order(desc EPExtendedEvent.TargetHash))" joinTables="EPOEvents"where="(where(eq EPOEvents.ThreatName "real Protect-LS!d5435f1fea5e"))"

screen shot 2018-10-31 at 10 03 49

14. Get an ePO table

Returns an ePO table.

Base Command
epo-get-tables
Input
Argument Name Description Required
table Name of the table to return. Optional
Context Output

There is no context output for this command.

Command Example

!epo-get-tables

Human Readable Output
screen shot 2018-10-29 at 15 19 13

15. Get the ePO version

Gets the ePO version. This command requires global admin permissions.

Base Command
epo-get-version
Context Output
Path Type Description
McAfee.ePO.Version string ePO version.
Human Readable Output

!epo-get-version

screen shot 2018-11-06 at 15 43 18

16. Find systems in the system tree

Finds systems in the system tree.

Base Command
epo-find-system
Input
Argument Name Description Required
searchText Hostname to search. Optional
verbose Print all system data Optional
Context Output
Path Type Description
Endpoint.Name string Endpoint name.
Endpoint.Domain string Endpoint domain.
Endpoint.Hostname string Endpoint hostname.
Endpoint.IPAddress string Endpoint IP address.
Endpoint.OS string Endpoint OS.
Endpoint.OSVersion string Endpoint OS version.
Endpoint.Processor string Processor model.
Endpoint.Processors number Number of processors.
Endpoint.Memory number Endpoint memory.
McAfee.ePO.Endpoint.ComputerName string Endpoint name.
McAfee.ePO.Endpoint.Domain string Endpoint domain.
McAfee.ePO.Endpoint.Hostname string Endpoint hostname.
McAfee.ePO.Endpoint.IPAddress string Endpoint IP address.
McAfee.ePO.Endpoint.OS string Endpoint OS.
McAfee.ePO.Endpoint.OSVersion string Endpoint OS version.
McAfee.ePO.Endpoint.Processor string Processor model.
McAfee.ePO.Endpoint.Processors number Number of processors.
McAfee.ePO.Endpoint.Memory number Endpoint memory.
Human Readable Output

!epo-find-system searchText=mar

screen shot 2018-11-06 at 15 46 12

17. Move a system to a different group

Moves a system to a different group.

Base Command

epo-move-system

Input
Argument Name Description Required
names Asset name. Required
parentGroupId Group ID. Required
Context Output

There is no context output for this command.

Command Example

!epo-move-system names=tie parentGroupId=3

Human Readable Output

Screen Shot 2019-07-31 at 11 34 28

Configuration parameters

  • address — https://<address>:port (required)
  • authentication — Username (required)
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings

Commands (17)

  • epo-advanced-command

    Executes the ePO command. Run the ''epo-help'' command to get a list of available commands. For example/:/ !epo-advanced-command command=clienttask.find commandArgs=searchText:On-demand. You can also specify the ''headers'' argument to filter table headers, for example/:/ !epo-command command=system.find searchText=10.0.0.1 headers=EPOBranchNode.AutoID,EPOComputerProperties.ComputerName.

  • epo-apply-tag

    Applies a tag to hostnames.

  • epo-clear-tag

    Clears a tag from hostnames.

  • epo-command

    Executes the ePO command. Receives the mandatory ''command'' argument, and other optional arguments. Run the ''epo-help'' command to get a list of available commands. You can also specify the ''headers'' argument to filter table headers. Example/:/ !epo-command command=system.find searchText=10.0.0.1 headers=EPOBranchNode.AutoID,EPOComputerProperties.ComputerName

  • epo-find-system

    Finds systems in the system tree.

  • epo-find-systems

    Finds computers within a specified group in the ePO tree.

  • epo-get-current-dat

    Checks the existing DAT file version in ePO.

  • epo-get-latest-dat

    Checks the latest DAT file in the McAfee repository.

  • epo-get-system-tree-group

    Returns system tree groups.

  • epo-get-tables

    Returns an ePO table.

  • epo-get-version

    Gets the ePO version. This requires global admin permissions.

  • epo-help

    Prints help (information) for ePO commands. If no command argument is specified, returns all ePO commands.

  • epo-move-system

    Moves a system to a different group.

  • epo-query-table

    Queries an ePO table.

  • epo-update-client-dat

    Runs a client task to update the DAT file.

  • epo-update-repository

    Triggers a server task in specific ePO servers to retrieve the latest signatures from the update server.

  • epo-wakeup-agent

    Wakes up an agent.

//GLOBALS//
var serverUrl = params.address;
if (serverUrl[serverUrl.length - 1] !== '/') {
    serverUrl += '/';
}

var EPO_SYSTEM_ATTRIBUTE_MAP = {
    'EPOComputerProperties.ComputerName': 'Name',
    'EPOComputerProperties.DomainName': 'Domain',
    'EPOComputerProperties.IPHostName': 'Hostname',
    'EPOComputerProperties.IPAddress': 'IPAddress',
    'EPOComputerProperties.OSType': 'OS',
    'EPOComputerProperties.OSVersion': 'OSVersion',
    'EPOComputerProperties.CPUType': 'Processor',
    'EPOComputerProperties.NumOfCPU': 'Processors',
    'EPOComputerProperties.TotalPhysicalMemory': 'Memory',
};

//HELPER//
function callEpo(pCommand, pArgs) {
    var url = serverUrl + 'remote/' + pCommand;
    url += encodeToURLQuery(pArgs);
    url += (Object.keys(pArgs).length > 0) ? '&' : '?';
    url += ':output=json';
    var result = http(
        url,
        {
            Method: 'GET',
            Username: params.authentication.identifier,
            Password: params.authentication.password
        },
        params.insecure,
        params.proxy
    );

    if (isResponseOK(result)) {
        trimmedRes = result.Body.substring(okStr.length);
        trimmedRes = trimmedRes.replace('\n',' ');
        parsedRes = JSON.parse(trimmedRes);
        return parsedRes;
    } else if (result.StatusCode == 200){
        throw 'Error accessing ePO interface. Command: ' + url + ". Body: " +  result.Body;
    } else {
        throw 'Error accessing ePO interface. Command: ' + url + ". Response: " + JSON.stringify(result);
    }
}

function doRawHttp(method, url, parameters, body) {
    if (!parameters) {
        parameters = {};
    }
    var result = http(
        url + encodeToURLQuery(parameters),
        {
            Headers: {'Content-Type': ['application/json']},
            Method: method,
            Body: ''
        },
        params.insecure,
        params.proxy
    );
    if (result.StatusCode < 200 && result.StatusCode > 299) {
        throw 'Failed to perform request ' + url + encodeToURLQuery(parameters) + ', request status code: ' + result.StatusCode;
    }
    return result;
}

function isResponseOK(response) {
    // EPO response if of format: OK -> data. Error: error string
    if (response.StatusCode === 200) {
        okStr = 'OK:';
        if (response.Body.indexOf(okStr) === 0) {
            return true;
        }
    }
    return false;
}

function systemsToMd(systems,verbose) {
    var i;
    var md='';
    if (verbose=="true") {
        for (i=0;i<systems.length;i++) {
            md += systemToMd(systems[i],verbose);
        }
    } else {
        var tmpHead='|';
        var tmpLine='|';
        for (var key in EPO_SYSTEM_ATTRIBUTE_MAP) {
            tmpHead += EPO_SYSTEM_ATTRIBUTE_MAP[key] + '|';
            tmpLine += '-|';
        }
        md += tmpHead + '\n'+tmpLine+'\n';
        for (i=0;i<systems.length;i++) {
            md += systemToMd(systems[i],verbose);
        }
    }
    return md;
}

function systemToMd(system,verbose) {
    var md='';
    var key;
    if (verbose=="true") {
        md += '#### '+ system["EPOComputerProperties.ComputerName"]+'\n';
        md += "Attribute|Value\n-|-\n";
        for (key in system) {
            md += key +"|"+system[key]+"\n";
        }
        md += "---\n";
    } else {
        md +='|';
        for (key in EPO_SYSTEM_ATTRIBUTE_MAP) {
            md += system[key] +"|";
        }
        md += '\n';
    }
    return md;
}

//COMMANDS//
function epoHelp() {
    var pArgs = {};
    if (args.command) {
        pArgs.command = args.command;
    }
    var readyRes = callEpo('core.help',pArgs);
    var md;
    var line;
    var cmd;
    var desc;

    if (args.command) {
        md = '#### ePO Help - ' + args.command + '\n';
        md += readyRes;
    } else {
        parsedRes = Array.isArray(parsedRes) ? parsedRes : [parsedRes];
        md = '#### ePO Help\n';
        for (var i=0;i<parsedRes.length;i++) {
            line = parsedRes[i];
            line = line.replace(/(\r\n|\n|\r)/gm," ");
            if (!args.search || (args.search.toLowerCase() && line.toLowerCase().indexOf(args.search.toLowerCase())>=0))
{
                desc = line.split('-')[1] ? line.split('-')[1].trim() : 'N/A';
                cmd = line.split('-')[0] ? line.split('-')[0].trim() : 'N/A';
                md += '- **' + cmd + "** - " + desc + '\n';
            }
        }
    }
    return {
        Type: entryTypes.note,
        Contents: readyRes,
        ContentsFormat: formats.json,
        HumanReadable: md
    };
}

function epoGetLatestDatRaw() {
    var url = "http://update.nai.com/products/commonupdater/gdeltaavv.ini";
    //Another option is to use avvdat.ini - provided here in case any additional data from that file is needed in the future
    //var url = "http://update.nai.com/Products/CommonUpdater/avvdat.ini"
    result = doRawHttp("GET",url);
    var res = '';
    var sections = result.Body.split('\r\n\r\n');
    var lines = sections[0].split('\r\n');
    for (var i=0;i<lines.length;i++) {
        if (lines[i].indexOf("CurrentVersion")===0){
            return lines[i].split('=')[1];
        }
    }
    throw 'Cannot get McAfee latest DAT file version';
}

function epoGetLatestDat() {
    var datVersion = epoGetLatestDatRaw();
    var md='McAfee Latest DAT file version is: **' + datVersion + '**\n';
    ec = {};
    ec.mcafee = {"latestDAT": datVersion};
    return {
        Type: entryTypes.note,
        Contents: datVersion,
        ContentsFormat: formats.json,
        HumanReadable: md,
        EntryContext: {
                "mcafee(val.latestDAT === obj.latestDAT)": ec.mcafee, //backward compatability
                "McAfee.ePO.latestDAT": datVersion
        }
    };
}

function epoGetCurrentDat() {
    var pArgs = {"searchText":"VSCANDAT1000"};
    var result = callEpo('repository.findPackages', pArgs);
    if (result && result.length>0) {
        result = result[0];
        var epoDAT = result.productDetectionProductVersion.split('.')[0];
        ec = {};
        ec.mcafee = {"epoDAT": epoDAT};
        var md = "McAfee ePO Current DAT file version in repository is: **" + epoDAT + '**\n';
        return {
            Type: entryTypes.note,
            Contents: result,
            ContentsFormat: formats.json,
            HumanReadable: md,
            EntryContext: {
                "mcafee(val.epoDAT==obj.epoDAT)": ec.mcafee, //backward compatability
                "McAfee.ePO.epoDAT": epoDAT
            }
        };
    } else {
        throw 'Error getting current DAT version. Please check that the DAT file exists. Response: ' + JSON.stringify(result);
    }
}

function epoUpdateClientDatTask() {
    var pArgs = {'searchText': 'VSEContentUpdateDemisto'}; //need to configure this task in ePO beforehand
    var result = callEpo('clienttask.find', pArgs);
    if (result && Array.isArray(result)) {
        result = result[0];
    }
    if (result) {
          return result.objectId;
        }
         // If reached here then the response is an empty "OK:", which means VSEContentUpdateDemisto was not found in the server
        throw 'Error getting DAT update task. It seems the task "VSEContentUpdateDemisto" is missing from the EPO server. Please contact support for more details';
}

function epoUpdateClientDat() {
    var clientTask = epoUpdateClientDatTask();
    var pArgs = {'names':args.systems, 'productId':'EPOAGENTMETA', 'taskId':clientTask};

    var options = ['retryAttempts', 'retryIntervalInSeconds', 'abortAfterMinutes', 'stopAfterMinutes', 'randomizationInterval'];
    for (var i=0;i<options.length;i++) {
        if (args[options[i]]) {
            pArgs[options[i]] = args[options[i]];
        }
    }
    var result = callEpo('clienttask.run', pArgs);
    var md = "ePO client DAT update task started: " + result;
    return {
        Type: entryTypes.note,
        Contents: result,
        ContentsFormat: formats.json,
        HumanReadable: md
    };
}

function epoUpdateRepository() {
    var pArgs = {
        'sourceRepository': 'McAfeeHttp',
        'targetBranch':'Current'
    };
    var result = callEpo('repository.pull', pArgs);

    var md = "ePO repository update started.\n";
    md += result;
    return {
        Type: entryTypes.note,
        Contents: result,
        ContentsFormat: formats.json,
        HumanReadable: md
    };
}

function prettifySystemTree(SystemTree) {
    var prettySystemTree = [];
    for (i=0; i < SystemTree.length; i++) {
        var system = SystemTree[i];
        prettySystemTree[i] = {
            'groupId': system.groupId,
            'groupPath': system.groupPath
        };
    }
    return prettySystemTree;
}

function epoGetSystemTreeGroups() {
    var pArgs = {};
    if (args.search) {
        pArgs.searchText=args.search;
    }
    var result = callEpo('system.findGroups', pArgs);
    if (result.length === 0) {
        return 'System Tree Group was not found.';
    }
    var md = "#### ePO System Tree groups\n";
    md += "Group ID | Group path\n-|-\n";
    for (var i=0;i<result.length;i++) {
        md += result[i].groupId + "|" + result[i].groupPath + "\n";
    }
    return {
        Type: entryTypes.note,
        Contents: result,
        ContentsFormat: formats.json,
        HumanReadable: md,
        EntryContext: {
            "McAfee.ePO(val.groupId==obj.groupId)": {'SystemTreeGroups': prettifySystemTree(result)}
        }
    };
}

function epoGetSystemGroupPath(groupId) {
    var result = epoGetSystemTreeGroups();
    result = result.Contents;
    for (var i=0;i<result.length;i++) {
        if (groupId == result[i].groupId) {
            return result[i].groupPath;
        }
    }
    return null;
}

function prettifyFindSystem(FindSystem) {
    var prettyFindSystem = [];
    for (i=0; i < FindSystem.length; i++) {
        var system = FindSystem[i];
        prettyFindSystem[i] = {
            'Name': system['EPOComputerProperties.ComputerName'],
            'Domain': system['EPOComputerProperties.DomainName'],
            'Hostname': system['EPOComputerProperties.IPHostName'],
            'IPAddress': system['EPOComputerProperties.IPAddress'],
            'OS': system['EPOComputerProperties.OSType'],
            'OSVersion': system['EPOComputerProperties.OSVersion'],
            'Processor': system['EPOComputerProperties.CPUType'],
            'Processors': system['EPOComputerProperties.NumOfCPU'],
            'Memory': system['EPOComputerProperties.TotalPhysicalMemory'],
        };
    }
    return prettyFindSystem;
}

function epoFindSystems() {
    var name = epoGetSystemGroupPath(args.groupId);

    if (!name) {
        throw 'System Tree group not found';
    }
    var pArgs = {'groupId':args.groupId};
    var result = callEpo('epogroup.findSystems', pArgs);
    if (result) {
        var md = '#### Systems in '+name+'\n';
        if (result.length>0) {
            md += systemsToMd(result,args.verbose);
        } else {
            md += 'No systems found\n';
        }
        return {
            Type: entryTypes.note,
            Contents: result,
            ContentsFormat: formats.json,
            HumanReadable: md,
            EntryContext: {
                'Endpoint(val.IPAddress==obj.IPAddress)': prettifyFindSystem(result),
                'McAfee.ePO.Endpoint(val.IPAddress==obj.IPAddress)': prettifyFindSystem(result),
            }
        };
    } else {
        throw 'No systems found. Response: ' + JSON.stringify(result);
    }
}

function epoFindSystem() {
    var pArgs = {'searchText':args.searchText};
    var result = callEpo('system.find', pArgs);
    if (result) {
        var md = '#### Systems in the System Tree\n';
        if (result.length>0) {
            md += systemsToMd(result,args.verbose);
        } else {
            md += 'No systems found\n';
        }
        return {
            Type: entryTypes.note,
            Contents: result,
            ContentsFormat: formats.json,
            HumanReadable: md,
            EntryContext: {
                'Endpoint(val.IPAddress==obj.IPAddress)': prettifyFindSystem(result),
                'McAfee.ePO.Endpoint(val.IPAddress==obj.IPAddress)': prettifyFindSystem(result),
            }
        };
    } else {
        throw 'No systems found. Response: ' + JSON.stringify(result);
    }
}

function epoWakeupAgent() {
    var pArgs = {'names':args.names};
    var result = callEpo('system.wakeupAgent', pArgs);

    var md = "ePO agent was awaken.\n";
    md += result;

    return {
        Type: entryTypes.note,
        Contents: result,
        ContentsFormat: formats.json,
        HumanReadable: md
    };
}

function epoApplyTag() {
    var pArgs = {
        'names': args.names,
        'tagName': args.tagName
    };
    var result = callEpo('system.applyTag', pArgs);

    var md = "ePO applied the tags on the hostnames successfully.\n";

    return {
        Type: entryTypes.note,
        Contents: result,
        ContentsFormat: formats.json,
        HumanReadable: md
    };
}

function epoClearTag() {
    var pArgs = {
        'names': args.names,
        'tagName': args.tagName
    };
    var result = callEpo('system.clearTag', pArgs);

    var md = "ePO cleared the tags from the hostnames successfully.\n";

    return {
        Type: entryTypes.note,
        Contents: result,
        ContentsFormat: formats.json,
        HumanReadable: md
    };
}

function epoGetTables() {
    var result;
    var pArgs = {};
    if (args.table) {
        pArgs.table = args.table;
    }

    result = callEpo('core.listTables', pArgs);

    var md = tableToMarkdown(
            'ePO tables:',
            Object.keys(result || {}).map(function (k) { return result[k]; }), // object keys
            args.headers && args.headers.split(',')
        );

    return {
        Type: entryTypes.note,
        Contents: result,
        ContentsFormat: formats.json,
        HumanReadable: md
    };
}

function epoQueryTable() {
    var pArgs = {'target': args.target};
    var result;
    var ec = {};
    var ec_key = '';
    if (args.select) {
        pArgs.select = args.select;
    }
    if (args.where) {
        pArgs.where = args.where;
    }
    if (args.order) {
        pArgs.order = args.order;
    }
    if (args.group) {
        pArgs.group = args.group;
    }
    if (args.joinTables) {
        pArgs.joinTables = args.joinTables;
    }

    result = callEpo('core.executeQuery', pArgs);

    var md = tableToMarkdown(
            'ePO Table Query:',
            Object.keys(result || {}).map(function (k) { return result[k]; }), // object keys
            args.headers && args.headers.split(',')
        );

    if (args.query_name) {
        ec_key = 'McAfee.ePO.Query.' + args.query_name;
    } else {
        var ts = (new Date()).getTime() / 1000;
        ec_key = 'McAfee.ePO.Query.' + ts;
    }
    ec[ec_key] = result;

    return {
        Type: entryTypes.note,
        Contents: result,
        ContentsFormat: formats.json,
        HumanReadable: md,
        EntryContext: ec
    };
}

function epoGetVersion() {
    var pArgs = {};
    var result;

    result = callEpo('epo.getVersion', pArgs);

    var md = "### ePO version is:\n" + result;
    var ec = {"McAfee.ePO.Version": result};

    return {
        Type: entryTypes.note,
        Contents: result,
        ContentsFormat: formats.text,
        HumanReadable: md,
        EntryContext: ec
    };

}

function epoMoveSystem() {
    var pArgs = {
        'names': args.names,
        'parentGroupId': args.parentGroupId
    };

    var result;
    result = callEpo('system.move', pArgs);

    if (result === true) {
        result = 'System ' + args.names + ' moved successfully to GroupId ' +  args.parentGroupId;
        return {
            Type: entryTypes.note,
            Contents: result,
            ContentsFormat: formats.text,
            HumanReadable: result
        };
    } else {
        result = 'System ' + args.names + ' failed to move to GroupId ' + args.parentGroupId;
        return {
            Type: entryTypes.error,
            Contents: result,
            ContentsFormat: formats.text,
            HumanReadable: result
          };
    }
}

function parseCommandArgs(command, commandArgs) {
    //commandArgs should be in the format of:  keyName1:keyValue1, keyName2:KeyValue2
    if (!commandArgs) {
        return null;
    }
    var commandArgsDict = {};
    commandArgsDict.command = command;
    var commandArgsList = commandArgs.split(',');
    var temp = [];
    for (i=0; i < commandArgsList.length; i++) {
        //commandArgsVal in commandArgsList:
        temp = commandArgsList[i].split(':');
        commandArgsDict[temp[0]] = temp[1];
    }
    return commandArgsDict;
}

function epoCommand(parsedArgs) {
    if (parsedArgs) {
        args = parsedArgs;
    }
    var pArgs = {};
    for (var key in args) {
        if (key != 'command' && key != 'headers') {
            pArgs[key] = args[key];
        }
    }
    var result = callEpo(args.command, pArgs);

    var md;
    var contents;
    if (typeof result === 'string') {
        md = "#### ePO command *" + args.command + "* results:\n" + result;
        contents = {result: result};
    } else {

        md = tableToMarkdown(
            'ePO command *' + args.command + '* results:',
            Object.keys(result || {}).map(function (k) { return result[k]; }),// object keys
            args.headers && args.headers.split(',')
        );
        contents = result;
    }
    return {
        Type: entryTypes.note,
        Contents: contents,
        ContentsFormat: formats.json,
        HumanReadable: md
    };
}

switch (command) {
    // This is the call made when pressing the integration test button.
    case 'test-module':
        epoHelp();
        return 'ok';

    case 'epo-help':
        return epoHelp();

    case 'epo-get-latest-dat':
        return epoGetLatestDat();

    case 'epo-get-current-dat':
        return epoGetCurrentDat();

    case 'epo-update-client-dat':
        return epoUpdateClientDat();

    case 'epo-update-repository':
        return epoUpdateRepository();

    case 'epo-get-system-tree-group':
        return epoGetSystemTreeGroups();

    case 'epo-find-systems':
        return epoFindSystems();

    case 'epo-find-system':
        return epoFindSystem();

    case 'epo-wakeup-agent':
        return epoWakeupAgent();

    case 'epo-apply-tag':
        return epoApplyTag();

    case 'epo-clear-tag':
        return epoClearTag();

    case 'epo-get-tables':
        return epoGetTables();

    case 'epo-query-table':
        return epoQueryTable();

    case 'epo-get-version':
        return epoGetVersion();

    case 'epo-move-system':
        return epoMoveSystem();


    case 'epo-command':
        if (!args.command) {
            throw 'ePO error: command argument is missing';
        }
        return epoCommand(undefined);

    case 'epo-advanced-command':
        if (!args.command) {
            throw 'ePO error: command argument is missing';
        }
        if (!args.commandArgs) {
            throw 'ePO error: commandArgs argument is missing';
        }
        var parsedArgs = parseCommandArgs(args.command, args.commandArgs);
        return epoCommand(parsedArgs);

    default:
        throw 'ePO Error: unknown command';
}