Lansweeper
The Lansweeper integration allows users to retrieve the asset details.
IT Services · Lansweeper
Details
| ID | Lansweeper |
|---|---|
| Provider | Insight Partners |
| Category | IT Services |
| From Version | 6.0.0 |
| Docker Image | demisto/python3:3.12.13.10116658 |
| Supported Modules | Agentix XSIAM |
README
The Lansweeper integration allows users to retrieve the asset details.
This integration was integrated and tested with version 2.0 of Lansweeper
Configure Lansweeper in Cortex
| Parameter | Description | Required |
|---|---|---|
| Application Identity Code | Identity code generated for the specific application. | True |
| Trust any certificate (not secure) | False | |
| Use system proxy settings | 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.
ls-site-list
Retrieve a list of all sites to which an application has access.
Base Command
ls-site-list
Input
There are no input arguments for this command.
Context Output
| Path | Type | Description |
|---|---|---|
| Lansweeper.Site.id | String | Site ID. |
| Lansweeper.Site.name | String | Site name. |
Command Example
#### Context Example
```json
{
"Lansweeper": {
"Site": [
{
"id": "401d153d-2a59-45eb-879a-c291390448ca",
"name": "api-demo-data"
},
{
"id": "56d4ed4f-b2ad-4587-91b5-07bd453c5c76",
"name": "api-demo-data-v2"
}
]
}
}
Human Readable Output
Authorized Site(s)
Site ID Site Name 401d153d-2a59-45eb-879a-c291390448ca api-demo-data 56d4ed4f-b2ad-4587-91b5-07bd453c5c76 api-demo-data-v2
ls-ip-hunt
Return a list of all assets associated with a given site and IP address.
Base Command
ls-ip-hunt
Input
| Argument Name | Description | Required |
|---|---|---|
| site_id | Specify the site ID to retrieve the assets. Note: To get site ID, execute ls-site-list command. |
Optional |
| ip | Specify the IP address to retrieve the specific asset. Note: Supports multiple comma separated values. |
Required |
| limit | Number of records to retrieve in the response. Note: The minimum value supported is 1 and maximum value supported is 500. Default is 50. |
Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| Lansweeper.IP.assetId | String | Asset ID. |
| Lansweeper.IP.assetBasicInfo.name | String | Asset name. |
| Lansweeper.IP.assetBasicInfo.domain | String | Domain the asset belongs to. |
| Lansweeper.IP.assetBasicInfo.description | String | Description of the asset. |
| Lansweeper.IP.assetBasicInfo.firstSeen | Date | Date and time at which the asset was first scanned. |
| Lansweeper.IP.assetBasicInfo.fqdn | String | FQDN of the asset. |
| Lansweeper.IP.assetBasicInfo.ipAddress | String | IP address associated with the asset. |
| Lansweeper.IP.assetBasicInfo.lastSeen | Date | Date and time at which the asset was last scanned. |
| Lansweeper.IP.assetBasicInfo.mac | String | Asset’s main MAC address. |
| Lansweeper.IP.assetBasicInfo.userName | String | Name of the last logged on user. |
| Lansweeper.IP.assetBasicInfo.type | String | Type of the asset. |
| Lansweeper.IP.assetBasicInfo.userDomain | String | Domain of the last logged on user. |
| Lansweeper.IP.assetCustom.sku | String | Asset’s SKU. |
| Lansweeper.IP.assetCustom.model | String | Model of the asset. |
| Lansweeper.IP.assetCustom.firmwareVersion | String | Firmware version, retrieved from plug and play devices via the UPnP, DNS-SD or SSDP protocol. |
| Lansweeper.IP.assetCustom.purchaseDate | Date | When the asset was purchased. |
| Lansweeper.IP.assetCustom.warrantyDate | Date | When the asset’s warranty expires. |
| Lansweeper.IP.assetCustom.comment | String | Comment on the asset.. |
| Lansweeper.IP.assetCustom.location | String | Location of the asset. |
| Lansweeper.IP.assetCustom.contact | String | Contact person of the asset. |
| Lansweeper.IP.assetCustom.manufacturer | String | Manufacturer of the asset. |
| Lansweeper.IP.assetCustom.serialNumber | String | Serial number of the asset. |
| Lansweeper.IP.assetCustom.dnsName | String | DNS name of the asset. |
| Lansweeper.IP.assetCustom.stateName | String | State name of the asset. |
| Lansweeper.IP.operatingSystem.caption | String | Short description of the object. The string includes the operating system version. |
| Lansweeper.IP.operatingSystem.productType | String | Type of the operating system. |
| Lansweeper.IP.url | String | URL to the summary of the asset. |
| Lansweeper.IP.siteId | String | The ID of the site to which the asset belongs. |
| Lansweeper.IP.siteName | String | The name of the site to which the asset belongs. |
Command Example
!ls-ip-hunt ip="192.168.2.1"
Context Example
{
"Lansweeper": {
"IP": [
{
"assetBasicInfo": {
"firstSeen": "2018-06-15T12:03:34.917Z",
"ipAddress": "192.168.2.1",
"lastSeen": "2018-07-19T14:45:58.793Z",
"mac": "02:0C:29:FE:A6:64",
"name": "192.168.2.1",
"type": "Network device"
},
"assetCustom": {
"stateName": "Active"
},
"assetId": "608fa4d61be3044511e7239e",
"siteId": "401d153d-2a59-45eb-879a-c291390448ca",
"siteName": "api-demo-data",
"url": "https://app.lansweeper.com/api-demo-data/asset/MTI3My1Bc3NldC0wZGYzZGRiYS0zNzA3LTQ0ZWUtOWI0My1jMTkxOTQ1NmZkYTE=/summary"
},
{
"assetBasicInfo": {
"firstSeen": "2018-06-15T10:02:34.917Z",
"ipAddress": "192.168.2.1",
"lastSeen": "2018-07-19T12:44:58.793Z",
"mac": "02:0C:29:FE:A6:64",
"name": "192.168.2.1",
"type": "Network device"
},
"assetCustom": {
"stateName": "Active"
},
"assetId": "60eed3ba8a037f9341893701",
"siteId": "56d4ed4f-b2ad-4587-91b5-07bd453c5c76",
"siteName": "api-demo-data-v2",
"url": "https://app.lansweeper.com/api-demo-data-v2/asset/MTI3My1Bc3NldC1mODdkZjg5MS1kNmVkLTQyYzgtYThmMS1jZDJmMTBlYmE1ZGU=/summary"
}
]
}
}
Human Readable Output
Asset(s)
Name Domain User Name User Domain FQDN Description Type IP Address Mac Address Model Manufacturer Serial Number SKU Site Name First Seen Last Seen XLAN-897 Demo-domain John Doe Demo-domain Demo67.com Video / Image Editing APC 192.168.2.1 03:00:00:00:00:57 iMac18,3 Apple LAN897 LN001 api-demo-data 2018-02-12T16:04:02.733Z 2018-02-12T16:04:02.733Z XLAN-897 Demo-domain John Doe Demo-domain Demo67.com Video / Image Editing APC 192.168.2.1 03:00:00:00:00:57 iMac18,3 Apple LAN897 LN001 api-demo-data-v2 2018-02-12T14:04:02.733Z 2021-08-10T14:18:20.913Z
ls-mac-hunt
Return a list of all assets associated with a given site and MAC address.
Base Command
ls-mac-hunt
Input
| Argument Name | Description | Required |
|---|---|---|
| site_id | Specify the site ID to retrieve the assets. Note: To get site ID, execute ls-site-list command. |
Optional |
| mac_address | Specify the MAC address to retrieve the specific asset. Note: Supports multiple comma separated values. |
Required |
| limit | Number of records to retrieve in the response. Note: The minimum value supported is 1 and maximum value supported is 500. Default is 50. |
Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| Lansweeper.Mac.assetId | String | Asset ID. |
| Lansweeper.Mac.assetBasicInfo.name | String | Asset name. |
| Lansweeper.Mac.assetBasicInfo.domain | String | Domain the asset belongs to. |
| Lansweeper.Mac.assetBasicInfo.description | String | Description of the asset. |
| Lansweeper.Mac.assetBasicInfo.firstSeen | Date | Date and time at which the asset was first scanned. |
| Lansweeper.Mac.assetBasicInfo.fqdn | String | FQDN of the asset. |
| Lansweeper.Mac.assetBasicInfo.ipAddress | String | IP address associated with the asset. |
| Lansweeper.Mac.assetBasicInfo.lastSeen | Date | Date and time at which the asset was last scanned. |
| Lansweeper.Mac.assetBasicInfo.mac | String | Asset’s main MAC address. |
| Lansweeper.Mac.assetBasicInfo.userName | String | Name of the last logged on user. |
| Lansweeper.Mac.assetBasicInfo.type | String | Type of the asset. |
| Lansweeper.Mac.assetBasicInfo.userDomain | String | Domain of the last logged on user. |
| Lansweeper.Mac.assetCustom.sku | String | Asset’s SKU. |
| Lansweeper.Mac.assetCustom.model | String | Model of the asset. |
| Lansweeper.Mac.assetCustom.firmwareVersion | String | Firmware version, retrieved from plug and play devices via the UPnP, DNS-SD or SSDP protocol. |
| Lansweeper.Mac.assetCustom.purchaseDate | Date | When the asset was purchased. |
| Lansweeper.Mac.assetCustom.warrantyDate | Date | When the asset’s warranty expires. |
| Lansweeper.Mac.assetCustom.comment | String | Comment on the asset.. |
| Lansweeper.Mac.assetCustom.location | String | Location of the asset. |
| Lansweeper.Mac.assetCustom.contact | String | Contact person of the asset. |
| Lansweeper.Mac.assetCustom.manufacturer | String | Manufacturer of the asset. |
| Lansweeper.Mac.assetCustom.serialNumber | String | Serial number of the asset. |
| Lansweeper.Mac.assetCustom.dnsName | String | DNS name of the asset. |
| Lansweeper.Mac.assetCustom.stateName | String | State name of the asset. |
| Lansweeper.Mac.operatingSystem.caption | String | Short description of the object. The string includes the operating system version. |
| Lansweeper.Mac.operatingSystem.productType | String | Type of the operating system. |
| Lansweeper.Mac.url | String | URL to the summary of the asset. |
| Lansweeper.Mac.siteId | String | The ID of the site to which the asset belongs. |
| Lansweeper.Mac.siteName | String | The name of the site to which the asset belongs. |
Command Example
!ls-mac-hunt mac_address="03:00:00:00:00:57"
Context Example
{
"Lansweeper": {
"Mac": [
{
"assetBasicInfo": {
"domain": "Demo-domain",
"firstSeen": "2018-02-12T16:04:02.733Z",
"fqdn": "Demo67.com",
"ipAddress": "10.10.11.104",
"lastSeen": "2018-02-12T16:04:02.733Z",
"mac": "03:00:00:00:00:57",
"name": "XLAN-897",
"type": "APC",
"userDomain": "Demo-domain"
},
"assetCustom": {
"location": "Main Branch",
"purchaseDate": "2018-02-02T00:00:00.000Z",
"serialNumber": "LAN897",
"stateName": "Active",
"warrantyDate": "2023-02-02T00:00:00.000Z"
},
"assetId": "608fa4c81be3044511e6d97f",
"siteId": "401d153d-2a59-45eb-879a-c291390448ca",
"siteName": "api-demo-data",
"url": "https://app.lansweeper.com/api-demo-data/asset/ODk3LUFzc2V0LTBkZjNkZGJhLTM3MDctNDRlZS05YjQzLWMxOTE5NDU2ZmRhMQ==/summary"
},
{
"assetBasicInfo": {
"domain": "Demo-domain",
"firstSeen": "2018-02-12T14:04:02.733Z",
"fqdn": "Demo67.com",
"ipAddress": "10.10.11.104",
"lastSeen": "2021-08-10T14:18:20.913Z",
"mac": "03:00:00:00:00:57",
"name": "XLAN-897",
"type": "APC",
"userDomain": "Demo-domain"
},
"assetCustom": {
"location": "Main Branch",
"purchaseDate": "2018-02-02T02:00:00.000Z",
"serialNumber": "LAN897",
"stateName": "Active",
"warrantyDate": "2023-02-02T02:00:00.000Z"
},
"assetId": "60eed3b78a037f934189271c",
"siteId": "56d4ed4f-b2ad-4587-91b5-07bd453c5c76",
"siteName": "api-demo-data-v2",
"url": "https://app.lansweeper.com/api-demo-data-v2/asset/ODk3LUFzc2V0LWY4N2RmODkxLWQ2ZWQtNDJjOC1hOGYxLWNkMmYxMGViYTVkZQ==/summary"
}
]
}
}
Human Readable Output
Asset(s)
Name Domain User Name User Domain FQDN Description Type IP Address Mac Address Model Manufacturer Serial Number SKU Site Name First Seen Last Seen XLAN-897 Demo-domain John Doe Demo-domain Demo67.com Video / Image Editing APC 10.10.11.104 03:00:00:00:00:57 iMac18,3 Apple LAN897 LN001 api-demo-data 2018-02-12T16:04:02.733Z 2018-02-12T16:04:02.733Z XLAN-897 Demo-domain John Doe Demo-domain Demo67.com Video / Image Editing APC 10.10.11.104 03:00:00:00:00:57 iMac18,3 Apple LAN897 LN001 api-demo-data-v2 2018-02-12T14:04:02.733Z 2021-08-10T14:18:20.913Z
Configuration parameters
identity_code— Application Identity Code (required)insecure— Trust any certificate (not secure)proxy— Use system proxy settings
Commands (3)
-
ls-ip-huntReturn a list of all assets associated with a given site and IP address.
-
ls-mac-huntReturn a list of all assets associated with a given site and MAC address.
-
ls-site-listRetrieve a list of all sites to which an application has access.
import traceback from collections.abc import Callable from typing import Any import demistomock as demisto # noqa: F401 import urllib3 from CommonServerPython import * # noqa: F401 from CommonServerUserPython import * # noqa # Disable insecure warnings urllib3.disable_warnings() """ CONSTANTS """ DATE_FORMAT = "%Y-%m-%dT%H:%M:%SZ" # ISO8601 format with UTC, default in XSOAR COMMON_GRAPHQL_ENDPOINT = "https://api.lansweeper.com/api/v2/graphql" MESSAGES = { "AUTHENTICATION_ERROR": "Authentication error. Please provide valid 'Application Identity Code'.", "INTERNAL_SERVER_ERROR": "The server encountered an internal error for Lansweeper and was unable to complete your " "request.", "REQUIRED_ARGUMENT": "Invalid argument value. '{}' is a required argument.", "INVALID_IP": "Provided IP Address(es) are invalid.", "INVALID_MAC": "Provided Mac Address(es) are invalid.", "INVALID_LIMIT": "{} is an invalid value for limit. Limit must be between 1 and 500.", "NO_AUTHORIZED_SITES_FOUND": "No authorized sites found for configured 'Application Identity Code'", } """ CLIENT CLASS """ class Client(BaseClient): """Client class to interact with the service API""" def http_request(self, full_url, method="POST", json_data=None, params=None) -> Any: """ Function to make http requests using inbuilt _http_request() method. Handles token expiration case and makes request using refreshed token. :param json_data: The data to send in a 'POST' request. :param method: http method to use :param full_url: the API endpoint :param params: parameters to send with request :return: response from the request """ response = self._http_request( method=method, full_url=full_url, params=params, json_data=json_data, error_handler=self.exception_handler ) errors = response.get("errors", []) if errors: extensions = errors[0].get("extensions", {}) if extensions.get("exception", {}): err_msg = extensions.get("exception", {}).get("message", "") else: error_list = ( extensions.get("error", {}).get("extensions", {}).get("response", {}).get("body", {}).get("errors", []) ) err_msg = "\n".join(error.get("message", "") for error in error_list) raise DemistoException(err_msg) return response def site_list(self) -> Dict: """ Returns response :return: API response :rtype: ``Dict`` """ query = """query { authorizedSites { sites { id name } } }""" return self.http_request(full_url=COMMON_GRAPHQL_ENDPOINT, json_data={"query": query}) def asset_list(self, query) -> Dict: """ Returns response :return: API response :rtype: ``Dict`` """ params = {"query": query} return self.http_request(full_url=COMMON_GRAPHQL_ENDPOINT, json_data=params) @staticmethod def exception_handler(response: requests.models.Response): """ Handle error in the response and display error message based on status code. :type response: ``requests.models.Response`` :param response: response from API. :raises: raise DemistoException based on status code of response. """ err_msg = "" if response.status_code == 400: err_msg = MESSAGES["AUTHENTICATION_ERROR"] elif response.status_code >= 500: err_msg = MESSAGES["INTERNAL_SERVER_ERROR"] raise DemistoException(err_msg) """ HELPER FUNCTIONS """ def prepare_hr_for_site(sites: List[Dict[str, Any]]) -> str: """ Prepare human readable for list sites command. :type sites: ``List[Dict[str, Any]]`` :param sites:The site data. :rtype: ``str`` :return: Human readable. """ hr_list = [] for site in sites: hr_record = {"Site ID": site.get("id", ""), "Site Name": site.get("name", "")} hr_list.append(hr_record) return tableToMarkdown("Authorized Site(s)", hr_list, ["Site ID", "Site Name"], removeNull=True) def prepare_query(site_id: str, condition: str) -> str: """ Creates GraphQL query :type site_id: ``str`` :param site_id: Site ID entered by user :type condition: ``str`` :param condition: filter conditions :rtype: ``str`` :return: GraphQL query """ query = f"""query getAssetResources($pagination: AssetsPaginationInputValidated) {{ site(id: "{site_id}") {{ assetResources ( assetPagination: $pagination, fields: [ "assetBasicInfo.name", "assetBasicInfo.domain", "assetBasicInfo.userName", "assetBasicInfo.userDomain", "assetBasicInfo.fqdn", "assetBasicInfo.description", "assetBasicInfo.type", "assetBasicInfo.mac", "assetBasicInfo.ipAddress", "assetBasicInfo.firstSeen" "assetBasicInfo.lastSeen" "assetCustom.model", "assetCustom.serialNumber", "assetCustom.manufacturer", "assetCustom.sku", "assetCustom.firmwareVersion", "assetCustom.purchaseDate", "assetCustom.warrantyDate", "assetCustom.comment", "assetCustom.location", "assetCustom.department", "assetCustom.contact", "assetCustom.dnsName", "assetCustom.stateName", "operatingSystem.caption", "operatingSystem.productType", "url" ], filters: {{ conjunction: OR, conditions: [{condition}] }} ) {{ total pagination {{ limit current next page }} items }} }} }}""" return query def prepare_hr_for_asset(assets: List[Dict[str, Any]]) -> str: """ Prepare human readable for ls-ip-hunt command. :type assets: ``List[Dict[str, Any]]`` :param assets:The asset data. :rtype: ``str`` :return: Human readable. """ hr_list = [] for asset in assets: hr_record = { "Site Name": asset.get("siteName"), "Name": f"[{asset.get('assetBasicInfo', {}).get('name', '')}]({asset.get('url', '')})", "Domain": asset.get("assetBasicInfo", {}).get("domain", ""), "User Name": asset.get("assetBasicInfo", {}).get("userName", ""), "User Domain": asset.get("assetBasicInfo", {}).get("userDomain", ""), "FQDN": asset.get("assetBasicInfo", {}).get("fqdn", ""), "Description": asset.get("assetBasicInfo", {}).get("description", ""), "Type": asset.get("assetBasicInfo", {}).get("type", ""), "IP Address": asset.get("assetBasicInfo", {}).get("ipAddress", ""), "Mac Address": asset.get("assetBasicInfo", {}).get("mac", ""), "Model": asset.get("assetCustom", {}).get("model", ""), "Manufacturer": asset.get("assetCustom", {}).get("manufacturer", ""), "Serial Number": asset.get("assetCustom", {}).get("serialNumber", ""), "SKU": asset.get("assetCustom", {}).get("sku", ""), "First Seen": asset.get("assetBasicInfo", {}).get("firstSeen", ""), "Last Seen": asset.get("assetBasicInfo", {}).get("lastSeen", ""), } hr_list.append(hr_record) return tableToMarkdown( "Asset(s)", hr_list, [ "Name", "Domain", "User Name", "User Domain", "FQDN", "Description", "Type", "IP Address", "Mac Address", "Model", "Manufacturer", "Serial Number", "SKU", "Site Name", "First Seen", "Last Seen", ], removeNull=True, ) def prepare_site_list(client: Client, args: Dict) -> List: """ Prepare list of authorized sites :type client: ``Client`` :param client: Client object to be used. :type args: ``Dict`` :param args: The command arguments provided by the user. :return: site list :rtype: ``List`` """ site_id = args.get("site_id") site_response = get_authorized_sites(client) if not (site_id or site_response): raise ValueError(MESSAGES["NO_AUTHORIZED_SITES_FOUND"]) if site_id and site_response: for site in site_response: if site["id"] == site_id: return [site] site_list = [{"id": site_id}] elif site_id: site_list = [{"id": site_id}] else: site_list = site_response return site_list def get_authorized_sites(client: Client) -> List: """ Get the authorized sites from integration context if present else call the endpoint to retrieve authorized sites :type client: ``Client`` :param client: Client object to be used. :return: List of authorized sites :rtype: ``List`` """ site_response = get_integration_context() authorized_sites = site_response.get("authorized_sites") if authorized_sites: return authorized_sites response = client.site_list() site_response = get_integration_context() sites = {"authorized_sites": response.get("data", {}).get("authorizedSites", {}).get("sites", [])} site_response.update(sites) set_integration_context(site_response) return site_response["authorized_sites"] def creds_changed(context: dict, identity_code: str) -> bool: """ Check whether the credentials were changed by the user. Args: context (dict): Integration context from Demisto. identity_code (str): Lansweeper application identity code. Returns: creds_changed (bool): True if credentials were changed, False otherwise. """ return context.get("identity_code", "") != identity_code def update_context(identity_code: str) -> None: """ Invalidate the Demisto integration context and set new identity code. Args: identity_code (str): Lansweeper application identity code. """ set_integration_context({"identity_code": identity_code}) """ COMMAND FUNCTIONS """ def lansweeper_site_list_command(client: Client) -> CommandResults: """ Retrieves the list of authorized sites :type client: ``Client`` :param client: Client object to be used. :return: Standard command result or no records found message. :rtype: ``CommandResults`` """ response = client.site_list() records = response.get("data", {}).get("authorizedSites", {}).get("sites", []) context = remove_empty_elements(records) readable_hr = prepare_hr_for_site(records) return CommandResults( outputs_prefix="Lansweeper.Site", outputs_key_field="id", outputs=context, readable_output=readable_hr, raw_response=response, ) def lansweeper_ip_hunt_command(client: Client, args: Dict[str, str]) -> CommandResults: """ Retrieves the list of assets :type client: ``Client`` :param client: Client object to be used. :type args: ``Dict[str, str]`` :param args: The command arguments provided by the user. :return: Standard command result or no records found message. :rtype: ``CommandResults`` """ total_records = [] site_list = prepare_site_list(client, args) limit = arg_to_number(args.get("limit", 50)) ip_list = argToList(args["ip"]) if not ip_list: raise ValueError(MESSAGES["REQUIRED_ARGUMENT"].format("ip")) if limit <= 0 or limit > 500: # type:ignore raise ValueError(MESSAGES["INVALID_LIMIT"].format(limit)) ip_condition = "" for ip in ip_list: if is_ip_valid(ip): ip_condition += f"""{{operator: EQUAL,path: "assetBasicInfo.ipAddress",value: "{ip}"}},""" if not ip_condition: raise ValueError(MESSAGES["INVALID_IP"]) for site in site_list: query = prepare_query(site.get("id"), ip_condition[:-1]) response = client.asset_list(query) records = response.get("data", {}).get("site", {}).get("assetResources", {}).get("items", []) for record in records: record["assetId"] = record.pop("key", None) record["siteId"] = site.get("id") record["siteName"] = site.get("name") total_records.append(remove_empty_elements(record)) context = total_records[:limit] readable_hr = prepare_hr_for_asset(context) return CommandResults( outputs_prefix="Lansweeper.IP", outputs_key_field="assetId", outputs=context, readable_output=readable_hr, raw_response=response, ) def lansweeper_mac_hunt_command(client: Client, args: Dict[str, str]) -> CommandResults: """ Retrieves the list of assets :type client: ``Client`` :param client: Client object to be used. :type args: ``Dict[str, str]`` :param args: The command arguments provided by the user. :return: Standard command result or no records found message. :rtype: ``CommandResults`` """ total_records = [] site_list = prepare_site_list(client, args) limit = arg_to_number(args.get("limit", 50)) mac_list = argToList(args["mac_address"]) if not mac_list: raise ValueError(MESSAGES["REQUIRED_ARGUMENT"].format("mac_address")) if limit <= 0 or limit > 500: # type:ignore raise ValueError(MESSAGES["INVALID_LIMIT"].format(limit)) mac_condition = "" for mac in mac_list: if is_mac_address(mac): mac_condition += f"""{{operator: EQUAL,path: "assetBasicInfo.mac",value: "{mac}"}},""" if not mac_condition: raise ValueError(MESSAGES["INVALID_MAC"]) for site in site_list: query = prepare_query(site.get("id"), mac_condition[:-1]) response = client.asset_list(query) records = response.get("data", {}).get("site", {}).get("assetResources", {}).get("items", []) for record in records: record["assetId"] = record.pop("key", None) record["siteId"] = site.get("id") record["siteName"] = site.get("name") total_records.append(remove_empty_elements(record)) context = total_records[:limit] readable_hr = prepare_hr_for_asset(context) return CommandResults( outputs_prefix="Lansweeper.Mac", outputs_key_field="assetId", outputs=context, readable_output=readable_hr, raw_response=response, ) def test_module(client: Client) -> str: """Tests API connectivity and authentication' Returning 'ok' indicates that the integration works like it is supposed to. Connection to the service is successful. Raises: exceptions if something goes wrong. Args: client: client to use Returns: 'ok' if test passed, anything else will fail the test. """ client.site_list() return "ok" def main(): """main function, parses params and runs command functions""" command = demisto.command() demisto.debug(f"[Lansweeper] Command being called is {command}") params = demisto.params() verify_certificate = not params.get("insecure", False) proxy = params.get("proxy", False) identity_code = params.get("identity_code") if creds_changed(get_integration_context(), identity_code): update_context(identity_code) # Commands dictionary commands: Dict[str, Callable] = {"ls-ip-hunt": lansweeper_ip_hunt_command, "ls-mac-hunt": lansweeper_mac_hunt_command} try: headers: Dict = {"Authorization": f"Token {identity_code}"} client = Client(base_url=COMMON_GRAPHQL_ENDPOINT, verify=verify_certificate, proxy=proxy, headers=headers) if command == "test-module": # This is the call made when pressing the integration Test button. return_results(test_module(client)) elif command == "ls-site-list": return_results(lansweeper_site_list_command(client)) elif command in commands: args = {key: value.strip() for key, value in demisto.args().items()} return_results(commands[command](client, args)) else: raise NotImplementedError(f"Command {demisto.command()} is not implemented") # Log exceptions and return errors except Exception as e: demisto.error(traceback.format_exc()) # print the traceback return_error(f"Failed to execute {command} command.\nError:\n{e!s}") if __name__ in ("__main__", "__builtin__", "builtins"): # pragma: no cover main()