Get Intune (or other Microsoft 365) Service Health messages in a Teams channel

Microsoft PM Mark Hopper shared an article on Tech Community “Using Power Automate to notify admins on Intune Connector health“. I like this automation solution to get the connector health messages via Power Automate, but I changed the flow in our environment a little to post these messages in a Teams channel (instead of sending an email).

So besides the Autopilot Deployment events which I described in a previous post, I now also have these connector health messages in Teams. What I also like to receive in Teams are the Intune Service Health messages. I know you can easily receive these messages via email when an incident is opened, via the Microsoft 365 portal, but to keep all these service health related messages in one place I thought of creating a Logic Apps flow to pull these messages via an API from the health service and post these in a Teams channel.

So again, I created a flow using Logic Apps to get this job done.

The solution in short

The complete Logic Apps flow which we’re going to create is shown below.

The flow starts with a Recurrence trigger. It runs every hour. The first action is an HTTP action to query the Office 365 Management API for the Service Messages. In the query, I use a filter to only retrieve the messages from the Intune workload. This action is followed by a Data operation, to select the values from the output of the HTTP action which I need in the following actions. To use this retrieved data in further actions, this data needs to get parsed.
Next, a Condition is added to the flow. With this condition, I make sure only the messages are further processed that received an update in the last hour. If we don’t use this kind of filtering, every hour all pulled messages are posted to Teams, also the messages which are already archived for some time. We finish the flow with another HTTP action to post a Teams messages via a Teams incoming webhook.


We have some requirements for this flow.

First of all, we need to have the appropriate permissions to run the API query. The HTTP action we use in the flow uses an Azure App Registration to authenticate to the Office 365 API. On this App Registration, we set the required permission we need for our API queries.

This is an Application permission on the Office 365 Management API. The required permission is ServiceHealth.Read.

In this previous blog post I described in detail how to create an App Registration.

To post a message to a Teams channel we can use an Incoming Webhook. So make sure to add an incoming webhook to your Teams channel and save the webhook URL, to use it in one of the actions in our flow.

To secure the HTTP actions I use an Azure Key Vault, which is described in this previous post, but this is optional (but recommended).

Setup the Logic Apps

Sign-in to the Azure portal and open the Logic Apps service. Here create a new, blank Logic App.

In the search box for connections and triggers search for Schedule. Select Schedule and select Recurrence which functions as our flow trigger.

I choose to run this Logic Apps flow every hour.

The first action we add is an Azure Key Vault action to retrieve the secret for authentication of the upcoming HTTP action. Search for Azure Key Vault and select Get secret.

Enter at least the Vault name and click sign-in.

Enter the name of the secret.

Add a <strong>HTTP</strong> action.<br>

Add a HTTP action.
As Method select GET.
As URI enter:[TENANTID]/ServiceComms/Messages?$filter=Workload%20eq%20'Intune'

Replace [TENANTID] by your tenant ID or domain name.

Check Authentication and choose Active Directory OAuth as Authentication type. Enter the TenantClient ID (from the app registration) and Audience.
And make sure to select the Key Vault secret value from the Key Vault action (found via Dynamic content).

This is how our HTTP action looks like.

We add a Data Operations action called Select.

We use an expression to get the data from the value array of the HTTP output. Add below expression in the From field via the expression tab. Make sure to replace HTTP_ACTION_NAME with the name of your HTTP action, but with underscores instead of spaces.


Next enter all the key names on the left. You can choose the key names yourself.

On the right, we need the values (items) from the previous HTTP action.
To grab these items we use an expression like below:


For example to get the Title:


These are the expressions I use in this example:


When you use this for all or multiple workloads, you might want to add WorkloadDisplayName as well.

Enter all the expressions one by one.



This is the complete Select action.

Save the Logic App and run the flow.
When it’s finished open the flow from the Runs history and open the Select action.
Copy the Outputs body. We use this as a sample payload in the next action.

Switch back to the designer.
Add a Parse JSON action to the flow, which is a Data Operation action.
As content, we use the Output from the previous Select action.
We fill the schema by using the sample payload we just copied in the previous step. Click Use sample payload to generate the schema and paste the copied data in the box which will generate the schema.

Next, we add a Condition, which is a Control action. With this condition, we filter out all the older messages, which didn’t get an update in the last hour (based on the Last Updated Time value).

As value add LastUpdatedTime. Choose is greater than from the drop-down box. In the right value box, we enter an expression to add the current time (UTC) minus 1 hour.
The expression is addHours(utcNow(),-1)

As soon as we add LastUpdatedTime to the Condition, the action is automatically placed in a For each action.


If you want to do some more filtering, for example when you’re only interested in the status Service Degradation and Service restored, we can implement that in the condition as well.

For this, we create two groups like below, which we set to And. In the top left corner, we switch AND to OR.
Besides filtering on Last Updated Time, we then also use Status.

Let’s go further with the required actions:
Under True, we enter an HTTP action.

As Method select POST.
As URI enter the webhook URL.
As Headers enter Content-Type – application/json

In the body, we add the text and title in JSON format. Below is the JSON format we need to use for this, without our variables:


We can use dynamic content (variables) from the previous PARSE JSON action and enter our own text.
Use \n\n in the text to create new lines in the text message, otherwise, the message consists of one long line of text.
And I used ** to get some text in bold.

This is the JSON from my above example:

  "text": "**Title:** @{items('For_each')['Title']}\n\n **ID:** @{items('For_each')['ID']}\n\n **Start Time:** @{items('For_each')['Start Time']}\n\n **Status:** @{items('For_each')['Status']}\n\n **Classification:** @{items('For_each')['Classification']}\n\n **Last Updated Time:** @{items('For_each')['Last Updated Time']}",
  "title": "@{items('For_each')['ID']} "

This is our complete Logic App flow to get the job done.

The end result

This flow should post a message when an incident is added to the Service Health Dashboard based on the service degradation status.
And it should post a message when the service is restored.

This Logic App flow could of course also be used to get all Microsoft 365 Service Health messages in a Teams channel by removing the filter in the HTTP GET action. Or change the filter if you’re interested in another workload.

Thanks for reading and leave a comment when you have a question or have suggestions for this flow.

Be the first to comment

Leave a Reply

Your email address will not be published.