Microsoft Teams

Table of Contents


Release Notes

Version

Date

Notes

3.0.0

08/2024

Added Approval Request process and ability to work with MS Teams Workflows.

2.1.0

05/2023

Add playbooks and removed workflows

2.0.1

12/2022

Bug fix in workflows for MS Teams: Enable Teams for Groups and MS Teams: Read messages

2.0.0

12/2022

Added support for creating and deleting MS Groups, Teams and Channels

1.0.0

10/2019

Post Incident/task information to MS Teams

3.0.0 Changes

In v3.0, an approval request process has been added to make requests for process changes. Added is a datatable to track approval request with a poller to review changes in MS Teams based on approval or rejection replies. See V3.0 Changes for poller for additional changes needed to the app.config file to enable this capability. –> v3.0 supports MS Teams Workflows and Adaptive Cards. See the section Setting up Workflows for more information needed to configure this capability.

2.1.0 Changes

In v2.1, the existing rules and workflows have been replaced with playbooks. This change is made to support the ongoing, newer capabilities of playbooks. Each playbook has the same functionality as the previous, corresponding rule/workflow.

If upgrading from a previous release, you’ll notice that the previous release’s rules/workflows remain in place. Both sets of rules and playbooks are active. For manual actions, playbooks have the same name as it’s corresponding rule, but with “(PB)” added at the end. For automatic actions, the playbooks will be disabled by default.

You can continue to use the rules/workflows. But migrating to playbooks provides greater functionality along with future app enhancements and bug fixes.


screenshot: main.png

Overview

This IBM Security QRadar SOAR application extends the meeting and collaboration functionality of Microsoft Teams. It includes the ability to create MS Teams Groups, Teams and Channels. Functionality also exists to post SOAR Incident or task information to a MS Teams Channel.

Microsoft 365 Groups are created with resources that members of the group share, including:

  • Outlook conversations

  • Outlook calendar

  • SharePoint files

  • OneNote notebook

  • SharePoint team site

  • Planner plans

  • Intune device management

Key Features

  • Create or delete Groups, Channels, and Teams, as well as archive or un-archive Teams. Incident and task members can be assigned to a Team.

  • It is now possible to create Groups, Teams, and Channels with members who are not a part of an incident or task but who have a functioning MS account that is a part of the same organization.

  • Post information about the Incident or task directly to a MS Channel.

  • Example rules/workflows are included that perform the aforementioned operations and store related information as a incident or a task note.


Requirements

This app supports the IBM Security QRadar SOAR Platform and the IBM Security QRadar SOAR for IBM Cloud Pak for Security.

SOAR platform

The SOAR platform supports two app deployment mechanisms, App Host and integration server.

If deploying to a SOAR platform with an App Host, the requirements are:

  • SOAR platform >= 51.0.0.

  • The app is in a container-based format (available from the AppExchange as a zip file).

If deploying to a SOAR platform with an integration server, the requirements are:

  • SOAR platform >= 51.0.0.

  • The app is in the older integration format (available from the AppExchange as a zip file which contains a tar.gz file).

  • Integration server is running resilient_circuits>=45.0.0.

  • If using an API key account, make sure the account provides the following minimum permissions:

    Name

    Permissions

    Org Data

    Read

    Function

    Read

    Incident

    Read, Write

    Incident Private Tasks

    Read

    Group

    Read

    Users

    Read

The following SOAR platform guides provide additional information:

  • App Host Deployment Guide: provides installation, configuration, and troubleshooting information, including proxy server settings.

  • Integration Server Guide: provides installation, configuration, and troubleshooting information, including proxy server settings.

  • System Administrator Guide: provides the procedure to install, configure and deploy apps.

The above guides are available on the IBM Documentation website at ibm.biz/soar-docs. On this web page, select your SOAR platform version. On the follow-on page, you can find the App Host Deployment Guide or Integration Server Guide by expanding Apps in the Table of Contents pane. The System Administrator Guide is available by expanding System Administrator.

Cloud Pak for Security

If you are deploying to IBM Cloud Pak for Security, the requirements are:

  • IBM Cloud Pak for Security >= 1.10.

  • Cloud Pak is configured with an App Host.

  • The app is in a container-based format (available from the AppExchange as a zip file).

The following Cloud Pak guides provide additional information:

  • App Host Deployment Guide: provides installation, configuration, and troubleshooting information, including proxy server settings. From the Table of Contents, select Case Management and Orchestration & Automation > Orchestration and Automation Apps.

  • System Administrator Guide: provides information to install, configure, and deploy apps. From the IBM Cloud Pak for Security IBM Documentation table of contents, select Case Management and Orchestration & Automation > System administrator.

These guides are available on the IBM Documentation website at ibm.biz/cp4s-docs. From this web page, select your IBM Cloud Pak for Security version. From the version-specific IBM Documentation page, select Case Management and Orchestration & Automation.

Proxy Server

The app does support a proxy server.

Python Environment

Both Python 3.9 and Python 3.11 are supported. Additional package dependencies may exist for each of these packages:

  • msal ~= 1.30

  • pymsteams ~= 0.2.3

  • resilient_circuits>=50.0.0

Endpoint Developed With MS Teams

This app has been implemented using:

Product Name

API URL

API Version

Microsoft Graph REST API

https://graph.microsoft.com/

V1.0


Installation

  • To install or uninstall an App or Integration on the SOAR platform, see the documentation at ibm.biz/soar-docs.

  • To install or uninstall an App on IBM Cloud Pak for Security, see the documentation at ibm.biz/cp4s-docs and follow the instructions above to navigate to Orchestration and Automation.

Endpoint Configuration

This application needs an access token from the Microsoft identity platform for use with Microsoft Graph APIs. The access token includes details about the application and the permission it has to use the Microsoft Graph resources and APIs. The app needs to be registered with the Microsoft identity platform and given permission to access the required Microsoft Graph resources by a user or an administrator in order to obtain an access token.

Register a new application using the Azure portal

The application must be registered with the identity provider for the identity provider to be aware that a specific app is attempting to access user information. The configuration necessary for the application to interface with the Microsoft identity platform is then made available when it registers with Microsoft Entra ID (formally Azure AD). You can learn more about this at learn.microsoft.com/application-model

  • Sign in to the Azure portal using either an enterprise account.

  • If your account gives you access to more than one tenant, select your account in the top right corner, and set your portal session to the Azure AD tenant that you want.

  • In the left-hand navigation pane, select the Microsoft Entra ID, and then select App registrations > New registration.

  • When the Register an application page appears, enter your application’s registration information:

    • Name - Enter a meaningful application name that will be displayed to users of the app.

    • Supported account types - Select which accounts you would like your application to support.

    • Redirect URI - Enter the redirect URI (or reply URL) for this application, i.e : https://localhost:8080/callback

screenshot: app_registration_overview.png

  • Note this information as this would be required later while setting up the application in the SOAR platform.

  • When finished, select Register.

  • In the left-hand navigation pane under the Manage section, select Authentication.

  • Select Yes for Enable the following mobile and desktop flows then click Save.

API Permissions

The application requires admins consent to access a protected resource, such as user information and Team settings. Microsoft Graph exposes certain predetermined APIs and only accepts requests made to them. These predetermined APIs or permissions can be added to individual applications thereby limiting them to only make controlled changes to the objects they are exposed to. In this case, we require permission to operate on Groups, Teams, and to read User information. You can learn more about this concept at learn.microsoft.com/scopes-oidc.

