McAfee ePO v2

McAfee ePolicy Orchestrator.

Endpoint · McAfee ePO

Details

IDMcAfee ePO v2
ProviderTrellix
CategoryEndpoint
From Version5.5.0
Docker Imagedemisto/python3:3.12.8.3296088
Supported ModulesAgentix XSIAM EDR Cortex Cloud Cloud Runtime Security

README

McAfee ePolicy Orchestrator
This integration was integrated and tested with version 5.3.2 and 5.10 of McAfee ePO

Permissions

McAfee ePO has a highly flexible and powerful permissions system. The permissions required for the user who 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 information 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":

Configure McAfee ePO v2 in Cortex

Parameter Description Required
McAfee ePO Server URI   True
Username   True
Password   True
Trust any certificate (not secure)   False
Use system proxy settings   False
HTTP Timeout The timeout of the HTTP requests sent to McAfee ePO API (in seconds). False

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.

epo-help


Displays 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 the core.help command output. Optional
command The command for which to display help information. Optional
prefix Displays help information for commands with the specified prefix. Optional

Context Output

There is no context output for this command.

Command Example

!epo-help command="core.help"

Human Readable Output

ePO Help - core.help

core.help [command] [prefix=<>]
Lists all registered commands and displays help strings. Returns the list of
commands or throws on error.
Parameters:
command (param 1) - If specified, the help string for a specific command is
displayed. If omitted, a list of all commands is displayed.
prefix - if specified, only commands with the given prefix are listed. This is
useful for showing the commands for a single plug-in. This has no effect if the
‘command’ argument is specified.

epo-get-latest-dat


Checks the latest available DAT file version in the public McAfee repository.

Base Command

epo-get-latest-dat

Input

| Argument Name | Description | Required |
| — | — | — |

Context Output

Path Type Description
McAfee.ePO.latestDAT number Latest available McAfee DAT file version.

Command Example


#### Context Example

```json
{
    "McAfee": {
        "ePO": {
            "latestDAT": "10200"
        }
    }
}

Human Readable Output

McAfee ePO Latest DAT file version available is: 10200

epo-get-current-dat


Checks the existing DAT file version in the ePO repository.

Base Command

epo-get-current-dat

Input

| Argument Name | Description | Required |
| — | — | — |

Context Output

Path Type Description
McAfee.ePO.epoDAT number Current installed McAfee DAT file in ePO repository

Command Example


#### Context Example

```json
{
    "McAfee": {
        "ePO": {
            "epoDAT": "10200"
        }
    }
}

Human Readable Output

McAfee ePO Current DAT file version in repository is: 10200

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 control the response format to be text instead of the default json format using resp_type=text, 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

Input

| Argument Name | Description | Required |
| — | — | — |

Context Output

There is no context output for this command.

Command Example

!epo-command command="system.find" searchText="10.0.0.1" headers="EPOBranchNode.AutoID,EPOComputerProperties.ComputerName"

Human Readable Output

ePO command system.find results

EPOBranchNode.AutoID EPOComputerProperties.ComputerName
2 10.0.0.1
2 10.0.0.11

epo-update-client-dat


Runs a client task to update the DAT file on the given endpoints.

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. 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. Default is 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="TIE"

Human Readable Output

ePO client DAT update task started: Succeeded

epo-update-repository


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

Base Command

epo-update-repository

Input

| Argument Name | Description | Required |
| — | — | — |

Context Output

There is no context output for this command.

Command Example


#### Human Readable Output

>ePO repository update started.
>success
>skipped: Current\LMASECORE2000\2.2.0.9309\SpamEngine\0000
>skipped: Current\BOCVSE__1000\657\DAT\0000
>skipped: Current\AMCORDAT1000\1359.1\DAT\0000
>skipped: Current\VIRUSCAN8700\8.7.0\LangPack\0000
>skipped: Current\VIRUSCAN8800\8.8.0\LangPack\0000
>skipped: Current\SUPPMVTCT1000\8.3.0.357\MVTContentUpdate\0000
>skipped: Current\PHCONTENMETA\6006\PHContent\0000
>skipped: Current\MASECORE2000\2.2.0.9309\SpamEngine\0000
>skipped: Current\DBSECDAMMETA\97.3112\DAT\0000
>skipped: Current\MVEDR_R_3000\3.5.2\DAT\0000
>skipped: Current\DBSECDVMMETA\195.2097\DVMCHECKS\0000
>skipped: Current\Findings\1310\FNDContent\0000
>skipped: Current\AUENGINEMETA\1335\BMContent\0000
>skipped: Current\ENDPCNT_1000_LYNX\10.7.0\DAT\0000
>skipped: Current\ENCPTCNT6000\8.0.0.11953\DAT\0000

### epo-get-system-tree-group

***
Returns a system tree group.

#### 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. |

#### Command Example

```!epo-get-system-tree-group search="Lost"```

#### Context Example

