Absolute
Absolute is an adaptive endpoint security solution that delivers device security, data security, and asset management of endpoints.
Endpoint · Absolute
Details
| ID | Absolute |
|---|---|
| Provider | Absolute Software |
| Category | Endpoint |
| From Version | 6.0.0 |
| Docker Image | demisto/auth-utils:1.0.0.10133006 |
| Supported Modules | Agentix XSIAM |
README
Absolute is an adaptive endpoint security solution that delivers device security, data security, and asset management of endpoints.
This integration was integrated and tested with the API version 1.7 of Absolute.
Some changes have been made that might affect your existing content.
If you are upgrading from a previous version of this integration, see Breaking Changes.
Configure Absolute in Cortex
| Parameter | Description | Required |
|---|---|---|
| Your Absolute server URL | True | |
| Token ID | Token ID and Secret Key. | True |
| Secret Key | True | |
| Trust any certificate (not secure) | False | |
| Use system proxy settings | False | |
| Events Fetch Interval | Only in XSIAM | False |
| Max number of events per fetch | Only in XSIAM | False |
| Fetch Events | Only in XSIAM | 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.
absolute-custom-device-field-list
Returns a list of custom device fields associated with the given device_id, based on the authorization token.
Base Command
absolute-custom-device-field-list
Input
| Argument Name | Description | Required |
|---|---|---|
| device_id | The system unique identifier of the device. | Required |
| limit | Maximum number of results to return. Default is 50. | Optional |
| all_results | Whether to retrieve all results or not. Possible values are: true, false. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| Absolute.CustomDeviceField.DeviceUID | String | The system-defined unique identifier of the device. |
| Absolute.CustomDeviceField.CDFValues.CDFUID | String | The unique identifier of the custom device field. |
| Absolute.CustomDeviceField.CDFValues.FieldKey | String | The unique identifier of the custom device field in the classic version of Absolute. |
| Absolute.CustomDeviceField.CDFValues.FieldName | String | The name assigned to the custom device field. |
| Absolute.CustomDeviceField.CDFValues.CategoryCode | String | The type of custom device field. Possible values are: PREDEFINED, ESNCOLUMN, UDF. |
| Absolute.CustomDeviceField.CDFValues.FieldValue | String | The current value of the custom device field. |
| Absolute.CustomDeviceField.CDFValues.Type | String | The data type of the field value. Possible values are: Text, Date, Dropdown. |
Command example
!absolute-custom-device-field-list device_id=1234
Context Example
{
"Absolute": {
"CustomDeviceField": {
"CDFValues": [
{
"CDFUID": "4m9fUCZqTYec1bJgDSNg",
"CategoryCode": "ESNCOLUMN",
"FieldKey": 1,
"FieldName": "Asset Number",
"FieldValue": "aa",
"Type": "Text"
},
{
"CDFUID": "2iS3ryiSvSDsksJ289vtQ",
"CategoryCode": "UDF",
"FieldKey": 30,
"FieldName": "Custom2",
"FieldValue": "TPB",
"Type": "Text"
}
],
"DeviceUID": "1234"
}
}
}
Human Readable Output
Absolute Custom device field list
CDF ID Field Value Filed Name 4m9fUCZqTYec1bJgDSNg Asset Number Asset Number 2iS3ryiSvSDsksJ289vtQ Custom2 Custom2
absolute-custom-device-field-update
Updates the value of the included custom device fields for the given device_id.
Base Command
absolute-custom-device-field-update
Input
| Argument Name | Description | Required |
|---|---|---|
| device_id | The system unique identifier of the device. | Required |
| cdf_uid | The unique identifier of the custom device field. Note: In order to get this value, use the “absolute-custom-device-field-list” command. | Required |
| value | The new value of the custom device field to be set. | Required |
Context Output
There is no context output for this command.
Command example
!absolute-custom-device-field-update device_id=1234 cdf_uid=4m9fUCZqTYec1bJgDSNg value="test2"
Human Readable Output
Device 1234 with value test2 was updated successfully.
absolute-device-freeze-request
Creates a new Freeze request for the devices specified in the device_ids argument.
Base Command
absolute-device-freeze-request
Input
| Argument Name | Description | Required |
|---|---|---|
| device_ids | A comma-separated list of the unique identifiers of devices included in the request. The recommendation is to use up to 10,000 devices per request. | Required |
| request_name | The user-defined name for the Freeze request. The name should be a non-unique string and has 1-250 characters. | Required |
| html_message | The user-defined, HTML coded message shown on devices when the Freeze is applied. The message should be in a non-unique HTML format and has 1-4000 characters. | Required |
| message_name | The user-defined name for the Freeze message. | Required |
| device_freeze_type | The type of Freeze. You cannot freeze a device that has been reported Stolen in the Absolute console. - OnDemand: Freezes a device on its next connection to the Absolute Monitoring Center, which is typically within 15 minutes. This applies for all supported operating systems. - Scheduled: Freezes a device on its next connection to the Absolute Monitoring Center on or after a specified date and time. This applies to Windows and Mac devices. The scheduled freeze date is specified in the scheduled_freeze_date argument. Scheduled Freeze requests are only supported on Windows and Mac devices with an active Absolute agent that is regularly connecting to the Absolute Monitoring Center. - Offline: Freezes a device if it has been offline for a specified period of time. Applies to Windows and Mac devices. Offline period is specified in the offline_time_seconds arguments. Offline freeze is not available if your Absolute account has been migrated to Offline Freeze Rules. For more information, see the console Help. Possible values are: OnDemand, Scheduled, Offline. |
Required |
| scheduled_freeze_date | The date and time (in UTC) when the device should be frozen in ISO 8601 format: YYYY-MM-DDThh:mm:ss.SSSZ. Required if device_freeze_type is Scheduled. For example, 2022-01-01T00:00:00.000Z. | Optional |
| offline_time_seconds | The length of time (in seconds) that a device can be offline before the device is frozen. Required if device_freeze_type is Offline. Must be between 1200 seconds (20 minutes) and 172800000 seconds (2000 days). Default value is 30 days. Default is 22592000. | Optional |
| passcode_type | The type of passcode to unfreeze a device. - UserDefined: Manually set the passcode in passcode. You must specify the passcode argument. - RandomForEach: A unique passcode is randomly generated for each device. You must specify the passcode_length argument. - RandomForAll: A passcode is randomly generated and is the same for all devices. You must specify the passcode_length argument. Possible values are: UserDefined, RandomForEach, RandomForAll. |
Required |
| passcode | The passcode used to unfreeze the devices. Required if passcode_type is UserDefined. A valid passcode is a number that has 4-8 characters. For example, 12345678. | Optional |
| passcode_length | The length of the passcode when it is randomly generated. Required if passcode_type is RandomForEach or RandomForAll. A valid passcode is a number from 4-8. For example, 8. | Optional |
| notification_emails | A comma-separated list of user-entered email addresses that will receive an email notification when the status of the Freeze request changes. The API supports up to 10 email addresses. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| Absolute.FreezeRequest.RequestUID | String | The system-defined, unique identifier of the Freeze request. |
| Absolute.FreezeRequest.SucceededDeviceUIDs | Unknown | An array of the unique devices identifiers that succeeded in creating a Freeze request. |
| Absolute.FreezeRequest.Errors.detail.deviceUids | Unknown | An array of the unique identifiers of devices for the Freeze request error. |
| Absolute.FreezeRequest.Errors.message | String | The reason for the Freeze failure. |
| Absolute.FreezeRequest.Errors.messageKey | String | The reference key for the error message. |
Command example
!absolute-device-freeze-request device_ids=123456 device_freeze_type=Scheduled html_message="test" message_name="new name" request_name="name1" scheduled_freeze_date=2022-04-03T13:30:00.000Z passcode_type=RandomForEach passcode_length=5
Context Example
{
"Absolute": {
"FreezeRequest": {
"RequestUID": "2b62b290-d590-4237-8ba0-57e4779b9f1c",
"SucceededDeviceUIDs": [
"123456"
]
}
}
}
Human Readable Output
Absolute device freeze requests results
RequestUID SucceededDeviceUIDs 2b62b290-d590-4237-8ba0-57e4779b9f1c 123456
absolute-device-remove-freeze-request
Creates a new Remove Freeze request for one or more devices, regardless of their Freeze status. You can submit Remove Freeze requests to perform the following actions: unfreeze frozen devices, remove newly submitted Freeze requests, or remove outstanding Scheduled and Offline Freeze requests. In case of removing from offline: In addition to creating a Remove Freeze request for devices with a status of Frozen by Condition: Offline, removes Offline Freeze requests from devices with a status of Freeze Requested or Freeze Condition - Offline Set. In case of not removing from offline: a Remove Freeze request is created for the devices but the Conditional - Offline Freeze request is not deleted (deprecated).
Base Command
absolute-device-remove-freeze-request
Input
| Argument Name | Description | Required |
|---|---|---|
| device_ids | A comma-separated list of the unique identifiers of devices included in the request. The recommendation is to use up to 10,000 devices per request. | Required |
| remove_scheduled | Whether to remove only a Scheduled Freeze request. Note: When setting to true, if the Freeze request is a Scheduled Freeze request, the Freeze request is removed. Otherwise, when setting to false, if the Freeze request is not a Scheduled Freeze request, the Freeze request is not removed. Possible values are: true, false. | Optional |
| remove_offline | Whether to remove only an Offline Freeze request. Note: When setting to true, if the Freeze request is an Offline Freeze request, the Freeze request is removed. Otherwise, when setting to false, if the Freeze request is not a Offline Freeze request, the Freeze request is not removed. Possible values are: true, false. | Optional |
Context Output
There is no context output for this command.
Command example
!absolute-device-remove-freeze-request device_ids=123456 remove_scheduled=true
Human Readable Output
Successfully removed freeze request for devices ids: 123456.
absolute-device-freeze-request-get
Gets detailed information about the Freeze request specified by request_uid.
Base Command
absolute-device-freeze-request-get
Input
| Argument Name | Description | Required |
|---|---|---|
| request_uid | The system-defined, unique identifier of the Freeze request. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| Absolute.FreezeRequestDetail.ID | String | The system-defined, unique identifier of the Freeze request. |
| Absolute.FreezeRequestDetail.AccountUid | String | The system-defined, unique identifier associated with this Absolute account. |
| Absolute.FreezeRequestDetail.ActionRequestUid | String | The system-defined, unique identifier of the Freeze request (the same as ID). |
| Absolute.FreezeRequestDetail.DeviceUid | String | The system-defined, unique identifier of the device. |
| Absolute.FreezeRequestDetail.Statuses.actionUid | String | The system-defined, unique identifier of the Freeze action. |
| Absolute.FreezeRequestDetail.Statuses.messageKey | String | The reference key for the error message or the info message. Error messages start with ‘dds’. Info messages start with ‘ddsui’. |
| Absolute.FreezeRequestDetail.Statuses.messageParams | Unknown | A list of strings describing the error message when the status is LaunchFailed. If the status isn’t LaunchFailed, messageParams is empty. |
| Absolute.FreezeRequestDetail.Statuses.message | String | The message for the status change that occurred. |
| Absolute.FreezeRequestDetail.Statuses.updatedBy | String | The last entity to update the Freeze request. |
| Absolute.FreezeRequestDetail.Statuses.updatedDateTimeUtc | Date | The time (in Unix epoch) when the Freeze request was last updated. |
| Absolute.FreezeRequestDetail.Statuses.triggerActionUid | String | The system-defined, unique identifier of a new Freeze request that replaces another Freeze request of the same type. |
| Absolute.FreezeRequestDetail.Statuses.eventType | String | Device freeze type event. |
| Absolute.FreezeRequestDetail.Statuses.ackClientTS | Number | The acknowledgment timestamp (in UNIX epoch local time) when the request was downloaded on the device. |
| Absolute.FreezeRequestDetail.Statuses.ackClientDateTimeUtc | Number | The acknowledgment timestamp (in UNIX epoch UTC) when the request was downloaded to the device. |
| Absolute.FreezeRequestDetail.Statuses.instruction | String | All action instructions which are sent from the device DFZ agent component. |
| Absolute.FreezeRequestDetail.Statuses.scheduledFreezeDateTimeUtc | Number | The date and time (in Unix epoch) when a Scheduled Freeze request was scheduled to be performed. |
| Absolute.FreezeRequestDetail.Configuration.messageName | String | The user-defined name for the Freeze message. |
| Absolute.FreezeRequestDetail.Configuration.htmlClear | String | The user-defined, HTML coded message shown on the device when the Freeze is applied (the same as Configuration.freezeMessage except it contains the HTML tags). |
| Absolute.FreezeRequestDetail.Configuration.passcodeClear | String | The passcode that can be used to unfreeze the device. |
| Absolute.FreezeRequestDetail.Configuration.passcodeOption | String | The type of passcode to unfreeze a device. |
| Absolute.FreezeRequestDetail.Configuration.freezeMessage | String | The content of the Freeze message without the HTML tags. |
| Absolute.FreezeRequestDetail.Configuration.freezeId | String | The user-friendly identifier of the request that is displayed in the event history in the Absolute console (same as EventHistoryId). |
| Absolute.FreezeRequestDetail.Configuration.configurationUid | String | The system-defined unique identifier assigned to the Freeze configuration. |
| Absolute.FreezeRequestDetail.Configuration.action | String | The type of action being performed on the device. |
| Absolute.FreezeRequestDetail.Configuration.type | String | The type of Freeze. |
| Absolute.FreezeRequestDetail.Configuration.passcodeLength | Number | The length of the device unfreeze passcode when it is randomly generated. |
| Absolute.FreezeRequestDetail.Configuration.passcodeSalt | String | The salt used for hashing the passcode before the passcode is sent to the device. |
| Absolute.FreezeRequestDetail.Configuration.passcodeHashed | String | The hashed value of the passcode. |
| Absolute.FreezeRequestDetail.Configuration.html | String | The encoded value of Configuration.htmlClear. |
| Absolute.FreezeRequestDetail.Configuration.disableRemoteLogin | Boolean | Whether remote login is disabled on the device. |
| Absolute.FreezeRequestDetail.Configuration.disableFileSharing | Boolean | Whether file sharing is disabled on the device. |
| Absolute.FreezeRequestDetail.Configuration.Conditions.secondsUntilFreeze | Number | The amount of time (in seconds) a device can be offline before the device is frozen. |
| Absolute.FreezeRequestDetail.Configuration.Conditions.scheduledFreezeDate | Date | The date and time (in UTC) when a Scheduled Freeze request is scheduled to be performed. |
| Absolute.FreezeRequestDetail.Configuration.issuedDateTimeUTC | Date | The date and time (in UNIX epoch) when the Freeze request was created. |
| Absolute.FreezeRequestDetail.Configuration.preLoginEnabled | Boolean | Whether pre-login is enabled on the device. |
| Absolute.FreezeRequestDetail.Configuration.serviceControlList | String | List of service controls that the server sends to the device. |
| Absolute.FreezeRequestDetail.Name | String | The user-defined name for the Freeze request. |
| Absolute.FreezeRequestDetail.Requester | String | The user ID of the entity that created the Freeze request. |
| Absolute.FreezeRequestDetail.CreatedUTC | Date | The date and time (in UNIX epoch) when the Freeze request was created. |
| Absolute.FreezeRequestDetail.ChangedUTC | Date | The date and time (in UNIX epoch) when the Freeze request was last modified. |
| Absolute.FreezeRequestDetail.NotificationEmails | Unknown | An array of user-entered email addresses that will receive an email notification when the status of the Freeze request changes. Supports up to 10 email addresses. |
| Absolute.FreezeRequestDetail.EventHistoryId | String | The user-friendly identifier of the request that is displayed in the event history in the Absolute console (same as freezeId). |
| Absolute.FreezeRequestDetail.PolicyGroupUid | String | The system-defined unique identifier of the policy group that the device belongs to. |
| Absolute.FreezeRequestDetail.PolicyConfigurationVersion | Number | The version of the configuration for the policy. |
| Absolute.FreezeRequestDetail.FreezePolicyUid | String | The unique identifier of the Freeze policy. |
| Absolute.FreezeRequestDetail.Downloaded | Boolean | Whether the Freeze request has been downloaded to the device. |
| Absolute.FreezeRequestDetail.IsCurrent | Boolean | Internal flag. |
Command example
!absolute-device-freeze-request-get request_uid=c638c2dc-1dd1-4cfa-8708-46f368012398
Context Example
{
"Absolute": {
"FreezeRequestDetail": {
"AccountUid": "accountID",
"ActionRequestUid": "c638c2dc-1dd1-4cfa-8708-46f368012398",
"ChangedBy": null,
"ChangedUTC": "2022-03-29T10:30:55.462+00:00",
"Configuration": {
"action": "DFZ",
"conditions": [
{
"scheduledFreezeDate": "2022-03-29T10:30:22.000+00:00"
}
],
"configurationUid": "c61b0cb7-3846-4d1e-9e78-641084b7747a",
"disableFileSharing": true,
"disableRemoteLogin": true,
"forceReboot": false,
"freezeId": "DeviceFreeze-0010",
"freezeMessage": "test",
"htmlClear": "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"></head><body><p style=\"font-size: small\">DeviceFreeze-0010</p><hr>test</body></html>",
"issuedUTC": "2022-03-29T10:30:24.268+00:00",
"messageName": "new name",
"passcodeClear": "26148",
"passcodeHashed": "c5pr+oaojn37SFZJ3uokRe0Uy/+kAhzPNv6TyrCzXOdL1vu/KyoFF7T6rQfLK6ej2jYWXPGRzxWCfrS9f/S8JA==",
"passcodeLength": 5,
"passcodeOption": "RandomForEach",
"passcodeSalt": "/4VA8uE3DUv04mWy9iGkZp5rL3zDwtEP/YsqAvL190VIn9bhPZUzYXozoSSEPro0tVSVMtG9Rfssqpy2yvsm6g==",
"preLoginEnabled": true,
"type": "Scheduled"
},
"Content": null,
"CreatedBy": null,
"CreatedUTC": "2022-03-29T10:30:24.279+00:00",
"DeviceUid": "123456",
"Downloaded": false,
"EventHistoryId": "DeviceFreeze-0010",
"FreezePolicyUid": null,
"ID": "fa72b6ed-62f4-40bd-b581-ef5c114efb8e",
"IsCurrent": false,
"Name": "name1",
"NotificationEmails": [],
"PolicyConfigurationVersion": 0,
"PolicyGroupUid": null,
"Requester": "example@test.com",
"RequesterUid": "778f8cce-8cc6-4de1-b025-e0538f97e072",
"Statuses": [
{
"ackClientTS": 0,
"ackClientUTC": 1,
"eventType": "Remove",
"scheduledFreezeDateUTC": 0,
"status": "Removed",
"statusUid": "9e413f56-8b2d-4605-9527-536427b9ad02",
"updatedBy": "example@test.com",
"updatedUTC": "2022-03-29T10:30:55.462+00:00"
},
{
"ackClientTS": 0,
"ackClientUTC": 0,
"scheduledFreezeDateUTC": 0,
"status": "FreezeRequested",
"updatedBy": "example@test.com",
"updatedUTC": "2022-03-29T10:30:24.268+00:00"
}
]
}
}
}
Human Readable Output
Absolute Freeze request details for: c638c2dc-1dd1-4cfa-8708-46f368012398
ID Name AccountUid ActionRequestUid EventHistoryId CreatedUTC ChangedUTC Requester fa72b6ed-62f4-40bd-b581-ef5c114efb8e name1 accountID c638c2dc-1dd1-4cfa-8708-46f368012398 DeviceFreeze-0010 2022-03-29T10:30:24.279+00:00 2022-03-29T10:30:55.462+00:00 example@test.com
absolute-device-freeze-message-list
Gets all the Freeze messages that are configured for the account by the given message_id. If message_id is not given all the messages will be returned.
Base Command
absolute-device-freeze-message-list
Input
| Argument Name | Description | Required |
|---|---|---|
| message_id | The system-defined, unique identifier of the Freeze message. | Optional |
| limit | Maximum number of results to return. Default is 50. | Optional |
| page | The page number of the results to retrieve. Default is 0. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| Absolute.FreezeMessage.ID | String | The system-defined, unique identifier of the Freeze message. |
| Absolute.FreezeMessage.Name | String | The user-defined name for the Freeze message. |
| Absolute.FreezeMessage.Content | String | The user-defined, HTML coded message that shows on a device when a Freeze is applied. |
| Absolute.FreezeMessage.CreatedBy | String | The username of the entity that created the Freeze message. |
| Absolute.FreezeMessage.ChangedBy | String | The username of the entity that last updated the Freeze message. |
| Absolute.FreezeMessage.CreatedUTC | String | The date and time when the Freeze message was created. |
| Absolute.FreezeMessage.ChangedUTC | String | The date and time when the Freeze message was last modified. |
Command example
Human Readable Output
Absolute Device freeze message details
ID Name CreatedUTC ChangedUTC ChangedBy CreatedBy 711b5da9-3867-473f-9d8f-9aba3de42b7a name 2022-04-03T07:45:01.487+00:00 2022-04-03T07:45:01.487+00:00 778f8cce-8cc6-4de1-b025-e0538f97e072 example@test.com
absolute-device-freeze-message-create
Creates a new Freeze message for the account.
Base Command
absolute-device-freeze-message-create
Input
| Argument Name | Description | Required |
|---|---|---|
| html_message | The user-defined, HTML coded message that shows on a device when a Device Freeze is applied. Should be in HTML format with 1-4000 characters. | Required |
| message_name | The user-defined name for the Device Freeze message. The name should be a string with 1-255 characters. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| Absolute.FreezeMessage.ID | String | The system-defined, unique identifier of the Freeze message. |
Command example
!absolute-device-freeze-message-create html_message="some text" message_name="name name"
Context Example
{
"Absolute": {
"FreezeMessage": {
"ID": "bdaf3a55-411a-4393-a0bf-7340f38fbc68"
}
}
}
Human Readable Output
Absolute New freeze message was created with ID: bdaf3a55-411a-4393-a0bf-7340f38fbc68
absolute-device-freeze-message-update
Updates the content of an existing Freeze message.
Base Command
absolute-device-freeze-message-update
Input
| Argument Name | Description | Required |
|---|---|---|
| html_message | The user-defined, HTML coded message that shows on a device when a Device Freeze is applied. Should be in HTML format with 1-4000 characters. | Required |
| message_name | The user-defined name for the Device Freeze message. The name should be a string with 1-255 characters. | Required |
| message_id | The system-defined, unique identifier of the Freeze message. | Required |
Context Output
There is no context output for this command.
Command example
!absolute-device-freeze-message-update html_message="new mesg" message_id=711b5da9-3867-473f-9d8f-9aba3de42b7a message_name="name-new"
Human Readable Output
Absolute Freeze message: 711b5da9-3867-473f-9d8f-9aba3de42b7a was updated successfully
absolute-device-freeze-message-delete
Deletes an existing Freeze message for the account.
Base Command
absolute-device-freeze-message-delete
Input
| Argument Name | Description | Required |
|---|---|---|
| message_id | The system-defined, unique identifier of the Freeze message. | Required |
Context Output
There is no context output for this command.
Command example
!absolute-device-freeze-message-delete message_id="711b5da9-3867-473f-9d8f-9aba3de42b7a"
Human Readable Output
Absolute Freeze message: 711b5da9-3867-473f-9d8f-9aba3de42b7a was deleted successfully
absolute-device-unenroll
Initiates an unenroll request on a list of eligible devices.
Base Command
absolute-device-unenroll
Input
| Argument Name | Description | Required |
|---|---|---|
| device_ids | A comma-separated list of device UIDs that should be unenrolled. | Required |
| exclude_missing_devices | Whether to exclude missing devices or not. Possible values are: true, false. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| Absolute.DeviceUnenroll.TotalDevices | String | The total number of devices in the request. |
| Absolute.DeviceUnenroll.Pending | Number | The number of pending devices. |
| Absolute.DeviceUnenroll.Processing | Number | The number of processing devices. |
| Absolute.DeviceUnenroll.Completed | Number | The number of completed device unenroll. |
| Absolute.DeviceUnenroll.Canceled | Number | The number of canceled device unenroll. |
| Absolute.DeviceUnenroll.Failed | Number | The number of failed device unenroll. |
| Absolute.DeviceUnenroll.RequestId | String | The unique ID identifier of the request. |
| Absolute.DeviceUnenroll.RequestUid | String | The unique GUID identifier of the request. |
| Absolute.DeviceUnenroll.RequestStatus | String | The status of the request. |
| Absolute.DeviceUnenroll.UpdatedDateTimeUtc | Date | The time (in Unix epoch) when the request was last updated. |
| Absolute.DeviceUnenroll.CreatedDateTimeUtc | Date | The time (in Unix epoch) when the request was created. |
| Absolute.DeviceUnenroll.Requester | String | The requester of the request. |
| Absolute.DeviceUnenroll.ExcludeMissingDevices | Boolean | Whether the request includes missing devices or not. |
| Absolute.DeviceUnenroll.Devices.DeviceUid | String | The unique GUID identifier of the device. |
| Absolute.DeviceUnenroll.Devices.ActionUid | String | The unique GUID identifier of the action. |
| Absolute.DeviceUnenroll.Devices.RequestUid | String | The unique GUID identifier of the request. |
| Absolute.DeviceUnenroll.Devices.DeviceName | String | The unique device name of the device. |
| Absolute.DeviceUnenroll.Devices.ActionStatus | String | The status of the action. |
| Absolute.DeviceUnenroll.Devices.ESN | String | The unique Electronic SerialNumber (ESN) that is assigned to the agent installed on the device. |
| Absolute.DeviceUnenroll.Devices.UpdatedDateTimeUtc | Date | The time (in Unix epoch) when the request was last updated. |
| Absolute.DeviceUnenroll.Devices.CreatedDateTimeUtc | Date | The time (in Unix epoch) when the request was created. |
Command example
!absolute-device-unenroll device_ids="1"
Context Example
{
"Absolute": {
"DeviceUnenroll": [
{
"DeviceUid": "1",
"ESN": "2BU2PJD28VAA1UYL0008",
"EligibleStatus": 0,
"Serial": "CNF83051BN",
"SystemName": "user1",
"Username": "example@test.com"
},
{
"DeviceUid": "2",
"ESN": "2BU2PJ545L0008",
"EligibleStatus": 1,
"Serial": "CNF43051BN",
"SystemName": "user2",
"Username": "example2@test.com"
}
]
}
}
Human Readable Output
Absolute unenroll devices
DeviceUid ESN EligibleStatus Serial SystemName Username 1 2BU2PJD28VAA1UYL0008 0 CNF83051BN user1 example@test.com 2 2BU2PJ545L0008 1 CNF43051BN user2 example2@test.com
absolute-device-application-list
Gets a list of device records and the corresponding software application data for each device on the account that you have access to or that meets the given filter.
Base Command
absolute-device-application-list
Input
| Argument Name | Description | Required |
|---|---|---|
| filter | The query by which to filter the device applications. If this argument is set, it overrides the others. For example, appName eq ‘someName’ or availableVirtualMemoryBytes lt 1073741824. | Optional |
| return_fields | A comma-separated list of all specific values to return. If not set, all possible values will be returned. | Optional |
| device_ids | A comma-separated list of the system-defined unique identifier of the devices. | Optional |
| device_names | A comma-separated list of the devices names. | Optional |
| app_names | A comma-separated list of the application names. | Optional |
| app_publishers | A comma-separated list of the name of the software publishers of the application. | Optional |
| user_names | A comma-separated list of the user names of the users logged in to the device. | Optional |
| os | A comma-separated list of the operating systems that are installed on the device. | Optional |
| esn | A comma-separated list of the system-defined unique Electronic Serial Numbers (ESN) assigned to the Absolute agent installed on the device. | Optional |
| limit | Maximum number of results to return. Default is 50. | Optional |
| page | The page number of the results to retrieve. Minimum value is 0. Default is 0. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| Absolute.DeviceApplication.DeviceAppId | String | The unique ID of the application. |
| Absolute.DeviceApplication.DeviceUid | String | The system-defined unique identifier of the device. |
| Absolute.DeviceApplication.AppId | String | The identifier of the application. |
| Absolute.DeviceApplication.AppName | String | The name of the application. |
| Absolute.DeviceApplication.AppPublisher | String | The name of the software publisher of the application. |
| Absolute.DeviceApplication.AppOriginalPublisher | String | The original name of the software publisher of the application. |
| Absolute.DeviceApplication.AppVersion | String | The version of the application. |
| Absolute.DeviceApplication.Ens | String | The system-defined unique Electronic Serial Number (ESN) assigned to the Absolute agent installed on the device. |
| Absolute.DeviceApplication.DeviceName | String | The name of the device. |
| Absolute.DeviceApplication.DeviceSerialNumber | String | The identification number that is assigned to the device by the device manufacturer. |
| Absolute.DeviceApplication.UserName | String | Includes the device name and the username of the user logged in to the device at the time of the agent call. |
| Absolute.DeviceApplication.InstallPath | String | The location where the application is installed. |
| Absolute.DeviceApplication.InstallDate | Date | The date (in UNIX epoch time) when the application was installed. |
| Absolute.DeviceApplication.FirstDetectUtc | Date | The date and time (in Unix epoch time) when the indicated version of the application was first detected on the device. |
| Absolute.DeviceApplication.OsName | String | The operating system that is installed on the device. |
| Absolute.DeviceApplication.LastScanTimeUtc | Date | The date and time (in Unix epoch time) of the most recent installed software (SNG) scan. |
Command example
!absolute-device-application-list device_ids=1234 filter="appName eq 'Notepad++' or appName eq 'Settings'"
Context Example
{
"Absolute": {
"DeviceApplication": [
{
"AccountUid": "accountID",
"AppId": "U2V0dGluZ3N8fE1pY3Jvc29mdHx8MTAuMC4yLjEwMDA=",
"AppName": "Settings",
"AppOriginalName": "Settings",
"AppOriginalPublisher": "Microsoft Corporation",
"AppOriginalVersion": "10.0.2.1000",
"AppPublisher": "Microsoft",
"AppVersion": "10.0.2.1000",
"DeviceAppId": "123456_24222cfe5ccbe45e6d5a78faa58cd977921b4c1dd552884ec38653934c3b75f9",
"DeviceName": "ABSOLUTE-ASSET-",
"DeviceSerialNumber": "GoogleCloud-B8736A4405BF0E968020BCBC46EDA096",
"DeviceUid": "123456",
"Esn": "D0001",
"FirstDetectUtc": 1648601001193,
"InstallDate": 1536995941018,
"InstallPath": "C:\\Windows\\ImmersiveControlPanel",
"LastScanTimeUtc": 1648627356120,
"OsName": "Microsoft Windows Server 2019 Datacenter"
},
{
"AccountUid": "accountID",
"AppId": "Tm90ZXBhZCsrfHxOb3RlUGFkfHw4LjMuMw==",
"AppName": "Notepad++",
"AppOriginalName": "Notepad++ (64-bit x64)",
"AppOriginalPublisher": "Notepad++ Team",
"AppOriginalVersion": "8.3.3",
"AppPublisher": "NotePad",
"AppVersion": "8.3.3",
"DeviceAppId": "1234_3653d2a872cd1208dfc4845a20670a6c9364a626cd6c987cd5e916ca71f38105",
"DeviceName": "ABSOLUTE-ASSET-",
"DeviceSerialNumber": "GoogleCloud-6420CF930DEE84DE8497CF40F0D56AFA",
"DeviceUid": "1234",
"Esn": "D0004",
"FirstDetectUtc": 1648027180153,
"InstallDate": 1648026266334,
"InstallPath": "C:\\Program Files\\Notepad++",
"LastScanTimeUtc": 1648894013571,
"OsName": "Microsoft Windows Server 2022 Datacenter"
},
{
"AccountUid": "accountID",
"AppId": "U2V0dGluZ3N8fE1pY3Jvc29mdHx8MTAuMC40LjEwMDA=",
"AppName": "Settings",
"AppOriginalName": "Settings",
"AppOriginalPublisher": "Microsoft Corporation",
"AppOriginalVersion": "10.0.4.1000",
"AppPublisher": "Microsoft",
"AppVersion": "10.0.4.1000",
"DeviceAppId": "1234_f3ef442d95c3b7155fe9b138384bda2219afb3048c2a9466f1174fc1488ca671",
"DeviceName": "ABSOLUTE-ASSET-",
"DeviceSerialNumber": "GoogleCloud-6420CF930DEE84DE8497CF40F0D56AFA",
"DeviceUid": "1234",
"Esn": "D0004",
"FirstDetectUtc": 1648027180153,
"InstallDate": 1620462024187,
"InstallPath": "C:\\Windows\\ImmersiveControlPanel",
"LastScanTimeUtc": 1648894013571,
"OsName": "Microsoft Windows Server 2022 Datacenter"
}
]
}
}
Human Readable Output
Absolute device applications list
|AccountUid|AppId|AppName|AppOriginalName|AppOriginalPublisher|AppOriginalVersion|AppPublisher|AppVersion|DeviceAppId|DeviceName|DeviceSerialNumber|DeviceUid|Esn|FirstDetectUtc|InstallDate|InstallPath|LastScanTimeUtc|OsName|
|—|—|—|—|—|—|—|—|—|—|—|—|—|—|—|—|—|—|
| accountID | U2V0dGluZ3N8fE1pY3Jvc29mdHx8MTAuMC4yLjEwMDA= | Settings | Settings | Microsoft Corporation | 10.0.2.1000 | Microsoft | 10.0.2.1000 | 123456_24222cfe5ccbe45e6d5a78faa58cd977921b4c1dd552884ec38653934c3b75f9 | ABSOLUTE-ASSET- | GoogleCloud-B8736A4405BF0E968020BCBC46EDA096 | 123456 | D0001 | 1648601001193 | 1536995941018 | C:\Windows\ImmersiveControlPanel | 1648627356120 | Microsoft Windows Server 2019 Datacenter |
| accountID | Tm90ZXBhZCsrfHxOb3RlUGFkfHw4LjMuMw== | Notepad++ | Notepad++ (64-bit x64) | Notepad++ Team | 8.3.3 | NotePad | 8.3.3 | 1234_3653d2a872cd1208dfc4845a20670a6c9364a626cd6c987cd5e916ca71f38105 | ABSOLUTE-ASSET- | GoogleCloud-6420CF930DEE84DE8497CF40F0D56AFA | 1234 | D0004 | 1648027180153 | 1648026266334 | C:\Program Files\Notepad++ | 1648894013571 | Microsoft Windows Server 2022 Datacenter |
| accountID | U2V0dGluZ3N8fE1pY3Jvc29mdHx8MTAuMC40LjEwMDA= | Settings | Settings | Microsoft Corporation | 10.0.4.1000 | Microsoft | 10.0.4.1000 | 1234_f3ef442d95c3b7155fe9b138384bda2219afb3048c2a9466f1174fc1488ca671 | ABSOLUTE-ASSET- | GoogleCloud-6420CF930DEE84DE8497CF40F0D56AFA | 1234 | D0004 | 1648027180153 | 1620462024187 | C:\Windows\ImmersiveControlPanel | 1648894013571 | Microsoft Windows Server 2022 Datacenter |
Above results are with page number: 0 and with size: 50.
absolute-device-list
Gets a list of device records and their corresponding data that meets the required filter for all devices in your account, based on your authorization token.
Base Command
absolute-device-list
Input
| Argument Name | Description | Required |
|---|---|---|
| filter | The query by which to filter all the devices managed by the account. If this argument is set, it overrides the others. For example, agentStatus eq ‘A’ or lastConnectedUtc lt datetime’2021-01-01T00:00:00Z’. | Optional |
| agent_status | The status of the Absolute agent on the device. Possible values are: Active, Disabled, Inactive. | Optional |
| os_name | Short description of the operating system expressed as a one-line string that includes the version of the operating system. | Optional |
| os_version | The version of the operating system. | Optional |
| manufacturer | The manufacturer of the device. | Optional |
| model | The product name from the manufacturer. | Optional |
| user_names | A comma-separated list of the usernames of the users who were logged in to the device at the time of the most recent agent call. If no user was logged in during the last agent call, the last detected username is used. | Optional |
| limit | Maximum number of results to return. Default is 50. | Optional |
| page | The page number of the results to retrieve. Minimum value is 0. Default is 0. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| Absolute.Device.Id | String | The unique identifier assigned to the device. |
| Absolute.Device.Esn | String | The unique ESN (Absolute Identifier) assigned to the agent installed on the device. |
| Absolute.Device.LastConnectedUtc | Number | The date and time (in Unix epoch) when the device last connected to the Absolute Monitoring Center. |
| Absolute.Device.SystemName | String | The name assigned to the device. |
| Absolute.Device.FullSystemName | String | The full name assigned to the device consisting of the system name and the domain name. |
| Absolute.Device.AgentStatus | String | The status of the Absolute agent on the device. |
| Absolute.Device.osName | String | Short description of the operating system expressed as a one-line string that includes the version of the operating system. |
| Absolute.Device.SystemManufacturer | String | The manufacturer of the device. |
| Absolute.Device.SystemModel | String | The product name from the manufacturer. |
| Absolute.Device.SystemType | String | The system running on the Windows-based computer. |
| Absolute.Device.Serial | String | The manufacturer-defined unique identifier assigned to the device. May correspond to the serial number of the BIOS, the motherboard, or the chassis, depending on the manufacturer. |
| Absolute.Device.LocalIp | String | Last known local IP address of this device. |
| Absolute.Device.PublicIp | String | Last known public IP address of this device. |
| Absolute.Device.EncryptionStatus | String | The summarized encryption status of the device. |
Command example
!absolute-device-list os_name="Microsoft Windows Server 2019 Datacenter"
Context Example
{
"Absolute": {
"Device": {
"AgentStatus": "A",
"Esn": "D0001",
"FullSystemName": "ABSOLUTE-ASSET-.WORKGROUP",
"Id": "123456",
"LastConnectedUtc": 1648971645189,
"LocalIp": "127.0.0.1",
"PublicIp": "127.0.0.1",
"Serial": "GoogleCloud-B8736A4405BF0E968020BCBC46EDA096",
"SystemManufacturer": "Google",
"SystemModel": "GOOGLE COMPUTE ENGINE",
"SystemName": "ABSOLUTE-ASSET-",
"SystemType": "x64-based PC",
"osName": "Microsoft Windows Server 2019 Datacenter"
}
}
}
Human Readable Output
Absolute devices list
|AgentStatus|Esn|FullSystemName|Id|LastConnectedUtc|LocalIp|PublicIp|Serial|SystemManufacturer|SystemModel|SystemName|SystemType|osName|
|—|—|—|—|—|—|—|—|—|—|—|—|—|
| A | D0001 | ABSOLUTE-ASSET-.WORKGROUP | 123456 | 1648971645189 | 127.0.0.1 | 127.0.0.1 | GoogleCloud-B8736A4405BF0E968020BCBC46EDA096 | Google | GOOGLE COMPUTE ENGINE | ABSOLUTE-ASSET- | x64-based PC | Microsoft Windows Server 2019 Datacenter |
Above results are with page number: 0 and with size: 50.
absolute-device-get
Gets a list of device records and their corresponding data that meets the required fields for all devices in your account. Note that the command supports returning a maximum of 500 distinct devices.
Base Command
absolute-device-get
Input
| Argument Name | Description | Required |
|---|---|---|
| fields | A comma-separated list of all specific values to return. | Optional |
| device_ids | A comma-separated list of the system-defined unique identifier of the devices. | Optional |
| device_names | A comma-separated list of the devices names. | Optional |
| local_ips | A comma-separated list of the last known local IP addresses of a device. | Optional |
| public_ips | A comma-separated list of the last known public IP addresses of a device. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| Absolute.Device.Id | String | The unique identifier assigned to the device. |
| Absolute.Device.Esn | String | The unique ESN (Absolute Identifier) assigned to the agent installed on the device. |
| Absolute.Device.Domain | String | The name of the Windows domain to which this device belongs. |
| Absolute.Device.LastConnectedUtc | Number | The date and time (in Unix epoch) when the device last connected to the Absolute Monitoring Center. |
| Absolute.Device.SystemName | String | The name assigned to the device. |
| Absolute.Device.FullSystemName | String | The full name assigned to the device consisting of the system name and the domain name. |
| Absolute.Device.AgentStatus | String | The status of the Absolute agent on the device. |
| Absolute.Device.Os.name | String | Short description of the operating system expressed as a one-line string that includes the version of the operating system. |
| Absolute.Device.Os.version | String | The version of the operating system. |
| Absolute.Device.Os.currentBuild | String | The current build number of the operating system. |
| Absolute.Device.Os.architecture | String | The architecture of the operating system. |
| Absolute.Device.Os.installDate | Number | The date and time (in Unix epoch) when the operating system was installed. |
| Absolute.Device.Os.productKey | String | The product key of the operating system. |
| Absolute.Device.Os.serialNumber | String | The serial identification number of the operating system. |
| Absolute.Device.Os.lastBootTime | Number | The date and time (in Unix epoch) when the operating system was last restarted. |
| Absolute.Device.Bios.id | String | The unique identifier of this BIOS given by the manufacturer. |
| Absolute.Device.Bios.serialNumber | String | The serial number assigned to the BIOS. |
| Absolute.Device.Bios.smBiosVersion | String | The major version number of the BIOS, as reported by SMBIOS. |
| Absolute.Device.Bios.version | String | The version of the BIOS, as reported by SMBIOS. |
| Absolute.Device.Bios.versionDate | String | A substring of the manufacturer of the BIOS + the version of the BIOS version, as reported by SMBIOS + the release date of the Window BIOS. |
| Absolute.Device.SystemManufacturer | String | The manufacturer of the device. |
| Absolute.Device.SystemModel | String | The product name from the manufacturer. |
| Absolute.Device.SystemType | String | The system running on the Windows-based computer. |
| Absolute.Device.Serial | String | The manufacturer-defined unique identifier assigned to the device. May correspond to the serial number of the BIOS, the motherboard, or the chassis, depending on the manufacturer. |
| Absolute.Device.LocalIp | String | Last known local IP address of this device. |
| Absolute.Device.PublicIp | String | Last known public IP address of this device. |
| Absolute.Device.EncryptionStatus | String | The summarized encryption status of the device. |
| Absolute.Device.Username | String | The unique username of the user that was logged in to the device at the time of the most recent agent call. |
| Absolute.Device.PolicyGroupUid | String | The unique identifier of the policy group that the device belongs to. |
| Absolute.Device.PolicyGroupName | String | The name of the policy group that the device belongs to. |
| Absolute.Device.IsStolen | String | Indicates whether this device was reported as stolen. |
| Absolute.Device.DeviceStatus.type | String | The status of the device. Possible values are STOLEN or MISSING. |
| Absolute.Device.DeviceStatus.reported | Number | The data and time (in Unix epoch) when the device was reported missing or stolen. |
| Absolute.Device.NetworkAdapters.networkSSID | String | The Service Set Identifier (SSID) of the connected Wi-Fi adapter. |
Command example
!absolute-device-get device_names="ABSOLUTE-ASSET-"
Context Example
{
"Absolute": {
"Device": [
{
"AgentStatus": "A",
"Bios": {
"id": "Google - 1 Google ",
"serialNumber": "GoogleCloud-B8736A4405BF0E968020BCBC46EDA096",
"smBiosVersion": "2.4",
"version": "Google - 1 Google ",
"versionDate": "Google Google, 01/01/2011"
},
"Domain": "WORKGROUP",
"Esn": "D0001",
"FullSystemName": "ABSOLUTE-ASSET-.WORKGROUP",
"Id": "123456",
"LastConnectedUtc": 1648971645189,
"LocalIp": "127.0.0.1",
"NetworkAdapters": [
{},
{}
],
"Os": {
"architecture": "64-bit",
"currentBuild": "17763",
"installDate": 1643800616000,
"lastBootTime": 1646884562500,
"name": "Microsoft Windows Server 2019 Datacenter",
"productKey": "WMDGN-G9PQG-XVVXX-R3X43-63DFG",
"serialNumber": "00430-00000-00000-AA691",
"version": "10.0.17763"
},
"PolicyGroupName": "Global Policy Group",
"PublicIp": "127.0.0.1",
"Serial": "GoogleCloud-B8736A4405BF0E968020BCBC46EDA096",
"SystemManufacturer": "Google",
"SystemModel": "GOOGLE COMPUTE ENGINE",
"SystemName": "ABSOLUTE-ASSET-",
"SystemType": "x64-based PC",
"Username": "Administrator"
},
{
"AgentStatus": "A",
"Bios": {
"id": "Google - 1 Google ",
"serialNumber": "GoogleCloud-6420CF930DEE84DE8497CF40F0D56AFA",
"smBiosVersion": "2.4",
"version": "Google - 1 Google ",
"versionDate": "Google Google, 01/01/2011"
},
"Domain": "WORKGROUP",
"Esn": "D0004",
"FullSystemName": "ABSOLUTE-ASSET-.WORKGROUP",
"Id": "1234",
"LastConnectedUtc": 1648971873079,
"LocalIp": "127.0.0.1",
"NetworkAdapters": [
{},
{}
],
"Os": {
"architecture": "64-bit",
"currentBuild": "20348",
"installDate": 1648025097000,
"lastBootTime": 1648025060499,
"name": "Microsoft Windows Server 2022 Datacenter",
"productKey": "WX4NM-KYWYW-QJJR4-XV3QB-6VM33",
"serialNumber": "00454-60000-00001-AA937",
"version": "10.0.20348"
},
"PolicyGroupName": "Global Policy Group",
"PublicIp": "127.0.0.1",
"Serial": "GoogleCloud-6420CF930DEE84DE8497CF40F0D56AFA",
"SystemManufacturer": "Google",
"SystemModel": "GOOGLE COMPUTE ENGINE",
"SystemName": "ABSOLUTE-ASSET-",
"SystemType": "x64-based PC",
"Username": "Administrator"
}
]
}
}
Human Readable Output
Absolute devices list
AgentStatus Bios Domain Esn FullSystemName Id LastConnectedUtc LocalIp NetworkAdapters Os PolicyGroupName PublicIp Serial SystemManufacturer SystemModel SystemName SystemType Username A id: Google - 1 Google
serialNumber: GoogleCloud-B8736A4405BF0E968020BCBC46EDA096
version: Google - 1 Google
versionDate: Google Google, 01/01/2011
smBiosVersion: 2.4WORKGROUP D0001 ABSOLUTE-ASSET-.WORKGROUP 123456 1648971645189 127.0.0.1 {},
{}architecture: 64-bit
installDate: 1643800616000
lastBootTime: 1646884562500
name: Microsoft Windows Server 2019 Datacenter
productKey: WMDGN-G9PQG-XVVXX-R3X43-63DFG
serialNumber: 00430-00000-00000-AA691
version: 10.0.17763
currentBuild: 17763Global Policy Group 127.0.0.1 GoogleCloud-B8736A4405BF0E968020BCBC46EDA096 GOOGLE COMPUTE ENGINE ABSOLUTE-ASSET- x64-based PC Administrator A id: Google - 1 Google
serialNumber: GoogleCloud-6420CF930DEE84DE8497CF40F0D56AFA
version: Google - 1 Google
versionDate: Google Google, 01/01/2011
smBiosVersion: 2.4WORKGROUP D0004 ABSOLUTE-ASSET-.WORKGROUP 1234 1648971873079 127.0.0.1 {},
{}architecture: 64-bit
installDate: 1648025097000
lastBootTime: 1648025060499
name: Microsoft Windows Server 2022 Datacenter
productKey: WX4NM-KYWYW-QJJR4-XV3QB-6VM33
serialNumber: 00454-60000-00001-AA937
version: 10.0.20348
currentBuild: 20348Global Policy Group 127.0.0.1 GoogleCloud-6420CF930DEE84DE8497CF40F0D56AFA GOOGLE COMPUTE ENGINE ABSOLUTE-ASSET- x64-based PC Administrator
absolute-device-location-get
Gets a list of devices geo locations records and their corresponding data that meets the required devices IDs.
Base Command
absolute-device-location-get
Input
| Argument Name | Description | Required |
|---|---|---|
| device_ids | A comma-separated list of the system-defined unique identifier of the devices. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| Absolute.LocationReport.Coordinates | Unknown | A comma-separated list where the first number is the estimated latitude and the second number is the estimated longitude (in degrees) where the device is located. |
| Absolute.LocationReport.ID | String | The system-defined unique identifier of the device. |
| Absolute.LocationReport.City | String | The city where the device is located. |
| Absolute.LocationReport.State | String | The state or province where the device is located. |
| Absolute.LocationReport.CountryCode | String | The country code for the country where the device is located. |
| Absolute.LocationReport.Country | String | The country where the device is located. |
| Absolute.LocationReport.LocationTechnology | String | The technology used to get the location. |
| Absolute.LocationReport.Accuracy | Number | The estimated accuracy (in meters) of the technology used to locate the device. |
| Absolute.LocationReport.LastUpdate | Number | The date and time (in Unix epoch) when the device last changed its location. |
Command example
!absolute-device-location-get device_ids=1234
Human Readable Output
No device locations found in Absolute for the given filters: {‘device_ids’: ‘1234’}
absolute-device-get-events
Retrieves a list of events from the Absolute device instance.
Base Command
absolute-device-get-events
Input
| Argument Name | Description | Required |
|---|---|---|
| should_push_events | Set this argument to True in order to create events, otherwise the command will only display them. Possible values are: true, false. Default is false. | Optional |
| start_date | Filters the results to the records on or after the start date. | Optional |
| end_date | Filters the results to the records until the end date. | Optional |
| limit | The maximum number of records to return per page. Note, this may be restricted by fixed system limits. | Optional |
Command Example
!absolute-device-get-events start_date="one minute ago" end_date="now" limit=10
Creating a filtering and sorting query
The following commands have the option to insert a filter argument:
- absolute-device-application-list
- absolute-device-list
Absolute uses a subset of query options from Open Data Protocol (OData) for filtering and sorting.
OData version 1 and 2 are supported. OData query parameters must be alphabetized and URI encoded.
For more information about OData, see: https://www.odata.org/documentation.
A few examples of creating a query (i.e., passing a filter argument):
- Using the eq operator
- Get a list of all devices with an active status: agentStatus eq ‘A’
- Get a list of all devices that are currently frozen: dfStatus.statusCode eq ‘FRZN’
- Get a list of all devices that have 1734 in their ESN (Identifier): substringof(‘1734’,esn) eq true
- Using the ne operator
- Get a list of all devices that are not active: agentStatus ne ‘A’
- Using the gt operator
- Get a list of all devices with greater than 1 GB (1073741824 bytes) of available physical: availablePhysicalRamBytes gt 1073741824
- Using the or operator:
- Get a list of all devices with less than 1 GB (1073741824 bytes) of available physical ram or less than 1 GB (1073741824 bytes) of available virtual raml: availablePhysicalMemroyBytes lt 1073741824 or availableVirtualMemoryBytes lt 1073741824
For more examples and explanations, see the Absolute docs (from page 10).
Breaking changes from the previous version of this integration - Absolute
The following sections list the changes in this version.
Arguments
The following arguments were removed in this version
In the absolute-device-application-list command, the following argument was removed:
- account_uids
Outputs
- In the absolute-device-unenroll command the following outputs were replaced:
- Absolute.DeviceUnenroll.DeviceUid - replaced by Absolute.DeviceUnenroll.Devices.DeviceUid.
- Absolute.DeviceUnenroll.ESN - replaced by Absolute.DeviceUnenroll.Devices.ESN.
- In the absolute-device-freeze-request-get command the following outputs were replaced:
- Absolute.FreezeRequestDetail.Configuration.issuedUtc - replaced by Absolute.FreezeRequestDetail.Configuration.issuedDateTimeUTC.
- Absolute.FreezeRequestDetail.RequesterUid - replaced by Absolute.FreezeRequestDetail.Requester.
- Absolute.FreezeRequestDetail.Statuses.ackClientUtc - replaced by Absolute.FreezeRequestDetail.Statuses.ackClientDateTimeUtcs.
- Absolute.FreezeRequestDetail.Statuses.scheduledFreezeDateUTC - replaced by Absolute.FreezeRequestDetail.Statuses.scheduledFreezeDateTimeUtc.
- Absolute.FreezeRequestDetail.Statuses.updatedUtc - replaced by Absolute.FreezeRequestDetail.Statuses.updatedDateTimeUtc.
- In the absolute-device-application-list command the following output was removed:
- Absolute.DeviceApplication.AccountUid
- In the absolute-custom-device-field-list command the following output was removed:
- Absolute.CustomDeviceField.ESN
- In the absolute-device-freeze-request-get command the following outputs were removed:
- Absolute.FreezeRequestDetail.Statuses.statusUid
- Absolute.FreezeRequestDetail.RequesterUid
- In the absolute-device-unenroll command the following outputs were removed:
- Absolute.DeviceUnenroll.EligibleStatus
- Absolute.DeviceUnenroll.Serial
- Absolute.DeviceUnenroll.SystemName
- Absolute.DeviceUnenroll.Username
<~PLATFORM>
License Requirements
The following configuration parameters require the Cortex XSIAM license:
- Fetch Events
</~PLATFORM>
Configuration parameters
url— Your Absolute server URL (required)credentials— Token ID (required)insecure— Trust any certificate (not secure)proxy— Use system proxy settingseventFetchInterval— Events Fetch Intervalmax_events_per_fetch— Max number of events per fetchisFetchEvents—
Commands (15)
-
absolute-custom-device-field-listReturns a list of custom device fields associated with the given device_id, based on the authorization token.
-
absolute-custom-device-field-updateUpdates the value of the included custom device fields for the given device_id.
-
absolute-device-application-listGets a list of device records and the corresponding software application data for each device on the account that you have access to or that meets the given filter.
-
absolute-device-freeze-message-createCreates a new Freeze message for the account.
-
absolute-device-freeze-message-deleteDeletes an existing Freeze message for the account. Use absolute-device-freeze-message-list in order to get the message_id.
-
absolute-device-freeze-message-listGets all the Freeze messages that are configured for the account by the given message_id. If message_id is not given all the messages will be returned.
-
absolute-device-freeze-message-updateUpdates the content of an existing Freeze message. Use absolute-device-freeze-message-list in order to get the message_id.
-
absolute-device-freeze-requestCreates a new Freeze request for the devices specified in the device_ids argument.
-
absolute-device-freeze-request-getGets detailed information about the Freeze request specified by request_uid.
-
absolute-device-getGets a list of device records and their corresponding data that meets the required fields for all devices in your account. Note that the command supports returning a maximum of 500 distinct devices.
-
absolute-device-get-eventsRetrieves a list of events from the Absolute instance.
-
absolute-device-listGets a list of device records and their corresponding data that meets the required filter for all devices in your account, based on your authorization token.
-
absolute-device-location-getGets a list of devices geo location records and their corresponding data that meets the required devices IDs.
-
absolute-device-remove-freeze-requestCreates a new Remove Freeze request for one or more devices, regardless of their Freeze status. You can submit Remove Freeze requests to perform the following actions: unfreeze frozen devices, remove newly submitted Freeze requests, or remove outstanding Scheduled and Offline Freeze requests. In case of removing from offline: In addition to creating a Remove Freeze request for devices with a status of Frozen by Condition: Offline, removes Offline Freeze requests from devices with a status of Freeze Requested or Freeze Condition - Offline Set. In case of not removing from offline: a Remove Freeze request is created for the devices but the Conditional - Offline Freeze request is not deleted (deprecated).
-
absolute-device-unenrollInitiates an unenroll request on a list of eligible devices.
import copy import urllib.parse import demistomock as demisto # noqa: F401 import jwt from CommonServerPython import * # noqa: F401 from CommonServerUserPython import * # noqa """ CONSTANTS """ ABSOLUTE_URL_TO_API_URL = { "https://cc.absolute.com": "https://api.absolute.com", "https://cc.us.absolute.com": "https://api.us.absolute.com", "https://cc.eu2.absolute.com": "https://api.eu2.absolute.com", "https://cc.fr1.absolutegov.com": "https://api.fr1.absolutegov.com", "https://cc.in1.absolute.com": "https://api.in1.absolute.com", } ABSOLUTE_AGET_STATUS = { "Active": "A", "Disabled": "D", "Inactive": "I", } INTEGRATION = "Absolute" DEFAULT_LIMIT = 50 DEVICE_LIST_RETURN_FIELDS = [ "deviceUid", "esn", "lastConnectedDateTimeUtc", "deviceName", "systemModel", "fullSystemName", "agentStatus", "operatingSystem.name", "systemManufacturer", "serialNumber", "systemType", "localIp", "publicIp", "espInfo.encryptionStatus", ] DEVICE_GET_COMMAND_RETURN_FIELDS = [ "deviceUid", "esn", "domain", "lastConnectedDateTimeUtc", "deviceName", "systemModel", "systemType", "fullSystemName", "agentStatus", "operatingSystem.name", "operatingSystem.version", "operatingSystem.currentBuild", "operatingSystem.architecture", "operatingSystem.installDate", "operatingSystem.productKey", "operatingSystem.serialNumber", "operatingSystem.lastBootTime", "systemManufacturer", "serial", "serialNumber", "localIp", "publicIp", "username", "espInfo.encryptionStatus", "bios.id", "bios.serialNumber", "bios.version", "bios.versionDate", "bios.smBiosVersion", "policyGroupUid", "policyGroupName", "isStolen", "deviceStatus.type", "deviceStatus.reported", "networkSSID", ] DEVICE_GET_LOCATION_COMMAND_RETURN_FIELDS = [ "geoData.location.point.coordinates", "geoData.location.geoAddress.city", "geoData.location.geoAddress.state", "geoData.location.geoAddress.countryCode", "geoData.location.geoAddress.country", "geoData.location.locationTechnology", "geoData.location.accuracy", "geoData.location.lastUpdateDateTimeUtc", ] DEVICE_OUTPUT_TO_XSOAR_CONTEXT_PATH = { "installDateTimeUtc": "InstallDate", "firstDetectDateTimeUtc": "FirstDetectUtc", "lastScanDateTimeUtc": "LastScanTimeUtc", "deviceUid": "Id", "lastConnectedDateTimeUtc": "LastConnectedUtc", "serialNumber": "Serial", "publicIp": "PublicIp", "localIp": "LocalIp", "username": "Username", } SEIM_EVENTS_PAGE_SIZE = 1000 CLIENT_V3_JWS_VALIDATION_URL_SUFFIX = "/jws/validate" VENDOR = "Absolute" PRODUCT = "Secure Endpoint" HEADERS_V3: dict = {"content-type": "text/plain"} MAX_PAGE_SIZE = 500 # Max allowed page size to solve the issue on absolute end where reaching the page size yield all results. class ClientV3(BaseClient): def __init__(self, base_url: str, token_id: str, secret_key: str, verify: bool, proxy: bool, headers: dict = HEADERS_V3): """ Client to use in the Absolute integration for API v3. Overrides BaseClient. Args: base_url (str): URL to access when doing a http request. token_id (str): The Absolute token id secret_key (str): User's Absolute secret key verify (bool): Whether to check for SSL certificate validity. proxy (bool): Whether the client should use proxies. headers (dict): Dictionary of HTTP headers to send with the Request. """ super().__init__(base_url=base_url, verify=verify, proxy=proxy) self._token_id = token_id self._headers = headers self._secret_key = secret_key def prepare_request(self, method: str, url_suffix: str, query_string: str, payload: dict = {}) -> str: """ Prepares the signed HTTP request data for making an API call. Args: method (str): The HTTP method to be used for the request. url_suffix (str): The endpoint URL suffix for the API call. query_string (str): The query string parameters for the API call. Returns: bytes: The prepared signed HTTP request data. """ if payload: request_payload_data = {"data": payload} else: request_payload_data = {"data": {}} headers = { "alg": "HS256", "kid": self._token_id, "method": method, "content-type": "application/json", "uri": url_suffix, "query-string": query_string, "issuedAt": round(time.time() * 1000), } demisto.debug(f"ABS: Making JWS token with headers: {headers}, request_payload_data: {request_payload_data}") return jwt.encode(request_payload_data, self._secret_key, algorithm="HS256", headers=headers) def prepare_query_string_for_canonical_request(self, query_string: str) -> str: """ Query is given as a string represents the filter query. For example, query_string = "$top=10 $skip=20" 1. Splitting into a list (by space as a separator). 2. Sorting arguments in ascending order; for example, 'A' is before 'a'. 3. URI encode the parameter name and value using URI generic syntax. 4. Reassembling the list into a string. """ if not query_string: return "" return urllib.parse.quote(query_string, safe="=&") def send_request_to_api( self, method: str, url_suffix: str, query_string: str, ok_codes: tuple, payload: dict = {}, resp_type: str = "json" ): # pragma: no cover """Sends the request to Absolute Args: method (str): HTTP request method (GET/PUT/POST/DELETE). url_suffix (str): The API endpoint. query_string (str): The query to filter results by. ok_codes (tuple): An HTTP status code of success payload (dict, optional): The payload to send. Defaults to {}. resp_type (str, optional): The response type of the request. Defaults to "json". """ signed = self.prepare_request(method=method, url_suffix=url_suffix, query_string=query_string, payload=payload) return self._http_request( method="POST", data=signed, full_url=f"{self._base_url}{CLIENT_V3_JWS_VALIDATION_URL_SUFFIX}", return_empty_response=True, ok_codes=ok_codes, resp_type=resp_type, ) def add_pagination(self, next_page: str, page_size: int) -> str: """ Add pagination query format """ query = "" if next_page: query += f"&nextPage={next_page}" if page_size: query += f"&pageSize={page_size}" return query def get_specific_page_data( self, url_suffix: str, page_to_return: int, page_size: int, query_string: str, ok_codes: tuple ) -> dict: """Return a specific page data Args: url_suffix (str): The url suffix to fetch from. page_to_return (int): The page number to return. page_size (int): The pga size to return. query_string (str): The query to filter results by. ok_codes (tuple): An HTTP status code of success. """ current_page = 0 # the first page number to fetch next_page = "" while current_page <= page_to_return: response = self.send_request_to_api( "GET", url_suffix, query_string + self.add_pagination(next_page, page_size), ok_codes=ok_codes ) data = response.get("data", {}) current_page += 1 next_page = response.get("metadata", {}).get("pagination", {}).get("nextPage", "") if not next_page: break if current_page <= page_to_return and not next_page: demisto.debug( "ABS: Returning empty data, as next_page is empty, and " f"current_page ({current_page}) <= page_to_return ({page_to_return})" ) # no more results in the API return {} return data def get_all_results(self, url_suffix: str, page_size: int, query_string: str, ok_codes: tuple) -> dict: """Return all the results from the API Args: url_suffix (str): The url suffix to fetch from. page_size (int): The pga size to return. query_string (str): The query to filter results by. ok_codes (tuple): An HTTP status code of success. """ next_page = "" response = self.send_request_to_api( "GET", url_suffix, query_string + self.add_pagination(next_page, page_size), ok_codes=tuple(ok_codes) ) data = response.get("data") while next_page := response.get("metadata", {}).get("pagination", {}).get("nextPage", ""): response = self.send_request_to_api( "GET", url_suffix, query_string + self.add_pagination(next_page, page_size), ok_codes=tuple(ok_codes) ) data += response.get("data") return data def api_request_absolute( self, method: str, url_suffix: str, body: dict = {}, success_status_code=(), query_string: str = "", page: int = 0, page_size: int = 0, specific_page: bool = False, resp_type: str = "json", ): """Makes an HTTP request to the Absolute API. Args: method (str): HTTP request method (GET/PUT/POST/DELETE). url_suffix (str): The API endpoint. body (dict, optional): The body to set. Defaults to {}. success_status_code (tuple, optional): An HTTP status code of success. Defaults to None. query_string (str): The query to filter results by. Defaults to ''. page (int): The specific page number to return. Defaults to 0. page_size (int): The page size of the response. Defaults to DEFAULT_API_PAGE_SIZE. specific_page (bool): Wether to return a specific page or not. Defaults to False. resp_type (str): The response type of the request. Defaults to "json". """ demisto.debug(f"current request is: method={method}, url suffix={url_suffix}, body={body}") if not success_status_code: success_status_code = [200] query_string = self.prepare_query_string_for_canonical_request(query_string) if method == "GET": if specific_page: data = self.get_specific_page_data(url_suffix, page, page_size, query_string, ok_codes=tuple(success_status_code)) else: data = self.get_all_results(url_suffix, page_size, query_string, ok_codes=tuple(success_status_code)) return data elif method == "DELETE": response = self.send_request_to_api("DELETE", url_suffix, query_string, ok_codes=tuple(success_status_code)) return response elif method == "PUT": response = self.send_request_to_api( "PUT", url_suffix, query_string, payload=body, ok_codes=tuple(success_status_code), resp_type=resp_type ) return response elif method == "POST": response = self.send_request_to_api( "POST", url_suffix, query_string, payload=body, ok_codes=tuple(success_status_code), resp_type=resp_type ) if isinstance(response, dict): # response is not empty return response.get("data") return None def fetch_events_between_dates(self, fetch_limit: int, start_date: datetime, end_date: datetime) -> List[Dict[str, Any]]: """ Helper function to fetch events with time window from the API based on the provided parameters. Args: fetch_limit (int): The maximum number of events to fetch. start_date (datetime): The start date for the events to be fetched. end_date (datetime): The end date for the events to be fetched. Returns: list: A list of fetched events. """ all_events: List[Dict[str, Any]] = [] next_page_token = "" ok_codes = [200] while len(all_events) < fetch_limit: page_size = min(SEIM_EVENTS_PAGE_SIZE, fetch_limit - len(all_events)) query_string = self.prepare_query_string_for_fetch_events( page_size=page_size, start_date=start_date, end_date=end_date, next_page=next_page_token ) response = self.send_request_to_api("GET", "/v3/reporting/siem-events", query_string, tuple(ok_codes)) all_events.extend(response.get("data", [])) next_page_token = response.get("metadata", {}).get("pagination", {}).get("nextPage", "") if not next_page_token: break demisto.debug(f"fetch_events_between_dates: Fetched {len(all_events)} events") return all_events def prepare_query_string_for_fetch_events( self, start_date: datetime, end_date: datetime, page_size: int = None, next_page: str = None ) -> str: """ Prepares the query string for fetching events based on the provided parameters. Args: start_date (datetime): The start date of the events to fetch. end_date (datetime): The end date of the events to fetch. page_size (int, optional): The size of each page to fetch. Defaults to None. next_page (str, optional): The next page token. Defaults to None. Returns: str: The prepared query string for fetching events. """ from_date_time_utc = f'fromDateTimeUtc={start_date.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3]}Z' to_date_time_utc = f'toDateTimeUtc={end_date.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3]}Z' query = f"{from_date_time_utc}&{to_date_time_utc}" if page_size: query += f"&pageSize={page_size}" if next_page: query += f"&nextPage={next_page}" demisto.debug(f"Query string for fetching events: {query}") return query def validate_absolute_api_url(base_url: str) -> str: """Validate the base url, and return the respective api url Args: base_url (str): The base url to validate """ if base_url not in ABSOLUTE_URL_TO_API_URL: raise_demisto_exception( f"The Absolute server url {base_url} in not a valid url. Possible options: {list(ABSOLUTE_URL_TO_API_URL.keys())}" ) return ABSOLUTE_URL_TO_API_URL[base_url] def test_module(client: ClientV3) -> str: # pragma: no cover """Tests API connectivity to Absolute""" try: client.api_request_absolute("GET", "/v3/reporting/devices", query_string="", page=0, page_size=1, specific_page=True) message = "ok" except DemistoException as e: if "Forbidden" in str(e) or "Authorization" in str(e): message = "Authorization Error: make sure API Key is correctly set" else: raise e return message def parse_device_field_list_response(response: dict, device_id: str, limit: Optional[int], all_results: bool) -> dict[str, Any]: """Parse the device field list response""" parsed_data = {"DeviceUID": device_id, "CDFValues": []} # type: ignore for cdf_item in response: parsed_data["CDFValues"].append( # type: ignore[attr-defined] { # type: ignore "CDFUID": cdf_item.get("cdfUid"), "FieldKey": cdf_item.get("cdfFieldKey"), "FieldName": cdf_item.get("cdfFieldName"), "CategoryCode": cdf_item.get("categoryCode"), "FieldValue": cdf_item.get("cdfFieldValue"), "Type": cdf_item.get("type"), } ) if not all_results: parsed_data["CDFValues"] = parsed_data["CDFValues"][:limit] return parsed_data def parse_device_field_list_response_human_readable(outputs: dict) -> list: """Parse the device field list response for the HR""" human_readable = [] for cdf_values in outputs.get("CDFValues", []): human_readable.append( { "Field Name": cdf_values.get("FieldName"), "CDF ID": cdf_values.get("CDFUID"), "Field Value": cdf_values.get("FieldValue"), } ) return human_readable def get_custom_device_field_list_command(args, client) -> CommandResults: """Gets custom device field""" device_id = args.get("device_id") limit = arg_to_number(args.get("limit", DEFAULT_LIMIT)) all_results = argToBoolean(args.get("all_results", False)) res = client.api_request_absolute("GET", f"/v3/configurations/customfields/devices/{device_id}") outputs = parse_device_field_list_response(res, device_id, limit, all_results) human_readable = tableToMarkdown( f"{INTEGRATION} Custom device field list", parse_device_field_list_response_human_readable(outputs), removeNull=True ) return CommandResults( outputs=outputs, outputs_prefix="Absolute.CustomDeviceField", outputs_key_field="DeviceUID", readable_output=human_readable, raw_response=res, ) def update_custom_device_field_command(args, client) -> CommandResults: """Updates custom device field""" device_id = args.get("device_id") cdf_uid = args.get("cdf_uid") field_value = args.get("value") payload = [{"cdfUid": cdf_uid, "cdfFieldValue": field_value}] client.api_request_absolute( "PUT", f"/v3/configurations/customfields/devices/{device_id}", body=payload, success_status_code=[202], resp_type="response", ) return CommandResults(readable_output=f"Device {device_id} with value {field_value} was updated successfully.") def validate_device_freeze_type_offline(offline_time_seconds: Optional[int]) -> int: """Validate the Offline type arg""" if not offline_time_seconds: # the default is 30 days offline_time_seconds = 22592000 else: # must be between 1200 seconds (20 minutes) and 172800000 seconds (2000 days) offline_time_seconds_valid = 1200 <= offline_time_seconds <= 172800000 if not offline_time_seconds_valid: raise_demisto_exception( "the offline_time_seconds arg is not valid. Must be between 1200 seconds" " (20 minutes) and 172800000 seconds (2000 days)." ) return offline_time_seconds def raise_demisto_exception(msg): raise DemistoException(f"{INTEGRATION} error: {msg}") def validate_device_freeze_type_scheduled(scheduled_freeze_date: str) -> str: """Validate the scheduled type arg""" if not scheduled_freeze_date: raise_demisto_exception( "When setting device_freeze_type to be Scheduled, you must specify the scheduled_freeze_date arg." ) return scheduled_freeze_date def validate_passcode_type_args(passcode_type: str, passcode: str, passcode_length: Optional[int], payload: dict) -> dict: """Validate the passcode type arguments, and return the payload Args: passcode_type (str): The passcode type passcode (str): The passcode passcode_length (int): The passcode length payload (dict): The payload """ if passcode_type == "UserDefined": if not passcode: raise_demisto_exception("when setting passcode_type to be UserDefined, you must specify the passcode arg.") payload["passcodeDefinition"].update({"passcode": passcode}) elif passcode_type == "RandomForEach" or passcode_type == "RandomForAll": not_valid_passcode_length = not passcode_length or passcode_length > 8 or passcode_length < 4 if not_valid_passcode_length: raise_demisto_exception( "when setting passcode_type to be RandomForEach or RandomForAll, " "you must specify the passcode_length arg to be between 4 to 8." ) payload["passcodeDefinition"].update({"length": passcode_length}) return payload def parse_freeze_device_response(response: dict, device_ids: str) -> dict: """Parse the device freeze response Args: response (dict): The response to parse device_ids (str): The device ids in the request """ outputs = {"RequestUID": response.get("requestUid"), "SucceededDeviceUIDs": device_ids} errors = response.get("errors", []) human_readable_errors = [] if errors: for error in errors: human_readable_errors.append( {"Failed UID": ",".join(error.get("detail", []).get("deviceUids")), "Error Message": error.get("message", "")} ) outputs["Errors"] = errors outputs["FailedDeviceUIDs"] = human_readable_errors return outputs def device_freeze_request_command(args, client) -> CommandResults: """Requests to freeze devices""" payload = prepare_payload_to_freeze_request(args) res = client.api_request_absolute("POST", "/v3/actions/requests/freeze", body=payload) outputs = parse_freeze_device_response(res, args.get("device_ids")) human_readable = tableToMarkdown( f"{INTEGRATION} device freeze requests results", outputs, headers=["FailedDeviceUIDs", "RequestUID", "SucceededDeviceUIDs"], removeNull=True, json_transform_mapping={"FailedDeviceUIDs": JsonTransformer()}, ) outputs.pop("FailedDeviceUIDs", "") return CommandResults( readable_output=human_readable, outputs=outputs, outputs_prefix="Absolute.FreezeRequest", outputs_key_field="RequestUID", raw_response=res, ) def prepare_payload_to_freeze_request(args) -> dict: """prepares the pyload for the freeze request""" request_name = args.get("request_name") html_message = args.get("html_message") message_name = args.get("message_name") device_ids = argToList(args.get("device_ids")) notification_emails = argToList(args.get("notification_emails")) device_freeze_type = args.get("device_freeze_type") passcode_type = args.get("passcode_type") payload = { "requestTitle": request_name, "message": html_message, "messageName": message_name, "freezeDefinition": {"deviceFreezeType": device_freeze_type}, "deviceUids": device_ids, "notificationEmails": notification_emails, "passcodeDefinition": {"option": passcode_type}, } scheduled_freeze_date = args.get("scheduled_freeze_date") offline_time_seconds = arg_to_number(args.get("offline_time_seconds"), required=False) if device_freeze_type == "Scheduled": scheduled_freeze_date = validate_device_freeze_type_scheduled(scheduled_freeze_date) payload["freezeDefinition"].update({"scheduledFreezeDateTimeUtc": scheduled_freeze_date}) elif device_freeze_type == "OffLine": offline_time_seconds = validate_device_freeze_type_offline(offline_time_seconds) payload["freezeDefinition"].update({"offlineTimeSeconds": offline_time_seconds}) passcode = args.get("passcode") passcode_length = arg_to_number(args.get("passcode_length"), required=False) payload = validate_passcode_type_args(passcode_type, passcode, passcode_length, payload) remove_nulls_from_dictionary(payload) return payload def remove_device_freeze_request_command(args, client) -> CommandResults: """Removes device freeze request""" device_ids = argToList(args.get("device_ids")) remove_scheduled = argToBoolean(args.get("remove_scheduled", False)) remove_offline = argToBoolean(args.get("remove_offline", False)) payload = {"deviceUids": device_ids, "removeScheduled": remove_scheduled, "removeOffline": remove_offline} client.api_request_absolute( "POST", "/v3/actions/freeze/remove-freeze", body=payload, success_status_code=[202], resp_type="response" ) return CommandResults(readable_output=f"Successfully removed freeze request for devices ids: {args.get('device_ids')}.") def parse_get_device_freeze_response(response: list) -> list: """Parse the device freeze response Args: response (list): The response to parse """ parsed_data = [] for freeze_request in response: parsed_data.append( { "ID": freeze_request.get("id"), "ActionRequestUid": freeze_request.get("requestUid"), "DeviceUid": freeze_request.get("deviceUid"), "Name": freeze_request.get("requestTitle"), "Statuses": freeze_request.get("statuses", []), "Configuration": freeze_request.get("configuration", {}), "Requester": freeze_request.get("requester"), "CreatedUTC": freeze_request.get("createdDateTimeUtc"), "ChangedUTC": freeze_request.get("changedDateTimeUtc"), "NotificationEmails": freeze_request.get("notificationEmails"), "EventHistoryId": freeze_request.get("eventHistoryId"), "PolicyGroupUid": freeze_request.get("policyGroupUid"), "PolicyConfigurationVersion": freeze_request.get("policyConfigurationVersion"), "FreezePolicyUid": freeze_request.get("freezePolicyUid"), "Downloaded": freeze_request.get("isDownloaded"), "IsCurrent": freeze_request.get("isCurrent"), # for the freeze message command "Content": freeze_request.get("content"), "CreatedBy": freeze_request.get("createdBy"), "ChangedBy": freeze_request.get("changedBy"), } ) return parsed_data def parse_device_freeze_message_response(response: list) -> list: """Parse the device freeze message response Args: response (list): The response to parse """ if not isinstance(response, list): response = [response] parsed_data = [] for freeze_request in response: parsed_data.append( { "ID": freeze_request.get("messageUid"), "Name": freeze_request.get("name"), "CreatedUTC": freeze_request.get("createdDateTimeUtc"), "ChangedUTC": freeze_request.get("changedDateTimeUtc"), "Content": freeze_request.get("content"), "CreatedBy": freeze_request.get("createdBy"), "ChangedBy": freeze_request.get("changedBy"), } ) return parsed_data def get_device_freeze_request_command(args, client) -> CommandResults: """Gets a device freeze request""" request_uid = args.get("request_uid") res = client.api_request_absolute("GET", f"/v3/actions/freeze/requests/{request_uid}") outputs = parse_get_device_freeze_response(res) human_readable = tableToMarkdown( f"{INTEGRATION} Freeze request details for: {request_uid}", outputs, headers=["ID", "Name", "ActionRequestUid", "EventHistoryId", "CreatedUTC", "ChangedUTC", "Requester"], removeNull=True, ) return CommandResults( outputs=outputs, outputs_prefix="Absolute.FreezeRequestDetail", outputs_key_field="ID", readable_output=human_readable, raw_response=res, ) def list_device_freeze_message_command(args, client) -> CommandResults: """Lists device freeze messages""" message_id = args.get("message_id") if message_id: res = client.api_request_absolute("GET", f"/v3/actions/freeze/messages/{message_id}") else: page = arg_to_number(args.get("page", 0)) limit = arg_to_number(args.get("limit", DEFAULT_LIMIT)) res = client.api_request_absolute( "GET", "/v3/actions/freeze/messages", page=page, page_size=limit, specific_page=True, success_status_code=(200, 204) ) outputs = parse_device_freeze_message_response(res) human_readable = tableToMarkdown( f"{INTEGRATION} Device freeze message details:", outputs, headers=["ID", "Name", "CreatedUTC", "ChangedUTC", "ChangedBy", "CreatedBy"], removeNull=True, ) return CommandResults( outputs=outputs, outputs_prefix="Absolute.FreezeMessage", outputs_key_field="ID", readable_output=human_readable, raw_response=res, ) def create_device_freeze_message_command(args, client) -> CommandResults: """Creates device freeze message""" html_message = args.get("html_message") message_name = args.get("message_name") payload = {"name": message_name, "content": html_message} res = client.api_request_absolute("POST", "/v3/actions/freeze/messages", body=payload, success_status_code=(200, 201)) message_id = res.get("messageUid", "") human_readable = f"{INTEGRATION} New freeze message was created with ID: {message_id}" return CommandResults( outputs={"ID": message_id}, outputs_prefix="Absolute.FreezeMessage", outputs_key_field="ID", readable_output=human_readable, raw_response=res, ) def update_device_freeze_message_command(args, client) -> CommandResults: """Updates device freeze message""" message_id = args.get("message_id") html_message = args.get("html_message") message_name = args.get("message_name") payload = {"name": message_name, "content": html_message} client.api_request_absolute("PUT", f"/v3/actions/freeze/messages/{message_id}", body=payload, success_status_code=(200, 204)) return CommandResults(readable_output=f"{INTEGRATION} Freeze message: {message_id} was updated successfully") def delete_device_freeze_message_command(args, client) -> CommandResults: """Deletes device freeze request""" message_id = args.get("message_id") client.api_request_absolute("DELETE", f"/v3/actions/freeze/messages/{message_id}", success_status_code=[204]) return CommandResults(readable_output=f"{INTEGRATION} Freeze message: {message_id} was deleted successfully") def parse_device_unenroll_request_data_response(response: dict) -> dict: """Parse the unenroll response Args: response (dict): The response to parse """ parsed_data = { "TotalDevices": response.get("totalDevices"), "Pending": response.get("pending"), "Processing": response.get("processing"), "Completed": response.get("completed"), "Canceled": response.get("canceled"), "Failed": response.get("failed"), "RequestId": response.get("requestId"), "RequestUid": response.get("requestUid"), "RequestStatus": response.get("requestStatus"), "CreatedDateTimeUtc": response.get("createdDateTimeUtc"), "UpdatedDateTimeUtc": response.get("updatedDateTimeUtc"), "Requester": response.get("requester"), "ExcludeMissingDevices": response.get("excludeMissingDevices"), } return parsed_data def parse_device_unenroll_response(response: list, request_uid: str) -> list: """Parse the unenroll response Args: response (list): The response to parse. request_uid (str): The request uid if the current request """ parsed_devices_data = [] for device in response: if device.get("requestUid") == request_uid: # only returning device data from the current unenroll request parsed_devices_data.append( { "DeviceUid": device.get("deviceUid"), "ActionUid": device.get("actionUid"), "RequestUid": device.get("requestUid"), "DeviceName": device.get("deviceName"), "ActionStatus": device.get("actionStatus"), "ESN": device.get("esn"), "CreatedDateTimeUtc": device.get("createdDateTimeUtc"), "UpdatedDateTimeUtc": device.get("updatedDateTimeUtc"), } ) return parsed_devices_data def device_unenroll_command(args, client) -> CommandResults: """Unenroll devices""" device_ids = argToList(args.get("device_ids")) exclude_missing_devices = args.get("exclude_missing_devices", "false") payload = {"deviceUids": device_ids, "excludeMissingDevices": exclude_missing_devices} # getting the requestUid from API 1 res_1 = client.api_request_absolute("POST", "/v3/actions/requests/unenroll", body=payload) request_uid = res_1.get("requestUid", "") # getting data from API 2 res_2 = client.api_request_absolute("GET", f"/v3/actions/requests/unenroll/{request_uid}") request_data_outputs = parse_device_unenroll_request_data_response(res_2) # getting data from API 3 payload = {"deviceUids": device_ids} res_3 = client.api_request_absolute("POST", "/v3/actions/unenroll/get-actions", body=payload) devices_data_outputs = parse_device_unenroll_response(res_3, request_uid) human_readable = tableToMarkdown( f"{INTEGRATION} Unenroll request data:", request_data_outputs, headers=["RequestUid", "RequestStatus"], removeNull=True ) human_readable += tableToMarkdown( f"{INTEGRATION} unenrolled devices:", devices_data_outputs, headers=["DeviceUid", "DeviceName", "ESN"], removeNull=True ) outputs = request_data_outputs outputs["Devices"] = devices_data_outputs return CommandResults( outputs_prefix="Absolute.DeviceUnenroll", outputs=outputs, readable_output=human_readable, raw_response=outputs ) def add_list_to_filter_string(field_name, list_of_values, query): if not list_of_values: return query query_list = [] list_of_values.sort() query_list.extend([f"substringof('{value}',{field_name})" for value in list_of_values]) new_query = " or ".join(query_list) if query: return f"{query} or {new_query}" return new_query def add_value_to_filter_string(field_name, value, query): if not value: return query if query: # if there is already a query, we should add 'or' before appending the new query return f"{query} or {field_name} eq '{value}'" return f"{field_name} eq '{value}'" def create_filter_query_from_args_helper(args, arg_name, source_name, query): list_no_duplicates = remove_duplicates_from_list_arg(args, arg_name) query = add_list_to_filter_string(source_name, list_no_duplicates, query) return query def create_filter_query_from_args(args: dict, change_device_name_to_system: bool = False, change_device_id: bool = False) -> str: """ Args: args: args given from the user. change_device_name_to_system: True if to filter by "systemName" parameter and False to filter by "deviceName". change_device_id: True if to filter by "id" parameter and False to filter by "deviceUid". Returns: filter query to send to the API. """ custom_filter = args.get("filter") if custom_filter: return f"$filter={custom_filter}" query = "" query = create_filter_query_from_args_helper(args, "account_uids", "accountUid", query) query = create_filter_query_from_args_helper(args, "app_names", "appName", query) query = create_filter_query_from_args_helper(args, "app_publishers", "appPublisher", query) query = create_filter_query_from_args_helper(args, "user_names", "userName", query) query = create_filter_query_from_args_helper(args, "user_names", "username", query) query = create_filter_query_from_args_helper(args, "os", "osName", query) query = create_filter_query_from_args_helper(args, "esn", "esn", query) query = create_filter_query_from_args_helper(args, "local_ips", "localIp", query) query = create_filter_query_from_args_helper(args, "public_ips", "publicIp", query) device_names = remove_duplicates_from_list_arg(args, "device_names") if device_names and change_device_name_to_system: query = add_list_to_filter_string("systemName", device_names, query) else: query = add_list_to_filter_string("deviceName", device_names, query) device_ids = remove_duplicates_from_list_arg(args, "device_ids") if device_ids and change_device_id: query = add_list_to_filter_string("id", device_ids, query) else: query = add_list_to_filter_string("deviceUid", device_ids, query) if args.get("agent_status"): agent_status = ABSOLUTE_AGET_STATUS[args.get("agent_status")] # type: ignore query = add_value_to_filter_string("agentStatus", agent_status, query) os_name = args.get("os_name") query = add_value_to_filter_string("operatingSystem.name", os_name, query) os_version = args.get("os_version") query = add_value_to_filter_string("operatingSystem.version", os_version, query) manufacturer = args.get("manufacturer") query = add_value_to_filter_string("systemManufacturer", manufacturer, query) model = args.get("model") query = add_value_to_filter_string("systemModel", model, query) return f"$filter={query}" def parse_return_fields(return_fields: str, query: str): """ Returns values only for the fields that meet the specified criteria in the query. All other fields are returned with a null value. """ if not return_fields: return query if query: return f"{query}&$select={return_fields}" return f"$select={return_fields}" def parse_device_list_response(response: list, keep_os_in_list=True, application_list=False) -> list: """Parse the device list response Args: response (list): The response to parse """ parsed_response = [] for device in response: parsed_device = {} for key, val in device.items(): if val: if key == "os" and not keep_os_in_list: parsed_device["osName"] = val.get("name") elif key == "deviceUid" and application_list: parsed_device["DeviceUid"] = val elif key in DEVICE_OUTPUT_TO_XSOAR_CONTEXT_PATH: parsed_device[DEVICE_OUTPUT_TO_XSOAR_CONTEXT_PATH[key]] = val elif key == "espInfo": parsed_device["encryptionStatus"] = val.get("encryptionStatus") elif key == "lastConnectedDateTimeUtc": parsed_device["LastConnectedUtc"] = val elif key == "installDateTimeUtc": parsed_device["InstallDate"] = val elif key == "firstDetectDateTimeUtc": parsed_device["FirstDetectUtc"] = val elif key == "lastScanDateTimeUtc": parsed_device["LastScanTimeUtc"] = val elif key == "operatingSystem": parsed_device["Os"] = { "architecture": val.get("architecture"), "currentBuild": val.get("currentBuild"), "installDate": val.get("installDateTimeUtc"), "lastBootTime": val.get("lastBootDateTimeUtc"), "name": val.get("name"), "productKey": val.get("productKey"), "serialNumber": val.get("serialNumber"), "version": val.get("version"), } else: parsed_device[key[0].upper() + key[1:]] = val parsed_response.append(parsed_device) return parsed_response def parse_geo_location_outputs(response): parsed_response = [] for device in response: parsed_device = {} geo_data = device.get("geoData", {}).get("location", {}) parsed_device["Coordinates"] = geo_data.get("point", {}).get("coordinates") parsed_device["LocationTechnology"] = geo_data.get("locationTechnology") parsed_device["Accuracy"] = geo_data.get("accuracy") parsed_device["LastUpdate"] = geo_data.get("lastUpdateDateTimeUtc") parsed_device["City"] = geo_data.get("geoAddress", {}).get("city") parsed_device["State"] = geo_data.get("geoAddress", {}).get("state") parsed_device["CountryCode"] = geo_data.get("geoAddress", {}).get("countryCode") parsed_device["Country"] = geo_data.get("geoAddress", {}).get("country") parsed_device["ID"] = device.get("deviceUid") remove_nulls_from_dictionary(parsed_device) parsed_response.append(parsed_device) if len(parsed_response) == 1: return parsed_response[0] return parsed_response def get_device_application_list_command(args, client) -> CommandResults: """Lists devices applications""" page = arg_to_number(args.get("page", 0)) limit = arg_to_number(args.get("limit", DEFAULT_LIMIT)) query_string = create_filter_query_from_args(args) query_string = parse_return_fields(args.get("return_fields"), query_string) try: res = client.api_request_absolute( "GET", "/v3/reporting/applications-advanced", query_string=query_string, page=page, page_size=limit, specific_page=True, ) except Exception as e: if "Your request is invalid, please contact us for details." in str(e): raise Exception(f"Error in request - make sure your filter is in accordance to the Absolute documentation.\n{e}") else: raise e if res: outputs = parse_device_list_response(res, application_list=True) human_readable = tableToMarkdown(f"{INTEGRATION} device applications list:", outputs, removeNull=True) human_readable += f"\nAbove results are with page number: {page} and with limit: {limit}." return CommandResults( outputs_prefix="Absolute.DeviceApplication", outputs=outputs, outputs_key_field="Appid", readable_output=human_readable, raw_response=res, ) else: return CommandResults(readable_output=f"No applications found in {INTEGRATION} for the given filters: {args}") def device_list_command(args, client) -> CommandResults: """Lists devices""" page = arg_to_number(args.get("page", 0)) limit = arg_to_number(args.get("limit", DEFAULT_LIMIT)) query_string = create_filter_query_from_args(args, change_device_name_to_system=True) query_string = parse_return_fields(",".join(DEVICE_LIST_RETURN_FIELDS), query_string) try: res = client.api_request_absolute( "GET", "/v3/reporting/devices", query_string=query_string, page=page, page_size=limit, specific_page=True ) except Exception as e: if "Your request is invalid, please contact us for details." in str(e): raise Exception(f"Error in request - make sure your filter is in accordance to the Absolute documentation.\n{e}") else: raise e if res: outputs = parse_device_list_response(copy.deepcopy(res), keep_os_in_list=False) human_readable = tableToMarkdown( f"{INTEGRATION} devices list:", outputs, headers=["Id", "LastConnectedUtc", "LocalIp", "AgentStatus", "Esn", "FullSystemName"], removeNull=True, ) human_readable += f"\nAbove results are with page number: {page} and with limit: {limit}." return CommandResults( outputs_prefix="Absolute.Device", outputs=outputs, outputs_key_field="Id", readable_output=human_readable, raw_response=res, ) else: return CommandResults(readable_output=f"No devices found in {INTEGRATION} for the given filters: {args}") def get_device_command(args, client) -> CommandResults: """Gets a device""" if not ("device_ids" in args or "device_names" in args or "local_ips" in args or "public_ips" in args): raise_demisto_exception( "at least one of the commands args (device_ids, device_names, local_ips, public_ips must be provided." ) query_string = create_filter_query_from_args(args, change_device_name_to_system=True, change_device_id=True) custom_fields_to_return = remove_duplicates_from_list_arg(args, "fields") if custom_fields_to_return: custom_fields_to_return.extend(DEVICE_GET_COMMAND_RETURN_FIELDS) query_string = parse_return_fields(",".join(custom_fields_to_return), query_string) else: query_string = parse_return_fields(",".join(DEVICE_GET_COMMAND_RETURN_FIELDS), query_string) res = client.api_request_absolute( "GET", "/v3/reporting/devices", query_string=query_string, page_size=MAX_PAGE_SIZE, ) if res: outputs = parse_device_list_response(copy.deepcopy(res)) human_readable = tableToMarkdown(f"{INTEGRATION} devices list:", outputs, removeNull=True) return CommandResults( outputs_prefix="Absolute.Device", outputs=outputs, outputs_key_field="Id", readable_output=human_readable, raw_response=res, ) else: return CommandResults(readable_output=f"No devices found in {INTEGRATION} for the given filters: {args}") def get_device_location_command(args, client) -> CommandResults: query_string = create_filter_query_from_args(args, change_device_id=True) query_string = parse_return_fields(",".join(DEVICE_GET_LOCATION_COMMAND_RETURN_FIELDS), query_string) res = client.api_request_absolute("GET", "/v3/reporting/devices", query_string=query_string) if res: outputs = parse_geo_location_outputs(copy.deepcopy(res)) human_readable = tableToMarkdown(f"{INTEGRATION} devices location:", outputs, removeNull=True) return CommandResults( outputs_prefix="Absolute.LocationReport", outputs=outputs, readable_output=human_readable, raw_response=res ) else: return CommandResults(readable_output=f"No device locations found in {INTEGRATION} for the given filters: {args}") """ EVENT COLLECTOR """ def fetch_events(client: ClientV3, fetch_limit: int, last_run: Dict[str, Any]) -> tuple[List[Dict[str, Any]], Dict[str, Any]]: """ Fetches events from the API client, with time window and duplication handling. The function using the client to fetch events, and then helper function to handle duplication, add time field and calculate the new latest events. Args: client (ClientV3): The client object used for fetching events. fetch_limit (int): The maximum number of events to fetch. last_run (Dict[str, Any]): A dictionary containing the last run information, including the latest events time and latest events ID. Returns: Tuple[List[Dict[str, Any]], Dict[str, Any]]: A tuple containing the fetched events and the updated last run information. """ latest_events_time = last_run.get("latest_events_time") end_date = datetime.utcnow() start_date: datetime = ( datetime.strptime(latest_events_time, "%Y-%m-%dT%H:%M:%S.%fZ") if latest_events_time else (end_date - timedelta(minutes=1)) ) # Adjust fetch_limit to ensure that the number of events fetched matches the user's desired amount. fetch_limit += len(last_run.get("latest_events_id", [])) demisto.debug(f"Starting new fetch: {fetch_limit=}, {start_date=}, {end_date=}, {last_run=}") all_events = client.fetch_events_between_dates(fetch_limit, start_date, end_date) events, updated_last_run = process_events(all_events, last_run) demisto.debug(f'fetch_events: {updated_last_run.get("latest_events_id")=}, {updated_last_run.get("latest_events_time")=}') return events, updated_last_run def process_events( events: List[Dict[str, Any]], last_run: Dict[str, Any], should_get_latest_events: bool = True ) -> tuple[List[Dict[str, Any]], Dict[str, Any]]: """ Processes events by handling duplication, adding a time field, and optionally getting the latest events ID and time. Args: events (List[Dict[str, Any]]): The list of events to be processed. last_run (Dict[str, Any]): The updated last run information. should_get_latest_events (bool, optional): A flag indicating whether to get the latest events ID. Defaults to True. Returns: Tuple[List[Dict[str, Any]], [Dict[str, Any]]]: A tuple containing the processed events and the updated last run object. """ demisto.debug( f"Handle duplicate events, adding _time field to events and optionally getting the latest events id and time." f" {events=}, {last_run=}" ) last_run_latest_events_id = last_run.get("latest_events_id", []) earliest_event_time = last_run.get("latest_events_time", "") latest_event_time = events[-1].get("createdDateTimeUtc") if events else "" latest_events_id = [] filtered_events = [] for event in events: event_time = event.get("createdDateTimeUtc") # handle duplication if event_time == earliest_event_time and event.get("id") in last_run_latest_events_id: continue # adding time field event["_time"] = event.get("eventDateTimeUtc") # latest events batch if should_get_latest_events and event_time == latest_event_time: latest_events_id.append(event.get("id")) filtered_events.append(event) return filtered_events, { "latest_events_id": latest_events_id if latest_events_id else last_run_latest_events_id, "latest_events_time": latest_event_time, } def get_events(client, args) -> tuple[List[Dict[str, Any]], CommandResults]: start_date = arg_to_datetime(args.get("start_date", "one minute ago")) end_date = arg_to_datetime(args.get("end_date", "now")) fetch_limit = int(args.get("limit", 50)) if (start_date and end_date) and (start_date > end_date): raise ValueError("Start date is greater than the end date. Please provide valid dates.") events = client.fetch_events_between_dates(fetch_limit, start_date, end_date) demisto.debug(f"get_events: Found {len(events)} events.") if events: events, _ = process_events(events, {}, should_get_latest_events=False) return events, CommandResults(readable_output=tableToMarkdown("Events", t=events)) """ MAIN FUNCTION """ def main() -> None: # pragma: no cover params = demisto.params() try: base_url = validate_absolute_api_url(params.get("url", "")) token_id = params.get("credentials", {}).get("identifier") secret_key = params.get("credentials", {}).get("password") verify_certificate = not params.get("insecure", False) proxy = params.get("proxy", False) demisto.debug(f"Command being called is {demisto.command()}") demisto.debug(f"base_url: {base_url}") client_v3 = ClientV3(base_url=base_url, verify=verify_certificate, proxy=proxy, token_id=token_id, secret_key=secret_key) args = demisto.args() if demisto.command() == "test-module": return_results(test_module(client_v3)) elif demisto.command() == "absolute-custom-device-field-list": return_results(get_custom_device_field_list_command(args=args, client=client_v3)) elif demisto.command() == "absolute-custom-device-field-update": return_results(update_custom_device_field_command(args=args, client=client_v3)) elif demisto.command() == "absolute-device-freeze-request": return_results(device_freeze_request_command(args=args, client=client_v3)) elif demisto.command() == "absolute-device-remove-freeze-request": return_results(remove_device_freeze_request_command(args=args, client=client_v3)) elif demisto.command() == "absolute-device-freeze-request-get": return_results(get_device_freeze_request_command(args=args, client=client_v3)) elif demisto.command() == "absolute-device-freeze-message-list": return_results(list_device_freeze_message_command(args=args, client=client_v3)) elif demisto.command() == "absolute-device-freeze-message-create": return_results(create_device_freeze_message_command(args=args, client=client_v3)) elif demisto.command() == "absolute-device-freeze-message-update": return_results(update_device_freeze_message_command(args=args, client=client_v3)) elif demisto.command() == "absolute-device-freeze-message-delete": return_results(delete_device_freeze_message_command(args=args, client=client_v3)) elif demisto.command() == "absolute-device-unenroll": return_results(device_unenroll_command(args=args, client=client_v3)) elif demisto.command() == "absolute-device-application-list": return_results(get_device_application_list_command(args=args, client=client_v3)) elif demisto.command() == "absolute-device-list": return_results(device_list_command(args=args, client=client_v3)) elif demisto.command() == "absolute-device-get": return_results(get_device_command(args=args, client=client_v3)) elif demisto.command() == "absolute-device-location-get": return_results(get_device_location_command(args=args, client=client_v3)) elif demisto.command() == "fetch-events": max_events_per_fetch = arg_to_number(params.get("max_events_per_fetch", 10000)) or 10000 events, last_run_object = fetch_events(client_v3, max_events_per_fetch, demisto.getLastRun()) if events: send_events_to_xsiam(events=events, vendor="Absolute", product="Secure Endpoint") demisto.setLastRun(last_run_object) elif demisto.command() == "absolute-device-get-events": demisto.debug(f"Fetching Absolute Device events with the following parameters: {args}") should_push_events = argToBoolean(args.get("should_push_events", False)) events, command_result = get_events(client=client_v3, args=args) if should_push_events and events: send_events_to_xsiam(events=events, vendor=VENDOR, product=PRODUCT) return_results(command_result) else: raise NotImplementedError(f"{demisto.command()} is not an existing {INTEGRATION} command.") except Exception as e: return_error(f"Failed to execute {demisto.command()} command.\nError:\n{e!s}") """ ENTRY POINT """ if __name__ in ("__main__", "__builtin__", "builtins"): # pragma: no cover main()