Azure Storage Table

Create and Manage Azure Storage Tables and Entities.

IT Services · Azure Storage Table

Details

IDAzure Storage Table
ProviderMicrosoft
CategoryIT Services
From Version6.0.0
Docker Imagedemisto/python3:3.12.13.10116658
Supported ModulesAgentix XSIAM

README

Azure Storage Table

Create and Manage Azure Storage Tables and Entities.
This integration was integrated and tested with version “2020-10-02” of Azure Storage Table

Configure Azure Storage Table in Cortex

Parameter Required
Storage account name True
Account SAS Token False
Use Azure Managed Identities False
Azure Managed Identities Client ID False
Use system proxy settings False
Trust any certificate (not secure) False

Shared Access Signatures (SAS) Permissions

In order to use the integration use-cases,
please make sure your SAS token contains the following permissions:

  1. ‘Table’ service.
  2. ‘Service’ and ‘Object’ resource types.
  3. ‘Read’, ‘Write’, ‘Delete’, ‘List’, ‘Create’, ‘Add’, ‘Update’ and ‘Immutable storage’ permissions.
  • Review and select “Generate”.

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.

azure-storage-table-create


Creates a new table in a storage account.

Base Command

azure-storage-table-create

Input

Argument Name Description Required
table_name The name of the new table to create. Rules for naming tables can be found here: https://docs.microsoft.com/en-us/rest/api/storageservices/understanding-the-table-service-data-model. Required

Context Output

Path Type Description
AzureStorageTable.Table.name String Table name.

Command Example

!azure-storage-table-create table_name="xsoar"

Context Example

{
    "AzureStorageTable": {
        "Table": {
            "name": "xsoar"
        }
    }
}

Human Readable Output

Table xsoar successfully created.

azure-storage-table-delete


Delete the specified table and any data it contains.

Base Command

azure-storage-table-delete

Input

Argument Name Description Required
table_name The name of the table to delete. Required

Context Output

There is no context output for this command.

Command Example

!azure-storage-table-delete table_name="xsoar"

Human Readable Output

Table xsoar successfully deleted.

azure-storage-table-query


List tables under the specified account.

Base Command

azure-storage-table-query

Input

Argument Name Description Required
limit Number of Tables to retrieve. Default is 50. Default is 50. Optional
filter Filter Tables Query expression.
Information about Query expression structure can be found here: https://docs.microsoft.com/en-us/rest/api/storageservices/querying-tables-and-entities#constructing-filter-strings.
Optional
page Page Number. Default is 1. Default is 1. Optional

Context Output

Path Type Description
AzureStorageTable.Table.name String Table name.

Command Example

!azure-storage-table-query filter="TableName%20eq%20'xsoar'"

Context Example

{
    "AzureStorageTable": {
        "Table": {
            "name": "xsoar"
        }
    }
}

Human Readable Output

Tables List

Current page size: 50
Showing page 1 out others that may exist

Name
xsoar

azure-storage-table-entity-insert


Insert a new entity into a table.

Base Command

azure-storage-table-entity-insert

Input

Argument Name Description Required
table_name Table name. Required
partition_key Unique identifier for the partition within a given table. Required
row_key Unique identifier for an entity within a given partition. Required
entity_fields Entity fields in JSON format: { “Key1”: Value1, “Key2”: Value2}. Required

Context Output

Path Type Description
AzureStorageTable.Table.Entity.PartitionKey String Entity partition key.
AzureStorageTable.Table.Entity.RowKey String Entity row key.
AzureStorageTable.Table.Entity.Timestamp Date Entity last update UTC time.
AzureStorageTable.Table.name String Entity table name.

Command Example

!azure-storage-table-entity-insert table_name="xsoar" partition_key="xsoar-partition" row_key="xsoar-row" entity_fields=`{"Age":20}`

Context Example

