Using PowerShell to Post Channel Messages with Teams Workflows

Replacing the Incoming Webhook Connector with the Teams Post to Channel Workflow

Last week, I discussed the looming end in sight for Office 365 connectors following their retirement from SharePoint Online and Microsoft 365 Groups. Connectors are still supported to bring information into Teams channels and the incoming webhook connector is a popular choice to create posts in channels from different network sources. For instance, this article describes how to post a notification about a report about expiring Microsoft 365 groups while this article discusses how to post information about service degradation for Office 365 workloads.

Both articles show how to use PowerShell to format the information sent for posting to a channel through the incoming webhook connector. I wanted to do the same thing with Power Automate workflows, specifically with the workflow called Post to a channel when a webhook request is received, which seems very close in concept to the incoming webhook connector: both publish a public URL for information to be sent to, and both demand that the information is formatted in a certain way.

The problem I ran into is a dearth of knowledge about how to construct the request body with PowerShell to send to the workflow. I knew that an adaptive card is used, but the example in Microsoft’s documentation wasn’t a great starting point. But persistence pays and the examples of formatting cards for Teams are better, and the adaptive card designer helped to debug various elements. In the end, I had a solution, and here’s how it works.

Create the Workflow

Channels have a workflows option in their overflow […] menu. Go to the channel you want to use as the target for the notifications and select Workflows (Figure 1).

The workflows option in a channel menu.

Teams post to channel workflow.
Figure 1: The workflows option in a channel menu

Select Post to a channel when a webhook request is received from the screen listing available workflow templates (Figure 2).

Select a workflow template.
Figure 2: Select a workflow template.

The workflow needs an account to authenticate connections and post to the channel (this is different to the incoming webhook connector, which doesn’t need to authenticate using an account). The account must be a member of the host team. If, like me, the organization uses a utility account for this kind of operation, you’ll need to add the account to the team or select one of the existing team members. Figure 3 shows that the utility account is selected and validated (green tick). If you want to use a different account, click the […] menu and choose another account to connect.

Select an account to post notifications via the webhook.
Figure 3: Select an account to post notifications via the webhook

After collecting all the necessary information, the dialog displays the name of the target team and channel. You can choose a different team or channel at this point. Once the correct target is chosen, click Add workflow. Power Automate proceeds to create the workflow and responds with the workflow URI (Figure 4).

Power Automate creates the workflow URI.
Figure 4: Power Automate creates the workflow URI

Copy the URL and keep it safe because it is needed to tell Power Automate where to post payloads. When a payload arrives, Power Automate parses its content and if it’s OK, posts the content to the target channel.

If you forget to copy the URI, you can find it by opening the Workflows app, selecting the workflow, and copying it from the When a Teams webhook request is received step (Figure 5). To avoid potential confusion if multiple workflows of the same type are in use, I suggest that you take the opportunity to rename the workflow to make its purpose obvious.

Steps for the post to a channel when a webhook request is received workflow in the Teams workflow app.
Figure 5: Steps for the post to a channel when a webhook request is received workflow in the Teams workflow app

Posting Requests to the Workflow

It’s at this point that we do some PowerShell magic to create the request sent to the workflow URI. To create a realistic example, I decided to use the Get Service Health Graph API to retrieve the current health status for critical services running in the tenant, like Exchange Online, SharePoint Online, Teams, and so on.

The request is an adaptive card, which is composed of elements like text blocks, images, and fact set. I settled on a simple design composed of an image, a heading (text block), and a fact set. A fact has a name and a value. In this case, the name is a service (like “OneDrive for Business”) and the value is the current service health status (like “service degraded”).

I created a prototype adaptive card with indicators where to add the header and facts. Creating the facts is a matter of retrieving the service health status, filtering the data to extract the status for critical services, adding a graphic indicator for each depending on the health status. After generating the data, it was then a matter of formatting it in JSON to meet the requirements of the adaptive card schema and inserting the facts and header into the right places in the prototype adaptive card. The final step is to submit the request using the Invoke-MgGraphRequest cmdlet. Figure 6 shows the result.

Microsoft 365 service health status posted to a Teams channel via a workflow webhook.
Figure 6: Microsoft 365 service health status posted to a Teams channel via a workflow webhook

You can download the script from GitHub.

Normal Migration Woes

I am no Power Automate expert and profess no insight into how Power Automate works behind the scenes. I approached this exercise from the perspective of a tenant administrator who needs to replace the incoming webhook connector with a workflow. Persistence, some experience with PowerShell, knowledge of how to navigate Microsoft documentation, and trial and error got me a result in a few hours.

Overall, the transition was harder than I expected, but that might be due to lack of knowledge. It’s always difficult to do things when you suffer from that problem. I’ll chalk the experience down to normal migration woes.


Learn about using Teams, Power Automate, and the rest of Office 365 by subscribing to the Office 365 for IT Pros eBook. Use our experience to understand what’s important and how best to protect your tenant.

15 Replies to “Using PowerShell to Post Channel Messages with Teams Workflows”

  1. Great work. I need to figure out how to perform automation like this that isn’t statically set on one authentication account. I need a team to be able to use it and if someone leaves, it won’t break the automation. I haven’t figured out yet how to get automation to behave like an app so that it uses the context of the team members or can perform automation without a user authentication. Over-permissioned “service accounts” is the concern and on the other hand, creating a ton of service accounts isn’t a good either.

    It would be great if Microsoft created a service principal for each workflow to run autonomously and isn’t shared among automations. It would be easier to manage if Microsoft took care of the dirty details of this setup. Right now, Power Platform services are a very manual process to setup and trial and error like you said.

  2. To run the workflow the frist time you have to fill out the fields “type” and “attachments”. What data or information I have to set in these fields ? I can’t get the flow installed

      1. Apologies if the answer is obvious (as I’m using this the first time), but where / how do I configure the webhook and use this with workflows?

  3. One pain point in migrating is that my existing webhook connector is posting to a Shared Teams Channel. But it seems that with the workflow webhook method of doing the same thing, the Teams channel MUST be a Public channel. Anyone else have this same issue? Any possible solutions? Thanks!

      1. Any update on this? I did find a workaround – I use the Power Automate web tool to change ‘Post As’ from Flow bot to User and that will work on a Shared Channel. The one downside is now each posted message comes from *me* as the User, not optimal.

      2. Given that I don’t work for Microsoft, I can’t say what they might do in the future to plug what seems to be a big gap. I have asked them to comment, but these things take time and could take months before a response appears.

  4. hello, thanks for provided information! what kind of auto-user have you created on figure 3? how to do it? should it be created in Microsoft entra id? what kind of permissions are required?
    Could you please share this info?

    1. That user account (Azure Management account) is simply a licensed utility account (Office 365) that I use to run workflows instead of tying the workflows to a user account. Hopefully, Microsoft will allow organizations to use service principals (apps) for this in future, but it’s not there now.

  5. Great post. Just a quick question, if my company wants to use this, there’s some kind of extra cost if we currently have a teams suscription?

Leave a Reply

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