How to Post Information to Microsoft 365 Groups or Teams Channels

Use Inbound WebHook Connector to Fetch and Post Service Information

Chapter 14 of the Office 365 for IT Pros eBook describes an example of how to post messages to an Office 365 group or a team channel using the inbound webhook connector. The inbound webhook connector is one of the standard connectors supported by Office 365. In this context, you can think of the webhook as a URI that Office 365 can use to find a target destination into which it posts messages. The posted messages are in JSON format and are called cards.

The process to connect a webhook to a team channel or Office 365 group is similar. Select the inbound webhook from the set of connectors available, give it a name and a replacement icon (if you want), and Office 365 responds with a webhook address. You can then copy that address and use it in scripts. The address will be something like this (the format changed in 2021):

https://outlook.office.com/webhook/5348781d-52a8-490f-b75b-a72e702114d1@b662313f-14fc-43a3-9a7a-d2e27f4f3478/IncomingWebhook/f286f53c0d244ebdba7fea50035f35df/eff4cd58-1bb8-4899-94de-795f656b4a18

Creating an inbound webhook for a Teams channel

inbound webhook connector
Figure 1: Creating an inbound webhook connector for a team channel

Using PowerShell to Post to the Inbound Webhook Connector

In any case, it’s pretty simple to write some PowerShell to fetch some data, format it, and post a card with the data to Office 365. The example we have in the book uses information about Office 365 service incidents, but anything you can fetch with PowerShell will do. The service incidents are gathered using the Office 365 service communications module for PowerShell.

The biggest challenge isn’t usually to find data to post. Instead, the usual issue that people run into is to format the JSON payload for the post. Microsoft has a message card “playground” to help people design actionable cards. We don’t need to go quite that far for the relatively simple and static card used in the demo, but you might like to explore the possibilities in the playground and see how the JSON structure is built out.

A Reader Suggestion

A reader suggested that instead of hand-crafting the card for each post, it would be simpler to create a template post and replace fields in the template before posting to the webhook. This seemed like a good idea, so we tried. The script below creates a template, then finds some service data, and updates the template to create a new JSON card before posting it to a team channel. Exactly the same code would work with a Microsoft 365 group if you change the target to a webhook pointing to the group.

$Notification = @"
    {
        "@type": "MessageCard",
        "@context": "https://schema.org/extensions",
        "summary": "Office 365 Notification",
        "themeColor": "0072C6",
        "title": "Office 365 Service Degradation",
         "sections": [
            {
            
                "facts": [
                    {
                        "name": "Service Incident:",
                        "value": "ID"
                    },
                    {
                        "name": "Start time:",
                        "value": "DATETIME"
                    },
                    {
                        "name": "Service:",
                        "value": "SERVICENAME"
                    },
                    {
                        "name": "Description:",
                        "value": "MESSAGE"
                    }
                ],
                "text": "Office 365 Service Problem"
            }
        ]
    }
"@

$Incidents = Get-SCEvent -EventTypes Incident -PastDays 2 -SCSession $O365ServiceSession | ? {$_.Status -eq "Service degradation"} | Sort StartTme -Descending | Select-Object Id, Status, StartTime, @{n='ServiceName'; e={$_.AffectedServiceHealthStatus.servicename}},
    @{n='Message';e={$_.messages[0].messagetext}}
ForEach ($Incident in $Incidents) {
   $IncidentID = $Incident.Id
   $IncidentStartTime = Get-Date ($Incident.StartTime) -format g
   $IncidentServiceName = $Incident.ServiceName
#   $IncidentMessage = out-string -InputObject $incident.message -Width 80
   $IncidentMessage = $Incident.Message
   $NotificationBody = $Notification.Replace("ID","$IncidentId").Replace("DATETIME","$IncidentStartTime").Replace("SERVICENAME","$IncidentServiceName").Replace("MESSAGE","$IncidentMessage")
   $Command = (Invoke-RestMethod -uri $TargetChannel -Method Post -body $NotificationBody -ContentType 'application/json')
}

Here’s what the cards look like after they are posted to the target channel.

How cards created using the webhook show up in a Teams channel using the Teams webhook connector
Cards for Office 365 service incidents posted in a team channel

The template method is probably better than the one we previously used, so we’re going to update Chapter 14 to include it. As I’ve often said, one of the joys of working on an eBook is that we can integrate new material and republish as often as we want – or in the case of Office 365 for IT Pros, monthly. And like the suggestion that lead to this update, we welcome comments and hints to improve our material.

PSTeams Module

If you’re interested in exploring the possibilities that exist in posting messages to Teams via the inbound webhook connection, you might consider the PSTeams module in GitHub, which is designed to help programmers build and send cards to Teams channels.


Read Chapter 14 in Office 365 for IT Pros for more information about using PowerShell to manage Office 365 Groups and Teams.

8 Replies to “How to Post Information to Microsoft 365 Groups or Teams Channels”

  1. Trying to post a message to ms teams using a webhook. The issue is the message contains underscores (this_or_that). The makrdown language messes with this. How can I turn off markdown language?

  2. I am trying to send a message to MS teams. My understanding is that jSON is not supported. I am sending a value that contains multiple underscores. They seem to indicate italic. I want them to appear as underscores. I tried using

    , but do not like this.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.