{
    "AzureStorageTable": {
        "Table": {
            "Entity": [
                {
                    "Age": 20,
                    "PartitionKey": "xsoar-partition",
                    "RowKey": "xsoar-row",
                    "Timestamp": "2021-11-28T13:23:18"
                }
            ],
            "name": "xsoar"
        }
    }
}

Human Readable Output

Entity Fields for xsoar Table

Age Partition Key Row Key Timestamp
20 xsoar-partition xsoar-row 2021-11-28T13:23:18

azure-storage-table-entity-update


Update an existing entity in a table. The Update Entity command does not replace the existing entity.

Base Command

azure-storage-table-entity-update

Input

Argument Name Description Required
table_name Entity table name. Required
partition_key Unique identifier for the partition within a given table. Required
row_key Unique identifier for an entity within a given partition. Required
entity_fields Entity fields in JSON format: { “Key1”: Value1, “Key2”: Value2}. Required

Context Output

There is no context output for this command.

Command Example

!azure-storage-table-entity-update table_name="xsoar" partition_key="xsoar-partition" row_key="xsoar-row" entity_fields=`{"Address":"New York"}`

Human Readable Output

Entity in xsoar table successfully updated.

azure-storage-table-entity-replace


Replace an existing entity in a table. The Replace Entity command replace the entire entity and can be used to remove properties.

Base Command

azure-storage-table-entity-replace

Input

Argument Name Description Required
table_name Table name. Required
partition_key Unique identifier for the partition within a given table. Required
row_key Unique identifier for an entity within a given partition. Required
entity_fields Entity records in JSON format: { “Key1”: Value1, “Key2”: Value2}. Required

Context Output

There is no context output for this command.

Command Example

!azure-storage-table-entity-replace table_name="xsoar" partition_key="xsoar-partition" row_key="xsoar-row" entity_fields=`{"City": "TLV" }`

Human Readable Output

Entity in xsoar table successfully replaced.

azure-storage-table-entity-query


Query Entities in a table.

Base Command

azure-storage-table-entity-query

Input

Argument Name Description Required
table_name Entity table name. Required
partition_key Unique identifier for the partition within a given table. If specified, ‘row_key’ argument must also be specified. Optional
row_key Unique identifier for an entity within a given partition. If specified, ‘partition_key’ argument must also be specified. Optional
filter Filter Entities query expression.
Information about Query expression structure can be found here: https://docs.microsoft.com/en-us/rest/api/storageservices/querying-tables-and-entities#constructing-filter-strings.
Optional
select Comma-separated Entity properties to return. If not specified - all fields will be retrieved. Optional
limit Number of entities to retrieve. Default is 50.
This argument is will be ignored when ‘partition_key’ or ‘row_key’ arguments are provided. Default is 50.
Optional
page Page number. Default is 1.
This argument is will be ignored when ‘partition_key’ or ‘row_key’ arguments are provided. Default is 1.
Optional

Context Output

Path Type Description
AzureStorageTable.Table.name String Entity table Name.

Command Example

!azure-storage-table-entity-query table_name="xsoar"

Context Example

{
    "AzureStorageTable": {
        "Table": {
            "Entity": [
                {
                    "Address": "New York",
                    "City": "TLV",
                    "PartitionKey": "xsoar-partition",
                    "RowKey": "xsoar-row",
                    "Timestamp": "2021-11-28T13:23:27"
                }
            ],
            "name": "xsoar"
        }
    }
}

Human Readable Output

Entity Fields for xsoar table

Current page size: 50
Showing page 1 out others that may exist

Address City Partition Key Row Key Timestamp
New York TLV xsoar-partition xsoar-row 2021-11-28T13:23:27

azure-storage-table-entity-delete


Delete an existing entity in a table.

Base Command

azure-storage-table-entity-delete

Input

Argument Name Description Required
table_name Entity table name. Required
partition_key Unique identifier for the partition within a given table. Required
row_key Unique identifier for an entity within a given partition. Required

Context Output

There is no context output for this command.

Command Example

