Teams Webhooks moving from O365 Connectors to Workflows (Power Automate)

jd-1607
Conversationalist

Teams Webhooks moving from O365 Connectors to Workflows (Power Automate)

Hey all,

 

Has anyone had any luck in migrating from an O365 connector to the new Workflows method for webhooks?
See this for info:
https://devblogs.microsoft.com/microsoft365dev/retirement-of-office-365-connectors-within-microsoft-...

13 Replies 13
PhilipDAth
Kind of a big deal
Kind of a big deal

I'm interesting in this as well.

trondve
Conversationalist

Been trying to migrate myself with no luck

amabt
Building a reputation

I tried this today and could not get it  to work ☹️

 

Here is the error I am getting on the Microsoft Flow Side

 

Action 'Send_each_adaptive_card' failed: The execution of template action 'Send_each_adaptive_card' failed: the result of the evaluation of 'foreach' expression '@triggerOutputs()?['body']?['attachments']' is of type 'Null'. The result must be a valid array.

 

amabt_0-1725236963845.png

 

amabt_3-1725237143947.png

 

 

The Flow template that I used

 

amabt_1-1725237029531.png

 

Also tried

amabt_2-1725237055171.png

 

Below links are likely useful in getting this working. I will play more with this when time permit.

 

https://blog.rdorman.net/the-new-world-of-teams-webhooks/

https://sysrestarting.blogspot.com/2024/07/teams-incoming-webhook-deprecated-use.html

https://www.reddit.com/r/MicrosoftFlow/comments/1eac9g9/meraki_webhook_alerts_to_teams_via_flow/

 

 https://github.com/prometheus/alertmanager/issues/3920

https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/connectors-...

 

jd-1607
Conversationalist

I ended up just parsing the json payload and formatting a simple message to the channel instead. I couldn't get the Adaptive cards working.

jd1607_0-1729125133104.png


Upload a sample payload from the Meraki webpage (I used the Meraki template because it was the most universal)

jd1607_1-1729125209072.png

Convert to your local timezone

jd1607_2-1729125247932.png


Prepare the message:

jd1607_3-1729125292829.png

Made the device URL the hyperlink:

jd1607_4-1729125344436.png

Looks like this:

jd1607_5-1729125412823.png

 

acook04111
Here to help

Hello,

 

I have managed to get this working using this link - https://support.microsoft.com/en-us/office/create-incoming-webhooks-with-workflows-for-microsoft-tea...

 

Follow the instructions for 'Set up an incoming webhook workflow from a template'. 

 

Once that's done you need to create a new template in the Meraki dashboard under the API & webhooks sections (organization wide).

Select Webhooks and then templates - 'create template' 

 

give it a name and then paste the json code into the liquid body section and click save.

 

acook04111_0-1731693171721.png

 

once this is working you can add more lines:

 

acook04111_2-1731693354522.png

 

It's quite basic but it does the job, next I will try to get the actions working so that a clickable button is created which points to the device or network that had the alert.

 

Now create a webhook receiver using the url that was setup in the webhook workflow and use the payload template that was just created. 

 

You should get something like this in teams:

 

 

Screenshot 2024-11-15 at 17.57.47.png

 

Hope this is useful to somebody! 

amabt
Building a reputation

Can you paste the actual code instead of screenshot?

acook04111
Here to help

Sure, i wasn't sure how to do it but see below:

{
       "type":"message",
       "attachments":[
          {
             "contentType":"application/vnd.microsoft.card.adaptive",
             "contentUrl":null,
             "content":{
                "$schema":"http://adaptivecards.io/schemas/adaptive-card.json",
                "type":"AdaptiveCard",
                "version":"1.2",
                "body":[
                    {
                    "type": "TextBlock",
                    "text": "**Meraki Alert For Organisation {{organizationName}}**"
                    },
                    {
                    "type": "TextBlock",
                    "text": "**Alert**: {{alertType}} - {{alertLevel}}"
                    },
                    {
                    "type": "TextBlock",
                    "text": "**Device**: {{deviceName}}"
                    },
                    {
                    "type": "TextBlock",
                    "text": "**When**: {{occurredAt}}"
                    }                                                                        
                ]
             }
          }
       ]
    }

 

bailey_hawker
Conversationalist

For anyone wanting to get Adaptive Cards working with the new Teams workflow with local time conversion, the following config works:

Step 1) Create the Meraki webhook receivers config as per the Meraki documentation. You will need to generate the public HTTPS webhook URL first from Step 3.

Step 2) Create a custom webhook template, and use the following config in the Liquid Body field. Edit or remove the URL field if you want a picture in the webhook card.

 

 