```json
{
    "McAfee": {
        "ePO": {
            "SystemTreeGroups": {
                "groupId": 3,
                "groupPath": "My Organization\\Lost&Found"
            }
        }
    }
}

Human Readable Output

ePO System Tree groups

Group ID Group path
3 My Organization\Lost&Found

epo-find-systems


Finds computers within a specified group in the McAfee ePO system tree.

Base Command

epo-find-systems

Input

Argument Name Description Required
groupId System tree group ID. Required
verbose Whether to return all system data. Possible values are: true, false. Optional

Context Output

Path Type Description
Endpoint.ID String The unique ID within the tool retrieving the endpoint.
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 The amount of memory in the endpoint.
McAfee.ePO.Endpoint.ParentID Number Endpoint parent ID.
McAfee.ePO.Endpoint.ComputerName String Endpoint computer name.
McAfee.ePO.Endpoint.Description String Endpoint description.
McAfee.ePO.Endpoint.SystemDescription String Endpoint system description.
McAfee.ePO.Endpoint.TimeZone String Endpoint time zone.
McAfee.ePO.Endpoint.DefaultLangID String Endpoint default language ID.
McAfee.ePO.Endpoint.UserName String Endpoint username.
McAfee.ePO.Endpoint.Domain String Endpoint domain name.
McAfee.ePO.Endpoint.Hostname String Endpoint IP host name
McAfee.ePO.Endpoint.IPV6 String Endpoint IPv6 address.
McAfee.ePO.Endpoint.IPAddress String Endpoint IP address.
McAfee.ePO.Endpoint.IPSubnet String Endpoint IP subnet.
McAfee.ePO.Endpoint.IPSubnetMask String Endpoint IP subnet mask
McAfee.ePO.Endpoint.IPV4x Number Endpoint IPV4x address.
McAfee.ePO.Endpoint.IPXAddress String Endpoint IPX address.
McAfee.ePO.Endpoint.SubnetAddress String Endpoint subnet address.
McAfee.ePO.Endpoint.SubnetMask String Endpoint subnet mask.
McAfee.ePO.Endpoint.NetAddress String Endpoint net address.
McAfee.ePO.Endpoint.OSType String Endpoint OS type.
McAfee.ePO.Endpoint.OSVersion String Endpoint OS version.
McAfee.ePO.Endpoint.OSServicePackVer String Endpoint OS service pack version.
McAfee.ePO.Endpoint.OSBuildNum Number Endpoint OS build number.
McAfee.ePO.Endpoint.OSPlatform String Endpoint OS platform.
McAfee.ePO.Endpoint.OSOEMID String Endpoint OS OEM ID.
McAfee.ePO.Endpoint.Processor String Endpoint CPU type.
McAfee.ePO.Endpoint.CPUSpeed Number Endpoint CPU speed.
McAfee.ePO.Endpoint.Processors Number The number of CPUs in the endpoint.
McAfee.ePO.Endpoint.CPUSerialNum String The CPU serial number in the endpoint.
McAfee.ePO.Endpoint.Memory Number The total amount of physical memory in the endpoint.
McAfee.ePO.Endpoint.FreeMemory Number The amount of free memory in the endpoint.
McAfee.ePO.Endpoint.FreeDiskSpace Number The amount of free disk space in the endpoint.
McAfee.ePO.Endpoint.TotalDiskSpace Number The total amount of disk space in the endpoint.
McAfee.ePO.Endpoint.UserProperty1 String Endpoint user property 1.
McAfee.ePO.Endpoint.UserProperty2 String Endpoint user property 2.
McAfee.ePO.Endpoint.UserProperty3 String Endpoint user property 3.
McAfee.ePO.Endpoint.UserProperty4 String Endpoint user property 4.
McAfee.ePO.Endpoint.SysvolFreeSpace Number EThe amount of system volume free space in the endpoint.
McAfee.ePO.Endpoint.SysvolTotalSpace Number The amount of system volume total space in the endpoint.
McAfee.ePO.Endpoint.Tags String Endpoint EPO tags.
McAfee.ePO.Endpoint.ExcludedTags String Endpoint EPO excluded tags.
McAfee.ePO.Endpoint.LastUpdate Date The date the endpoint ePO was last updated.
McAfee.ePO.Endpoint.ManagedState Number Endpoint EPO managed state.
McAfee.ePO.Endpoint.AgentGUID String Endpoint EPO agent GUID.
McAfee.ePO.Endpoint.AgentVersion String Endpoint EPO agent version.
McAfee.ePO.Endpoint.AutoID Number Endpoint EPO auto ID.

Command Example

!epo-find-systems groupId="2"

Context Example

{
    "Endpoint": [
        {
            "ID": "10.0.0.1"
        },      
        {
            "Domain": "WORKGROUP",
            "ID": "WIN-AQ0LQQOG4Q7",
            "Memory": 8589398016,
            "OS": "Windows Server 2012 R2",
            "OSVersion": "6.3",
            "Processor": "Intel(R) Xeon(R) Silver 4216 CPU @ 2.10GHz",
            "Processors": 4
        }
    ],
    "McAfee": {
        "ePO": {
            "Endpoint": [
                {
                    "AgentGUID": null,
                    "AgentVersion": null,
                    "AutoID": 2,
                    "CPUSerialNum": "",
                    "CPUSpeed": 0,
                    "CPUType": "",
                    "ComputerName": "10.0.0.1",
                    "DefaultLangID": "",
                    "Description": null,
                    "DomainName": "",
                    "ExcludedTags": "",
                    "FreeDiskSpace": 0,
                    "FreeMemory": 0,
                    "Hostname": "",
                    "IPAddress": "",
                    "IPSubnet": null,
                    "IPSubnetMask": null,
                    "IPV4x": null,
                    "IPV6": null,
                    "IPXAddress": "",
                    "LastUpdate": null,
                    "ManagedState": 0,
                    "NetAddress": "",
                    "NumOfCPU": 0,
                    "OSBuildNum": 0,
                    "OSOEMID": "",
                    "OSPlatform": "",
                    "OSServicePackVer": "",
                    "OSType": "",
                    "OSVersion": "",
                    "ParentID": 7,
                    "SubnetAddress": "",
                    "SubnetMask": "",
                    "SystemDescription": null,
                    "SysvolFreeSpace": 0,
                    "SysvolTotalSpace": 0,
                    "Tags": "Scan Now",
                    "TimeZone": "",
                    "TotalDiskSpace": 0,
                    "TotalPhysicalMemory": 0,
                    "UserName": "",
                    "UserProperty1": null,
                    "UserProperty2": null,
                    "UserProperty3": null,
                    "UserProperty4": null,
                },
                {
                    "AgentGUID": "CA0CE11A-DCE8-11E8-0805-000C2994FF62
                    "AutoID": 2,
                    "CPUSerialNum": "N/A",
                    "CPUSpeed": 2095,
                    "CPUType": "Intel(R) Xeon(R) Silver 4216 CPU @ 2.10GHz",
                    "ComputerName": "WIN-AQ0LQQOG4Q7",
                    "DefaultLangID": "0409",
                    "Description": null,
                    "DomainName": "WORKGROUP",
                    "ExcludedTags": "",
                    "FreeDiskSpace": 145005,
                    "FreeMemory": 1195880448,
                    "Hostname": "",
                    "IPAddress": "",
                    "IPV4x": null,
                    "IPXAddress": "N/A",
                    "LastUpdate": "2021-12-16T14:44:41-08:00",
                    "ManagedState": 1,
                    "NetAddress": "",
                    "NumOfCPU": 4,
                    "OSBuildNum": 9600,
                    "OSOEMID": "00252-00112-50691-AA377",
                    "OSPlatform": "Server",
                    "OSServicePackVer": "",
                    "OSType": "Windows Server 2012 R2",
                    "OSVersion": "6.3",
                    "ParentID": 17,
                    "SubnetAddress": "",
                    "SubnetMask": "",
                    "SystemDescription": "N/A",
                    "SysvolFreeSpace": 145005,
                    "SysvolTotalSpace": 204447,
                    "Tags": "Server",
                    "TimeZone": "Pacific Standard Time",
                    "TotalDiskSpace": 204447,
                    "TotalPhysicalMemory": 8589398016,
                    "UserName": "Administrator",
                    "UserProperty1": null,
                    "UserProperty2": null,
                    "UserProperty3": null,
                    "UserProperty4": null,
                }
            ]
        }
    }
}

Human Readable Output

Endpoint information

Memory Name Processors
0 10.0.0.1 0

epo-find-system


Finds systems in the McAfee ePO system tree.

Base Command

epo-find-system

Input

Argument Name Description Required
searchText Hostname to search for. Required
verbose Whether to display all system data. Possible values are: true, false. Optional

Context Output

Path Type Description
Endpoint.ID String The unique ID within the tool retrieving the endpoint.
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 The amount of memory in the endpoint.
McAfee.ePO.Endpoint.ParentID Number Endpoint Parent ID.
McAfee.ePO.Endpoint.ComputerName String Endpoint computer name.
McAfee.ePO.Endpoint.Description String Endpoint description.
McAfee.ePO.Endpoint.SystemDescription String Endpoint system description.
McAfee.ePO.Endpoint.TimeZone String Endpoint time zone.
McAfee.ePO.Endpoint.DefaultLangID String Endpoint default language ID.
McAfee.ePO.Endpoint.UserName String Endpoint username.
McAfee.ePO.Endpoint.Domain String Endpoint domain name.
McAfee.ePO.Endpoint.Hostname String Endpoint IP host name.
McAfee.ePO.Endpoint.IPV6 String Endpoint IPv6 address.
McAfee.ePO.Endpoint.IPAddress String Endpoint IP address.
McAfee.ePO.Endpoint.IPSubnet String Endpoint IP subnet.
McAfee.ePO.Endpoint.IPSubnetMask String Endpoint IP subnet mask.
McAfee.ePO.Endpoint.IPV4x Number Endpoint IPV4x address.
McAfee.ePO.Endpoint.IPXAddress String Endpoint IPX address.
McAfee.ePO.Endpoint.SubnetAddress String Endpoint subnet address.
McAfee.ePO.Endpoint.SubnetMask String Endpoint subnet mask.
McAfee.ePO.Endpoint.NetAddress String Endpoint net address.
McAfee.ePO.Endpoint.OSType String Endpoint OS type.
McAfee.ePO.Endpoint.OSVersion String Endpoint OS version.
McAfee.ePO.Endpoint.OSServicePackVer String Endpoint OS service pack version.
McAfee.ePO.Endpoint.OSBuildNum Number Endpoint OS build number.
McAfee.ePO.Endpoint.OSPlatform String Endpoint OS platform.
McAfee.ePO.Endpoint.OSOEMID String Endpoint OS OEM ID.
McAfee.ePO.Endpoint.Processor String Endpoint CPU type.
McAfee.ePO.Endpoint.CPUSpeed Number Endpoint CPU speed.
McAfee.ePO.Endpoint.Processors Number Number of CPUs in the endpoint.
McAfee.ePO.Endpoint.CPUSerialNum String Endpoint CPU serial number.
McAfee.ePO.Endpoint.Memory Number The total amount of physical memory in the endpoint.
McAfee.ePO.Endpoint.FreeMemory Number The amount of free memory in the endpoint.
McAfee.ePO.Endpoint.FreeDiskSpace Number The amount of free disk space in the endpoint.
McAfee.ePO.Endpoint.TotalDiskSpace Number The total amount of disk space in the endpoint.
McAfee.ePO.Endpoint.UserProperty1 String Endpoint user property 1.
McAfee.ePO.Endpoint.UserProperty2 String Endpoint user property 2.
McAfee.ePO.Endpoint.UserProperty3 String Endpoint user property 3.
McAfee.ePO.Endpoint.UserProperty4 String Endpoint user property 4.
McAfee.ePO.Endpoint.SysvolFreeSpace Number The amount of system volume free space in the endpoint.
McAfee.ePO.Endpoint.SysvolTotalSpace Number The total amount of system volume space in the endpoint.
McAfee.ePO.Endpoint.Tags String Endpoint ePO tags.
McAfee.ePO.Endpoint.ExcludedTags String Endpoint EPO excluded tags.
McAfee.ePO.Endpoint.LastUpdate Date Endpoint he date the endpoint was last updated.
McAfee.ePO.Endpoint.ManagedState Number Endpoint managed state.
McAfee.ePO.Endpoint.AgentGUID String Endpoint agent GUID.
McAfee.ePO.Endpoint.AgentVersion String Endpoint agent version.
McAfee.ePO.Endpoint.AutoID Number Endpoint auto ID.

Command Example

!epo-find-system searchText="TIE"

Context Example

{
    "Endpoint": {
        "Domain": "(none)",
        "ID": "tie",
        "IPAddress": "192.168.1.102",
        "Memory": 8364199936,
        "OS": "Linux",
        "OSVersion": "4.9",
        "Processor": "Intel(R) Xeon(R) CPU E5-2697A v4 @ 2.60GHz",
        "Processors": 8
    },
    "McAfee": {
        "ePO": {
            "Endpoint": {
                "AgentGUID": "E0F52A7C-A841-11E7-0467-000C2936A49A",
                "AutoID": 3,
                "CPUSerialNum": "N/A",
                "CPUSpeed": 2600,
                "CPUType": "Intel(R) Xeon(R) CPU E5-2697A v4 @ 2.60GHz",
                "ComputerName": "tie",
                "DefaultLangID": "0409",
                "Description": null,
                "DomainName": "(none)",
                "ExcludedTags": "",
                "FreeDiskSpace": 93781,
                "FreeMemory": 240263168,
                "Hostname": "tie",
                "IPV4x": 1084752230,
                "IPXAddress": "N/A",
                "LastUpdate": "2021-12-16T14:19:25-08:00",
                "ManagedState": 1,
                "NetAddress": "000C29B1EE8E",
                "NumOfCPU": 8,
                "OSBuildNum": 0,
                "OSOEMID": "McAfee TIE Platform Server 3.0.0.480",
                "OSPlatform": "Server",
                "OSServicePackVer": "189-1.mlos2.x86_64",
                "OSType": "Linux",
                "OSVersion": "4.9",
                "ParentID": 2,
                "SubnetAddress": "",
                "SubnetMask": "",
                "SystemDescription": "N/A",
                "SysvolFreeSpace": 0,
                "SysvolTotalSpace": 0,
                "Tags": "DXLBROKER, Server, TIESERVER",
                "TimeZone": "UTC",
                "TotalDiskSpace": 104488,
                "TotalPhysicalMemory": 8364199936,
                "UserName": "root",
                "UserProperty1": null,
                "UserProperty2": null,
                "UserProperty3": null,
                "UserProperty4": null,
            }
        }
    }
}

Human Readable Output

Systems in the System Tree

Name Domain Hostname IPAddress OS OSVersion Processor Processors Memory
tie (none) tie 192.168.1.102 Linux 4.9 Intel(R) Xeon(R) CPU E5-2697A v4 @ 2.60GHz 8 8364199936

epo-wakeup-agent


Wakes up an agent.

Base Command

epo-wakeup-agent

Input

Argument Name Description Required
names A comma-separated list of agent host names. Required

Context Output

There is no context output for this command.

Command Example

!epo-wakeup-agent names="TIE"

Human Readable Output

ePO agents was awaken

Completed Failed Expired
1 0 0

epo-apply-tag


Applies a tag to the specified host names.

Base Command

epo-apply-tag

Input

Argument Name Description Required
names A comma-separated list of host names on which to apply tags. Required
tagName Tag name. Required

Context Output

There is no context output for this command.

Command Example

!epo-apply-tag names="TIE" tagName="Server"

Human Readable Output

ePO could not find server or server already assigned to the given tag.

epo-clear-tag


Clears a tag from the specified host names.

Base Command

epo-clear-tag

Input

Argument Name Description Required
names A comma-separated list of host names from which to clear tags. Required
tagName Tag name. Required

Context Output

There is no context output for this command.

Command Example

!epo-clear-tag names="TIE" tagName="MARSERVER"

Human Readable Output

ePO could not find server or server already assigned to the given tag.

epo-list-tag


List tags that contain the searchText. If no searchText is specified, list all tags available in the ePO system.

Base Command

epo-list-tag

Input

Argument Name Description Required
searchText List tags that contains the searchText in their name field. Optional

Context Output

Path Type Description
McAfee.ePO.Tags.tagId number Tag ID..
McAfee.ePO.Tags.tagName string Tag name.
McAfee.ePO.Tags.tagNotes string Tag notes.

Command Example

!epo-list-tag searchText="server"

Context Example

{
    "McAfee": {
        "ePO": {
            "Tags": [
                {
                    "tagId": 1,
                    "tagName": "Server",
                    "tagNotes": "Default tag for systems identified as a Server"
                },
                {
                    "tagId": 4,
                    "tagName": "TIESERVER",
                    "tagNotes": "Apply Tag to TIEServers"
                },
                {
                    "tagId": 5,
                    "tagName": "MARSERVER",
                    "tagNotes": "Apply Tag to Active Response Server"
                }
            ]
        }
    }
}

Human Readable Output

ePO Tags

tagId tagName tagNotes
1 Server Default tag for systems identified as a Server
4 TIESERVER Apply Tag to TIEServers
5 MARSERVER Apply Tag to Active Response Server

epo-get-tables


Returns the ePO table of the table argument that is specified. If no table argument is specified, returns all ePO tables.

Base Command

epo-get-tables

Input

Argument Name Description Required
table Name of the table to retrieve. Optional

Context Output

There is no context output for this command.

Command Example

!epo-get-tables table="Client Events"

Human Readable Output

ePO tables

name target type databaseType description columns relatedTables foreignKeys
Client Events EPOProductEvents target   Retrieves information on client events from managed systems.
Name Type Select? Condition? GroupBy? Order? Number?
————- ————– ——- ———- ——– —— ——-
AutoID long False False False True True
AgentGUID string True False False True False
NodeID int False False False True True
TVDEventID eventIdInt True True True True True
TVDSeverity enum True True True True False
ReceivedUTC timestamp True True True True False
DetectedUTC timestamp True True True True False
HostName string True True True True False
UserName string True True True True False
IPV6 ipv6 True True True True False
ProductCode string False False False True False
version productVersion True True True True False
SPHotFix string True True True True False
ExtraDATNames string True True True True False
Type string_lookup True True True True False
Error enum True True True True False
Locale int True True True True True
SiteName string True True True True False
InitiatorID string True True True True False
InitiatorType string_lookup True True True True False
TenantId int False False False True True

Name
——————
EPOLeafNode
EPOSoftwareView
EPOEventFilterDesc

Source table Source Columns Destination table Destination columns Allows inverse? One-to-one? Many-to-one?
—————- ————– —————– ——————- ————— ———– ————
EPOProductEvents AgentGUID EPOLeafNode AgentGUID False False True
EPOProductEvents TVDEventID EPOEventFilterDesc EventId False False True
EPOProductEvents ProductCode EPOSoftwareView ProductCode False False True

epo-query-table


Queries an ePO table.

Base Command

epo-query-table

Input

Argument Name Description Required
target Name of the table. Required
select The columns to return, 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 Type Description
McAfee.ePO.Query unknown Query result.

Command Example

!epo-query-table target="FW_Rule" query_name="Test Query"

Context Example

{
    "McAfee": {
        "ePO": {
            "Query": {
                "Test Query": [
                        {
                            "FW_Rule.action": "JUMP",
                            "FW_Rule.direction": "EITHER",
                            "FW_Rule.enabled": 1,
                            "FW_Rule.intrusion": false,
                            "FW_Rule.lastModified": "2014-06-20T11:42:38-07:00",
                            "FW_Rule.lastModifyingUsername": "system",
                            "FW_Rule.localServiceList": "",
                            "FW_Rule.mediaFlags": 7,
                            "FW_Rule.name": "Outlook",
                            "FW_Rule.note": "",
                            "FW_Rule.remoteServiceList": "",
                            "FW_Rule.schedule_end": "0:00",
                            "FW_Rule.schedule_offHours": "NONE",
                            "FW_Rule.schedule_start": "0:00",
                            "FW_Rule.trafficLogged": false,
                            "FW_Rule.transportProtocol": 1024
                        },
                        {
                            "FW_Rule.action": "ALLOW",
                            "FW_Rule.direction": "IN",
                            "FW_Rule.enabled": 1,
                            "FW_Rule.intrusion": false,
                            "FW_Rule.lastModified": "2010-03-29T11:54:22-07:00",
                            "FW_Rule.lastModifyingUsername": "admin",
                            "FW_Rule.localServiceList": "0",
                            "FW_Rule.mediaFlags": 7,
                            "FW_Rule.name": "Allow ICMP Echo Reply Incoming for Services",
                            "FW_Rule.note": "",
                            "FW_Rule.remoteServiceList": "",
                            "FW_Rule.schedule_end": "0:00",
                            "FW_Rule.schedule_offHours": "NONE",
                            "FW_Rule.schedule_start": "0:00",
                            "FW_Rule.trafficLogged": false,
                            "FW_Rule.transportProtocol": 1
                        },
                        {
                            "FW_Rule.action": "BLOCK",
                            "FW_Rule.direction": "IN",
                            "FW_Rule.enabled": 1,
                            "FW_Rule.intrusion": false,
                            "FW_Rule.lastModified": "2009-10-22T17:32:08-07:00",
                            "FW_Rule.lastModifyingUsername": "admin",
                            "FW_Rule.localServiceList": "",
                            "FW_Rule.mediaFlags": 7,
                            "FW_Rule.name": "Block System TCP Incoming",
                            "FW_Rule.note": "",
                            "FW_Rule.remoteServiceList": "",
                            "FW_Rule.schedule_end": "0:00",
                            "FW_Rule.schedule_offHours": "NONE",
                            "FW_Rule.schedule_start": "0:00",
                            "FW_Rule.trafficLogged": false,
                            "FW_Rule.transportProtocol": 6
                        }
                    ]
                }
            }
        }
    }
}

Human Readable Output

ePO Table Query

FW_Rule.localServiceList FW_Rule.trafficLogged FW_Rule.lastModifyingUsername FW_Rule.transportProtocol FW_Rule.remoteServiceList FW_Rule.name FW_Rule.schedule_offHours FW_Rule.note FW_Rule.schedule_start FW_Rule.mediaFlags FW_Rule.intrusion FW_Rule.schedule_end FW_Rule.action FW_Rule.direction FW_Rule.lastModified FW_Rule.enabled
  false system 1024   Outlook NONE   0:00 7 false 0:00 JUMP EITHER 2014-06-20T11:42:38-07:00 1
0 false admin 1   Allow ICMP Echo Reply Incoming for Services NONE   0:00 7 false 0:00 ALLOW IN 2010-03-29T11:54:22-07:00 1
  false admin 6   Block System TCP Incoming NONE   0:00 7 false 0:00 BLOCK IN 2009-10-22T17:32:08-07:00 1

epo-get-version


Returns the ePO version.

Base Command

epo-get-version

Input

| Argument Name | Description | Required |
| — | — | — |

Context Output

Path Type Description
McAfee.ePO.Version string ePO version.

Command Example


#### Context Example

```json
{
    "McAfee": {
        "ePO": {
            "Version": "5.3.2"
        }
    }
}