!azure-storage-table-entity-delete table_name="xsoar" partition_key="xsoar-partition" row_key="xsoar-row"

Human Readable Output

Entity in xsoar table successfully deleted.

Configuration parameters

  • credentials — Storage account name
  • use_managed_identities — Use Azure Managed Identities
  • managed_identities_client_id
  • proxy — Use system proxy settings
  • insecure — Trust any certificate (not secure)

Commands (8)

  • azure-storage-table-create

    Creates a new table in a storage account.

  • azure-storage-table-delete

    Delete the specified table and any data it contains.

  • azure-storage-table-entity-delete

    Delete an existing entity in a table.

  • azure-storage-table-entity-insert

    Insert a new entity into a table.

  • azure-storage-table-entity-query

    Query Entities in a table.

  • azure-storage-table-entity-replace

    Replace an existing entity in a table. The Replace Entity command replace the entire entity and can be used to remove properties.

  • azure-storage-table-entity-update

    Update an existing entity in a table. The Update Entity command does not replace the existing entity.

  • azure-storage-table-query

    List tables under the specified account.

import copy

import demistomock as demisto  # noqa: F401
import urllib3
from CommonServerPython import *  # noqa: F401
from requests import Response

DATE_FORMAT = "%Y-%m-%dT%H:%M:%S.%fZ"
account_sas_token = ""
storage_account_name = ""


