Close Menu
Peter Klapwijk – In The Cloud 24-7Peter Klapwijk – In The Cloud 24-7
    Facebook X (Twitter) Instagram
    Peter Klapwijk – In The Cloud 24-7Peter Klapwijk – In The Cloud 24-7
    • Home
    • Intune
    • Windows
      • Modern Workplace
    • macOS
    • Android
    • iOS
    • Automation
      • Logic Apps
      • Intune Monitoring
      • GitHub
    • Security
      • Passwordless
      • Security
    • Speaking
    • About me
    Peter Klapwijk – In The Cloud 24-7Peter Klapwijk – In The Cloud 24-7
    Home»Android»MEM Monitoring: Get notified on Intune Configuration profile changes
    Android

    MEM Monitoring: Get notified on Intune Configuration profile changes

    Peter KlapwijkBy Peter KlapwijkAugust 2, 2021Updated:February 14, 20258 Mins Read

    You have configured your configuration profiles, compliance policies etc. in Microsoft Intune and after a lot of testing, piloting, and even more testing you are now live in production! Time to celebrate!

    But now that the environment is in production, a change in one of your production profiles might have a (big) impact on the user experience and maybe a policy change might even need approval by the Change Advisory Board.

    We already have an audit log available in the Endpoint Manager admin center. So the policy changes are all already available but there is no option to get notified on profile changes. I’d rather be notified by a profile change, instead that I need to dig in the logs as an incident is report about users with issues which might be caused by a profile change.

    Wouldn’t it be handy to get notified when one of the production profiles is (by accident) changed?

    As the events are available via Graph API, we should be able to build something to get this job done with Logic Apps.

    And I don’t want to be notified of every policy change, but only on changes to production profiles. If we make sure we have a naming convention implemented, by which we can make a shift between production (PRD) and test (TST) profiles we can do some filtering in the Logic Apps flow.

    When we have such a flow in place, we can get a notification for example via Teams or e-mail.

    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.

    Let’s see how to build such a Logic Apps flow.

    The solution in short

    The flow which we are going to build isn’t really large.

    The flow starts with a Recurrence trigger. You can schedule it to run once a day, once an hour, multiple times a day. Whatever is needed.

    Every run (in my example every hour), Microsoft Graph is queried for the audit events via an HTTP action. At that moment the audit events are retrieved from the previous hour.

    After this we use a Select action, to filter out the data we need in hour notification.

    To further process this data, we parse the data with a Parse JSON action.

    To get the filtering done, we use a Condition action. By this action, we drop the events from profiles which are not in production and only process the events from production profiles.

    In my example I use an HTTP Post action, to post a message in a Teams channel.



    Requirements

    We do have some requirements to get this flow up and running. First of all, we need an Azure App Registration. We need the app registration to authenticate to Microsoft Graph to perform an HTTP action. On this app registration, we set permissions so we are allowed to get the audit events via our queries. The minimum permission for this flow is DeviceManagementApps.Read.All.

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

    In this example, I use an HTTP Action to send a notification to a Teams channel. For this, a Teams incoming webhook connector needs to be in place.
    You could also send an email, by using a Send email action.

    The complete flow can also be downloaded as an ARM Template from my GitHub repository.

    Setup the Logic Apps flow

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

    Open the flow and 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 an HTTP action.
    As Method select GET.
    As URI enter:

    https://graph.microsoft.com/beta/deviceManagement/auditEvents?$filter=%20activityDateTime%20gt%20

    This URI is followed by an expression. The expression adds the current time (UTC) minus 1 hour. Or the current time minus one day. Which expression needs to be used, depends on how often the flow is triggered

    The expression for minus 1 hour is:

    formatDateTime(addHours(utcNow(),-1),'yyyy-MM-ddTHH:mm:ssZ')
    

    The expression for minus 1 day is:

    formatDateTime(addDays(utcNow(),-1),'yyyy-MM-ddTHH:mm:ssZ')

    In the HTTP action check Authentication and choose Active Directory OAuth as Authentication type. Enter the Tenant, Client 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.

    Below is an example of the output from the HTTP action.
    I want to get some values from this output to add in my notifications like:
    displayName
    displayName (found under resources)
    activityDateTime
    componentName
    activityOperationType
    userPrincipalName (found under actor)
    type (found under actor)

    As one of this output values is in an Array element, we can’t just use a Parse JSON to get the value (this would return the whole array). For this we need to use an expression with an integer index. Therefor we use an Select action, to get all values.

    We add a Data Operations action called Select.

    We use an expression to get the data from the output body 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 activityDateTime:

    item()?['activityDateTime']

    When the item is located under another object, we need an expression like below, as userPrincipalName is located under actor:

    item()?['actor']?['userPrincipalName']

    This is not possible for an Array, like Resources. We need to use an integer index. As the displayname is located in the first level of the array [0] as the integer index starts with a 0.

    item()['Resources']?[0]?['displayName']

    The expressions I used:

    item()?['displayName']
    item()['Resources']?[0]?['displayName']
    item()?['activityDateTime']
    item()?['componentName']
    item()?['activityOperationType']
    item()?['actor']?['userPrincipalName']
    item()?['actor']?['type']

    Enter all the expression 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.

    When the outputs field doesn’t contain any data, no changes are made during the last hour. Make a minor change to one of your Intune profiles.

    Next we add a Parse JSON action, which is also a Data Operations 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.

    To filter out non production audit events we can make use of a Condition, which is a Control action. I filter on the displayname found under resources as my production profiles al start with PRD in their displayname.

    When the audit event contains a displayname starting with PRD, the outcome of the condition is True. So our flow continues under True (and stops when the outcome is False).
    Add another HTTP action (under True).

    As Method select POST.
    As URI enter the incoming 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 JSON from my above example:

    {
      "text": "**Activity:** @{items('For_each_2')['displayName']}\n\n **Profile Name:** @{items('For_each_2')['ResourcesDisplayname']}\n\n **Date:** @{items('For_each_2')['activityDateTime']}\n\n **Component Name:** @{items('For_each_2')['componentName']}\n\n **Actor:** \n\n **UPN:** @{items('For_each_2')['UPN']}\n\n **Type:** @{items('For_each_2')['actortype']}\n\n",
      "title": "Intune profile activity '@{items('For_each_2')['ResourcesDisplayname']}' - @{items('For_each_2')['activityOperationType']}"
    }

    This is the flow to get notified on Intune profiles changes:

    I’ve chosen to not include the modified properties to the notification itself. This would make the notification a mess as the modified properties could contain a lot of (unstructered) data. With the information we do have in the notification we can lookup the event in the audit section in the portal

    But you could for example choose to send an email (instead of a Teams message) and add the modified properties data to an email attachment.

    Thanks for reading the article!

    Android Intune Intune Monitoring iOS Logic Apps macOS MEM MEMMonitoring Microsoft Endpoint Manager Power Automate Windows 10
    Share. Facebook Twitter LinkedIn Email WhatsApp
    Peter Klapwijk
    • Website
    • X (Twitter)
    • LinkedIn

    Peter is a Security (Intune) MVP since 2020 and is working as Modern Workplace Engineer at Wortell in The Netherlands. He has more than 15 years of experience in IT, with a strong focus on Microsoft technologies like Microsoft Intune, Windows, and (low-code) automation.

    Related Posts

    MEM Monitoring: Monitor Security baselines in Endpoint Security

    August 16, 2022

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

    May 26, 2021

    Export Endpoint Analytics Proactive remediation data with Logic Apps

    April 19, 2021
    Add A Comment

    Comments are closed.

    Peter Klapwijk

    Hi! Welcome to my blog post.
    I hope you enjoy reading my articles.

    Hit the About Me button to get in contact with me or leave a comment.

    Awards
    Sponsor
    Latest Posts

    Update Windows Defender during Windows Autopilot enrollments

    May 16, 2025

    Hide the “Turn on an ad privacy feature” pop-up in Chrome with Microsoft Intune

    April 19, 2025

    How to set Google as default search provider with Microsoft Intune

    April 18, 2025

    Using Windows Autopilot device preparation with Windows 365 Frontline shared cloud PCs

    April 13, 2025
    follow me
    • Twitter 4.8K
    • LinkedIn 6.1K
    • YouTube
    • Bluesky 1.5K
    Tags
    Administrative Templates Android Automation Autopilot Azure Azure AD Browser Conditional Access Edge EMS Exchange Online Feitian FIDO2 Flow Google Chrome Graph Graph API Identity Management Intune Intune Monitoring iOS KIOSK Logic Apps macOS MEM MEMMonitoring Microsoft 365 Microsoft Edge Microsoft Endpoint Manager Modern Workplace Office 365 OneDrive for Business Outlook Passwordless PowerApps Power Automate Security SharePoint Online Teams Windows Windows 10 Windows10 Windows 11 Windows Autopilot Windows Update
    Copy right

    This information is provided “AS IS” with no warranties, confers no rights and is not supported by the authors, or In The Cloud 24-7.

     

    Copyright © 2025 by In The Cloud 24-7/ Peter Klapwijk. All rights reserved, No part of the information on this web site may be reproduced or posted in any form or by any means without the prior written permission of the publisher.

    Shorthand; Don’t pass off my work as yours, it’s not nice.

    Recent Comments
    • Adam on Get notified on expiring Azure App Registration client secrets
    • Peter Klapwijk on Update Windows Defender during Windows Autopilot enrollments
    • Rob van de Ven on Add a certificate to the Trusted Publishers with Intune without reporting errors
    • Carl on Update Windows Defender during Windows Autopilot enrollments
    • Peter Klapwijk on The next step in a passwordless Windows experience
    most popular

    Application installation issues; Download pending

    October 1, 2024

    Restrict which users can logon into a Windows 10 device with Microsoft Intune

    April 11, 2020

    How to change the Windows 11 language with Intune

    November 11, 2022

    Update Microsoft Edge during Windows Autopilot enrollments

    July 9, 2024
    Peter Klapwijk – In The Cloud 24-7
    X (Twitter) LinkedIn YouTube RSS Bluesky
    © 2025 ThemeSphere. Designed by ThemeSphere.

    Type above and press Enter to search. Press Esc to cancel.

    Manage Cookie Consent
    To provide the best experiences, we use technologies like cookies to store and/or access device information. Consenting to these technologies will allow us to process data such as browsing behavior or unique IDs on this site. Not consenting or withdrawing consent, may adversely affect certain features and functions.
    Functional Always active
    The technical storage or access is strictly necessary for the legitimate purpose of enabling the use of a specific service explicitly requested by the subscriber or user, or for the sole purpose of carrying out the transmission of a communication over an electronic communications network.
    Preferences
    The technical storage or access is necessary for the legitimate purpose of storing preferences that are not requested by the subscriber or user.
    Statistics
    The technical storage or access that is used exclusively for statistical purposes. The technical storage or access that is used exclusively for anonymous statistical purposes. Without a subpoena, voluntary compliance on the part of your Internet Service Provider, or additional records from a third party, information stored or retrieved for this purpose alone cannot usually be used to identify you.
    Marketing
    The technical storage or access is required to create user profiles to send advertising, or to track the user on a website or across several websites for similar marketing purposes.
    Manage options Manage services Manage {vendor_count} vendors Read more about these purposes
    View preferences
    {title} {title} {title}