Human Readable Output

ePO version is: 5.3.2

epo-move-system


Moves a system to a different group in the McAfee ePO.

Base Command

epo-move-system

Input

Argument Name Description Required
names A comma-separated list of asset names. 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

System(s) TIE moved successfully to GroupId 3

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 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"

Human Readable Output

ePO command clienttask.find results

objectName productId productName objectId typeName typeId
On-Demand Scan - Full Scan ENDP_AM_1000 Endpoint Security Threat Prevention 26 Endpoint Security Threat Prevention: Policy Based On-Demand Scan 11
On-Demand Scan - Quick Scan ENDP_AM_1000 Endpoint Security Threat Prevention 27 Endpoint Security Threat Prevention: Policy Based On-Demand Scan 11

epo-find-client-task


Finds client tasks.

Base Command

epo-find-client-task

Input

Argument Name Description Required
searchText List client tasks that contains the searchText in their name field. Optional

Context Output

Path Type Description
McAfee.ePO.ClientTask.objectId number Client task object ID.
McAfee.ePO.ClientTask.objectName string Client task object name.
McAfee.ePO.ClientTask.productId string Client task product ID.
McAfee.ePO.ClientTask.productName string Client task product name.
McAfee.ePO.ClientTask.typeId number Client task type ID.
McAfee.ePO.ClientTask.typeName string Client task type name.

Command Example

!epo-find-client-task searchText="On-Demand"

Context Example

{
    "McAfee": {
        "ePO": {
            "ClientTask": [
                {
                    "objectId": 26,
                    "objectName": "On-Demand Scan - Full Scan",
                    "productId": "ENDP_AM_1000",
                    "productName": "Endpoint Security Threat Prevention ",
                    "typeId": 11,
                    "typeName": "Endpoint Security Threat Prevention: Policy Based On-Demand Scan"
                },
                {
                    "objectId": 27,
                    "objectName": "On-Demand Scan - Quick Scan",
                    "productId": "ENDP_AM_1000",
                    "productName": "Endpoint Security Threat Prevention ",
                    "typeId": 11,
                    "typeName": "Endpoint Security Threat Prevention: Policy Based On-Demand Scan"
                }
            ]
        }
    }
}

Human Readable Output

ePO Client Tasks

productName objectName productId typeId objectId typeName
Endpoint Security Threat Prevention On-Demand Scan - Full Scan ENDP_AM_1000 11 26 Endpoint Security Threat Prevention: Policy Based On-Demand Scan
Endpoint Security Threat Prevention On-Demand Scan - Quick Scan ENDP_AM_1000 11 27 Endpoint Security Threat Prevention: Policy Based On-Demand Scan

epo-find-policy


Finds policy.

Base Command

epo-find-policy

Input

Argument Name Description Required
searchText List policies that contains the searchText in their name field. If no searchText is specified, list all policies in the ePO system. Optional

Context Output

There is no context output for this command.

Command Example

!epo-find-policy searchText="On-Access"

Context Example

{
    "McAfee": {
        "ePO": {
            "Policy": [
                {
                    "featureId": "ENDP_AM_1000",
                    "featureName": " Policy Category",
                    "objectId": 84,
                    "objectName": "McAfee Default",
                    "objectNotes": "",
                    "productId": "ENDP_AM_1000",
                    "productName": "Endpoint Security Threat Prevention ",
                    "typeId": 40,
                    "typeName": "On-Access Scan"
                },
                {
                    "featureId": "ENDP_AM_1000",
                    "featureName": " Policy Category",
                    "objectId": 86,
                    "objectName": "On-Access Scan for Exchange",
                    "objectNotes": "",
                    "productId": "ENDP_AM_1000",
                    "productName": "Endpoint Security Threat Prevention ",
                    "typeId": 40,
                    "typeName": "On-Access Scan"
                },
                {
                    "featureId": "ENDP_AM_1000",
                    "featureName": " Policy Category",
                    "objectId": 90,
                    "objectName": "My Default",
                    "objectNotes": "",
                    "productId": "ENDP_AM_1000",
                    "productName": "Endpoint Security Threat Prevention ",
                    "typeId": 40,
                    "typeName": "On-Access Scan"
                }
            ]
        }
    }
}

Human Readable Output

ePO Policies

objectName featureName productId productName objectId typeName featureId typeId
McAfee Default Policy Category ENDP_AM_1000 Endpoint Security Threat Prevention 84 On-Access Scan ENDP_AM_1000 40
On-Access Scan for Exchange Policy Category ENDP_AM_1000 Endpoint Security Threat Prevention 86 On-Access Scan ENDP_AM_1000 40
My Default Policy Category ENDP_AM_1000 Endpoint Security Threat Prevention 90 On-Access Scan ENDP_AM_1000 40

epo-assign-policy-to-group


Assigns a policy to the specified group or resets the group’s inheritance for the specified policy.

Base Command

epo-assign-policy-to-group

Input

Argument Name Description Required
groupId System tree group ID (as returned by system.findGroups). Required
productId Product ID (as returned by policy.find). Required
objectId Object ID (as returned by policy.find). Required
resetInheritance If true, resets the inheritance for the specified policy on the given group. Default is false. Possible values are: true, false. Optional

Context Output

There is no context output for this command.

Command Example

!epo-assign-policy-to-group groupId="2" productId="ENDP_AM_1000" objectId="86"

Human Readable Output

Policy productId:ENDP_AM_1000 objectId:86 assigned successfully to GroupId 2

epo-assign-policy-to-system


Assigns a policy to a supplied list of systems or resets the systems’ inheritance for the specified policy.

Base Command

epo-assign-policy-to-system

Input

Argument Name Description Required
names EEither supply a comma-separated list of names/ip addresses or a comma-separated list of IDs to which the policy is to be assigned. Required
productId Product ID (as returned by policy.find). Required
typeId Type ID (as returned by policy.find). Required
objectId Object ID (as returned by policy.find). Required
resetInheritance If true, resets the inheritance for the specified object. Default is false. Possible values are: true, false. Optional

Context Output

There is no context output for this command.

Command Example

!epo-assign-policy-to-system names="TIE" productId="ENDP_AM_1000" typeId="40" objectId="84"

Human Readable Output

ePO Policies

status name message id
0 TIE Assign policy succeeded 2

epo-list-issues


List the issue for the ID that is specified. If no ID is specified, list all issues in the McAfee ePO system.

Base Command

epo-list-issues

Input

Argument Name Description Required
id The ID of the issue to display. Optional

Context Output

Path Type Description
McAfee.ePO.Issue.activityLog.date string Date of the issue activity log.
McAfee.ePO.Issue.activityLog.details string Details of the issue activity log.
McAfee.ePO.Issue.activityLog.id number The ID of the issue activity log.
McAfee.ePO.Issue.activityLog.issueId number The issue ID of the activity log.
McAfee.ePO.Issue.activityLog.title string The title of the issue activity log.
McAfee.ePO.Issue.activityLog.username string The username of the issue activity log.
McAfee.ePO.Issue.id number Issue ID.
McAfee.ePO.Issue.name string Issue name.
McAfee.ePO.Issue.type string Issue type.
McAfee.ePO.Issue.description string Issue description.
McAfee.ePO.Issue.state string Issue state.
McAfee.ePO.Issue.priority string Issue priority.
McAfee.ePO.Issue.severity string Issue severity.
McAfee.ePO.Issue.resolution string Issue resolution.
McAfee.ePO.Issue.creatorName string Issue creator name.
McAfee.ePO.Issue.assignee number Issue assignee ID.
McAfee.ePO.Issue.assigneeName string Issue assignee name.
McAfee.ePO.Issue.createdDate string Date the issue was created.
McAfee.ePO.Issue.dueDate string Date the issue is due.
McAfee.ePO.Issue.ticketId string Ticket ID of the issue.
McAfee.ePO.Issue.ticketServerName string Issue ticket server name.

Command Example


#### Context Example