class Client:
    """
    API Client
    """

    def __init__(
        self,
        server_url,
        verify,
        proxy,
        account_sas_token,
        storage_account_name,
        api_version,
        managed_identities_client_id: Optional[str] = None,
    ):
        self.ms_client = MicrosoftStorageClient(
            server_url, verify, proxy, account_sas_token, storage_account_name, api_version, managed_identities_client_id
        )

    def create_table_request(self, table_name: str) -> dict:
        """
        Creates a new table in a storage account.

        Args:
            table_name (str): Table name.

        Returns:
            dict: API response from Azure.

        """
        headers = {"Content-Type": "application/json", "Accept": "application/json;odata=nometadata"}

        data = {"TableName": table_name}

        response = self.ms_client.http_request(
            method="POST", url_suffix="Tables", headers=headers, resp_type="json", json_data=data
        )

        return response

    def delete_table_request(self, table_name: str) -> Response:
        """
        Delete the specified table and any data it contains.

        Args:
            table_name (str): Table name.

        Returns:
            Response: API response from Azure.

        """
        url_suffix = f"Tables('{table_name}')"

        response = self.ms_client.http_request(method="DELETE", url_suffix=url_suffix, return_empty_response=True)

        return response

    def query_tables_request(self, limit: str = None, query_filter: str = None, next_table: str = None) -> Response:
        """
        List tables under the specified account.

        Args:
            limit (str): Retrieve top n tables.
            query_filter (str): Query expression.
            next_table (str): Identifies the portion of the list to be returned.

        Returns:
            Response: API response from Azure.

        """
        headers = {"Accept": "application/json;odata=nometadata"}

        params = remove_empty_elements({"$top": limit, "$filter": query_filter, "NextTableName": next_table})

        response = self.ms_client.http_request(
            method="GET", url_suffix="Tables", headers=headers, params=params, return_empty_response=True
        )

        return response

    def insert_entity_request(self, table_name: str, entity_fields: dict) -> dict:
        """
        Insert a new entity into a table.

        Args:
            table_name (str): Table name.
            entity_fields (dict): Entity fields data.

        Returns:
            dict: API response from Azure.

        """
        headers = {"Content-Type": "application/json", "Accept": "application/json;odata=nometadata"}

        response = self.ms_client.http_request(
            method="POST", url_suffix=f"{table_name}", headers=headers, resp_type="json", json_data=entity_fields
        )

        return response

    def update_entity_request(self, table_name: str, partition_key: str, row_key: str, entity_fields: dict) -> Response:
        """
        Update an existing entity in a table.

        Args:
            table_name (str): Table name.
            partition_key (str): Unique identifier for the partition within a given table.
            row_key (str): Unique identifier for an entity within a given partition.
            entity_fields (dict): Entity fields data.

        Returns:
            Response: API response from Azure.

        """

        headers = {"Content-Type": "application/json"}

        url_suffix = f"{table_name}(PartitionKey='{partition_key}',RowKey='{row_key}')"

        response = self.ms_client.http_request(
            method="MERGE", url_suffix=url_suffix, headers=headers, return_empty_response=True, json_data=entity_fields
        )

        return response

    def replace_entity_request(self, table_name: str, partition_key: str, row_key: str, entity_fields: dict) -> Response:
        """
        Replace an existing entity in a table.

        Args:
            table_name (str): Table name.
            partition_key (str): Unique identifier for the partition within a given table.
            row_key (str): Unique identifier for an entity within a given partition.
            entity_fields (dict): Entity fields data.

        Returns:
            Response: API response from Azure.

        """
        headers = {"Content-Type": "application/json"}

        url_suffix = f"{table_name}(PartitionKey='{partition_key}',RowKey='{row_key}')"

        response = self.ms_client.http_request(
            method="PUT", url_suffix=url_suffix, headers=headers, return_empty_response=True, json_data=entity_fields
        )

        return response

    def query_entity_request(
        self,
        table_name: str,
        partition_key: str = None,
        row_key: str = None,
        query_filter: str = None,
        select: str = None,
        limit: str = None,
        next_partition_key: str = None,
        next_row_key: str = None,
    ) -> Response:
        """
        Query entities in a table.

        Args:
            table_name (str): Table name.
            partition_key (str): Unique identifier for the partition within a given table.
            row_key (str): Unique identifier for an entity within a given partition.
            query_filter (str): Query expression.
            select (str): Entity properties to return.
            limit (str): Retrieve top n entities.
            next_partition_key (str): Identifies the portion of the list to be returned.
            next_row_key (str): Identifies the portion of the list to be returned.

        Returns:
            Response: API response from Azure.

        """
        headers = {"Accept": "application/json;odata=nometadata"}

        params = remove_empty_elements(
            {
                "$filter": query_filter,
                "$select": select,
                "$top": limit,
                "NextPartitionKey": next_partition_key,
                "NextRowKey": next_row_key,
            }
        )

        url_suffix = f"{table_name}(PartitionKey='{partition_key}',RowKey='{row_key}')" if partition_key else f"{table_name}()"

        response = self.ms_client.http_request(
            method="GET", url_suffix=url_suffix, params=params, headers=headers, return_empty_response=True
        )

        return response

    def delete_entity_request(self, table_name: str, partition_key: str, row_key: str) -> Response:
        """
        Delete an existing entity in a table

        Args:
            table_name (str): Table name.
            partition_key (str): Unique identifier for the partition within a given table.
            row_key (str): Unique identifier for an entity within a given partition.

        Returns:
            Response: API response from Azure.

        """
        headers = {"If-Match": "*"}

        url_suffix = f"{table_name}(PartitionKey='{partition_key}',RowKey='{row_key}')"

        response = self.ms_client.http_request(
            method="DELETE", url_suffix=url_suffix, headers=headers, return_empty_response=True
        )

        return response


def create_table_command(client: Client, args: Dict[str, Any]) -> CommandResults:
    """
    Creates a new table in a storage account.

    Args:
        client (Client): Azure Table Storage API client.
        args (dict): Command arguments from XSOAR.

    Returns:
        CommandResults: outputs, readable outputs and raw response for XSOAR.

    """
    table_name = args["table_name"]

    table_name_regex = "^[A-Za-z][A-Za-z0-9]{2,62}$"
    # Rules for naming tables can be found here:
    # https://docs.microsoft.com/en-us/rest/api/storageservices/understanding-the-table-service-data-model

    if not re.search(table_name_regex, table_name):
        raise Exception("The specified table name is invalid.")

    response = client.create_table_request(table_name)
    outputs = {"name": response.get("TableName")}

    command_results = CommandResults(
        readable_output=f"Table {table_name} successfully created.",
        outputs_prefix="AzureStorageTable.Table",
        outputs_key_field="name",
        outputs=outputs,
        raw_response=response,
    )

    return command_results


