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

Update January 2022: as the Office 365 Management API is deprecated and the new service communications API in Microsoft Graph replaces this legacy API, I did an update to this blog post.

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.

This blog post is part of the MEM (Intune) Monitoring series. An article with a short explanation of every MEM Monitoring flow I shared and links to the related articles can be found here.

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 Microsoft Graph API for the service communication issues. In the query, I use a filter to only retrieve the issues from the Microsoft Intune service. 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 issues are further processed which are modified 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 been archived for some time. We finish the flow with another HTTP action to post a Teams messages via a Teams incoming webhook.

Requirements

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 Graph API. On this App Registration, we set the required permission we need for our API queries.

This is an Application permission on Microsoft Graph. The required permission is ServiceHealth.Read.All.



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).

The complete flow can also be downloaded from my GitHub repository and deployed using PowerShell/ Bicep.

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 HTTP action.

Add a HTTP action.
As Method select GET.
As URI enter:

https://graph.microsoft.com/v1.0/admin/serviceAnnouncement/issues?$filter=service%20eq%20'Microsoft%20Intune'

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.

body('HTTP_ACTION_NAME')?['value']

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:

item()?['ITEMNAME']

For example to get the Title:

item()?['Title']

These are the expressions I use in this example:

item()?['Title']
item()?['Id']
item()?['impactDescription']
item()?['Classification']
item()?['startDateTime']
item()?['lastModifiedDateTime']
item()?['Status']
item()?['isResolved']

When you use this for all or multiple workloads, you might want to add Service 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 a value add Last Modified Date Time. 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.



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:

{
 "text": "WRITE YOUR MESSAGE TEXT HERE",
  "title": "WRITE YOUR TITLE HERE"
}

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 body from my above example:

{
  "text": "**Title:** @{items('For_each')['Title']}\n\n **ID:** @{items('For_each')['ID']}\n\n **Impact Description:** @{items('For_each')['Impact Description']}\n\n **Classification:** @{items('For_each')['Classification']}\n\n **Start Time:** @{items('For_each')['Start Date Time']}\n\n **Last Modified Time:** @{items('For_each')['Last Modified Time']}\n\n **Status:** @{items('For_each')['Status']}\n\n **Is Resolved:** @{items('For_each')['Is Resolved']}",
  "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.

9 Comments

  1. Hello Peter, Great Stuff,

    when i run the above i get the error “ValidationFailed. The schema validation failed.” at the Parse JSOnN step. Any inputs will be appreciated. thanks

  2. Hi, I did everything correct but for some reason the addHours(utcNow(),-1) is returning false but there is data there. The flow does fire off hourly but does not email anything with that expression.

Leave a Reply

Your email address will not be published.


*