{
  "type": "message",
  "attachments": [
    {
      "contentType": "application/vnd.microsoft.card.adaptive",
      "contentUrl": null,
      "content": {
        "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
        "type": "AdaptiveCard",
        "version": "1.2",
        "body": [
          {
            "type": "Image",
            "url": "ADD  HTTPS URL FOR A PICTURE",
            "altText": "Logo"
          },
          {
            "type": "TextBlock",
            "text": "**{{networkName}}**",
            "wrap": true,
            "size": "large"
          },
          {
            "type": "TextBlock",
            "text": "**Message**: {{alertType}}  \n**Device**: {{deviceName}}  \n**Alert Level**: {{alertLevel}}  \n**Alert Data**: {{alertData | markdown_with_additional_formatting_for_teams}}",
            "wrap": true,
            "size": "medium"
          },
          {% if alertData.imageUrl %}
          {
            "type": "Image",
            "url": "{{alertData.imageUrl}}",
            "altText": "Alert Image"
          },
          {% endif %}
          {
            "type": "TextBlock",
            "text": "**Alert Triggered**: {{occurredAt | date: '%Y-%m-%dT%H:%M:%S'}}",
            "wrap": true,
            "size": "medium"
          },
          {
            "type": "ActionSet",
            "actions": [
              {
                "type": "Action.OpenUrl",
                "title": "View Network",
                "url": "{{networkUrl}}"
              },
              {
                "type": "Action.OpenUrl",
                "title": "View Device",
                "url": "{{deviceUrl}}"
              }
            ]
          }
        ]
      }
    }
  ]
}

 

 
Step 3) Open Teams, right click on the chat group and select Workflows. Create a new workflow based using the "Post to a Teams chat using an incoming webhook". Complete the wizard as per your requirements.

Step 4) Edit the workflow and build out the following action flow:

bailey_hawker_0-1736888315656.png

bailey_hawker_1-1736888354288.pngbailey_hawker_2-1736888370835.png

Schema config:

 