def delete_table_command(client: Client, args: Dict[str, Any]) -> CommandResults:
    """
    Delete the specified table and any data it contains.

    Args:
        client (Client): Azure Table Storage API client.
        args (dict): Command arguments from XSOAR.

    Returns:
        CommandResults: outputs, readable outputs and raw response for XSOAR.
    """
    table_name = args["table_name"]

    client.delete_table_request(table_name)
    command_results = CommandResults(readable_output=f"Table {table_name} successfully deleted.")

    return command_results


def query_tables_command(client: Client, args: Dict[str, Any]) -> CommandResults:
    """
    List tables under the specified account.

    Args:
        client (Client): Azure Table Storage API client.
        args (dict): Command arguments from XSOAR.

    Returns:
        CommandResults: outputs, readable outputs and raw response for XSOAR.

    """
    limit = args.get("limit") or "50"
    query_filter = args.get("filter")
    page = arg_to_number(args.get("page") or "1")
    next_table = None

    readable_message = f"Tables List:\n Current page size: {limit}\n Showing page {page} out others that may exist"

    if page > 1:  # type: ignore
        offset = int(limit) * (page - 1)  # type: ignore
        response = client.query_tables_request(str(offset), query_filter)

        response_headers = response.headers
        next_table = response_headers.get("x-ms-continuation-NextTableName")

        if not next_table:
            return CommandResults(
                readable_output=readable_message, outputs_prefix="AzureStorageTable.Table", outputs=[], raw_response=[]
            )

    raw_response = client.query_tables_request(limit, query_filter, next_table).json()

    outputs = []
    for table in raw_response.get("value"):
        outputs.append({"name": table.get("TableName")})

    readable_output = tableToMarkdown(readable_message, outputs, headerTransform=pascalToSpace)
    command_results = CommandResults(
        readable_output=readable_output,
        outputs_prefix="AzureStorageTable.Table",
        outputs_key_field="name",
        outputs=outputs,
        raw_response=raw_response,
    )

    return command_results


def convert_dict_time_format(data: dict, keys: list):
    """
    Convert dictionary data values time format.
    Args:
        data (dict): Data.
        keys (list): Keys list to convert

    """
    for key in keys:
        if data.get(key):
            str_time = data.get(key)[:-2] + "Z"  # type: ignore
            iso_time = FormatIso8601(datetime.strptime(str_time, DATE_FORMAT))
            data[key] = iso_time


def insert_entity_command(client: Client, args: Dict[str, Any]) -> CommandResults:
    """
    Insert a new entity into a table.

    Args:
        client (Client): Azure Table Storage API client.
        args (dict): Command arguments from XSOAR.

    Returns:
        CommandResults: outputs, readable outputs and raw response for XSOAR.

    """
    table_name = args["table_name"]
    partition_key = args["partition_key"]
    row_key = args["row_key"]
    entity_fields = args["entity_fields"]

    try:
        entity_fields = json.loads(entity_fields)
    except ValueError:
        raise ValueError("Failed to parse entity_fields argument. Please provide valid JSON format entity data.")

    entity_fields["PartitionKey"] = partition_key
    entity_fields["RowKey"] = row_key

    response = client.insert_entity_request(table_name, entity_fields)

    outputs = {"name": table_name, "Entity": [copy.deepcopy(response)]}

    convert_dict_time_format(outputs.get("Entity")[0], ["Timestamp"])  # type: ignore

    readable_output = tableToMarkdown(
        f"Entity Fields for {table_name} Table:", outputs.get("Entity"), headerTransform=pascalToSpace
    )

    command_results = CommandResults(
        readable_output=readable_output,
        outputs_prefix="AzureStorageTable.Table",
        outputs_key_field="name",
        outputs=outputs,
        raw_response=response,
    )

    return command_results


