Monitoring Microsoft Tunnel Gateway health with Power Automate

I want to give credit to my colleague Mark Hopper, whose work on monitoring various Intune connectors was a helpful reference for this post. Big shoutout to Mark. If you are interested in learning more about Intune monitoring, check out his post here. https://techcommunity.microsoft.com/t5/intune-customer-success/using-power-automate-to-notify-admins-on-intune-connector-health/ba-p/2274944

Microsoft Tunnel Gateway (MTG) provides VPN connectivity capabilities, allowing mobile devices to access corporate internal resources. This is a core service for many organizations, and ensuring the servers are in a healthy state is critical.

The current Intune portal includes a section that allows IT admins to monitor and check the server status. Some of the metrics that can be monitored from this section include those outlined in the following article: https://learn.microsoft.com/en-us/mem/intune/protect/microsoft-tunnel-monitor

Although the server’s status is displayed in the portal, it’s unlikely that admins are constantly monitoring the UI portal to ensure everything is okay. As a result, admins may only realize there is a problem when users start reporting that they cannot access internal resources.

In this post I will cover how to monitor the MTG servers via Power Automate and get IM notifications in Teams if something goes wrong with the server’s health.

Spoiler alert: I am not a Power Automate expert 🙂

Register an enterprise application in Azure Active Directory

Note: This step may be optional if you already have a registered app with the required permissions assigned.

As we are going to contact a protected API, we need to register an application to set up the necessary authentication and authorization for Power Automate to query the server’s status. Go to the Enterprise Application blade in the Azure Active Directory portal and create a new application by selecting ‘Create your own application’.

Next, we need to configure the supported account types and the redirect URI, which is the location where the authorization server sends the user once the app has been successfully authorized and granted an authorization code or access token. To set up the redirect URI, select ‘Web’ and enter https://global.consent.azure-apim.net/redirect, then click on Register.

Once the app is registered, we have to grant the read-only permissions to perform the operation. To do it go to the app we just registered. select ‘Permissions’ and then ‘Application registration’.

Select ‘Add a permission’ and under Microsoft APIs, select Microsoft Graph, then ‘Application permissions’; finally, select ‘DeviceManagementConfiguration.Read.All’

After adding permission, grant admin consent. It should look as follows:

Next, navigate to ‘Certificates & secrets’ and generate a client secret. This secret will be used by the Power Automate flow to authenticate as itself against the Graph API.
Give a description and set the expiration time (Client secret lifetime is limited to two years or less. You can’t specify a custom lifetime longer than 24 months).
Save the secret’s value for use in your client application code. This secret value is never displayed again after you leave this page. And we will use it during the power Automate flow configuration. Again, make sure to save this value for later use!

Now that we have finished with the app registration, we have to proceed with Power Automate.

Create the flow in Power Automate

Let’s configure a scheduled flow in Power Automate. Navigate to the Power Automate console, select ‘My Flows’, and then select ‘New Flow’ > ‘Scheduled Cloud Flow’.

STEP 1
Configure the start time and the frequency for the flow execution, in my case, I want to have the flow checking-in every hour.

STEP 2
Configure the HTTP action to query each MTG site our tenant has. In this HTTP action we define:

To obtain the {microsoftTunnelSiteId} you can go the Intune portal -> Tenant Administration -> Microsoft Tunnel Gateway -> Sites -> select the site you want to validate.  Then copy the site ID from the browser’s URL:

  • The Authentication method: Active Directory OAuth.
  • The authority: https://login.microsoft.com
  • The Tenant ID, which is listed under the basic information of the Azure AD portal.
  • Audience: which is the API our registered app has permissions on: https://graph.microsoft.com
  • Client ID: which is the Application ID our registered app has assigned.
  • Credential Type is Secret.
  • Secret: is the value that you saved during the app registration process. 

Once configured it will look as follows:

