In this blog post I will describe how you easily can help yourself and your management to know if someone changed configurations or apps in your Microsoft Intune environment.
Many of my customers do have more than one administrator. With a modern way of working “Hybrid work” we sit at different locations, and it is not always that we remember to share what we configured or changed in the system.
The case could also be, that you want to be in control and that no one can do changes without you being aware of it. – Still curious how to do this? Then read along!
I will showcase to you the different ways to achieve this. We will look at Logic Apps and Power Automate and the cost of utilizing the different methods.
Microsoft Intune changes using Logic App
Prerequisites
- Intune diagnostic configured (AuditLogs)
- Azure Subscription
- Log Analytics
Creating your Logic App flow
Start by going to portal.azure.com
Search for Logic apps
Click Add
Add relevant information
- Choose subscription and create a new Resource Group
- Logic App name needs to be unique. A good tip is to add a corporate identifier, but keep it simple.
- Choose your region
- I choose Standard and you can see more on the pricing here
- Review + Create
TIP:
If you use standard you will have a bunch of benefits, but at the same time the price will rise. As a sum up I will show you how much it will cost you using this method. You can also read more here
If you only need to run a small amount of flows then I’d suggest that you use comsumption based instead. It is much cheaper, and I will show you the difference in the summary.
INFO!
Be aware that if you choose the consumption plan, the next couple of pictures will not be the ones you see. – I think you will find your way through anyway, as it is pretty logical.
Create
Click into the new Logic app choose Workflows and click add
Call it whatever you like as long as it makes sense.
Choose Designer
Add Recurrence and set it to a schedule that fit your needs.
Add Run query and visualize results add parameters where you have configured your Log Analytics Workspace
Kudos to Oliver for providing a great example of KQL
IntuneAuditLogs
| where OperationName == "Patch DeviceConfiguration"
or OperationName == "Patch DeviceManagementConfigurationPolicy"
or OperationName == "Patch DeviceManagementIntent"
or OperationName == "Patch DeviceCompliancePolicy"
or OperationName == "Update GroupPolicyConfiguration"
or OperationName == "Create DeviceConfiguration"
or OperationName == "Create DeviceManagementConfigurationPolicy"
or OperationName == "Create DeviceManagementIntent"
or OperationName == "Create DeviceCompliancePolicy"
or OperationName == "Create GroupPolicyConfiguration"
or OperationName == "Delete DeviceConfiguration"
or OperationName == "Delete DeviceManagementConfigurationPolicy"
or OperationName == "Delete DeviceManagementIntent"
or OperationName == "Delete GroupPolicyConfiguration"
or OperationName == "Delete DeviceCompliancePolicy"
or OperationName == "Patch MobileApp"
or OperationName == "Create MobileApp"
or OperationName == "Delete MobileApp"
or OperationName == "Create WindowsFeatureUpdateProfile"
or OperationName == "Patch WindowsFeatureUpdateProfile"
or OperationName == "Delete WindowsFeatureUpdateProfile"
or OperationName == "Create WindowsQualityUpdateProfile"
or OperationName == "Patch WindowsQualityUpdateProfile"
or OperationName == "Delete WindowsQualityUpdateProfile"
| extend PropertiesJson = parse_json(Properties)
| where TimeGenerated > now() - 24hours
| extend ActorJson = parse_json(PropertiesJson.Actor)
| extend Policy = replace_regex(tostring(todynamic(Properties).TargetDisplayNames), @'["\[\]]', "")
| extend ChangedBy = todynamic(Properties).Actor.UPN
| project
TimeGenerated=TimeGenerated,
Policy,
ChangedBy,
Operation=OperationName
| order by TimeGenerated
Again add Run query and visualize results add parameters where you have configured your Log Analytics Workspace. (all settings should be the same as the other object we just configured.)
Kudos to Ugur for providing a great example of KQL
IntuneAuditLogs
| where OperationName == "Patch DeviceConfiguration"
or OperationName == "Patch DeviceManagementConfigurationPolicy"
or OperationName == "Patch DeviceManagementIntent"
or OperationName == "Patch DeviceCompliancePolicy"
or OperationName == "Update GroupPolicyConfiguration"
or OperationName == "Create DeviceConfiguration"
or OperationName == "Create DeviceManagementConfigurationPolicy"
or OperationName == "Create DeviceManagementIntent"
or OperationName == "Create DeviceCompliancePolicy"
or OperationName == "Create GroupPolicyConfiguration"
or OperationName == "Delete DeviceConfiguration"
or OperationName == "Delete DeviceManagementConfigurationPolicy"
or OperationName == "Delete DeviceManagementIntent"
or OperationName == "Delete GroupPolicyConfiguration"
or OperationName == "Delete DeviceCompliancePolicy"
or OperationName == "Patch MobileApp"
or OperationName == "Create MobileApp"
or OperationName == "Delete MobileApp"
or OperationName == "Create WindowsFeatureUpdateProfile"
or OperationName == "Patch WindowsFeatureUpdateProfile"
or OperationName == "Delete WindowsFeatureUpdateProfile"
or OperationName == "Create WindowsQualityUpdateProfile"
or OperationName == "Patch WindowsQualityUpdateProfile"
or OperationName == "Delete WindowsQualityUpdateProfile"
| where TimeGenerated > now() - 24hours
| extend ChangedBy = todynamic(Properties).Actor.UPN
| extend Apps = todynamic(Properties).Actor.ApplicationName
| extend Device = todynamic(Properties).TargetObjectIds
//| extend Policy = todynamic(Properties).TargetDisplayNames
| extend Policy = replace_regex(tostring(todynamic(Properties).TargetDisplayNames), @'["\[\]]', "")
| mv-expand todynamic(Properties).Targets[0].ModifiedProperties
| extend Configuration = todynamic(Properties_Targets_0_ModifiedProperties).Name
| extend ['New Value'] = todynamic(Properties_Targets_0_ModifiedProperties).New
| extend ['Old Value'] = todynamic(Properties_Targets_0_ModifiedProperties).Old
| project TimeGenerated, Policy, Configuration, ['New Value'], ['Old Value'], ChangedBy
| order by TimeGenerated
Add new step and setup Send an email (V2)
TIP:
You can tell the difference on run query and visualize results as when multiple are added, they are numbered. The purple have number 2 where the first (the green) has no number.
You can also rename them if you like, that will make it easier to identify what value you are putting into your body
Click Save
To test your flow right away you can trigger it manually by going to Overview
This is cool. We get an email every day with the changes in it, where we can easily track changes and have no surprises.
Logic app cost per month
A forecast for Logic apps where we use the “Standard” with 1 trigger per day is about 1200dkk pr month.
A forecast for Logic apps where we use the “Consumtion based” with 1 trigger per day is about 2dkk pr month.
Microsoft Intune changes using Power Automate
Prerequisites
- Intune diagnostic configured (AuditLogs)
- Azure Subscription
- Log Analytics
- Power Automate premium connector license (Pricing | Microsoft Power Automate)
Creating your Power Automate flow
Start by going to Power Automate
Click Create and click Scheduled cloud flow
Give it a proper name
Click New Step
Search for Azure monitor logs
We need the one called Run query and visualize results
TIP:
This one requires the Premium license. All other connectors we will be using does not.
Add all the needed informations.
These should be the ones where your log analytics is stored
IntuneAuditLogs
| where OperationName == "Patch DeviceConfiguration"
or OperationName == "Patch DeviceManagementConfigurationPolicy"
or OperationName == "Patch DeviceManagementIntent"
or OperationName == "Patch DeviceCompliancePolicy"
or OperationName == "Update GroupPolicyConfiguration"
or OperationName == "Create DeviceConfiguration"
or OperationName == "Create DeviceManagementConfigurationPolicy"
or OperationName == "Create DeviceManagementIntent"
or OperationName == "Create DeviceCompliancePolicy"
or OperationName == "Create GroupPolicyConfiguration"
or OperationName == "Delete DeviceConfiguration"
or OperationName == "Delete DeviceManagementConfigurationPolicy"
or OperationName == "Delete DeviceManagementIntent"
or OperationName == "Delete GroupPolicyConfiguration"
or OperationName == "Delete DeviceCompliancePolicy"
or OperationName == "Patch MobileApp"
or OperationName == "Create MobileApp"
or OperationName == "Delete MobileApp"
or OperationName == "Create WindowsFeatureUpdateProfile"
or OperationName == "Patch WindowsFeatureUpdateProfile"
or OperationName == "Delete WindowsFeatureUpdateProfile"
or OperationName == "Create WindowsQualityUpdateProfile"
or OperationName == "Patch WindowsQualityUpdateProfile"
or OperationName == "Delete WindowsQualityUpdateProfile"
| extend PropertiesJson = parse_json(Properties)
| where TimeGenerated > now() - 24hours
| extend ActorJson = parse_json(PropertiesJson.Actor)
| extend Policy = replace_regex(tostring(todynamic(Properties).TargetDisplayNames), @'["\[\]]', "")
| extend ChangedBy = todynamic(Properties).Actor.UPN
| project
TimeGenerated=TimeGenerated,
Policy,
ChangedBy,
Operation=OperationName
| order by TimeGenerated
In order to convert the output we need to use Initialize variable
Add your own name to it and make sure you use Type: string
Then you search for Set Variable and in the dropdown you choose what you specified above.
In Value you add the attachment Content from the Run query and visualize results from above
Create yet another Run query and visualize results
IntuneAuditLogs
| where OperationName == "Patch DeviceConfiguration"
or OperationName == "Patch DeviceManagementConfigurationPolicy"
or OperationName == "Patch DeviceManagementIntent"
or OperationName == "Patch DeviceCompliancePolicy"
or OperationName == "Update GroupPolicyConfiguration"
or OperationName == "Create DeviceConfiguration"
or OperationName == "Create DeviceManagementConfigurationPolicy"
or OperationName == "Create DeviceManagementIntent"
or OperationName == "Create DeviceCompliancePolicy"
or OperationName == "Create GroupPolicyConfiguration"
or OperationName == "Delete DeviceConfiguration"
or OperationName == "Delete DeviceManagementConfigurationPolicy"
or OperationName == "Delete DeviceManagementIntent"
or OperationName == "Delete GroupPolicyConfiguration"
or OperationName == "Delete DeviceCompliancePolicy"
or OperationName == "Patch MobileApp"
or OperationName == "Create MobileApp"
or OperationName == "Delete MobileApp"
or OperationName == "Create WindowsFeatureUpdateProfile"
or OperationName == "Patch WindowsFeatureUpdateProfile"
or OperationName == "Delete WindowsFeatureUpdateProfile"
or OperationName == "Create WindowsQualityUpdateProfile"
or OperationName == "Patch WindowsQualityUpdateProfile"
or OperationName == "Delete WindowsQualityUpdateProfile"
| where TimeGenerated > now() - 24hours
| extend ChangedBy = todynamic(Properties).Actor.UPN
| extend Apps = todynamic(Properties).Actor.ApplicationName
| extend Device = todynamic(Properties).TargetObjectIds
//| extend Policy = todynamic(Properties).TargetDisplayNames
| extend Policy = replace_regex(tostring(todynamic(Properties).TargetDisplayNames), @'["\[\]]', "")
| mv-expand todynamic(Properties).Targets[0].ModifiedProperties
| extend Configuration = todynamic(Properties_Targets_0_ModifiedProperties).Name
| extend ['New Value'] = todynamic(Properties_Targets_0_ModifiedProperties).New
| extend ['Old Value'] = todynamic(Properties_Targets_0_ModifiedProperties).Old
| project TimeGenerated, Policy, Configuration, ['New Value'], ['Old Value'], ChangedBy
| order by TimeGenerated
and again we need to change our output using variables
Add information so it looks like you want it to be
Save your flow
Run Flow
And you should see something similar to mine
And shortly after a mail going into your mailbox
Power Automate cost per month
A forecast for Power Automate with 1 trigger per day is about 370dkk pr month. (unfortunately don’t have any graphics for that.)
Summary
There are several ways to automate flows when it comes to Azure and I’ve shown you 2 ways to accomplish a task that can help your daily operations.
It depends on your use which solution will be the cheapest, but if you only need a simple flow with few triggers a month, then I would strongly recommend using consumption based logic app flows.
I hope this blog post was helping you to decide where to add you flow and give you some inspiration to automate stuff using low code.
For more inspiration please have a look at my MVP colleague Peter Klapwijk as he has made a lot of great stuff in this area.
Mattias Melkersen is a community driven and passionate modern workplace consultant with 20 years’ experience in automating software, driving adoption and technology change within the Enterprise. He lives in Denmark and works at Mindcore.
He is an Enterprise Mobility Intune MVP, Official Contributor in a LinkedIn group with 41.000 members and Microsoft 365 Enterprise Administrator Expert.
Mattias blogs, gives interview and creates a YouTube content on the channel "MSEndpointMgr" where he creates helpful content in the MEM area and interview MVP’s who showcase certain technology or topic.
Official Contributor here "Modern Endpoint Management":
https://www.linkedin.com/groups/8761296/