def replace_entity_command(client: Client, args: Dict[str, Any]) -> CommandResults:
    """
    Replace an existing entity in a table.
    The Replace Entity operation replace the entire entity and can be used to remove properties.

    Args:
        client (Client): Azure Table Storage API client.
        args (dict): Command arguments from XSOAR.

    Returns:
        CommandResults: outputs, readable outputs and raw response for XSOAR.

    """
    table_name = args["table_name"]
    partition_key = args["partition_key"]
    row_key = args["row_key"]
    entity_fields = args["entity_fields"]

    try:
        entity_fields = json.loads(entity_fields)
    except ValueError:
        raise ValueError("Failed to parse entity_fields argument. Please provide valid JSON format entity data.")

    client.replace_entity_request(table_name, partition_key, row_key, entity_fields)
    command_results = CommandResults(readable_output=f"Entity in {table_name} table successfully replaced.")

    return command_results


def update_entity_command(client: Client, args: Dict[str, Any]) -> CommandResults:
    """
    Update an existing entity in a table.
    This operation does not replace the existing entity.

    Args:
        client (Client): Azure Table Storage API client.
        args (dict): Command arguments from XSOAR.

    Returns:
        CommandResults: outputs, readable outputs and raw response for XSOAR.

    """

    table_name = args["table_name"]
    partition_key = args["partition_key"]
    row_key = args["row_key"]
    entity_fields = args["entity_fields"]

    try:
        entity_fields = json.loads(entity_fields)
    except ValueError:
        raise ValueError("Failed to parse entity_fields argument. Please provide valid JSON format entity data.")

    client.update_entity_request(table_name, partition_key, row_key, entity_fields)
    command_results = CommandResults(readable_output=f"Entity in {table_name} table successfully updated.")

    return command_results


def create_query_entity_output(table_name: str, raw_response: dict, is_entity_query: bool) -> dict:
    """
    Create query_entity_command outputs.
    Args:
        table_name (str): Command table name.
        raw_response (str): API response from Azure.
        is_entity_query (bool): Indicates to path to the response data.

    Returns:
        dict: Command response.

    """
    outputs = {"name": table_name}
    response_copy = copy.deepcopy(raw_response)

    if is_entity_query:
        outputs["Entity"] = [response_copy]  # type: ignore
    else:
        outputs["Entity"] = response_copy.get("value")  # type: ignore

    for entity in outputs.get("Entity"):  # type: ignore
        convert_dict_time_format(entity, ["Timestamp"])  # type: ignore

    return outputs


def query_entity_command(client: Client, args: Dict[str, Any]) -> CommandResults:
    """
    Query entities in a table.

    Args:
        client (Client): Azure Table Storage API client.
        args (dict): Command arguments from XSOAR.

    Returns:
        CommandResults: outputs, readable outputs and raw response for XSOAR.

    """
    table_name = args["table_name"]
    partition_key = args.get("partition_key")
    row_key = args.get("row_key")
    query_filter = args.get("filter")
    select = args.get("select")
    limit = None if partition_key else args.get("limit") or "50"
    page = None if partition_key else arg_to_number(args.get("page") or "1")
    next_partition_key = None
    next_row_key = None

    if (partition_key and not row_key) or (row_key and not partition_key):
        raise Exception("Please provide both 'partition_key' and 'row_key' arguments, or no one of them.")

    readable_message = (
        f"Entity Fields for {table_name} table:\n Current page size: {limit or 50}\n "
        f"Showing page {page or 1} out others that may exist"
    )

    if page and page > 1:
        offset = int(limit) * (page - 1)  # type: ignore
        response = client.query_entity_request(table_name, partition_key, row_key, query_filter, select, str(offset))

        response_headers = response.headers
        next_partition_key = response_headers.get("x-ms-continuation-NextPartitionKey")
        next_row_key = response_headers.get("x-ms-continuation-NextRowKey")

        if not next_partition_key:
            return CommandResults(
                readable_output=readable_message, outputs_prefix="AzureStorageTable.Table", outputs=[], raw_response=[]
            )

    raw_response = client.query_entity_request(
        table_name, partition_key, row_key, query_filter, select, limit, next_partition_key, next_row_key
    ).json()

    outputs = create_query_entity_output(table_name, raw_response, is_entity_query=partition_key is not None)

    readable_output = tableToMarkdown(readable_message, outputs.get("Entity"), headerTransform=pascalToSpace)

    command_results = CommandResults(
        readable_output=readable_output,
        outputs_prefix="AzureStorageTable.Table",
        outputs_key_field="name",
        outputs=outputs,
        raw_response=raw_response,
    )

    return command_results