If you have multiple sites, you need to create an HTTP action for each MTG site. To ensure that the HTTP actions run independently and simultaneously, use parallel branches (as shown in the image at the end of this post.)

STEP 3
Add a Parse JSON action, to parse the return value of the previous HTTP call against the API (it comes in JSON format). To do it, we need to configure two values:

  • For Content field, select HTTP Body (this is the section of the answer we want to parse)
  • The Schema field represents how the data is structured. Here is the structure of the response we are waiting for from the service. You can copy and paste the structure in the schema section (there is no need to use the ‘Generate from Sample’ option)
{
    "type": "object",
    "properties": {
        "@@odata.context": {
            "type": "string"
        },
        "value": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string"
                    },
                    "displayName": {
                        "type": "string"
                    },
                    "tunnelServerHealthStatus": {
                        "type": "string"
                    },
                    "lastCheckinDateTime": {
                        "type": "string"
                    },
                    "agentImageDigest": {
                        "type": "string"
                    },
                    "serverImageDigest": {
                        "type": "string"
                    }
                },
                "required": [
                    "id",
                    "displayName",
                    "tunnelServerHealthStatus",
                    "lastCheckinDateTime",
                    "agentImageDigest",
                    "serverImageDigest"
                ]
            }
        }
    }
}

Once added, it looks as follows:

STEP 4
Create a Condition action to evaluate the properties received in the HTTP response and make a decision based on the “tunnelServerHealthStatus” property.
The logic for this condition is as follows: If “tunnelServerHealthStatus”, is not healthy, then send an Instant Message to the IT pro via Microsoft Teams. If “tunnelServerHealthStatus” is healthy do nothing.
Checking for non-healthy states allows us to report if the server is in any other state, such as unhealthy, warning, offline, upgradeFailed, upgradeInProgress, etc.
With that said, let’s create a condition where if the “tunnelServerHealthStatus” is not equal to healthy then send a Teams IM notification with some details about the problem and next steps:

And that would be it. If you have more than one site, you can add a parallel branch and trigger a flow for the second MTG site. (This is because the URI we enter for each HTTP action contains the site ID).
For example, I have multiple servers distributed in two sites. Here is how my cloud flow looks:

When the flow runs, it sends a notification indicating that three servers are not healthy. This allows me to quickly take action and resolve any issues before they potentially impact end-users.”

This is the notification I received:

PRO TIPS

Would you like to monitor server performance metrics? You can run a POST operation against the API to retrieve the data. The URL and HTTP operation are defined here: https://learn.microsoft.com/en-us/graph/api/intune-mstunnel-microsofttunnelserver-gethealthmetrics?view=graph-rest-beta

Make sure to include the following structure and data as part of the request body section.

{
    "metricNames": [
        "cpuUsage",
        "cpuCores",
        "memoryUsage",
        "tlsCert",
        "agentCert",
        "latency",
        "diskSpaceUsage",
        "totalDiskSpace",
        "upgradeability",
        "serverVersion",
        "onPremNetworkAccess",
        "serverConfiguration",
        "serverContainer",
        "serverLogs",
        "currentConnections",
        "throughput"
    ]
}

For example, doing the query with Graph Explorer (you can use any other tool that allows automation to perform these actions as well)

The API will provide you’re the current values for the metrics requested.

Another thing to consider is that the processes I am sharing here do not tell if a client device cannot connect to the VPN (unless the server is offline). Checking if the connection from a device is possible will cover this scenario. For example, if you perform a GET operation against your VPN site name and it responds successfully (HTTP code 200), it will tell you that:

  • The service is up and running.
  • The TLS handshake could be completed.
  • No problems at the transport layer were observed or detected (TCP handshake completed).

The Power Automate cloud version does not offer a way to run this test (I think Power Automate Desktop could do it) However, it could be easily tested using a web browser or automating this task through a PowerShell script. I will let you figure this out.

A successful test using a web browser looks like this:

Leave a Comment

Your email address will not be published. Required fields are marked *