```json
{
    "McAfee": {
        "ePO": {
            "Issue": [
                {
                    "activityLog": [
                        {
                            "date": "2021-05-09T03:36:56-07:00",
                            "details": "",
                            "id": 1,
                            "issueId": 1,
                            "title": "Issue Created",
                            "username": "admin"
                        }
                    ],
                    "assignee": null,
                    "assigneeName": "dxl",
                    "createdDate": "2021-05-09T03:36:56-07:00",
                    "creatorName": "admin",
                    "description": "aaaa",
                    "dueDate": null,
                    "id": 1,
                    "name": "aaaa",
                    "priority": "MEDIUM",
                    "resolution": "NONE",
                    "severity": "LOWEST",
                    "state": "NEW",
                    "subtype": null,
                    "ticketId": null,
                    "ticketServerName": null,
                    "type": "issue.type.untyped"
                },
                {
                    "activityLog": [
                        {
                            "date": "2021-11-23T00:46:25-08:00",
                            "details": "",
                            "id": 2,
                            "issueId": 2,
                            "title": "Issue Created",
                            "username": "admin"
                        },
                        {
                            "date": "2021-11-23T23:26:20-08:00",
                            "details": "assignee changed from test_api to admin",
                            "id": 3,
                            "issueId": 2,
                            "title": "Issue Changed",
                            "username": "admin"
                        },
                        {
                            "date": "2021-11-23T23:32:08-08:00",
                            "details": "yakovi",
                            "id": 4,
                            "issueId": 2,
                            "title": "User Comment",
                            "username": "admin"
                        }
                    ],
                    "assignee": null,
                    "assigneeName": "admin",
                    "createdDate": "2021-11-23T00:46:25-08:00",
                    "creatorName": "admin",
                    "description": "test1",
                    "dueDate": null,
                    "id": 2,
                    "name": "Wissam",
                    "priority": "HIGH",
                    "resolution": "NONE",
                    "severity": "MEDIUM",
                    "state": "NEW",
                    "subtype": null,
                    "ticketId": null,
                    "ticketServerName": null,
                    "type": "issue.type.untyped"
                }
            ]
        }
    }
}

Human Readable Output

ePO Issue List

ticketId dueDate createdDate creatorName resolution subtype assigneeName description priority type ticketServerName name assignee severity activityLog id state
    2021-05-09T03:36:56-07:00 admin NONE   dxl aaaa MEDIUM issue.type.untyped   aaaa   LOWEST {‘date’: ‘2021-05-09T03:36:56-07:00’, ‘details’: ‘’, ‘id’: 1, ‘issueId’: 1, ‘title’: ‘Issue Created’, ‘username’: ‘admin’} 1 NEW
    2021-11-23T00:46:25-08:00 admin NONE   admin test1 HIGH issue.type.untyped   Wissam   MEDIUM {‘date’: ‘2021-11-23T00:46:25-08:00’, ‘details’: ‘’, ‘id’: 2, ‘issueId’: 2, ‘title’: ‘Issue Created’, ‘username’: ‘admin’},
{‘date’: ‘2021-11-23T23:26:20-08:00’, ‘details’: ‘assignee changed from test_api to admin’, ‘id’: 3, ‘issueId’: 2, ‘title’: ‘Issue Changed’, ‘username’: ‘admin’},
{‘date’: ‘2021-11-23T23:32:08-08:00’, ‘details’: ‘yakovi’, ‘id’: 4, ‘issueId’: 2, ‘title’: ‘User Comment’, ‘username’: ‘admin’}
2 NEW

epo-delete-issue


Delete an issue.

Base Command

epo-delete-issue

Input

Argument Name Description Required
id The ID of the issue to delete. Required

Context Output

There is no context output for this command.

Command Example

!epo-delete-issue id=8

Human Readable Output

Issue with id=0 was deleted

epo-create-issue


Create an issue.

Base Command

epo-create-issue

Input

Argument Name Description Required
name Issue name. Required
description Issue description. Required
type Issue type. Optional
state Issue state. Possible values are: UNKNOWN, NEW, ASSIGNED, RESOLVED, CLOSED, TICKETED, TICKET_PENDING. Optional
priority Issue priority. Possible values are: UNKNOWN, LOWEST, LOW, MEDIUM, HIGH, HIGHEST. Optional
severity Issue severity. Possible values are: UNKNOWN, LOWEST, LOW, MEDIUM, HIGH, HIGHEST. Optional
resolution Issue resolution. Possible values are: NONE, FIXED, WAIVED, WILLNOTFIX. Optional
due Due date of the issue in the format yyyy-mm-dd hh:mm:ss. Optional
assignee_name Name of the user assigned to the issue. Optional
ticketServerName Ticket server name of the issue. Optional
ticketId Ticket ID of the issue. Optional
properties Properties of the issue. Optional

Context Output

Path Type Description
McAfee.ePO.Issue.id number Issue ID.
McAfee.ePO.Issue.name string Issue name.
McAfee.ePO.Issue.description string Issue description.

Command Example

!epo-create-issue name="test-epo-integration" description="automatically generated by epo integration" assignee_name="admin"

Context Example

{
    "McAfee": {
        "ePO": {
            "Issue": {
                
                    "description": "automatically generated by epo integration",
                    "id": 35,
                    "name": "test-epo-integration"
            }
        }
    }
}

Human Readable Output

Issue with the following ID: 35 was created successfully

epo-update-issue


Update an issue.

Base Command

epo-update-issue

Input

Argument Name Description Required
id The ID of the issue to update. Required
name Name of the issue to update. Required
description Description of the issue to update. Required
state State of the issue to update. Possible values are: UNKNOWN, NEW, ASSIGNED, RESOLVED, CLOSED, TICKETED, TICKET_PENDING. Optional
priority Priority of the issue to update. Possible values are: UNKNOWN, LOWEST, LOW, MEDIUM, HIGH, HIGHEST. Optional
severity Severity of the issue to update. Possible values are: UNKNOWN, LOWEST, LOW, MEDIUM, HIGH, HIGHEST. Optional
resolution Resolution of the issue to update. Possible values are: NONE, FIXED, WAIVED, WILLNOTFIX. Optional
due Due date of the issue to update. Optional
assignee_name Name of the user assigned to the issue. Optional
ticketServerName Ticket server name of the issue. Optional
ticketId Ticket ID of the issue. Optional
properties Properties of the issue. Optional

Context Output

There is no context output for this command.

Command Example

!epo-update-issue id=10 name="test" description="testing epo integration" state="NEW"

Human Readable Output

Issue with id=10 was updated

Configuration parameters

  • address — McAfee ePO Server URI (required)
  • authentication — Username (required)
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings
  • timeout — HTTP Timeout

Commands (26)

  • 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 the specified host names.

  • epo-assign-policy-to-group

    Assigns a policy to the specified group or resets the group's inheritance for the specified policy.

  • epo-assign-policy-to-system

    Assigns a policy to a supplied list of systems or resets the systems' inheritance for the specified policy.

  • epo-clear-tag

    Clears a tag from the specified host names.

  • 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 control the response format to be text instead of the default JSON format using resp_type=text. 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-create-issue

    Create an issue.

  • epo-delete-issue

    Delete an issue.

  • epo-find-client-task

    Finds client tasks.

  • epo-find-policy

    Finds policy.

  • epo-find-system

    Finds systems in the McAfee ePO system tree.

  • epo-find-systems

    Finds computers within a specified group in the McAfee ePO system tree.

  • epo-get-current-dat

    Checks the existing DAT file version in the ePO repository.

  • epo-get-latest-dat

    Checks the latest available DAT file version in the public McAfee repository.

  • epo-get-system-tree-group

    Returns a system tree group.

  • epo-get-tables

    Returns the ePO table of the table argument that is specified. If no table argument is specified, returns all ePO tables.

  • epo-get-version

    Returns the ePO version.

  • epo-help

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

  • epo-list-issues

    List the issue for the ID that is specified. If no ID is specified, list all issues in the McAfee ePO system.

  • epo-list-tag

    List tags that contain the searchText. If no searchText is specified, list all tags available in the ePO system.

  • epo-move-system

    Moves a system to a different group in the McAfee ePO.

  • epo-query-table

    Queries an ePO table.

  • epo-update-client-dat

    Runs a client task to update the DAT file on the given endpoints.

  • epo-update-issue

    Update an issue.

  • epo-update-repository

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

  • epo-wakeup-agent

    Wakes up an agent.

import json
import traceback
from typing import Any

import demistomock as demisto
import urllib3
from CommonServerPython import *

from CommonServerUserPython import *

# Disable insecure warnings
urllib3.disable_warnings()

""" CONSTANTS """

GET = "GET"
DATE_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
EPO_SYSTEM_ATTRIBUTE_MAP = {
    "Name": "EPOComputerProperties.ComputerName",
    "Domain": "EPOComputerProperties.DomainName",
    "Hostname": "EPOComputerProperties.IPHostName",
    "IPAddress": "EPOComputerProperties.IPAddress",
    "OS": "EPOComputerProperties.OSType",
    "OSVersion": "EPOComputerProperties.OSVersion",
    "Processor": "EPOComputerProperties.CPUType",
    "Processors": "EPOComputerProperties.NumOfCPU",
    "Memory": "EPOComputerProperties.TotalPhysicalMemory",
}

""" CLIENT CLASS """


class Client(BaseClient):
    def __init__(self, base_url: str, headers: dict, auth: tuple, timeout: int = 120, proxy: bool = False, verify: bool = True):
        self.timeout = timeout
        super().__init__(base_url=base_url, headers=headers, auth=auth, proxy=proxy, verify=verify)

    def test_module(self) -> str:
        """
        Tests API connectivity and authentication

        """
        _, response = self.epo_help()
        return json.dumps(response)

    def epo_help(self, command: str = None, prefix: str = None) -> tuple[dict, dict]:
        """

        Args:
            command (str): command to get detail help
            prefix (str): list all commands with the given prefix

        Returns (str):
            core.help command json output
        """
        params = {":output": "json"}
        if command:
            params["command"] = command
        elif prefix:
            params["prefix"] = prefix

        epo_response = self._http_request(
            method="GET", url_suffix="core.help", params=params, timeout=self.timeout, resp_type="text"
        )
        return self._parse_response(epo_response)

    def epo_get_latest_dat(self) -> tuple[dict, dict]:
        """
        a direct call to specific url to get the version of the most updated dat file
        dat file is the McAfee A/V software definitions file.
        """
        dat_file_url = "http://update.nai.com/products/commonupdater/gdeltaavv.ini"
        raw_response = self._http_request(method=GET, full_url=dat_file_url, resp_type="text", timeout=self.timeout)
        latest_version = raw_response.split("\r\n\r\n")[0].split("CurrentVersion=")[1]
        json_response = {"LatestVersion": latest_version}

        return json_response, raw_response

    def epo_get_current_dat(self) -> tuple[dict, dict]:
        """
        returns the currently installed dat file on the ePO system
        Returns(str):
        returns the version number of the currently installed dat file
        """
        params = {"searchText": "VSCANDAT1000", ":output": "json"}
        url_suffix = "repository.findPackages"
        response = self._http_request(method=GET, url_suffix=url_suffix, params=params, resp_type="text", timeout=self.timeout)
        return self._parse_response(response)

    def epo_command(self, command: str, params: dict, resp_type: str = "json") -> tuple[dict, dict]:
        """
        Runs any given command
        Args:
            command (str): command
            resp_type (str): define response type format
            params (dict): dictionary represents the arguments
        Returns:
        the command result
        """
        if resp_type == "json":
            params[":output"] = "json"

        response = self._http_request(method=GET, url_suffix=command, params=params, resp_type="text", timeout=self.timeout)
        return self._parse_response(response)

    def update_client_dat(
        self,
        names: str,
        product_id: str,
        task_id: str,
        retry_attempts: str = None,
        retry_interval_in_seconds: str = None,
        abort_after_minutes: str = None,
        stop_after_minutes: str = None,
        randomization_interval: str = None,
    ) -> tuple[dict, dict]:
        params = {"names": names, ":output": "json", "productId": product_id, "taskId": task_id}

        if retry_attempts:
            params["retryAttempts"] = retry_attempts
        if retry_interval_in_seconds:
            params["retryIntervalInSeconds"] = retry_interval_in_seconds
        if abort_after_minutes:
            params["abortAfterMinutes"] = abort_after_minutes
        if stop_after_minutes:
            params["stopAfterMinutes"] = stop_after_minutes
        if randomization_interval:
            params["randomizationInterval"] = randomization_interval

        response = self._http_request(
            method=GET, url_suffix="clienttask.run", params=params, resp_type="text", timeout=self.timeout
        )
        return self._parse_response(response)

    def get_client_task_id_by_name(self, search_text: str) -> tuple[str, str]:
        """
         list all client tasks in ePO server
        Args:
            search_text (str): filter client task list and list task contain searchText

        Returns:
            list the found the client task
        """
        params = {"searchText": search_text, ":output": "json"}
        raw_response = self._http_request(
            method=GET, url_suffix="clienttask.find", params=params, resp_type="text", timeout=self.timeout
        )

        json_response, response = self._parse_response(raw_response)

        if len(json_response) > 0:
            if json_response and isinstance(json_response, list):
                json_response = json_response[0]

            if "objectId" in json_response:
                object_id = json_response["objectId"]
            else:
                object_id = ""
                demisto.debug("no objectId in json_response")
            if "productId" in json_response:
                product_id = json_response["productId"]
            else:
                product_id = ""
                demisto.debug("no productId in json_response")

            return object_id, product_id
        else:
            # If reached here then the response is an empty "OK:", which means VSEContentUpdateDemisto was not found in
            # the server
            raise DemistoException(
                'Error getting DAT update task. It seems the task "VSEContentUpdateDemisto" is missing from the EPO '
                "server. Please contact support for more details"
            )

    def update_repository(self, source_repo: str, target_branch: str) -> tuple[dict, dict]:
        """
        Updating the local repository on the ePO from the public server.
        Returns:
        command submission status
        """
        params = {"sourceRepository": "McAfeeHttp", "targetBranch": "Current"}
        raw_response = self._http_request(
            method=GET, url_suffix="repository.pull", params=params, resp_type="text", timeout=self.timeout
        )
        return self._parse_response(raw_response)

    def get_system_tree_groups(self, search_text: str = None):
        """
        find a group of machine in the epo system tree
        Args:
            search_text (str): group name
        Returns:

        """
        params = {":output": "json"}
        if search_text:
            params["searchText"] = search_text

        raw_response = self._http_request(
            method=GET, url_suffix="system.findGroups", params=params, resp_type="text", timeout=self.timeout
        )
        return self._parse_response(raw_response)

    def get_system_group_path(self, group_id: int) -> str:
        """
        return the system group path for giving group_id
        Args:
            group_id (str): the groupID to find
        Returns (str): returns the system group path for a giving group id
        """
        response_json, response = self.get_system_tree_groups(search_text="")
        if response is None:
            return ""

        for entry in response_json:
            if group_id == entry["groupId"]:
                return entry["groupPath"]
        return ""

    def find_systems(self, group_id: int) -> tuple[dict, dict]:
        """
        find all systems belongs to the given group Id
        Args:
            group_id (int): group Id to find in the system tree
        Returns:
            a list of system in json
        """

        params = {":output": "json", "groupId": group_id}
        raw_response = self._http_request(
            method=GET, url_suffix="epogroup.findSystems", params=params, resp_type="text", timeout=self.timeout
        )
        return self._parse_response(raw_response)

    def find_system(self, search_text: str) -> tuple[dict, dict]:
        """
        find system in the ePO Server system tree
        Args:
            search_text (str): system name
        Returns:
            a list of system in json
        """
        params = {"searchText": search_text, ":output": "json"}
        response = self._http_request(method=GET, url_suffix="system.find", params=params, resp_type="text", timeout=self.timeout)
        return self._parse_response(response)

    def wakeup_agent(self, names: str) -> tuple[dict, dict]:
        """
        wakeup agent for as system or list of systems
        Args:
            names (str):
        Returns:
            operation result
        """
        params = {"names": names, ":output": "json"}

        response = self._http_request(
            method=GET, url_suffix="system.wakeupAgent", params=params, resp_type="text", timeout=self.timeout
        )

        # response = response.split('"')[1] if response.startswith('"') else response
        # response = response.replace(r'\n', '\n')
        return self._parse_response(response)

    def apply_tag(self, names: str, tag_name: str) -> tuple[int, dict]:
        """
        Apply the given tag name to machine(s) in names
        Args:
            names (str): machine id or list of machine ids
            tag_name (str):
        Returns:
            operation result
        """
        params = {"names": names, "tagName": tag_name, ":output": "json"}
        response = self._http_request(
            method=GET, url_suffix="system.applyTag", params=params, resp_type="text", timeout=self.timeout
        )
        return self._parse_response(response)

    def clear_tag(self, names: str, tag_name: str) -> tuple[int, dict]:
        """
        Clear the given tag name for machine(s) in names
        Args:
            names (str): machine id or list of machine ids
            tag_name (str):
        Returns:
            operation result
        """
        params = {"names": names, "tagName": tag_name, ":output": "json"}
        response = self._http_request(
            method=GET, url_suffix="system.clearTag", params=params, resp_type="text", timeout=self.timeout
        )
        return self._parse_response(response)

    def list_tag(self, search_text: str = None) -> tuple[dict, dict]:
        """
        List tags available on ePO server
        Args:
            search_text (str): filter tags contains search_text
        Returns:
            list of tags
        """
        params = {"searchText": search_text, ":output": "json"}
        response = self._http_request(
            method=GET, url_suffix="system.findTag", params=params, resp_type="text", timeout=self.timeout
        )
        return self._parse_response(response)

    def get_table(self, table_name: str = None) -> tuple[dict, dict]:
        """
        Get tables from ePO server
        Args:
            table_name (): list tables that contains table_name
        Returns:
            lists of tables
        """
        params = {":output": "json"}
        if table_name:
            params["table"] = table_name

        response = self._http_request(
            method=GET, url_suffix="core.listTables", params=params, resp_type="text", timeout=self.timeout
        )
        return self._parse_response(response)

    def query_table(
        self,
        target: str = None,
        select: str = None,
        where: str = None,
        order: str = None,
        group: str = None,
        join_tables: str = None,
    ) -> tuple[dict, dict]:
        """
        query tables from ePO server
        Args:
            target (str): tablename to run query on
            select (str): The columns to select, in SQUID syntax.
                          Example: "(select EPOEvents.AutoID EPOEvents.DetectedUTC EPOEvents.ReceivedUTC)"
            where (str): Filter results, in SQUID syntax. Example: "(where ( eq ( OrionTaskLogTask .UserName "ga" )))"
            order (str): Order in which to return the results, in SQUID syntax.
                         Example: "(order (asc OrionTaskLogTask.StartDate) )"
            group (str): Group the results, in SQUID Syntax. Example: "(group EPOBranchNode.NodeName)"
            join_tables (str): The comma-separated list of SQUID targets to join with the target
                              type; * means join with all types
        Returns:
            query result
        """
        params = {":output": "json"}
        if target:
            params["target"] = target

        if select:
            params["select"] = select

        if where:
            params["where"] = where

        if order:
            params["order"] = order

        if group:
            params["group"] = group

        if join_tables:
            params["joinTables"] = join_tables

        response = self._http_request(
            method=GET, url_suffix="core.executeQuery", params=params, resp_type="text", timeout=self.timeout
        )
        return self._parse_response(response)

    def get_version(self) -> tuple[dict, dict]:
        """
        Get ePO Software Version
        Returns:
            return ePO Software version
        """
        params = {":output": "json"}
        response = self._http_request(
            method=GET, url_suffix="epo.getVersion", params=params, resp_type="text", timeout=self.timeout
        )
        return self._parse_response(response)

    def move_system(self, names: str, parent_group_id: int) -> tuple[dict, dict]:
        """
           Moves systems to a specified destination group by name or ID as returned
        Args:
           names (str): List of machine or machine id
           parent_group_id (int): destination parent group id
        Returns:
           lists of tables
        """
        params = {"names": names, "parentGroupId": parent_group_id}
        response = self._http_request(method=GET, url_suffix="system.move", params=params, resp_type="text", timeout=self.timeout)
        return self._parse_response(response)

    def find_client_task(self, search_text: str = None) -> tuple[dict, dict]:
        """
           find client task in the ePo system
        Args:
           search_text (str): List client tasks that contains searchText in their name field.
        Returns:
           lists of tables
        """
        params = {":output": "json"}
        if search_text:
            params["searchText"] = search_text
        response = self._http_request(
            method=GET, url_suffix="clienttask.find", params=params, resp_type="text", timeout=self.timeout
        )
        return self._parse_response(response)

    def find_policy(self, search_text: str = None) -> tuple[dict, dict]:
        """
           find policy task in the ePo system
        Args:
           search_text (str): List policies that contains searchText in their name field.
        Returns:
           lists of tables
        """
        params = {":output": "json"}
        if search_text:
            params["searchText"] = search_text
        response = self._http_request(method=GET, url_suffix="policy.find", params=params, resp_type="text", timeout=self.timeout)
        return self._parse_response(response)

    def assign_policy_to_group(
        self, group_id: int, product_id: str, object_id: int, reset_inheritance: str = "false"
    ) -> tuple[int, dict]:
        """
           Assign policy to group of machines
        Args:
           group_id (int): System tree Group ID.(as returned by system.findGroups)
           product_id (int): Product ID.(as returned by policy.find)
           object_id (int): Object ID.(as returned by policy.find)
           reset_inheritance (str):If true resets the inheritance for the specified policy on the given group. Defaults
                                    to false.
        Returns:
           string indication
        """
        params = {
            ":output": "json",
            "groupId": group_id,
            "productId": product_id,
            "objectId": object_id,
            "resetInheritance": reset_inheritance,
        }
        response = self._http_request(
            method=GET, url_suffix="policy.assignToGroup", params=params, resp_type="text", timeout=self.timeout
        )
        return self._parse_response(response)

    def assign_policy_to_system(
        self, names: str, product_id: str, type_id: int, object_id: int, reset_inheritance: str = "false"
    ) -> tuple[dict, dict]:
        """
           Assign policy to system(s)
        Args:
           names (int): list of system or system
           product_id (int): Product ID.(as returned by policy.find)
           type_id (int): Type ID.(as returned by policy.find)
           object_id (int): Object ID.(as returned by policy.find)
           reset_inheritance (str):If true resets the inheritance for the specified policy on the given group. Defaults
                                    to false.
        Returns:
           string indication
        """
        params = {
            ":output": "json",
            "names": names,
            "productId": product_id,
            "typeId": type_id,
            "objectId": object_id,
            "resetInheritance": reset_inheritance,
        }
        response = self._http_request(
            method=GET, url_suffix="policy.assignToSystem", params=params, resp_type="text", timeout=self.timeout
        )
        return self._parse_response(response)

    def list_issue(self, issue_id: str = "") -> tuple[dict, dict]:
        """
        list issue in the system
        Args:
            issue_id (str): issue id to list if given
        Returns:
            list of issue
        """
        params = {":output": "json"}
        if issue_id:
            params["id"] = issue_id

        response = self._http_request(
            method=GET, url_suffix="issue.listIssues", params=params, resp_type="text", timeout=self.timeout
        )
        return self._parse_response(response)

    def delete_issue(self, issue_id: str) -> tuple[dict, dict]:
        """
        delete issue in the system
        Args:
            issue_id (str): issue id to list if given
        Returns:
            list of issue
        """
        params = {":output": "json", "id": issue_id}

        response = self._http_request(
            method=GET, url_suffix="issue.deleteIssue", params=params, resp_type="text", timeout=self.timeout
        )
        return self._parse_response(response)

    def update_issue(
        self,
        issue_id: str,
        issue_name: str = None,
        issue_description: str = None,
        issue_state: str = None,
        issue_priority: str = None,
        issue_severity: str = None,
        issue_resolution: str = None,
        issue_due: str = None,
        issue_assignee_name: str = None,
        issue_ticket_server_name: str = None,
        issue_ticket_id: str = None,
        issue_properties: str = None,
    ) -> tuple[dict, dict]:
        """
        update an issue
        Args:
            issue_id (str): issue Id
            issue_name (str): Optional issue name
            issue_description (str): Optional issue description
            issue_state (str): Optional issue state
            issue_priority (str): Optional issue priority
            issue_severity (str): Optional issue severity
            issue_resolution (str): Optional issue resolution
            issue_due (str): Optional issue due
            issue_assignee_name (str): Optional  issue assignee name
            issue_ticket_server_name (str): Optional ticket server name
            issue_ticket_id (str): Optional issue ticket id
            issue_properties (str): Optional issue properties
        Returns:

        """
        params = {":output": "json", "id": issue_id}
        if issue_name:
            params["name"] = issue_name
        if issue_description:
            params["desc"] = issue_description
        if issue_state:
            params["state"] = issue_state
        if issue_priority:
            params["priority"] = issue_priority
        if issue_severity:
            params["severity"] = issue_severity
        if issue_resolution:
            params["resolution"] = issue_resolution
        if issue_due:
            params["due"] = issue_due
        if issue_assignee_name:
            params["assigneeName"] = issue_assignee_name
        if issue_ticket_server_name:
            params["ticketServerName"] = issue_ticket_server_name
        if issue_ticket_id:
            params["ticketId"] = issue_ticket_id
        if issue_properties:
            params["properties"] = issue_properties

        response = self._http_request(
            method=GET, url_suffix="issue.updateIssue", params=params, resp_type="text", timeout=self.timeout
        )
        return self._parse_response(response)

    def create_issue(
        self,
        issue_name: str,
        issue_description: str,
        issue_state: str = None,
        issue_priority: str = None,
        issue_severity: str = None,
        issue_resolution: str = None,
        issue_due: str = None,
        issue_assignee_name: str = None,
        issue_ticket_server_name: str = None,
        issue_ticket_id: str = None,
        issue_properties: str = None,
    ) -> tuple[dict, dict]:
        """
        create an issue
        Args:
            issue_name (str): Optional issue name
            issue_description (str): Optional issue description
            issue_state (str): Optional issue state
            issue_priority (str): Optional issue priority
            issue_severity (str): Optional issue severity
            issue_resolution (str): Optional issue resolution
            issue_due (str): Optional issue due
            issue_assignee_name (str): Optional  issue assignee name
            issue_ticket_server_name (str): Optional ticket server name
            issue_ticket_id (str): Optional issue ticket id
            issue_properties (str): Optional issue properties
        Returns:

        """
        params = {":output": "json", "name": issue_name, "desc": issue_description}
        if issue_state:
            params["state"] = issue_state
        if issue_priority:
            params["priority"] = issue_priority
        if issue_severity:
            params["severity"] = issue_severity
        if issue_resolution:
            params["resolution"] = issue_resolution
        if issue_due:
            params["due"] = issue_due
        if issue_assignee_name:
            params["assigneeName"] = issue_assignee_name
        if issue_ticket_server_name:
            params["ticketServerName"] = issue_ticket_server_name
        if issue_ticket_id:
            params["ticketId"] = issue_ticket_id
        if issue_properties:
            params["properties"] = issue_properties

        response = self._http_request(
            method=GET, url_suffix="issue.createIssue", params=params, resp_type="text", timeout=self.timeout
        )
        return self._parse_response(response)

    @staticmethod
    def _parse_response(response: str) -> tuple[Any, Any]:
        """
        Parses the raw response returned from a remote command invocation, returning
        its content, which is trimmed of leading and trailing whitespace.
        The input will look like the following:

        OK:\r\ntrue                                ---->  returns "true"

        or in the error case,

        "Error # :\r\nSome error string goes here  ---->  throws CommandInvokerError(#, "Some error string goes here")

        where # is the integer representing the error code returned.

        @param response - the raw response from the server
        @throws DemistoException if the response from the server indicates an Error state
        @returns response from the server stripped of the protocol

        """
        code = 0
        try:
            status = response[: response.index(":")].split(" ")[0]
            result = response[response.index(":") + 1 :].strip()
            if status == "Error":
                code = int(response[: response.index(":")].split(" ")[1])
            else:
                code = 0
            res = {"status": status, "code": code, "result": result}
        except Exception:
            # for thoroughness, in case there's no colon in the output or something else
            # Or there was an error parsing the returned result from the server
            res = {"status": "Error", "code": code, "result": "Unable to parse the server's response"}
            err_msg = "Error in API call [{}] - {}".format(demisto.command, res["result"])
            demisto.error(err_msg)
            raise DemistoException(f"Error occurred. Status: ({res['status']}) Code: ({res['code']}) Result: {res['result']}")

        if res["status"] == "OK":
            try:
                json_response = json.loads(str(res["result"]))
            except (TypeError, json.JSONDecodeError):
                json_response = res["result"]
            return json_response, json_response
        elif res["status"] == "Error":
            raise DemistoException(f"Error occurred. Status: ({res['status']}) Code: ({res['code']}) Result: {res['result']}")
        else:
            raise DemistoException(f"Unknown error occurred.  Status: {res['status']} Result: {res['result']}")


""" HELPER FUNCTION"""


def prettify_system_tree(system_tree: dict) -> list:
    """
    reformatting the system tree output to fit the integration requirements

    :type system_tree: ``dict``
    :param system_tree: A dictionary that represent system tree

    Returns:
        List of dictionaries that to be populated in the context data
    """
    context_data_system_tree = []
    for system in system_tree:
        context_data_system_tree.append({"groupId": system["groupId"], "groupPath": system["groupPath"]})
    return context_data_system_tree


def prettify_find_system(find_system: list, extended: bool = True) -> list:
    """
    returns the list of dictionaries that fit with the context data requirements
    Args:
        find_system (list): dictionary contains list of systems
        extended (bool): to export all system information as context data this is the default behavior

    Returns: returns the list of dictionaries that fit with the context data requirements
    """
    context_data_find_system = []
    for system in find_system:
        if extended:
            system_xsoar = {}
            for key in system:
                modified_key = key.split(".")[1]
                system_xsoar[modified_key] = system[key]
            context_data_find_system.append(system_xsoar)
        else:
            context_data_find_system.append(
                {
                    "Name": system.get(EPO_SYSTEM_ATTRIBUTE_MAP.get("Name")),
                    "Domain": system.get(EPO_SYSTEM_ATTRIBUTE_MAP.get("Domain")),
                    "Hostname": system.get(EPO_SYSTEM_ATTRIBUTE_MAP.get("Hostname")),
                    "IPAddress": system.get(EPO_SYSTEM_ATTRIBUTE_MAP.get("IPAddress")),
                    "OS": system.get(EPO_SYSTEM_ATTRIBUTE_MAP.get("OS")),
                    "OSVersion": system.get(EPO_SYSTEM_ATTRIBUTE_MAP.get("OSVersion")),
                    "Processor": system.get(EPO_SYSTEM_ATTRIBUTE_MAP.get("Processor")),
                    "Processors": system.get(EPO_SYSTEM_ATTRIBUTE_MAP.get("Processors")),
                    "Memory": system.get(EPO_SYSTEM_ATTRIBUTE_MAP.get("Memory")),
                }
            )
    return context_data_find_system


def system_to_md(system: dict, verbose: bool = False) -> str:
    """
        reformatting system information dictionary to markdown
    Args:
        system (dict): dictionary representation for system information
        verbose (boolean): verbosity boolean

    Returns:
        markdown representation for system information
    """
    md = ""
    if verbose:
        md += f'#### {system.get("EPOComputerProperties.ComputerName")} \n'
        md += "Attribute|Value\n-|-\n"
        for key in system:
            md += f"{key} | {system[key]}\n"

        md += "---\n"
    else:
        md += "|"
        for key in EPO_SYSTEM_ATTRIBUTE_MAP:
            md += f"{system.get(EPO_SYSTEM_ATTRIBUTE_MAP.get(key))} |"

        md += "\n"
    return md


def systems_to_md(systems: dict, verbose: bool = False) -> str:
    """
        reformatting system information dictionary to markdown
    Args:
        systems (list): list of dictionaries, each dictionary represent a system
        verbose (boolean): verbosity boolean

    Returns:
        markdown representation for systems list
    """
    md = ""
    if verbose:
        for system in systems:
            md += system_to_md(system, verbose)
    else:
        tmp_head = "|"
        tmp_line = "|"
        for key in EPO_SYSTEM_ATTRIBUTE_MAP:
            tmp_head += key + "|"
            tmp_line += "-|"

        md += f"{tmp_head} \n {tmp_line} \n"
        for system in systems:
            md += system_to_md(system, verbose)
    return md


def parse_command_args(command: str, command_args: str) -> dict:
    # commandArgs should be in the format of:  keyName1:keyValue1, keyName2:KeyValue2
    if not command_args:
        return {}

    command_args_dict = {"command": command}
    command_args_list = command_args.split(",")
    key = []
    for arg in command_args_list:
        # commandArgsVal in commandArgsList:
        key = arg.split(":")
        command_args_dict[key[0]] = key[1]
    return command_args_dict


""" COMMAND FUNCTIONS """


def epo_help_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
    Displays a list of all commands and help strings.
    XSOAR Cmd example: !epo-help command=epo.help
    Args:
        client (Client: BaseClient): a utility class used for communicating with ePO Server
        args (dict): a dictionary that store the command argument.

    Returns:
        CommandResults with fancy help command output

    """

    command = args.get("command")
    search = args.get("search")
    prefix = args.get("prefix")

    json_response, raw_response = client.epo_help(command=command, prefix=prefix)

    if "command" in args:
        readable_output = f"#### ePO Help - {args['command']} \n "
        for line in json_response:
            line = line.replace("\r\n", " ")
            line = line.replace("\n", " ")
            readable_output += line
    else:
        if search:
            search = search.lower()
        readable_output = "#### ePO Help\n"
        for line in json_response:
            line = line.replace("\r\n", " ")
            line = line.replace("\n", " ")

            if (not search) or (search in line.lower()):
                desc = ""
                cmd = ""
                if "-" in line:
                    desc = line.split("-")[1] if line.split("-")[1] else "N/A"
                    cmd = line.split("-")[0].rstrip() if line.split("-")[0] else "N/A"
                    readable_output += "- **" + cmd + "** - " + desc + "\n"

    return CommandResults(readable_output=readable_output)


def epo_get_latest_dat_command(client: Client) -> CommandResults:
    """
    get the latest available version of the dat file.
    dat file is the McAfee A/V software definition file.
    XSOAR Cmd example: !epo-get-latest-dat
    Args:
        client (Client: BaseClient): a utility class used for communicating with ePO Server
    Returns:
        CommandResults (dict)
    """

    json_response, raw_response = client.epo_get_latest_dat()

    latest_dat_version = json_response.get("LatestVersion")
    readable_output = f"McAfee ePO Latest DAT file version available is: **{latest_dat_version}**\n"

    return CommandResults(
        readable_output=readable_output,
        outputs_prefix="McAfee.ePO.latestDAT",
        outputs=latest_dat_version,
        raw_response=raw_response,
    )


def epo_get_current_dat_command(client: Client) -> CommandResults:
    """
    return the current installed dat file.
    dat file contains
    XSOAR CMD example: !epo-get-current-dat
    Args:
        client (Client: BaseClient): a utility class used for communicating with ePO Server
    Returns:
        CommandResults
    """
    json_response, raw_response = client.epo_get_current_dat()
    if "productDetectionProductVersion" in json_response[0]:
        current_dat_version = json_response[0]["productDetectionProductVersion"].split(".")[0]
    else:
        raise DemistoException("The installed DAT file version key is missing")

    current_version = {"CurrentVersion": current_dat_version}
    current_dat_version = current_version.get("CurrentVersion")
    readable_output = f"McAfee ePO Current DAT file version in repository is: **{current_dat_version}**\n"

    return CommandResults(
        outputs_prefix="McAfee.ePO.epoDAT",
        outputs=current_dat_version,
        readable_output=readable_output,
        raw_response=raw_response,
    )


def epo_command_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """Executes the ePO command
    XSOAR CMD example: !epo-command command=system.find searchText=10.0.0.1
    headers=EPOBranchNode.AutoID,EPOComputerProperties.ComputerName
        Args: client (Client: BaseClient): a utility class used for communicating with ePO Server
        args (dict): a dictionary that store the command argument.

    Returns:
        CommandResults
    """
    command = args.get("command")
    if not command:
        raise DemistoException("missing argument: **command**")

    resp_type = args.get("resp_type", "json")

    params = {}

    if len(args) > 0:
        for key in args:
            if key in ["command", "headers", "resp_type"]:
                continue
            params[key] = args.get(key)

    response_json, raw_response = client.epo_command(command=command, params=params, resp_type=resp_type)

    if resp_type != "json":
        response_json = raw_response  # type: ignore

    if "headers" in args:
        headers_list = list(args["headers"].split(","))
        md = tableToMarkdown(f'ePO command *{args["command"]}* results:', response_json, headers=headers_list)
    else:
        if isinstance(response_json, dict):
            headers_list = list(response_json.keys())
            md = tableToMarkdown(f'ePO command *{args["command"]}* results:', response_json, headers=headers_list)
        elif isinstance(response_json, str):
            md = f'#### ePO command *{args["command"]} * results:\n  {response_json}'
        elif isinstance(response_json, list) and len(response_json) and isinstance(response_json[0], str):
            headers_list = "output"
            md = tableToMarkdown(f'ePO command *{args["command"]}* results:', response_json, headers_list)
        else:
            try:
                headers_list = list(set().union(*(entry.keys() for entry in response_json)))
                md = tableToMarkdown(f'ePO command *{args["command"]}* results:', response_json, headers_list)
            except Exception:
                md = tableToMarkdown(f'ePO command *{args["command"]}* results:', response_json)

    return CommandResults(raw_response=raw_response, readable_output=md)


def epo_update_client_dat_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """Executes the ePO command
    XSOAR CMD example: !epo-update-client-dat systems=192.168.1
    Args:
        client (Client: BaseClient): a utility class used for communicating with ePO Server
        args (dict): a dictionary that store the command argument.

    Returns:
        CommandResults
    """
    names: str = args.get("systems", str)
    if names is None:
        raise ValueError("Must provide systems")
    client_task_id, client_product_id = client.get_client_task_id_by_name(search_text="VSEContentUpdateDemisto")
    retry_attempts = args.get("retryAttempts", "")
    retry_interval_in_seconds = args.get("retryIntervalInSeconds", "")
    abort_after_minutes = args.get("abortAfterMinutes", "")
    stop_after_minutes = args.get("stopAfterMinutes", "")
    randomization_interval = args.get("randomizationInterval", "")

    json_response, response = client.update_client_dat(
        names,
        client_product_id,
        client_task_id,
        retry_attempts=retry_attempts,
        retry_interval_in_seconds=retry_interval_in_seconds,
        abort_after_minutes=abort_after_minutes,
        stop_after_minutes=stop_after_minutes,
        randomization_interval=randomization_interval,
    )

    md = f"ePO client DAT update task started: {json_response}"
    return CommandResults(raw_response=response, readable_output=md)


def epo_update_repository_command(client: Client) -> CommandResults:
    """
    Triggers a server task in specific ePO servers to retrieve the latest signatures from the update server.

    Args:
         client (Client: BaseClient): a utility class used for communicating with ePO Server
    Returns:
        CommandResults

    """

    source_repo = "McAfeeHttp"
    target_branch = "Current"
    json_response, response = client.update_repository(source_repo, target_branch)

    md = "ePO repository update started.\n"
    md += str(json_response)
    return CommandResults(raw_response=response, readable_output=md)


def epo_get_system_tree_groups_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
        find a group of machine in the epo system tree
        XSOAR CMD example:!epo-get-system-tree-group search="Lost"
    Args:
        client (Client: BaseClient): a utility class used for communicating with ePO Server
        args (dict): a dictionary that store the command argument.
    Returns:
        CommandResults
    """
    search_text = args.get("search")

    json_response, raw_response = client.get_system_tree_groups(search_text=search_text)
    if isinstance(raw_response, str) and len(raw_response) == 0:
        return CommandResults(raw_response=raw_response, readable_output=f"System Tree Group {search_text} was not found.")

    md = "#### ePO System Tree groups\n"
    md += "Group ID | Group path\n-|-\n"
    for entry in json_response:
        md += f'{entry["groupId"]}  | {entry["groupPath"]} \n'

    return CommandResults(
        raw_response=raw_response,
        readable_output=md,
        outputs_prefix="McAfee.ePO.SystemTreeGroups",
        outputs_key_field="groupId",
        outputs=prettify_system_tree(json_response),
    )


def epo_find_systems_command(client: Client, args: dict[str, Any]) -> List[CommandResults]:
    """
        find a group of machine in the epo system tree
        XSOAR CMD Example: !epo-find-systems groupId=2
    Args:
        client (Client: BaseClient): a utility class used for communicating with ePO Server
        args (dict): a dictionary that store the command argument.
    Returns:
        CommandResults
    """
    group_id = arg_to_number(args.get("groupId", str))
    if group_id is None:
        raise ValueError("Must provide groupId")

    verbose = args.get("verbose", "false") == "true"
    name = client.get_system_group_path(group_id)

    if not name:
        raise DemistoException(f"Could not find group with the given group id {group_id}")

    response_json, response = client.find_systems(group_id)

    if response:
        md = "#### Systems in " + name + "\n"
        if len(response_json) > 0:
            md += systems_to_md(response_json, verbose)
            endpoints = prettify_find_system(list(response_json))
            res = [
                CommandResults(
                    raw_response=response,
                    readable_output=md,
                    outputs_prefix="McAfee.ePO.Endpoint",
                    outputs_key_field="IPAddress",
                    outputs=endpoints,
                )
            ]
            count = 0
            for endpoint_info in endpoints:
                endpoint = Common.Endpoint(
                    id=endpoint_info.get(EPO_SYSTEM_ATTRIBUTE_MAP.get("Hostname", str).split(".")[1], ""),
                    hostname=endpoint_info.get(EPO_SYSTEM_ATTRIBUTE_MAP.get("Hostname", str).split(".")[1], ""),
                    ip_address=endpoint_info.get(EPO_SYSTEM_ATTRIBUTE_MAP.get("IPAddress", str).split(".")[1], ""),
                    domain=endpoint_info.get(EPO_SYSTEM_ATTRIBUTE_MAP.get("Domain", str).split(".")[1], ""),
                    os=endpoint_info.get(EPO_SYSTEM_ATTRIBUTE_MAP.get("OS", str).split(".")[1], ""),
                    os_version=endpoint_info.get(EPO_SYSTEM_ATTRIBUTE_MAP.get("OSVersion", str).split(".")[1], ""),
                    processor=endpoint_info.get(EPO_SYSTEM_ATTRIBUTE_MAP.get("Processor", str).split(".")[1], ""),
                    processors=endpoint_info.get(EPO_SYSTEM_ATTRIBUTE_MAP.get("Processors", str).split(".")[1], ""),
                    memory=endpoint_info.get(EPO_SYSTEM_ATTRIBUTE_MAP.get("Memory", str).split(".")[1], ""),
                )

                md = tableToMarkdown(
                    "Endpoint information:", prettify_find_system([response_json[count]], False), removeNull=True
                )
                res.append(CommandResults(readable_output=md, indicator=endpoint))

            return res
        else:
            md += "No systems found\n"
            return [CommandResults(raw_response=response, readable_output=md)]
    else:
        raise DemistoException(f"No systems found. Response: {response}")


def epo_find_system_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
        find a a system in the epo system tree
        XSOAR CMD example: !epo-find-system searchText="TIE"
    Args:
        client (Client: BaseClient): a utility class used for communicating with ePO Server
        args (dict): a dictionary that store the command argument.
    Returns:
        CommandResults
    """

    search_text: str = args.get("searchText", str)
    verbose = args.get("verbose", "false") == "true"

    response_json, response = client.find_system(search_text)

    md = "#### Systems in the System Tree\n"
    if len(response_json) > 0:
        md += systems_to_md(response_json, verbose)
        endpoint_info = prettify_find_system(list(response_json))
        endpoint = Common.Endpoint(
            id=endpoint_info[0].get(EPO_SYSTEM_ATTRIBUTE_MAP.get("Hostname", str).split(".")[1], ""),
            hostname=endpoint_info[0].get(EPO_SYSTEM_ATTRIBUTE_MAP.get("Hostname", str).split(".")[1], ""),
            ip_address=endpoint_info[0].get(EPO_SYSTEM_ATTRIBUTE_MAP.get("IPAddress", str).split(".")[1], ""),
            domain=endpoint_info[0].get(EPO_SYSTEM_ATTRIBUTE_MAP.get("Domain", str).split(".")[1], ""),
            os=endpoint_info[0].get(EPO_SYSTEM_ATTRIBUTE_MAP.get("OS", str).split(".")[1], ""),
            os_version=endpoint_info[0].get(EPO_SYSTEM_ATTRIBUTE_MAP.get("OSVersion", str).split(".")[1], ""),
            processor=endpoint_info[0].get(EPO_SYSTEM_ATTRIBUTE_MAP.get("Processor", str).split(".")[1], ""),
            processors=endpoint_info[0].get(EPO_SYSTEM_ATTRIBUTE_MAP.get("Processors", str).split(".")[1], ""),
            memory=endpoint_info[0].get(EPO_SYSTEM_ATTRIBUTE_MAP.get("Memory", str).split(".")[1], ""),
        )
        return CommandResults(
            raw_response=response,
            readable_output=md,
            outputs_prefix="McAfee.ePO.Endpoint",
            outputs_key_field="IPAddress",
            outputs=prettify_find_system(list(response_json)),
            indicator=endpoint,
        )
    else:
        md += "No systems found\n"
        return CommandResults(raw_response=response, readable_output=md)


def epo_wakeup_agent_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
        wake up agent for a system or list of systems
        XSOAR CMD example:epo-wakeup-agent names="TIE"
    Args:
        client (Client: BaseClient): a utility class used for communicating with ePO Server
        args (dict): a dictionary that store the command argument.
    Returns:
        CommandResults
    """
    names = args.get("names", str)
    response_json, response = client.wakeup_agent(names)
    response_str = json.dumps(response)
    if response_str.find("No systems found") >= 0:
        md = "#### No systems were found."
    else:
        md = "#### ePO agents was awaken.\n"
        pattern_match = re.search(r"completed:\s([-]*\d+)\\nfailed:\s([-]*\d+)\\nexpired:\s([-]*\d+)", response_str)
        if pattern_match:
            md += "| Completed | Failed | Expired |\n"
            md += "|-|-|-|\n"
            for i in pattern_match.groups():
                md += "|" + i
            md += "|"
    return CommandResults(raw_response=response, readable_output=md)


def epo_apply_tag_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
        apply tag to a machine or machines
        XSOAR CMD example: !epo-apply-tag names="TIE" tagName="Server"
    Args:
        client (Client: BaseClient): a utility class used for communicating with ePO Server
        args (dict): a dictionary that store the command argument.
    Returns:
        CommandResults
    """
    names = args.get("names", str)
    tag_name = args.get("tagName", str)

    response_int, response = client.apply_tag(names, tag_name)

    if response_int > 0:
        md = "ePO applied the tags on the hostnames successfully.\n"
    else:
        md = "ePO could not find server or server already assigned to the given tag.\n"

    return CommandResults(raw_response=response, readable_output=md)


def epo_clear_tag_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
        apply tag to a machine or machines
        XSOAR CMD example: !epo-clear-tag names="TIE" tagName="MARSERVER"
    Args:
        client (Client: BaseClient): a utility class used for communicating with ePO Server
        args (dict): a dictionary that store the command argument.
    Returns:
        CommandResults
    """
    names = args.get("names", str)
    tag_name = args.get("tagName", str)

    response_json, response = client.clear_tag(names, tag_name)

    if response_json > 0:
        md = "ePO cleared the tags from the hostnames successfully.\n"
    else:
        md = "ePO could not find server or server already assigned to the given tag.\n"

    return CommandResults(raw_response=response, readable_output=md)


def epo_list_tag_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
        apply tag to a machine or machines
        XSOAR CMD example: !epo-list-tag searchText="server"
    Args:
        client (Client: BaseClient): a utility class used for communicating with ePO Server
        args (dict): a dictionary that store the command argument.
    Returns:
        CommandResults
    """
    search_text = args.get("searchText")

    response_json, response = client.list_tag(search_text=search_text)

    md = tableToMarkdown("ePO Tags", response_json, headers=["tagId", "tagName", "tagNotes"])
    return CommandResults(
        outputs=response_json,
        outputs_prefix="McAfee.ePO.Tags",
        outputs_key_field="tagId",
        raw_response=response,
        readable_output=md,
    )


def epo_get_tables_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
        get table details from ePO
        XSOAR CMD example: !epo-get-tables table="Client Events"
    Args:
        client (Client: BaseClient): a utility class used for communicating with ePO Server
        args (dict): a dictionary that store the command argument.
    Returns:
        CommandResults
    """
    table_name = args.get("table")
    response_json, response = client.get_table(table_name=table_name)

    if type(response_json) is dict:
        headers = list(response_json.keys())
    else:
        headers = list(set().union(*(entry.keys() for entry in response_json)))
    md = tableToMarkdown(
        "ePO tables:",
        response_json,
        headers=headers,
    )
    return CommandResults(raw_response=response, readable_output=md)


def epo_query_table_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
        query table details from ePO
        XSOAR CMD example: !epo-query-table target="FW_Rule"
    Args:
        client (Client: BaseClient): a utility class used for communicating with ePO Server
        args (dict): a dictionary that store the command argument.
    Returns:
        CommandResults
    """

    target = args.get("target")
    select = args.get("select")
    where = args.get("where")
    order = args.get("order")
    group = args.get("group")
    join_tables = args.get("joinTables")
    query_name = args.get("query_name")

    response_json, response = client.query_table(
        target=target, select=select, where=where, order=order, group=group, join_tables=join_tables
    )

    if type(response_json) is dict:
        headers = list(response_json.keys())
    else:
        headers = list(set().union(*(entry.keys() for entry in response_json)))

    if query_name:
        query_title = query_name
    else:
        query_title = target

    md = tableToMarkdown(f"ePO Table Query: {query_title}", response_json, headers)
    prefix = f"McAfee.ePO.Query.{query_title}"
    return CommandResults(raw_response=response, readable_output=md, outputs=response_json, outputs_prefix=prefix)


def epo_get_version_command(client: Client) -> CommandResults:
    """
    Get ePO Server Software Version
    XSOAR CMD Example: !epo-get-version
    Args:
        client (Client: BaseClient): a utility class used for communicating with ePO Server
    Returns:
        CommandResults

    """
    response_json, response = client.get_version()

    readable_output = f"### ePO version is: {response_json}"

    return CommandResults(
        raw_response=response,
        readable_output=readable_output,
        outputs=response_json,
        outputs_prefix="McAfee.ePO.Version",
        outputs_key_field="Version",
    )


def epo_move_system_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
       Moves systems to a specified destination group ID
       XSOAR CMD example: !epo-move-system names="TIE" parentGroupId="3"
    Args:
        client (Client: BaseClient): a utility class used for communicating with ePO Server
        args (dict): a dictionary that store the command argument.
    Returns:
        CommandResults
    """
    names = args.get("names", str)
    parent_group_id = arg_to_number(args.get("parentGroupId"))
    if parent_group_id is None:
        raise ValueError("Must provide parentGroupId")

    json_response, raw_response = client.move_system(names=names, parent_group_id=parent_group_id)

    if json_response:
        response = f"System(s) {names} moved successfully to GroupId {parent_group_id}"
    else:
        response = f"System(s) {names} failed to move to GroupId {parent_group_id}"
    return CommandResults(raw_response=raw_response, readable_output=response)


def epo_advanced_command_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
        Executes the ePO command in advance mode
        XSOAR  CMD example: !epo-advanced-command command="clienttask.find" commandArgs="searchText:On-Demand"
    Args:
        client (Client: BaseClient): a utility class used for communicating with ePO Server
        args (dict): a dictionary that store the command argument.
    Returns:
        CommandResults
    """

    parsed_args = parse_command_args(args["command"], args["commandArgs"])
    return epo_command_command(client, parsed_args)


def epo_find_client_task_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
    find client task
    XSOAR CMD Example: !epo-find-client-task searchText="On-Demand"
    Args:
        client (Client: BaseClient): a utility class used for communicating with ePO Server
        args (dict): a dictionary that store the command argument.
    Returns:
        CommandResults
    """
    search_text = args.get("searchText")

    response_json, response = client.find_client_task(search_text=search_text)
    headers: List[Any] = list(set().union(*(entry.keys() for entry in response_json)))

    md = tableToMarkdown("ePO Client Tasks:", response_json, headers=headers)
    return CommandResults(
        raw_response=response,
        readable_output=md,
        outputs=response_json,
        outputs_prefix="McAfee.ePO.ClientTask",
        outputs_key_field="objectName",
    )


def epo_find_policy_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
    find policy in ePO
    XSOAR CMD Example: !epo-find-policy searchText="On-Access"
    Args:
        client (Client: BaseClient): a utility class used for communicating with ePO Server
        args (dict): a dictionary that store the command argument.
    Returns:
        CommandResults
    """
    search_text = args.get("searchText")

    response_json, response = client.find_policy(search_text=search_text)
    headers: List[Any] = list(set().union(*(entry.keys() for entry in response_json)))

    md = tableToMarkdown("ePO Policies:", response_json, headers=headers, removeNull=True)
    return CommandResults(outputs=response_json, outputs_prefix="McAfee.ePO.Policy", raw_response=response, readable_output=md)


def epo_assign_policy_to_group(client: Client, args: dict[str, Any]) -> CommandResults:
    """
        Assigns policy to the specified group or resets group's inheritance for the specified policy
        XSOAR CMD Example: !epo-assign-policy-to-group groupId="2" productId="ENDP_AM_1000" objectId="130"
    Args:
        client (Client: BaseClient): a utility class used for communicating with ePO Server
        args (dict): a dictionary that store the command argument.
    Returns:
        CommandResults
    """

    group_id = arg_to_number(args.get("groupId", str))
    if group_id is None:
        raise ValueError("Must provide groupId")
    product_id = args.get("productId", str)
    object_id = arg_to_number(args.get("objectId", str))
    if object_id is None:
        raise ValueError("Must provide objectId")
    reset_inheritance = args.get("resetInheritance", "false")

    json_response, raw_response = client.assign_policy_to_group(
        group_id, product_id, object_id, reset_inheritance=reset_inheritance
    )

    if json_response:
        response = f"Policy productId:{product_id} objectId:{object_id} assigned successfully to GroupId {group_id}"
    else:
        response = f"failed to assigned policy productId:{product_id} objectId:{object_id} to GroupId {group_id}"

    return CommandResults(raw_response=raw_response, readable_output=response)


def epo_assign_policy_to_system(client: Client, args: dict[str, Any]) -> CommandResults:
    """
        Assigns policy to a supplied list of systems or resets systems' inheritance for the specified policy
    Args:
        client (Client: BaseClient): a utility class used for communicating with ePO Server
        args (dict): a dictionary that store the command argument.
    Returns:
        CommandResults
    """

    names = args.get("names", str)
    product_id = args.get("productId", str)
    type_id = arg_to_number(args.get("typeId", str))
    if type_id is None:
        raise ValueError("Must provide typeId")
    object_id = arg_to_number(args.get("objectId", str))
    if object_id is None:
        raise ValueError("Must provide objectId")
    reset_inheritance = args.get("resetInheritance", "false")

    response_json, raw_response = client.assign_policy_to_system(
        names, product_id, type_id, object_id, reset_inheritance=reset_inheritance
    )
    headers: List[Any] = list(set().union(*(entry.keys() for entry in response_json)))

    md = tableToMarkdown("ePO Policies:", response_json, headers=headers)

    return CommandResults(raw_response=raw_response, readable_output=md)


def epo_list_issues_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
        list issue in the system
        XSOAR CMD Example: !epo-list-issues
    Args:
        client (Client: BaseClient): a utility class used for communicating with ePO Server
        args (dict): a dictionary that store the command argument.
    Returns:
        CommandResults
    """
    issue_id = args.get("id", "")
    response_json, raw_response = client.list_issue(issue_id)
    if response_json != "<null>":
        if isinstance(response_json, list):
            headers = list(set().union(*(entry.keys() for entry in response_json)))
        else:
            headers = response_json.keys()
        md = tableToMarkdown("ePO Issue List:", response_json, headers=headers)
        return CommandResults(
            raw_response=raw_response,
            outputs=response_json,
            outputs_prefix="McAfee.ePO.Issue",
            readable_output=md,
            outputs_key_field="id",
        )
    else:
        if issue_id:
            md = f"issue with id:{issue_id} is not exists\n"
        else:
            md = "The operation has failed\n"
        return CommandResults(raw_response=raw_response, readable_output=md)


def epo_delete_issue_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
        delete issue from the system
        XSOAR CMD Example: !epo-delete-issue id=8
    Args:
        client (Client: BaseClient): a utility class used for communicating with ePO Server
        args (dict): a dictionary that store the command argument.
    Returns:
        CommandResults
    """
    """
        delete issue in the system
    Args:
        client (Client: BaseClient): a utility class used for communicating with ePO Server
        args (dict): a dictionary that store the command argument.
    Returns:
        CommandResults
    """
    issue_id = args.get("id", str)
    json_response, raw_response = client.delete_issue(issue_id)

    md = f"Issue with id={json_response} was deleted"

    return CommandResults(raw_response=raw_response, readable_output=md)


def epo_update_issue_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
        update issue in the system
        XSOAR CMD Example: !epo-update-issue id="9" name="test issue" desc="update from epo integration"
    Args:
        client (Client: BaseClient): a utility class used for communicating with ePO Server
        args (dict): a dictionary that store the command argument.
    Returns:
        CommandResults
    """
    issue_id = args.get("id", str)
    if issue_id is None:
        raise ValueError("Must provide id")
    issue_name = args.get("name")
    issue_description = args.get("description")
    issue_state = args.get("state")
    issue_priority = args.get("priority")
    issue_severity = args.get("severity")
    issue_resolution = args.get("resolution")
    issue_due = args.get("due")
    issue_assignee_name = args.get("assignee_name")
    issue_ticket_server_name = args.get("ticketServerName")
    issue_ticket_id = args.get("ticketId")
    issue_properties = args.get("properties")
    json_response, raw_response = client.update_issue(
        issue_id,
        issue_name=issue_name,
        issue_description=issue_description,
        issue_state=issue_state,
        issue_priority=issue_priority,
        issue_severity=issue_severity,
        issue_resolution=issue_resolution,
        issue_due=issue_due,
        issue_assignee_name=issue_assignee_name,
        issue_ticket_server_name=issue_ticket_server_name,
        issue_ticket_id=issue_ticket_id,
        issue_properties=issue_properties,
    )
    md = f"Issue with id={json_response} was updated"

    return CommandResults(raw_response=raw_response, readable_output=md)


def epo_create_issue_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
        Create an issue
    Args:
        client (Client: BaseClient): a utility class used for communicating with ePO Server
        args (dict): a dictionary that store the command argument.
    Returns:
        CommandResults
    """
    """
        create issue in the system
    Args:
        client (Client: BaseClient): a utility class used for communicating with ePO Server
        args (dict): a dictionary that store the command argument.
    Returns:
        CommandResults
    """
    issue_name = args.get("name", str)
    if issue_name is None:
        raise ValueError("Must provide name")
    issue_description = args.get("description")
    if issue_description is None:
        raise ValueError("Must provide description")
    issue_state = args.get("state")
    issue_priority = args.get("priority")
    issue_severity = args.get("severity")
    issue_resolution = args.get("resolution")
    issue_due = args.get("due")
    issue_assignee_name = args.get("assignee_name")
    issue_ticket_server_name = args.get("ticketServerName")
    issue_ticket_id = args.get("ticketId")
    issue_properties = args.get("properties")
    response_json, raw_response = client.create_issue(
        issue_name,
        issue_description,
        issue_state=issue_state,
        issue_priority=issue_priority,
        issue_severity=issue_severity,
        issue_resolution=issue_resolution,
        issue_due=issue_due,
        issue_assignee_name=issue_assignee_name,
        issue_ticket_server_name=issue_ticket_server_name,
        issue_ticket_id=issue_ticket_id,
        issue_properties=issue_properties,
    )
    md = f"Issue with the following ID: {response_json} was created successfully"
    outputs = [{"id": response_json, "name": issue_name, "description": issue_description}]

    return CommandResults(
        raw_response=raw_response, readable_output=md, outputs=outputs, outputs_prefix="McAfee.ePO.Issue", outputs_key_field="id"
    )


"""MAIN"""


def main() -> None:
    """
    integration main function where command get executed
    Returns: None
    """

    # get the epo service url
    base_url = urljoin(demisto.params()["address"], "remote/")  # rename to url
    verify_certificate = not demisto.params().get("insecure", False)
    proxy = demisto.params().get("proxy", False)
    demisto.debug(f"****EPO****:Command being called is {demisto.command()}")

    try:
        timeout = int(demisto.params().get("timeout", 120))
    except ValueError as e:
        demisto.debug(f"Failed casting timeout parameter to int, falling back to 120 - {e}")
        timeout = 120

    try:
        headers = {
            "accept": "application/json"  # To do make sure all quotes are single qoute
        }
        client = Client(
            base_url=base_url,
            verify=verify_certificate,
            headers=headers,
            proxy=proxy,
            auth=(
                demisto.params().get("authentication", {}).get("identifier", ""),
                demisto.params().get("authentication", {}).get("password", ""),
            ),
            timeout=timeout,
        )

        args = demisto.args()

        if demisto.command() == "test-module":
            # This is the call made when pressing the integration Test button.
            client.test_module()
            return_results("ok")
        elif demisto.command() == "epo-help":
            return_results(epo_help_command(client, args))
        elif demisto.command() == "epo-get-latest-dat":
            return_results(epo_get_latest_dat_command(client))
        elif demisto.command() == "epo-get-current-dat":
            return_results(epo_get_current_dat_command(client))
        elif demisto.command() == "epo-command":
            return_results(epo_command_command(client, args))
        elif demisto.command() == "epo-update-client-dat":
            return_results(epo_update_client_dat_command(client, args))
        elif demisto.command() == "epo-update-repository":
            return_results(epo_update_repository_command(client))
        elif demisto.command() == "epo-get-system-tree-group":
            return_results(epo_get_system_tree_groups_command(client, args))
        elif demisto.command() == "epo-find-systems":
            return_results(epo_find_systems_command(client, args))
        elif demisto.command() == "epo-find-system":
            return_results(epo_find_system_command(client, args))
        elif demisto.command() == "epo-wakeup-agent":
            return_results(epo_wakeup_agent_command(client, args))
        elif demisto.command() == "epo-apply-tag":
            return_results(epo_apply_tag_command(client, args))
        elif demisto.command() == "epo-clear-tag":
            return_results(epo_clear_tag_command(client, args))
        elif demisto.command() == "epo-list-tag":
            return_results(epo_list_tag_command(client, args))
        elif demisto.command() == "epo-get-tables":
            return_results(epo_get_tables_command(client, args))
        elif demisto.command() == "epo-query-table":
            return_results(epo_query_table_command(client, args))
        elif demisto.command() == "epo-get-version":
            return_results(epo_get_version_command(client))
        elif demisto.command() == "epo-move-system":
            return_results(epo_move_system_command(client, args))
        elif demisto.command() == "epo-advanced-command":
            return_results(epo_advanced_command_command(client, args))
        elif demisto.command() == "epo-find-client-task":
            return_results(epo_find_client_task_command(client, args))
        elif demisto.command() == "epo-find-policy":
            return_results(epo_find_policy_command(client, args))
        elif demisto.command() == "epo-assign-policy-to-group":
            return_results(epo_assign_policy_to_group(client, args))
        elif demisto.command() == "epo-assign-policy-to-system":
            return_results(epo_assign_policy_to_system(client, args))
        elif demisto.command() == "epo-list-issues":
            return_results(epo_list_issues_command(client, args))
        elif demisto.command() == "epo-delete-issue":
            return_results(epo_delete_issue_command(client, args))
        elif demisto.command() == "epo-create-issue":
            return_results(epo_create_issue_command(client, args))
        elif demisto.command() == "epo-update-issue":
            return_results(epo_update_issue_command(client, args))
        else:
            raise NotImplementedError(f'Command "{demisto.command()}" is not implemented.')
    # Log exceptions and return errors
    except Exception as e:
        demisto.error(traceback.format_exc())  # print the traceback
        return_error(f"Failed to execute {demisto.command()} command.\nError:\n{e!s}")


""" ENTRY POINT """

if __name__ in ("__main__", "__builtin__", "builtins"):
    main()