def delete_entity_command(client: Client, args: Dict[str, Any]) -> CommandResults:
    """
    Delete an existing entity in a table

    Args:
        client (Client): Azure Table Storage API client.
        args (dict): Command arguments from XSOAR.

    Returns:
        CommandResults: outputs, readable outputs and raw response for XSOAR.

    Returns:

    """
    table_name = args["table_name"]
    partition_key = args["partition_key"]
    row_key = args["row_key"]

    client.delete_entity_request(table_name, partition_key, row_key)
    command_results = CommandResults(readable_output=f"Entity in {table_name} table successfully deleted.")

    return command_results


def test_module(client: Client) -> None:
    """
    Tests API connectivity and authentication.

    Args:
        client (Client): Azure Table API client.
    Returns:
        str : 'ok' if test passed, anything else will fail the test.
    """
    try:
        client.query_tables_request()
    except Exception as exception:
        if "ResourceNotFound" in str(exception):
            return return_results("Authorization Error: make sure API Credentials are correctly set")

        if "Error Type" in str(exception) or not client.ms_client._storage_account_name:
            return return_results(
                "Verify that the storage account name is correct and that you have access to the server from your host."
            )

        raise exception

    return_results("ok")
    return None


def main() -> None:
    """
    Main function
    """
    params: Dict[str, Any] = demisto.params()
    args: Dict[str, Any] = demisto.args()
    verify_certificate: bool = not params.get("insecure", False)
    proxy = params.get("proxy", False)

    global account_sas_token
    global storage_account_name
    account_sas_token = params.get("credentials", {}).get("password")
    storage_account_name = params["credentials"]["identifier"]
    api_version = "2020-10-02"
    base_url = f"https://{storage_account_name}.table.core.windows.net/"
    managed_identities_client_id = get_azure_managed_identities_client_id(params)

    command = demisto.command()
    demisto.debug(f"Command being called is {command}")

    try:
        urllib3.disable_warnings()
        client: Client = Client(
            base_url,
            verify_certificate,
            proxy,
            account_sas_token,
            storage_account_name,
            api_version,
            managed_identities_client_id,
        )

        commands = {
            "azure-storage-table-create": create_table_command,
            "azure-storage-table-delete": delete_table_command,
            "azure-storage-table-query": query_tables_command,
            "azure-storage-table-entity-insert": insert_entity_command,
            "azure-storage-table-entity-update": update_entity_command,
            "azure-storage-table-entity-query": query_entity_command,
            "azure-storage-table-entity-delete": delete_entity_command,
            "azure-storage-table-entity-replace": replace_entity_command,
        }

        if command == "test-module":
            test_module(client)
        elif command in commands:
            return_results(commands[command](client, args))
        else:
            raise NotImplementedError(f"{command} command is not implemented.")

    except Exception as e:
        return_error(str(e))


from MicrosoftAzureStorageApiModule import *  # noqa: E402

if __name__ in ["__main__", "builtin", "builtins"]:
    main()