{
    "type": "object",
    "properties": {
        "type": {
            "type": "string"
        },
        "properties": {
            "type": "object",
            "properties": {
                "type": {
                    "type": "object",
                    "properties": {
                        "type": {
                            "type": "string"
                        }
                    }
                },
                "attachments": {
                    "type": "object",
                    "properties": {
                        "type": {
                            "type": "string"
                        },
                        "items": {
                            "type": "object",
                            "properties": {
                                "type": {
                                    "type": "string"
                                },
                                "properties": {
                                    "type": "object",
                                    "properties": {
                                        "contentType": {
                                            "type": "object",
                                            "properties": {
                                                "type": {
                                                    "type": "string"
                                                }
                                            }
                                        },
                                        "content": {
                                            "type": "object",
                                            "properties": {
                                                "type": {
                                                    "type": "string"
                                                },
                                                "properties": {
                                                    "type": "object",
                                                    "properties": {
                                                        "$schema": {
                                                            "type": "object",
                                                            "properties": {
                                                                "type": {
                                                                    "type": "string"
                                                                }
                                                            }
                                                        },
                                                        "type": {
                                                            "type": "object",
                                                            "properties": {
                                                                "type": {
                                                                    "type": "string"
                                                                }
                                                            }
                                                        },
                                                        "version": {
                                                            "type": "object",
                                                            "properties": {
                                                                "type": {
                                                                    "type": "string"
                                                                }
                                                            }
                                                        },
                                                        "body": {
                                                            "type": "object",
                                                            "properties": {
                                                                "type": {
                                                                    "type": "string"
                                                                },
                                                                "items": {
                                                                    "type": "object",
                                                                    "properties": {
                                                                        "type": {
                                                                            "type": "string"
                                                                        },
                                                                        "properties": {
                                                                            "type": "object",
                                                                            "properties": {
                                                                                "type": {
                                                                                    "type": "object",
                                                                                    "properties": {
                                                                                        "type": {
                                                                                            "type": "string"
                                                                                        }
                                                                                    }
                                                                                }
                                                                            }
                                                                        },
                                                                        "required": {
                                                                            "type": "array",
                                                                            "items": {
                                                                                "type": "string"
                                                                            }
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                },
                                "required": {
                                    "type": "array",
                                    "items": {
                                        "type": "string"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

 

bailey_hawker_3-1736888439480.png

Add custom Inputs expression: 

 

@{split(first(body('Parse_JSON')?['attachments'])['content']['body'][3]['text'], ': ')[1]}

 

 

bailey_hawker_4-1736888531137.png

 

bailey_hawker_6-1736888641908.png

 

The final action requires you to create a custom Adaptive Card config. This can be generated by running a test flow and capturing the outputs from Action 1. Once you have a created this config, paste it into the Adaptive Card field and edit the following line to replace the time with the converted time output.
Here's an example of the what your config should look like:

 

{
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "type": "AdaptiveCard",
  "version": "1.2",
  "body": [
    {
      "type": "Image",
      "url": "ADD CUSTOM URL FOR PICTURE
      "altText": "Logo"
    },
    {
      "type": "TextBlock",
      "text": "**YOUR NETWORK NAME
      "wrap": true,
      "size": "large"
    },
    {
      "type": "TextBlock",
      "text": "**Message**: Power supply went down  \n**Device**: DEVICE NAME  Level**: critical  \n**Alert Data**: \n     num: 2",
      "wrap": true,
      "size": "medium"
    },
    {
      "type": "TextBlock",
      "text": "**Alert Triggered (NZST)**: @{body('Convert_time_zone')}",
      "wrap": true,
      "size": "medium"
    },
    {
      "type": "ActionSet",
      "actions": [
        {
          "type": "Action.OpenUrl",
          "title": "View Network",
          "url": "LINK TO MERAKI NETWORK"
        },
        {
          "type": "Action.OpenUrl",
          "title": "View Device",
          "url": "LINK TO MERAKI NETWORK"
        }
      ]
    }
  ]
}

 


Here's the custom time line that needs to be added, using the output of the Converted Time action (add using dynamic content):

bailey_hawker_7-1736889228957.png

 

Step 5) Run a test webhook from the Meraki dashboard, you should see a successful workflow with a message card posted into the Teams chat.

 

bailey_hawker_8-1736889533088.png

bailey_hawker
Conversationalist

Update: 

The Action 2 Parse JSON Schema should be:

 

 

{
    "type": "object",
    "properties": {
        "type": {
            "type": "string"
        },
        "attachments": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "contentType": {
                        "type": "string"
                    },
                    "contentUrl": {
                        "type": [
                            "string",
                            "null"
                        ]
                    },
                    "content": {
                        "type": "object",
                        "properties": {
                            "$schema": {
                                "type": "string"
                            },
                            "type": {
                                "type": "string"
                            },
                            "version": {
                                "type": "string"
                            },
                            "body": {
                                "type": "array",
                                "items": {
                                    "type": "object",
                                    "properties": {
                                        "type": {
                                            "type": "string"
                                        },
                                        "text": {
                                            "type": "string"
                                        },
                                        "url": {
                                            "type": [
                                                "string",
                                                "null"
                                            ]
                                        },
                                        "altText": {
                                            "type": "string"
                                        },
                                        "actions": {
                                            "type": "array",
                                            "items": {
                                                "type": "object",
                                                "properties": {
                                                    "type": {
                                                        "type": "string"
                                                    },
                                                    "title": {
                                                        "type": "string"
                                                    },
                                                    "url": {
                                                        "type": "string"
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

 

 


and the final Adaptive card config was wrong, here is the correct one generic one that can be used instead, make sure to edit and insert your own image URL. I couldn't get the dynamic links to work so just hard code the URL to your network dashboard instead.

 

 

{
  "type": "AdaptiveCard",
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "version": "1.2",
  "body": [
    {
      "type": "Image",
      "url": "<INSERT-HTTPS-IMAGE-URL>",
      "altText": "Logo"
    },
    {
      "type": "TextBlock",
      "text": "@{body('Parse_JSON')?['attachments']?[0]?['content']?['body']?[1]?['text']}",
      "wrap": true,
      "size": "large"
    },
    {
      "type": "TextBlock",
      "text": "@{body('Parse_JSON')?['attachments']?[0]?['content']?['body']?[2]?['text']}",
      "wrap": true,
      "size": "medium"
    },
    {
      "type": "TextBlock",
      "text": "**Alert Triggered**: @{body('Convert_time_zone')}",
      "wrap": true,
      "size": "medium"
    },
    {
      "type": "ActionSet",
      "actions": [
        {
          "type": "Action.OpenUrl",
          "title": "View Network",
          "url": "<INSERT-HTTPS-MERAKI-URL>"
        }
      ]
    }
  ]
}

 

 

 

Jeff6
Comes here often

I believe I got the dynamic network link to work.  I've only tested it on one of my networks so far.

 

        {
          "type": "Action.OpenUrl",
          "title": "View Network",
          "url": "@{body('Parse_JSON')?['attachments']?[0]?['content']?['body']?[4]?['actions']?[0]?['url']}"
        }

 

PhilipDAth
Kind of a big deal
Kind of a big deal

Wow!  That was a lot of work.

bailey_hawker
Conversationalist

@PhilipDAth thanks, getting the time conversion right was quite difficult but I can't really see the point in getting notifications in UTC time. I will update the guide if I find a simpler way to handle the time conversion.

PhilipDAth
Kind of a big deal
Kind of a big deal

UTC is quite handy when you are getting notifications from multiple countries.

Get notified when there are additional replies to this discussion.