This application requires two different types of permissions to access the required Graph Objects:

  • Application permission

  • Delegated permission (Optional)

Feature

Permission Type

Archive Team

Application

Create Channel

Application

Create Group

Application

Create Team

Application

Delete Channel

Application

Delete Group

Application

Enable Teams for Group

Application

Post Incident Information

Application

Read Channel Messages

Delegated

Application Permission

Application permissions, also called app roles, allow the app to access data on its own, without a signed-in user. In this access scenario, the application can interact with data on its own, without a signed in user. App-only access is used in scenarios such as automation, and is mostly used by apps that run as background services or daemons. It’s suitable when it’s undesirable to have a user signed in, or when the data required can’t be scoped to a single user.

Delegated Permission

This type of permission is optional and is only required for the Read Channel messages feature. If you wish to use the application without this feature (read channel messages), you can do so by leaving out the delegated permission setup process and following the remaining steps. Delegated permissions, also called scopes, allow the application to act on behalf of the signed-in user. In this access scenario, the user signs in on behalf of the application and provides it with the required permissions to call the Microsoft Graph API. Both the client and the user must be authorized to make the request. The Graph API’s read message method is one of Microsoft’s protected APIs since it has access to sensitive data. The user must grant this application permission to access their data in order for this application to function. This means that only the resources to which the user has access, such as channels and teams, will be available to this application.

Setting up API Permissions (Both Permissions)

  • In the left-hand navigation pane under the Manage section select API Permission.

  • Click Add a permission. On the Request API permission screen, select Microsoft Graph.

  • Select the Application permissions option and search for all relevant permissions and add them as shown below.

  • An admin account is required to Grant admin consent, to enable these permissions.

List of required permissions

Category

API/Permission

Permission Type

Description

Group

Create

Application

Create groups

Group

ReadWrite.All

Application

Read and write all groups

GroupMember

ReadWrite.All

Application

Read and write all group memberships

Team

Create

Application

Create teams

Team

ReadBasic.All

Application

Get a list of all teams

TeamMember

ReadWrite.All

Application

Add and remove members from all teams

TeamMember

ReadWriteNonOwnerRole.All

Application

Add and remove members with non-owner role

TeamSettings

ReadWrite.All

Application

Read and change all teams’ settings

User

Read.All

Application

Read all users’ full profiles

ChannelMessage

Read.All

Application

Read all messages

ChannelMessage

ReadWrite

Delegated

Read and write user channel messages

ChannelMessage

Send

Delegated

Send channel messages

offline_access

--

Delegated

Maintain access to data you have given it access to

screenshot: app_scopes_permissions.png

Create a client Secret Value (Both Permissions)

  • In the left-hand navigation pane under the Manage section, select Certificate and secrets.

  • Click on the New client secret button.

  • Enter a name for the client secret and click on the Add button.

  • Note this information as this would be required later while setting up the application in the SOAR platform.

screenshot: app_certificate_secrets.png

Setting up Incoming Webhooks (Both Permissions)

The SOAR Platform can share content in Microsoft channels using an incoming webhook. The webhooks are utilized as tracking and notifying mechanisms. The webhooks offer a specific URL that can be used to transmit a JSON payload along with a card-format message. To configure webhooks for a channel, please refer to this documentation Create Incoming Webhooks.

Note: Webhooks are now replaced by MS Teams Workflows. Refer to MS Teams Workflows on how to start using this new capability.

Setting up Delegated permissions (Delegated permissions)

This setup process is to provide the application with delegated permissions which is required only for Read channel message feature. If you wish to use the application without this feature, you can do so by skipping this process.

To provide the application with the necessary permission, the OAuth Utilities Documentation is to be used.

  • This tool provides the user with means to login on behalf of the application and provide the application with the required permissions to act on behalf of the user.

  • The application_id, directory_id and secret_value are used to generate a unique refresh_token, which is later used in the app.conf file.

  • There are several ways to generate this Refresh token using the OAuth Utilities tool, please refer to the documentation OAuth Utilities Documentation

  • Once such method would be using the CLI. A sample command has been provided below:

oauth-utils oauth2_generate_refresh_token \
-tu https://login.microsoftonline.com/<DIRECTORY_ID>/oauth2/v2.0/token \
-au https://login.microsoftonline.com/<DIRECTORY_ID>/oauth2/v2.0/authorize \
-ci <APPLICATION_ID> \
-cs <SECRET_VALUE> \
-sc "ChannelMessage.Send ChannelMessage.Read.All offline_access"

Upon successfully completing this process, you will be presented with a refresh_token. Note this information as this is required later while setting up the application in the SOAR platform.

App Configuration (Both Permissions)

The following table provides the settings you need to configure the app. These settings are made in the app.config file. These values are used by the SOAR platform to establish a secure connection with the Microsoft Endpoint. See the documentation discussed in the Endpoint Configuration section for the procedure. If you have successfully configured that endpoint, you can find these values:

Config

Required

Example

Description

application_id

Yes

18d10049-72e3-4652-ac9f-d9b13f24303c

Overview -> Application (client) ID

directory_id

Yes

1d8a5928-8678-408e-ab06-50ca7e01766a

Overview -> Directory (tenant) ID

secret_value

Yes

oCN******************

Certificate & secrets -> Secret Value

refresh_token

Optional

eyxn******************

Required only for delegated permissions

<channel_name>

Optional

****.webhook.office.com/webhookb2/

Webhook URL for a channel

selftest

Optional

https://teams.microsoft.com/l/channel/xxx

Webhook URL for channel connectors to test posting of messages. This capability is deprecated and selftest_workflows should be used starting with V3.0

selftest_workflows

Optional

https://azure.com/workflows/xxx

Webhook URL for Teams Workflows to test posting of messages.

*

Optional

https://azure.com/workflows/xxx

Additional webhook URLs. Reference the webhook label used when post messaging via the functions which use the teams_channel input field.

MS Teams Workflows

In V3.0, messages can be sent via the MS Teams Workflows capability. Although a powerful way to set up complex capabilities, the basic enablement can be performed via these steps:

  1. Within the MS Teams app (either Windows or Mac), select the Workflows app screenshot: Workflows app

  2. Add a workflow for Post to a channel when a webhook request is received screenshot: Adding a Workflow

  3. At the minimum, the workflow will have steps to send Adaptive Cards to a channel screenshot: Workflow Steps screenshot: Workflow Detail

The webhook request step contains the URL required to send Adaptive Cards to a teams channel. Copy this value and add it your app.config settings using a label of your choosing. This label will then be referred to in any message sent to the MS Teams channel via this Workflow.

screenshot: Approval Playbook


Function - MS Teams Post Message for Workflows

Post a message to a Microsoft Teams channel intended for Workflows

Inputs:

Name

Type

Required

Example

Tooltip

incident_id

number

No

2095

Incident id from which artifacts are to be fetched

task_id

number

No

-

-

teams_channel

text

Yes

-

Lookup value to channel to post a message

teams_payload

text

Yes

-

