Microsoft Teams via Webhook

Integration for sending notifications to a Microsoft Teams channel via a workflow of type `Post to a channel when a webhook request is received`.

Messaging and Conferencing · Microsoft Teams

Details

IDMicrosoft Teams via Webhook
ProviderMicrosoft
CategoryMessaging and Conferencing
From Version6.2.0
Docker Imagedemisto/python3:3.12.13.10116658
Supported ModulesAgentix Cortex Cloud Cloud Runtime Security Cloud Posture Security XSIAM EDR

README

Integration for sending notifications to a Microsoft Teams channel via workflow.
This integration was integrated and tested with version 6.8 of Microsoft Teams via Webhook

Configure Microsoft Teams via Webhook in Cortex

Parameter Description Required
Microsoft workflow URL The workflow URL in the Teams Channel 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.

ms-teams-message


Send a message to Microsoft Teams via Incoming Webhook.

Base Command

ms-teams-message

Input

Argument Name Description Required
message The message to send. For example: “This is a message from Cortex XSOAR”. To use a newline use \n\n or \r\r. Default is None. Optional
team_webhook The alternative webhook for a different team. If not defined, the integration’s default webhook is used. Optional
alternative_url The alternative URL to send in place of the link to the Cortex XSOAR Investigation. Optional
url_title The title for the link. Default is Cortex XSOAR URL. Optional
adaptive_cards_format Should the adaptive card format be used or a single text message. Possible values are: true, false. Default is True. Optional
overwrite_adaptive_card_json JSON object used to overwrite the default adaptive card JSON. Optional

Context Output

There is no context output for this command.

Troubleshooting

By default the message is being sent with a message template: X Used a Workflow template to send this card.
In order to eliminate this line you can use the following approach:

  1. Navigate to Microsoft’s Power Automate portal and sign into your Microsoft Teams account where you’ve previously set up the Flow.
  2. Click My flows from the left side menu.
  3. Click the newly created Flow to open its details page.
  4. On the Flow’s details page, click Save As.
  5. Give your new Flow a name and click **Save””.
  6. Navigate back to My flows from the left side menu.
  7. Find the copy Flow and click its name to access its details page.
  8. On the Flow’s details page, click Turn On.
  9. In order to find the new URL link, navigate to the Edit tab on the Flow’s details page.
  10. Click the action task and copy the HTTP URL.
  11. Configure an instance of the integration and add the copied Workflow URL for the Teams channel.

Configuration parameters

  • webhookurl — Microsoft workflow URL (required)
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings

Commands (1)

  • ms-teams-message

    Send a message to Microsoft Teams via Incoming Webhook.

from unittest.mock import patch

import pytest
from pytest_mock import MockerFixture
from MicrosoftTeamsWebhook import Client, send_teams_message_command, create_teams_message
from requests_mock import Mocker

WEBHOOK = "https://readywebookone"
MESSAGE = "Hello from XSOAR"
TITLE = "Cortex XSOAR URL"
SERVERURLS = {"investigation": "https://readyxsoarone:443/#/Details/8675309/"}


fake_client = Client(base_url=WEBHOOK, verify=True, proxy=False, is_workflow=False)


def test_create_teams_message_adaptive_cards():
    message = create_teams_message(MESSAGE, TITLE, SERVERURLS["investigation"], True)
    assert message
    assert message["attachments"][0]["content"]["body"][1]["text"] == MESSAGE
    assert message["attachments"][0]["content"]["actions"][0]["title"] == TITLE
    assert message["attachments"][0]["content"]["actions"][0]["url"] == SERVERURLS["investigation"]


def test_create_teams_message():
    message = create_teams_message(MESSAGE, TITLE, SERVERURLS["investigation"], is_workflow=False)
    assert message
    assert message["sections"][0]["activitySubtitle"] == MESSAGE
    assert message["potentialAction"][0]["name"] == TITLE
    assert message["potentialAction"][0]["targets"][0]["uri"] == SERVERURLS["investigation"]


def test_send_teams_message_command(requests_mock: Mocker):
    requests_mock.post(WEBHOOK, status_code=200, json={})
    res = send_teams_message_command(fake_client, MESSAGE, TITLE, SERVERURLS["investigation"])
    assert res.readable_output == "Message sent successfully"


def test_send_teams_message_command_with_adaptivecards(requests_mock: Mocker):
    requests_mock.post(WEBHOOK, status_code=200, json={})
    res = send_teams_message_command(fake_client, MESSAGE, TITLE, SERVERURLS["investigation"], True)
    assert res.readable_output == "Message sent successfully"