string-encoded json of teams conversation message: See [Adaptive Cards]](https://adaptivecards.io/)

Outputs:

NOTE: This example might be in JSON format, but results is a Python Dictionary on the SOAR platform.

results = {
  'version': 2.0,
  'success': True,
  'reason': None,
  'content': {'status_code': 202}, 
  'inputs': { ... }
}

Example Function Input Script:

import json
import datetime

ADAPTIVE_CARD_TYPE = "AdaptiveCard"
ADAPTIVE_CARD_VERSION = "1.4"

def create_textblock(text, 
                     style="Default", 
                     font_type="Default",
                     font_size="Default", 
                     font_weight="Default", 
                     color="Default",
                     is_visible=True):
  return {
    "type": "TextBlock",
    "text": text,
    "wrap": True,
    "weight": font_weight,
    "size": font_size,
    "color": color,
    "style": style,
    "isVisible": is_visible
  }
  
def create_factset(separator=False, facts=[], is_visible=True):
  return {
    "type": "FactSet",
    "facts": facts,
    "separator": separator,
    "isVisible": is_visible
  }
  
def create_fact(title, value):
  return {
    "title": title,
    "value": value
  }


# S T A R T

body = [
  create_textblock(f"SOAR Incident {incident.id}", font_weight="bolder", color="Attention"),
  create_factset(facts=[
    create_fact("Title", incident.name),
    create_fact("Description", incident.description.content.replace('"', '\\"') if incident.description else "-"),
    create_fact("Owner", incident.owner_id),
    create_fact("Types", ", ".join(str(x) for x in incident.incident_type_ids)),
    create_fact("NIST Attack Vectors", ", ".join(str(x) for x in incident.nist_attack_vectors)),
    create_fact("Create Date", datetime.datetime.fromtimestamp(incident.create_date/1000).strftime('%c')),
    create_fact("Date Occurred", datetime.datetime.fromtimestamp(incident.start_date/1000).strftime('%c') if incident.start_date else "-"),
    create_fact("Discovered Date", datetime.datetime.fromtimestamp(incident.discovered_date/1000).strftime('%c')),
    create_fact("Confirmed", incident.confirmed),
    create_fact("Severity", incident.severity_code)
  ])
]

if playbook.inputs.teams_additional_comments:
  body.append(create_textblock(playbook.inputs.teams_additional_comments.content))

adaptive_card = {
  "contentType": "application/vnd.microsoft.card.adaptive",
  "content": {
    "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
    "type": ADAPTIVE_CARD_TYPE,
    "version": ADAPTIVE_CARD_VERSION,
    "body": body,
    "actions": []
  }
}

inputs.incident_id = incident.id
inputs.teams_payload = json.dumps(adaptive_card)
inputs.teams_channel = playbook.inputs.teams_channel

Example Function Post Process Script:

import time
results = playbook.functions.results.ms_teams_post_result

if results["success"]:
  #
  row = incident.addRow("msteams_approval_process")
  row["date"] = int(time.time()*1000)
  row["status"] = "Pending"
  row["channel"] = playbook.inputs.teams_channel
  row["expiration"] = playbook.inputs.approval_expiration
  row["message"] =playbook.inputs.approval_message
  row["soar_message_id"] = playbook.properties.soar_message_id.message_id
  row["group"] = playbook.inputs.teams_group
  row["task_id"] = task.id
  row["task_name"] = task.name
else:
  incident.addNote(f"MS Teams approval post to channel {playbook.inputs.teams_channel} failed with: {results.reason}")


Function - MS Teams: Archive Team

This function allows for archiving or unarchiving a Microsoft Team. The archive_operation input parameter specifies if the team is to be archived or unarchived. Archiving does not delete the MS Team. To identify the team for archival or unarchival, one of the following inputs can be used:

  • ms_groupteam_id

  • ms_group_mail_nickname

  • ms_groupteam_name

Note: When multiple options are provided to locate the Graph object (Group or a Team), the ms_group_mail_nickname parameter will take precedence over ms_groupteam_name, and the ms_groupteam_id parameter will take precedence over the other two options.

screenshot: action_archive_team.png

Inputs:

Name

Type

Required

Example

Tooltip

archive_operation

select

No

archive

Specify the operation to be performed

ms_group_mail_nickname

text

No

Engineering

Unique value, as no two MS Objects can have the same email ID. The mail address need not include the domain suffix (i.e. @example.com)

ms_groupteam_id

text

No

4dfde5ae-4c27-4461

Unique id assigned to a MS Group or Team while being created

ms_groupteam_name

text

No

Engineering Team

Name assigned to the MS Group or Team while being created

Outputs:

NOTE: This example might be in JSON format, but results is a Python Dictionary on the SOAR platform.

results = {
  "version": 2.0,
  "success": true,
  "reason": null,
  "content": {
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#groups/$entity",
    "id": "87fd1ea0-6a3f-4078-b271-e4f8e6f8469e",
    "deletedDateTime": null,
    "classification": null,
    "createdDateTime": "2023-05-15T17:39:58Z",
    "creationOptions": [
      "Team",
      "ExchangeProvisioningFlags:3552"
    ],
    "description": "task testing",
    "displayName": "task testing",
    "expirationDateTime": null,
    "groupTypes": [
      "Unified"
    ],
    "isAssignableToRole": null,
    "mail": "tasktesting@example.com",
    "mailEnabled": true,
    "mailNickname": "tasktesting",
    "membershipRule": null,
    "membershipRuleProcessingState": null,
    "onPremisesDomainName": null,
    "onPremisesLastSyncDateTime": null,
    "onPremisesNetBiosName": null,
    "onPremisesSamAccountName": null,
    "onPremisesSecurityIdentifier": null,
    "onPremisesSyncEnabled": null,
    "preferredDataLocation": null,
    "preferredLanguage": null,
    "proxyAddresses": [
      "SMTP:tasktesting@example.com"
    ],
    "renewedDateTime": "2023-05-15T17:39:58Z",
    "resourceBehaviorOptions": [
      "HideGroupInOutlook",
      "SubscribeMembersToCalendarEventsDisabled",
      "WelcomeEmailDisabled"
    ],
    "resourceProvisioningOptions": [
      "Team"
    ],
    "securityEnabled": false,
    "securityIdentifier": "S-1-12-1-2281512608-1081633343-4175720882-2655451366",
    "theme": null,
    "visibility": "Private",
    "onPremisesProvisioningErrors": [],
    "status_code": 200,
    "message": "Successfully archived Team: task testing",
    "teamsEnabled": "Archived"
  },
  "raw": null,
  "inputs": {
    "ms_groupteam_id": "87fd1ea0-6a3f-4078-b271-e4f8e6f8469e",
    "archive_operation": "Archive",
    "ms_group_mail_nickname": "",
    "ms_groupteam_name": ""
  },
  "metrics": {
    "version": "1.0",
    "package": "fn-teams",
    "package_version": "2.1.0",
    "host": "local",
    "execution_time_ms": 2030,
    "timestamp": "2023-05-15 13:47:58"
  }
}

Example Pre-Process Script:

inputs.archive_operation = "Archive"
if playbook.inputs.archive_operation:
  inputs.archive_operation = playbook.inputs.archive_operation

if playbook.inputs.ms_groupteam_id:
  inputs.ms_groupteam_id = playbook.inputs.ms_groupteam_id

elif playbook.inputs.ms_group_mail_nickname:
  inputs.ms_group_mail_nickname = playbook.inputs.ms_group_mail_nickname

elif playbook.inputs.ms_groupteam_name:
  inputs.ms_groupteam_name = playbook.inputs.ms_groupteam_name

else:
  helper.fail("No input was provided")

Example Post-Process Script:

results = playbook.functions.results.archive_results
content = results.get("content")

if not results.get("success"):
  text = "Unable to archive the Microsoft Team"
  fail_reason = results.get("reason")
  if fail_reason:
    text = f"{text}:\n\tFailure reason: {fail_reason}"

else:
  text  = f"""<b>Microsoft Team Details:</b><br />
  <br />The Team associated with this Group has now been {content.get('teamsEnabled')}.<br />
  <br />Name: {content.get('displayName')}
  <br />Description: {content.get('description')}
  <br />Teams Enabled: {content.get('teamsEnabled')}
  <br />ID: {content.get('id')}
  <br />Mail: {content.get('mail')}
  <br />Visibility: {content.get('visibility')}
  <br />Group Types: {content.get('groupTypes')}
  <br />Created date and time: {content.get('createdDateTime')}"""
  if content.get("unfoundUsers"):
    text += f"<br />*Note the following users were unable to be added to the group: {content.get('unfoundUsers')}"

note = helper.createRichText(text)
incident.addNote(note)


Function - MS Teams: Create Channel

This function creates a Microsoft Channel for a MS Team. A MS Team can have multiple channels.

To create a Channel for an MS Team, 3 key attributes are required, namely: teamId, displayName, and description. Out of these attributes, teamId is crucial as the MS Team must be properly identified before channel addition operation can take place. This function has the ability to find the required teamId using anyone of the below mentioned options:

  • ms_groupteam_id

  • ms_group_mail_nickname

  • ms_groupteam_name

Note: When multiple options are provided to locate the Graph object (Group or a Team), the ms_group_mail_nickname parameter will take precedence over ms_groupteam_name, and the ms_groupteam_id parameter will take precedence over the other two parameters.

screenshot: action_create_channel.png

Inputs:

Name

Type

Required

Example

Tooltip

ms_channel_name

text

No

Team 2

Name of the Microsoft Teams channel

ms_description

text

No

Engineering SubTeam2

Description for the MS Graph Object (Group / Team / Channel) that is being created

ms_group_mail_nickname

text

No

Engineering2

Unique value, as no two MS Objects can have the same email ID. The mail address need not include the domain suffix (i.e. @example.com)

ms_groupteam_id

text

No

4dfde5ae-4c27-4461

Unique id assigned to the MS Group or Team

ms_groupteam_name

text

No

Engineering

Name assigned to the MS Group or Team

Outputs:

NOTE: This example might be in JSON format, but results is a Python Dictionary on the SOAR platform.

results = {
  "version": 2.0,
  "success": true,
  "reason": null,
  "content": {
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#teams('33333-450e-46d6-9338-f7e3b66a064c')/channels/$entity",
    "id": "19:c875f7333fb843aeacb01d1cbfa52ae5@thread.tacv2",
    "createdDateTime": "2023-05-15T18:26:57.6422279Z",
    "displayName": "test 1234",
    "description": "test 1234",
    "isFavoriteByDefault": false,
    "email": "",
    "webUrl": "https://teams.microsoft.com/l/channel/19%3ac875f7333fb843aeacb01d1cbfa52ae5%40thread.tacv2/test+1234?groupId=33333-450e-46d6-9338-f7e3b66a064c&tenantId=55555-b889-434d-802d-13b87c68047b",
    "membershipType": "standard",
    "status_code": 201,
    "message": "Successfully created channel: test 1234"
  },
  "raw": null,
  "inputs": {
    "ms_groupteam_id": "33333-450e-46d6-9338-f7e3b66a064c",
    "ms_channel_name": "test 1234",
    "ms_description": "test 1234"
  },
  "metrics": {
    "version": "1.0",
    "package": "fn-teams",
    "package_version": "2.1.0",
    "host": "local",
    "execution_time_ms": 4593,
    "timestamp": "2023-05-15 14:26:57"
  }
}

Example Pre-Process Script:

inputs.ms_channel_name = playbook.inputs.ms_channel_name if playbook.inputs.ms_channel_name else f"Incident {incident.id} {incident.name}"

if playbook.inputs.ms_description:
    inputs.ms_description = playbook.inputs.ms_description
else:
    description = incident.description.content if incident.description else ""
    inputs.ms_description = f"Incident {incident.id}: {incident.name} {description}"

if playbook.inputs.ms_groupteam_id:
  inputs.ms_groupteam_id = playbook.inputs.ms_groupteam_id
elif playbook.inputs.ms_group_mail_nickname:
  inputs.ms_group_mail_nickname = playbook.inputs.ms_group_mail_nickname
elif playbook.inputs.ms_groupteam_name:
  inputs.ms_groupteam_name = playbook.inputs.ms_groupteam_name
else:
  helper.fail("No input was provided")

Example Post-Process Script:

results = playbook.functions.results.create_channel_results
content = results.get("content")

if not results.get("success"):
  text = "Unable to create Microsoft Group"
  fail_reason = results.get("reason")
  if fail_reason:
    text = f"{text}:\n\tFailure reason: {fail_reason}"

else:
  text = f'''<a href="{content.get("webUrl")}">Click here</a>
  <b>Microsoft Channel Details:</b><br />
  <br />Name: {content.get("displayName")}
  <br />Web URL: {url}
  <br />Description: {content.get("description")}
  <br />Teams Enabled: {True}
  <br />ID: {content.get("id")}
  <br />Mail: {content.get("email")}
  <br />Membership Type: {content.get("membershipType")}'''

note = helper.createRichText(text)
incident.addNote(note)


Function - MS Teams: Create group

This function creates a Microsoft Group with the ability to add multiple owners by specifying their email addresses in a comma-separated list. At least one owner must be mentioned for group creation.

The function is developed to automatically add all members of an incident or a task to the MS Group. If the function is executed from within a task, in addition to task members, all incident members can also be automatically added if that option is selected. Apart from automatic member addition, individual members can be added by directly specifying their email addresses.

screenshot: action_create_group.png

Inputs:

Name

Type

Required

Example

Tooltip

add_members_from

select

Yes

Incident/Task

Add incident or task members to Team/Group

additional_members

text

No

user1@example.com, user2@example.com

Add additional Team members who are not members of this incident or task

incident_id

number

No

1098

Incident id of the current incident

ms_description

text

No

-

Description for the MS Group

ms_group_mail_nickname

text

No

SOAR

Unique value, as no two MS Objects can have the same email ID. The mail address need not include the domain suffix (i.e. @example.com)

ms_group_name

text

No

SOAR

Name of the MS Group

ms_owners_list

text

No

AdminSoarMS@.onmicrosoft.com

A list of owners for the Group

task_id

number

No

-

Incident task id if creating a Group from a task.

Outputs:

NOTE: This example might be in JSON format, but results is a Python Dictionary on the SOAR platform.

results = {
  "version": 2.0,
  "success": true,
  "reason": null,
  "content": {
    "id": "3cde21c1-7e9c-4f6d-b986-06d879c43dad",
    "deletedDateTime": null,
    "classification": null,
    "createdDateTime": "2023-05-15T18:13:38Z",
    "creationOptions": [],
    "description": "test1",
    "displayName": "test1",
    "expirationDateTime": null,
    "groupTypes": [
      "Unified"
    ],
    "isAssignableToRole": null,
    "mail": "test1@example.com",
    "mailEnabled": true,
    "mailNickname": "test1",
    "membershipRule": null,
    "membershipRuleProcessingState": null,
    "onPremisesDomainName": null,
    "onPremisesLastSyncDateTime": null,
    "onPremisesNetBiosName": null,
    "onPremisesSamAccountName": null,
    "onPremisesSecurityIdentifier": null,
    "onPremisesSyncEnabled": null,
    "preferredDataLocation": null,
    "preferredLanguage": null,
    "proxyAddresses": [
      "SMTP:test1@example.com"
    ],
    "renewedDateTime": "2023-05-15T18:13:38Z",
    "resourceBehaviorOptions": [],
    "resourceProvisioningOptions": [],
    "securityEnabled": false,
    "securityIdentifier": "S-1-12-1-1021190593-1332575900-3624306361-2906506361",
    "theme": null,
    "visibility": "Private",
    "onPremisesProvisioningErrors": [],
    "teamsEnabled": false,
    "unfoundUsers": []
  },
  "raw": null,
  "inputs": {
    "incident_id": 2122,
    "additional_members": "",
    "ms_owners_list": "markscherfling@example.com",
    "ms_group_name": "test1",
    "ms_group_mail_nickname": "test1",
    "add_members_from": "None",
    "task_id": null,
    "ms_description": "test1"
  },
  "metrics": {
    "version": "1.0",
    "package": "fn-teams",
    "package_version": "2.1.0",
    "host": "local",
    "execution_time_ms": 1560,
    "timestamp": "2023-05-15 14:13:39"
  }
}

Example Pre-Process Script:

if task:
  inputs.task_id = task.id

inputs.incident_id = str(incident.id)
inputs.ms_group_name = f"Incident {incident.id}: {incident.name}" if playbook.inputs.ms_group_name is None else playbook.inputs.ms_group_name

if playbook.inputs.ms_owners_list:
  inputs.ms_owners_list = playbook.inputs.ms_owners_list

if playbook.inputs.add_members_incident:
  _value = playbook.inputs.add_members_incident.lower().strip()
  if _value == "all incident members":
    inputs.add_members_from = "Incident"
  else:
    inputs.add_members_from = "None"

if playbook.inputs.additional_members.content:
  inputs.additional_members = playbook.inputs.additional_members.content

if playbook.inputs.ms_description:
  inputs.ms_description = playbook.inputs.ms_description
else:
  description = incident.description.content if incident.description else ""
  inputs.ms_description = f"Incident {incident.id}: {incident.name} {description}"

if playbook.inputs.ms_group_mail_nickname:
  inputs.ms_group_mail_nickname = playbook.inputs.ms_group_mail_nickname

Example Post-Process Script:

results = playbook.functions.results.create_group_results
content = results.get("content")

if not results.get("success"):
  text = "Unable to create Microsoft Group"
  fail_reason = results.get("reason")
  if fail_reason:
    text = f"{text}:\n\tFailure reason: {fail_reason}"

else:
  text  = f'''<b>Microsoft Group Details:</b><br />
  <br />Name: {content.get("displayName")}
  <br />Description: {content.get("description")}
  <br />Teams Enabled: {content.get("teamsEnabled")}
  <br />ID: {content.get("id")}
  <br />Mail: {content.get("mail")}
  <br />Visibility: {content.get("visibility")}
  <br />Group Types: {content.get("groupTypes")}
  <br />Created date and time: {content.get("createdDateTime")}'''
  if content.get("unfoundUsers"):
    text += f'<br />*Note the following users were unable to be added to the group: {content.get("unfoundUsers")}'

note = helper.createRichText(text)
incident.addNote(note)


Function - MS Teams: Create team

This function creates a Microsoft Team with the ability to add multiple owners by specifying their email addresses in a comma-separated list. At least one owner must be mentioned for group creation.

The function is developed to automatically add all members of an incident or a task to the MS Team. If the function is executed from within a task, in addition to task members, all incident members can also be automatically added if that option is selected. Apart from automatic member addition, individual members can be added by directly specifying their email addresses.

screenshot: action_create_team.png

Inputs:

Name

Type

Required

Example

Tooltip

add_members_from

select

Yes

Incident/Task

Allows for adding incident or task members to Team

additional_members

text

No

user1@example.com, user2@example.com

Add members who are not members of this incident or task

incident_id

number

No

1098

Incident Id associate with this workflow/playbook

ms_description

text

No

-

Description for the MS Graph Team that is being created

ms_owners_list

text

No

AdminSoarMS@.onmicrosoft.com

A comma separated list of owners for the group or team

ms_team_name

text

No

SoarTeam

Name of the Microsoft Team

task_id

number

No

-

Incident task id if this Team is associated with a task

Outputs:

NOTE: This example might be in JSON format, but results is a Python Dictionary on the SOAR platform.

results = {
  "version": 2.0,
  "success": true,
  "reason": null,
  "content": {
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#groups/$entity",
    "id": "87fd1ea0-6a3f-4078-b271-e4f8e6f8469e",
    "deletedDateTime": null,
    "classification": null,
    "createdDateTime": "2023-05-15T17:39:58Z",
    "creationOptions": [
      "Team",
      "ExchangeProvisioningFlags:3552"
    ],
    "description": "task testing",
    "displayName": "task testing",
    "expirationDateTime": null,
    "groupTypes": [
      "Unified"
    ],
    "isAssignableToRole": null,
    "mail": "tasktesting@example.com",
    "mailEnabled": true,
    "mailNickname": "tasktesting",
    "membershipRule": null,
    "membershipRuleProcessingState": null,
    "onPremisesDomainName": null,
    "onPremisesLastSyncDateTime": null,
    "onPremisesNetBiosName": null,
    "onPremisesSamAccountName": null,
    "onPremisesSecurityIdentifier": null,
    "onPremisesSyncEnabled": null,
    "preferredDataLocation": null,
    "preferredLanguage": null,
    "proxyAddresses": [
      "SMTP:tasktesting@example.com"
    ],
    "renewedDateTime": "2023-05-15T17:39:58Z",
    "resourceBehaviorOptions": [
      "HideGroupInOutlook",
      "SubscribeMembersToCalendarEventsDisabled",
      "WelcomeEmailDisabled"
    ],
    "resourceProvisioningOptions": [
      "Team"
    ],
    "securityEnabled": false,
    "securityIdentifier": "S-1-12-1-2281512608-1081633343-4175720882-2655451366",
    "theme": null,
    "visibility": "Private",
    "onPremisesProvisioningErrors": [],
    "status_code": 200,
    "teamsEnabled": true,
    "unfoundUsers": null
  },
  "raw": null,
  "inputs": {
    "ms_team_name": "task testing",
    "incident_id": 2120,
    "additional_members": "",
    "ms_owners_list": "markscherfling@example.com",
    "add_members_from": "None",
    "task_id": 126,
    "ms_description": "task testing"
  },
  "metrics": {
    "version": "1.0",
    "package": "fn-teams",
    "package_version": "2.1.0",
    "host": "local",
    "execution_time_ms": 50594,
    "timestamp": "2023-05-15 13:40:47"
  }
}

Example Pre-Process Script:

if task:
  inputs.task_id = task.id

inputs.incident_id = str(incident.id)
inputs.ms_team_name = f"Incident {incident.id}: {incident.name}" if playbook.inputs.ms_team_name is None else playbook.inputs.ms_team_name

if playbook.inputs.ms_owners_list:
  inputs.ms_owners_list = playbook.inputs.ms_owners_list

if playbook.inputs.add_members_incident:
  _value = playbook.inputs.add_members_incident.lower().strip()
  if _value == "all incident members":
    inputs.add_members_from = "Incident"
  else:
    inputs.add_members_from = "None"

if playbook.inputs.additional_members.content:
  inputs.additional_members = playbook.inputs.additional_members.content

if playbook.inputs.ms_description:
  inputs.ms_description = playbook.inputs.ms_description
else:
  description = incident.description.content if incident.description else ""
  inputs.ms_description = f"Incident {incident.id}: {incident.name} {description}"

Example Post-Process Script:

results = playbook.functions.results.create_team
content = results.get("content")

if not results.get("success"):
  text = "Unable to create Microsoft Team"
  fail_reason = results.get("reason")
  if fail_reason:
    text = f"{text}:\n\tFailure reason: {fail_reason}"

else:
  text  = f'''<b>Microsoft Group Details:</b><br />
  <br />Name: {content.get("displayName")}
  <br />Description: {content.get("description")}
  <br />Teams Enabled: {content.get("teamsEnabled")}
  <br />ID: {content.get("id")}
  <br />Mail: {content.get("mail")}
  <br />Visibility: {content.get("visibility")}
  <br />Group Types: {content.get("groupTypes")}
  <br />Created date and time: {content.get("createdDateTime")}'''
  if content.get("unfoundUsers"):
    text += f'<br />*Note the following users were unable to be added to the group: {content.get("unfoundUsers")}'

note = helper.createRichText(text)
incident.addNote(note)


Function - MS Teams: Delete Channel

This function deletes a MS Channel. A MS Team can be assigned to multiple channels. However, each MS Group can have only one Team. In order to delete an Channel, it’s MS Team/Group needs to be identified. To locate this team for this operation, one of the following inputs can be used:

  • ms_groupteam_id

  • ms_group_mail_nickname

  • ms_groupteam_name

Note: When multiple options are provided to locate the Graph object (Group or a Team), the ms_group_mail_nickname parameter will take precedence over ms_groupteam_name, and the ms_groupteam_id parameter will take precedence over the other two.

screenshot: action_delete_channel.png

Inputs:

Name

Type

Required

Example

Tooltip

ms_channel_name

text

No

Engineering Channel

Name of the Microsoft Teams channel

ms_group_mail_nickname

text

No

engineeringTeam

Unique nickname for a group. The mail address need not include the domain suffix (i.e. @example.com)

ms_groupteam_id

text

No

db7350fc-b6df-4041

Unique id assigned to a MS Group or Team while being created

ms_groupteam_name

text

No

Engineering Team

Name assigned to the MS Group or Team while being created

Outputs:

NOTE: This example might be in JSON format, but results is a Python Dictionary on the SOAR platform.

results = {
  "version": 2.0,
  "success": true,
  "reason": null,
  "content": {
    "status_code": 204,
    "message": "Successfully deleted channel: Incident 2121 testing channels"
  },
  "raw": null,
  "inputs": {
    "ms_groupteam_id": "33333-450e-46d6-9338-f7e3b66a064c",
    "ms_channel_name": "Incident 2121 testing channels"
  },
  "metrics": {
    "version": "1.0",
    "package": "fn-teams",
    "package_version": "2.1.0",
    "host": "local",
    "execution_time_ms": 3172,
    "timestamp": "2023-05-15 14:09:04"
  }
}

Example Pre-Process Script:

inputs.ms_channel_name = playbook.inputs.ms_channel_name

if playbook.inputs.ms_groupteam_id:
  inputs.ms_groupteam_id = playbook.inputs.ms_groupteam_id
elif playbook.inputs.ms_group_mail_nickname:
  inputs.ms_group_mail_nickname = playbook.inputs.ms_group_mail_nickname
elif playbook.inputs.ms_groupteam_name:
  inputs.ms_groupteam_name = playbook.inputs.ms_groupteam_name
else:
  helper.fail("No input was provided")

Example Post-Process Script:

results = playbook.functions.results.delete_channel
content = results.get("content")

if not results.get("success"):
  text = "Unable to delete Microsoft Channel"
  fail_reason = results.get("reason")
  if fail_reason:
    text = f"{text}:\n\tFailure reason: {fail_reason}"

else:
  text  = f"""<b>Microsoft Channels:</b><br />
  <br />{content.get('message')}"""

note = helper.createRichText(text)
incident.addNote(note)


Function - MS Teams: Delete Group

This function deletes a MS Group. To identify this Group, one of the following inputs can be used:

  • ms_group_id

  • ms_group_mail_nickname

  • ms_group_name

Note: When multiple parameters are provided to locate the Graph object (Group or a Team), the ms_group_mail_nickname parameter will take precedence over the ms_group_name, and the ms_group_id parameter will take precedence over the other two.

screenshot: action_delete_group.png

Inputs:

Name

Type

Required

Example

Tooltip

ms_group_id

text

No

db7350fc-b6df-4041

Unique id assigned to a group

ms_group_mail_nickname

text

No

ProductionTeam

Unique nickname, as no two MS Objects can have the same email ID. The mail address need not include the domain suffix (i.e. @example.com)

ms_group_name

text

No

ProductionTeam

Name of the MS Group

Outputs:

NOTE: This example might be in JSON format, but results is a Python Dictionary on the SOAR platform.

results = {
  "version": 2.0,
  "success": true,
  "reason": null,
  "content": {
    "status_code": 204,
    "message": "Successfully deleted Group: test1"
  },
  "raw": null,
  "inputs": {
    "ms_group_id": "3cde21c1-7e9c-4f6d-b986-06d879c43dad"
  },
  "metrics": {
    "version": "1.0",
    "package": "fn-teams",
    "package_version": "2.1.0",
    "host": "local",
    "execution_time_ms": 2032,
    "timestamp": "2023-05-15 14:15:02"
  }
}

Example Pre-Process Script:

if playbook.inputs.ms_group_id:
  inputs.ms_group_id = playbook.inputs.ms_group_id

elif playbook.inputs.ms_group_mail_nickname:
  inputs.ms_group_mail_nickname = playbook.inputs.ms_group_mail_nickname

elif playbook.inputs.ms_group_name:
  inputs.ms_group_name = playbook.inputs.ms_group_name

else:
  helper.fail("Atleast one option must be specified to delete a group")

Example Post-Process Script:

results = playbook.functions.results.delete_group
content = results.get("content")

if not results.get("success"):
  text = "Unable to delete Microsoft Group"
  fail_reason = results.get("reason")
  if fail_reason:
    text = f"{text}:\n\tFailure reason: {fail_reason}"

else:
  text = f'''<b>Microsoft Groups:</b><br />
  <br />{content.get("message")}'''

note = helper.createRichText(text)
incident.addNote(note)


Function - MS Teams: Enable Team

This function enables an MS Team for a MS Group. When an MS Group is created, the teams’ functionality is not enabled by default. Use this function to enable this for an MS Group that was recently created or for an existing Group.

To identify the Group, one of the following inputs can be used:

  • ms_group_id

  • ms_group_mail_nickname

  • ms_group_name

Note: When multiple parameters are provided to locate the Graph Group, the ms_group_mail_nickname parameter will take precedence over ms_group_name and the ms_group_id parameter will take precedence over the other two.

screenshot: action_enable_teams.png

Inputs:

Name

Type

Required

Example

Tooltip

ms_group_id

text

No

764a62f2-b759-4dd9

Group Unique id

ms_group_mail_nickname

text

No

engineeringTeam

Unique nickname, as no two MS Objects can have the same email ID. The mail address need not include the domain suffix (i.e. @example.com)

ms_group_name

text

No

Engineering Team

Name of the MS Group

Outputs:

NOTE: This example might be in JSON format, but results is a Python Dictionary on the SOAR platform.

results = {
  "version": 2.0,
  "success": true,
  "reason": null,
  "content": {
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#groups/$entity",
    "id": "3cde21c1-7e9c-4f6d-b986-06d879c43dad",
    "deletedDateTime": null,
    "classification": null,
    "createdDateTime": "2023-05-15T18:13:38Z",
    "creationOptions": [],
    "description": "test1",
    "displayName": "test1",
    "expirationDateTime": null,
    "groupTypes": [
      "Unified"
    ],
    "isAssignableToRole": null,
    "mail": "test1@example.com",
    "mailEnabled": true,
    "mailNickname": "test1",
    "membershipRule": null,
    "membershipRuleProcessingState": null,
    "onPremisesDomainName": null,
    "onPremisesLastSyncDateTime": null,
    "onPremisesNetBiosName": null,
    "onPremisesSamAccountName": null,
    "onPremisesSecurityIdentifier": null,
    "onPremisesSyncEnabled": null,
    "preferredDataLocation": null,
    "preferredLanguage": null,
    "proxyAddresses": [
      "SMTP:test1@example.com"
    ],
    "renewedDateTime": "2023-05-15T18:13:38Z",
    "resourceBehaviorOptions": [],
    "resourceProvisioningOptions": [],
    "securityEnabled": false,
    "securityIdentifier": "S-1-12-1-1021190593-1332575900-3624306361-2906506361",
    "theme": null,
    "visibility": "Private",
    "onPremisesProvisioningErrors": [],
    "status_code": 200,
    "message": "Successfully enabled Teams for Group: test1",
    "teamsEnabled": true
  },
  "raw": null,
  "inputs": {
    "ms_group_id": "3cde21c1-7e9c-4f6d-b986-06d879c43dad"
  },
  "metrics": {
    "version": "1.0",
    "package": "fn-teams",
    "package_version": "2.1.0",
    "host": "local",
    "execution_time_ms": 4333,
    "timestamp": "2023-05-15 14:14:23"
  }
}

Example Pre-Process Script:

if playbook.inputs.ms_group_id:
  inputs.ms_group_id = playbook.inputs.ms_group_id
elif playbook.inputs.ms_group_mail_nickname:
  inputs.ms_group_mail_nickname = playbook.inputs.ms_group_mail_nickname
elif playbook.inputs.ms_group_name:
  inputs.ms_group_name = playbook.inputs.ms_group_name
else:
  helper.fail("No input was provided.")

Example Post-Process Script:

results = playbook.functions.results.enable_team
content = results.get("content")

if not results.get("success"):
  text = "Could not enable Teams for this MS Group"
  fail_reason = results.get("reason")
  if fail_reason:
    text = f"{text}:\n\tFailure reason: {fail_reason}"

else:
  text  = f'''<b>Microsoft Group Details:</b><br />
  <br />Name: {content.get("displayName")}
  <br />Description: {content.get("description")}
  <br />Teams Enabled: {content.get("teamsEnabled")}
  <br />ID: {content.get("id")}
  <br />Mail: {content.get("mail")}
  <br />Visibility: {content.get("visibility")}
  <br />Group Types: {content.get("groupTypes")}
  <br />Created date and time: {content.get("createdDateTime")}'''
  if content.get("unfoundUsers"):
    text += f'<br />*Note the following users were unable to be added to the group: {content.get("unfoundUsers")}'

note = helper.createRichText(text)
incident.addNote(note)


Function - MS Teams: Post Message

This application posts Incident or Task details to a MS Teams channel. The channel name, specified by the teams_channel parameter, is used to lookup the appropriate channel webhook url maintained in app.config.

screenshot: output_post_teams.png

Inputs:

Name

Type

Required

Example

Tooltip

incident_id

number

No

-

Unique id for the associated Incident

task_id

number

No

-

Unique id for a task if task information will be posted

teams_channel

text

Yes

-

Lookup value of channel to post a message

teams_mrkdown

boolean

Yes

-

-

teams_payload

text

Yes

-

String encoded JSON including incident or task information: sections, title, text, facts

Outputs:

NOTE: This example might be in JSON format, but results is a Python Dictionary on the SOAR platform.

results = {
  "version": 2.0,
  "success": true,
  "reason": null,
  "content": {
    "message": "Information successfully posted in channel General"
  },
  "raw": null,
  "inputs": {
    "teams_channel": "General",
    "incident_id": 2121,
    "teams_mrkdown": true,
    "teams_payload": "{ \"summary\": \"SOAR Incident\", \"sections\": [ \n  { \"facts\": [ \n    { \"name\": \"Name\", \"value\": \"testing channels\" }, \n    { \"name\": \"Description\", \"value\": \"-\" }, \n    { \"name\": \"Id\", \"value\": \"2121\" }, \n    { \"name\": \"Owner\", \"value\": \"i@example.com\" }, \n    { \"name\": \"Types\", \"value\": \"\" }, \n    { \"name\": \"NIST Attack Vectors\", \"value\": \"\" }, \n    { \"name\": \"Create Date\", \"value\": \"1684173230796\" }, \n    { \"name\": \"Date Occurred\", \"value\": \"-\" }, \n    { \"name\": \"Discovered Date\", \"value\": \"1684173210301\" }, \n    { \"name\": \"Confirmed\", \"value\": \"True\" }, \n    { \"name\": \"Severity\", \"value\": \"Low\" } \n   ]\n  }\n ] \n} \n"
  },
  "metrics": {
    "version": "1.0",
    "package": "fn-teams",
    "package_version": "2.1.0",
    "host": "local",
    "execution_time_ms": 2038,
    "timestamp": "2023-05-15 14:21:57"
  }
}

Example Pre-Process Script:

inputs.incident_id = incident.id

"""
format of a payload. * = optional
{ "title"*: xx,
  "summary": xx,
  "sections": [{ "title"*: yy, "text"*: yy,
                        "facts"*: [{"name": zz, "value": zz}]
              }]
}
"""

payload = '''{{ "summary": "SOAR Incident", "sections": [
  {{ "facts": [
    {{ "name": "Name", "value": "{}" }},
    {{ "name": "Description", "value": "{}" }},
    {{ "name": "Id", "value": "{}" }},
    {{ "name": "Owner", "value": "{}" }},
    {{ "name": "Types", "value": "{}" }},
    {{ "name": "NIST Attack Vectors", "value": "{}" }},
    {{ "name": "Create Date", "value": "{}" }},
    {{ "name": "Date Occurred", "value": "{}" }},
    {{ "name": "Discovered Date", "value": "{}" }},
    {{ "name": "Confirmed", "value": "{}" }},
    {{ "name": "Severity", "value": "{}" }}
   ]
  }}
 ]
}}
'''.format(incident.name, incident.description.content.replace('"', '\\"') if incident.description else "-", incident.id,
  incident.owner_id if incident.owner_id else "-",
  ", ".join(str(x) for x in incident.incident_type_ids), ", ".join(str(x) for x in incident.nist_attack_vectors),
  incident.create_date, incident.start_date if incident.start_date else "-", incident.discovered_date,
  "True" if incident.confirmed else "False",
  "-" if not incident.severity_code else incident.severity_code)

inputs.teams_payload = payload
inputs.teams_channel = "General"
inputs.teams_mrkdown = True

Example Post-Process Script:

results = playbook.functions.results.post_message
content = results.get("content")

if not results.get("success"):
  text = "Unable to Post message"
  fail_reason = results.get("reason")
  if fail_reason:
    text = f"{text}:\n\tFailure reason: {fail_reason}"
  text = helper.createRichText(text)
  incident.addNote(text)


Function - MS Teams: Read Message

Read messages from a Teams Channel

screenshot: action_read_message.png

Inputs:

Name

Type

Required

Example

Tooltip

ms_channel_id

text

No

abs7350fc-b6df-4041

Unique Id assigned to a channel while being created

ms_channel_name

text

No

soarmessages

Name of the Microsoft Teams channel

ms_group_mail_nickname

text

No

soarmailbox

Unique value, as no two MS Objects can have the same email ID. The mail address need not include the domain suffix (i.e. @example.com)

ms_groupteam_id

text

No

db7350fc-b6df-4041

Unique id assigned to a MS Group or Team while being created

ms_groupteam_name

text

No

soar

Name of the MS Team or Group

ms_message_id

text

No

111233344

Each message has a unique ID

Outputs:

NOTE: This example might be in JSON format, but results is a Python Dictionary on the SOAR platform.

results = {
  "version": 2.0,
  "success": true,
  "reason": null,
  "content": [
    {
      "id": "1684173756348",
      "replyToId": null,
      "etag": "1684173756348",
      "messageType": "message",
      "createdDateTime": "2023-05-15T18:02:36.348Z",
      "lastModifiedDateTime": "2023-05-15T18:02:36.348Z",
      "lastEditedDateTime": null,
      "deletedDateTime": null,
      "subject": null,
      "summary": null,
      "chatId": null,
      "importance": "normal",
      "locale": "en-us",
      "webUrl": "https://teams.microsoft.com/l/message/19%3Aa62cab990d8648b6a9047787e030fa7e%40thread.tacv2/1684173756348?groupId=33333-450e-46d6-9338-f7e3b66a064c&tenantId=55555-b889-434d-802d-13b87c68047b&createdTime=1684173756348&parentMessageId=1684173756348",
      "policyViolation": null,
      "eventDetail": null,
      "from": {
        "application": null,
        "device": null,
        "user": {
          "@odata.type": "#microsoft.graph.teamworkUserIdentity",
          "id": "43dd7b73-6a70-475e-88c3-609a9f30b514",
          "displayName": "Mark Scherfling",
          "userIdentityType": "aadUser",
          "tenantId": "55555-b889-434d-802d-13b87c68047b"
        }
      },
      "body": {
        "contentType": "text",
        "content": "hello world"
      },
      "channelIdentity": {
        "teamId": "33333-450e-46d6-9338-f7e3b66a064c",
        "channelId": "19:a62cab990d8648b6a9047787e030fa7e@thread.tacv2"
      },
      "attachments": [],
      "mentions": [],
      "reactions": []
    }
  ],
  "raw": null,
  "inputs": {
    "ms_groupteam_id": "33333-450e-46d6-9338-f7e3b66a064c",
    "ms_channel_name": "Incident 2121 testing channels"
  },
  "metrics": {
    "version": "1.0",
    "package": "fn-teams",
    "package_version": "2.1.0",
    "host": "local",
    "execution_time_ms": 3707,
    "timestamp": "2023-05-15 14:06:30"
  }
}

Example Pre-Process Script:

if playbook.inputs.ms_message_id:
  inputs.ms_message_id = playbook.inputs.ms_message_id
if playbook.inputs.ms_channel_id:
  inputs.ms_channel_id = playbook.inputs.ms_channel_id
if playbook.inputs.ms_groupteam_id:
  inputs.ms_groupteam_id = playbook.inputs.ms_groupteam_id
if playbook.inputs.ms_channel_name:
  inputs.ms_channel_name = playbook.inputs.ms_channel_name
if playbook.inputs.ms_groupteam_id:
  inputs.ms_groupteam_id = playbook.inputs.ms_groupteam_id
if playbook.inputs.ms_group_mail_nickname:
  inputs.ms_group_mail_nickname = playbook.inputs.ms_group_mail_nickname
if playbook.inputs.ms_groupteam_name:
  inputs.ms_groupteam_name = playbook.inputs.ms_groupteam_name

Example Post-Process Script:

results = playbook.functions.results.read_message
content = results.get("content", {})

if not results.get("success"):
  text = "Unable to read messages from Microsoft Channel"
  fail_reason = results.get("reason")
  if fail_reason:
    text = f"{text}:\n\tFailure reason: {fail_reason}"

else:
  text  = f"""<b>Microsoft Channels:</b><br />
  Successfully retrieved <b>{len(content)}</b> messages <br /><br />"""

  for message in content:
    url = f'''<a href="{message.get("webUrl")}">Click here</a>
    Message Id : {message.get("id")} <br />
    Channel Id : {message.get("channelIdentity", {}).get("channelId")} <br />
    Team Id : {message.get("channelIdentity", {}).get("teamId")} <br />'''

    if message.get("from"):
      user_messages = message.get("from", {}).get("user", {})
      if user_messages:
        text += f'From User : {user_messages.get("displayName")} <br />'
      else:
        text += f'From Application : {message.get("from", {}).get("application", {}).get("displayName")} <br />'

    text += f'''Body Content : {message.get("body", {}).get("content")} <br />
    Content Type : {message.get("body", {}).get("contentType")} <br />
    Created Time : {message.get("createdDateTime")} <br />
    Web URL : {url} <br />
    <br />'''

note = helper.createRichText(text)
incident.addNote(note)


Playbooks

Playbook Name

Description

Activation Type

Object

Status

Condition

MS Teams: Archive Team From Task (PB)

None

Manual

task

enabled

-

MS Teams: Archive Team (PB)

None

Manual

incident

enabled

-

MS Teams: Create Channel From Task (PB)

None

Manual

task

enabled

-

MS Teams: Create Channel (PB)

None

Manual

incident

enabled

-

MS Teams: Create Group From Task (PB)

None

Manual

task

enabled

-

MS Teams: Create Group (PB)

None

Manual

incident

enabled

-

MS Teams: Create Team From Task (PB)

None

Manual

task

enabled

-

MS Teams: Create Team (PB)

None

Manual

incident

enabled

-

MS Teams: Delete Channel From Task (PB)

None

Manual

task

enabled

-

MS Teams: Delete Channel (PB)

None

Manual

incident

enabled

-

MS Teams: Delete Group From Task (PB)

None

Manual

task

enabled

-

MS Teams: Delete Group (PB)

None

Manual

incident

enabled

-

MS Teams: Enable Teams for Group From Task (PB)

None

Manual

task

enabled

-

MS Teams: Enable Teams for Group (PB)

None

Manual

incident

enabled

-

MS Teams: Post Incident Information (PB)

None

Manual

incident

enabled

-

MS Teams: Post Message for Workflows

Post a message to a Teams channel using the new Workflows model

Manual

incident

enabled

-

MS Teams: Post Chat Message (using Workflows)

incident

enabled

-

MS Teams: Post Chat Task Message (using Workflows)

task

enabled

-

MS Teams: Post Task Information (PB)

None

Manual

task

enabled

-

MS Teams: Read Channel Messages From task (PB)

None

Manual

task

enabled

-

MS Teams: Read Channel Messages (PB)

None

Manual

incident

enabled

-

MS Teams: Send Approval Request

Playbook to send an approval for change to a MS Teams channel. The status of the approval is tracked in the ‘MS Teams Approval Process’ datatable.

Manual

incident

enabled

-

MS Teams: Send Approval Request for Tasks

Playbook to send an approval for change to a MS Teams channel. The status of the approval is tracked in the ‘MS Teams Approval Process’ datatable.

Manual

task

enabled

-



Troubleshooting & Support

Refer to the documentation listed in the Requirements section for troubleshooting information.

For Support

This is a IBM Community provided App. Please search the Community ibm.biz/soarcommunity for assistance.