def test_send_teams_message_command_with_adaptivecards_overwrite(requests_mock: Mocker):
    requests_mock.post(WEBHOOK, status_code=200, json={})
    res = send_teams_message_command(fake_client, MESSAGE, TITLE, SERVERURLS["investigation"], True, {"Hello": "World"})
    assert res.readable_output == "Message sent successfully"


def test_test_module(requests_mock: Mocker):
    from MicrosoftTeamsWebhook import test_module

    requests_mock.post(WEBHOOK, status_code=200, json={})

    res = test_module(fake_client, "fake")
    assert res == "ok"


workflow_client = Client(base_url=WEBHOOK, verify=True, proxy=False, is_workflow=True)


def test_create_teams_message_adaptive_cards_is_workflow():
    """
    Given:
      - The command arguments with is_workflow = true.
    When:
      - Executing the create_teams_message function.
    Then:
      - Verify request message- should use the full adaptive card template.
    """
    message = create_teams_message(MESSAGE, TITLE, SERVERURLS["investigation"], True, True)
    assert message
    assert message["attachments"][0]["content"]["body"][1]["text"] == MESSAGE
    assert message["attachments"][0]["content"]["actions"][0]["title"] == TITLE
    assert message["attachments"][0]["content"]["actions"][0]["url"] == SERVERURLS["investigation"]


def test_create_teams_message_with_newlines():
    """
    Given:
      - Message with newlines characters with multi backslash.
    When:
      - Executing the create_teams_message function.
    Then:
      - Verify request message with only one backslash for newlines.
    """
    message = create_teams_message("Hello from \\n\\rXSOAR", TITLE, SERVERURLS["investigation"], True, False)
    assert message["attachments"][0]["content"]["body"][1]["text"] == "Hello from \n\rXSOAR"


def test_create_teams_message_is_workflow():
    """
    Given:
      - The command arguments with is_workflow = true.
    When:
      - Executing the create_teams_message function.
    Then:
      - Verify request message- should use the only text template.
    """
    message = create_teams_message(MESSAGE, TITLE, SERVERURLS["investigation"], is_workflow=True)
    assert message
    assert message["attachments"][0]["content"]["body"][0]["text"] == MESSAGE
    assert message["attachments"][0].get("content", {}).get("actions") is None


def test_send_teams_message_command_is_workflow(requests_mock: Mocker):
    """
    Given:
      - The command arguments with is_workflow = true.
    When:
      - Executing the send_teams_message_command command.
    Then:
      - Verify when status is 202 we receive `Message sent successfully`.
    """
    requests_mock.post(WEBHOOK, status_code=202, json={})
    res = send_teams_message_command(workflow_client, MESSAGE, TITLE, SERVERURLS["investigation"])
    assert res.readable_output == "Message sent successfully"


def test_send_teams_message_command_with_full_adaptivecards_is_workflow(requests_mock: Mocker):
    """
    Given:
      - The command arguments with is_workflow = true.
    When:
      - Executing the send_teams_message_command command.
    Then:
      - Verify when status is 202 we receive `Message sent successfully`.
    """
    requests_mock.post(WEBHOOK, status_code=202, json={})
    res = send_teams_message_command(workflow_client, MESSAGE, TITLE, SERVERURLS["investigation"], True)
    assert res.readable_output == "Message sent successfully"


@pytest.mark.parametrize(
    "client,messagecard, adaptive_cards_format, expected_full_url",
    [
        (fake_client, {"type": "MessageCard", "text": "Hello World"}, False, None),
        (fake_client, {"type": "AdaptiveCard", "text": "Hello Adaptive Card"}, True, "https://example.com/webhook"),
        (workflow_client, {"type": "AdaptiveCard", "text": "Hello Workflow Card"}, False, "https://example.com/webhook"),
    ],
)
@patch("MicrosoftTeamsWebhook.demisto.info")
def test_send_teams_message(
    mock_demisto_info,
    client: Client,
    messagecard: dict,
    adaptive_cards_format: bool,
    expected_full_url: str | None,
    mocker: MockerFixture,
):
    sender = client
    http_request = mocker.patch.object(client, "_http_request")
    http_request.return_value = "OK"
    sender.send_teams_message(messagecard, adaptive_cards_format)
    if expected_full_url:
        http_request.assert_called_once_with(
            method="POST", json_data=messagecard, raise_on_status=True, resp_type="text", full_url=sender.base_url
        )
    else:
        http_request.assert_called_once_with(method="POST", json_data=messagecard, raise_on_status=True, resp_type="text")
    mock_demisto_info.assert_called_once_with("completed post of message. response text: OK")