Dynamic Device Scope Tags with Azure Functions

In this previous blog post I showed you how to set dynamic device scope tags with azure automation. This time we will be using azure functions which will suite larger environments better. Based on my experience I would say that if you have 10k devices or less, go with the azure automation solution. If you have 10k devices or more, go with the azure functions solution.

I will explain how you could set this up by creating dynamic user groups, for example for the HR department, and then have azure functions gather all the HR users devices and add them to the correct device group automatically. If the user attribute changes, for example if a user leaves the HR department, their devices will be removed from the device group automatically.

Note that it’s critical that the user and device group names are consistent and have a matching ending. The first part of the group names will need to be defined in the azure functions application settings as “UserGroupNames” and “DeviceGroupNames”.

If you enter the following application settings:

  • Name = UserGroupNames
    Value = Endpoint-DUDE Users
  • Name = DeviceGroupNames
    Value = Endpoint-DUDE Devices

All your user group names should start with “Endpoint-DUDE Users” and all your device group names should start with “Endpoint-DUDE Devices”. Whatever you choose to put after this in the group names have to match between the two.

User Group Names:

  • Endpoint-DUDE Users HR
  • Endpoint-DUDE Users IT
  • Endpoint-DUDE Users Sweden
  • Endpoint-DUDE Users North Europe

Device Group Names:

  • Endpoint-DUDE Devices HR
  • Endpoint-DUDE Devices IT
  • Endpoint-DUDE Devices Sweden
  • Endpoint-DUDE Devices North Europe

There are two new settings in this script, “DeviceFilter” and “RunLevel”, which is controlled via the azure functions application settings with the following options:

  • Name = DeviceFilter
    Value = “All” or “Managed” (All will include all Intune and Azure AD devices. Managed will include all Intune and only managed Azure AD devices.)
  • Name = RunLevel
    Value = “Prod” or “Debug” (Use Prod to make changes. Debug for logging only.)

Another new feature in this script is that it will match users and devices primarily based on registeredOwner from the Azure AD device object and fallback to userPrincipalName from the Intune device object. This means that if you change primary user on a device, for example from a HR user to a IT user, the device will automatically be removed from the HR device group and added to the IT device group.

Let’s dig in…

User & Device Groups

To make this as dynamic as possible we would want to create dynamic user groups based on a user attribute. In this example I will create two dynamic user groups based on the departments “HR” and “IT”. DUDE in the group names stands for Dynamic User and Device Enumeration. Head over to Groups – Microsoft Azure to create our groups.

User group 1 – HR

User group 2 – IT

For each dynamic user group we need to create the corresponding device group. The device groups will have the assigned membership type so that our function can add and remove devices.

Device group 1 – HR

Device group 2 – IT

Scope Tags

Head over to Endpoint Manager roles – Microsoft Endpoint Manager admin center to create scope tags for our newly created device groups.

Azure Functions

Let’s create our function app! Go to Function App – Microsoft Azure, click “Create” and fill the required information and click “Next”

Select a storage account, Windows as the operating system and the desired Plan. I will not go into azure functions pricing in this post, you can read about it here, however there are some limitations that we need to consider like the fact that the consumption plan have a maximum runtime of 10 min. More info about azure functions scale and hosting can be found here. For the purpose of this blog I will select the consumption plan and hit “Next”

Leave the Enable network injection off and click “Next”

Enable application insight and click “Next”

Add any desired tags and click “Next”.

Click “Create”

We will use a managed identity to access our resources securely. When the deployment is completed, head back to Function App – Microsoft Azure, select your newly created function app, select “Identity”, enable system assigned managed identity, hit save and make a note of the “Object (principal) ID”

We need to add the permissions needed via PowerShell. Install the AzureAD module if you don’t already have (Install-Module AzureAD). Make sure to update the $TenantID and $PrincipalID variables before executing

# Variables
$TenantID = ".onmicrosoft.com"
$PrincipalID = "e2deedc8-390b-4c25-a456-7bc8ad3ff520"

# Add permissions
$Permissions = "Device.Read.All", "DeviceManagementManagedDevices.Read.All", "Group.Read.All", "GroupMember.ReadWrite.All", "User.Read.All"
Connect-AzureAD -TenantId $TenantID
$GraphServicePrincipal = Get-AzureADServicePrincipal -SearchString "Microsoft Graph" | Select-Object -first 1
$AppRole = $GraphServicePrincipal.AppRoles | Where-Object { $Permissions -contains $_.Value -and $_.AllowedMemberTypes -contains "Application" }
foreach ($Role in $AppRole) {
    New-AzureAdServiceAppRoleAssignment -ObjectId $PrincipalID -PrincipalId $PrincipalID -ResourceId $GraphServicePrincipal.ObjectId -Id $Role.Id

Head over to Enterprise applications – Microsoft Azure to verify the permissions. Select “managed identities” as the application type and open your system assigned managed identity. The object ID value matches the object ID of the managed identity that you previously created.

Select “permissions” and it should look something like this:

Head back to Function App – Microsoft Azure, select your function app, select “App files”, select “profile.ps1”, remove the following lines or use # and click “Save”

It’s time to configure our application settings. We need to add the following application settings:

  • Name = UserGroupNames
    Value = “”
  • Name = DeviceGroupNames
    Value = “”
  • Name = DeviceFilter
    Value = “All” or “Managed” (All will include all Intune and Azure AD devices. Managed will include all Intune and only managed Azure AD devices.)
  • Name = RunLevel
    Value = “Prod” or “Debug” (Use Prod to make changes. Debug for logging only.)

Go to “Configuration” and click on “New application setting” to add the desired values for each config

If you choose to include managed devices and run this in debug mode it should look like this:

Select “Functions”, click “Create”, select “Timer trigger”, add a name and a schedule. In my example “0 0 11,23 * * *” will schedule this to run at 11 and 23 (UTC) every day. Hit “Create”

Open the newly created function

Select “Code + Test” and remove any existing code from “run.ps1”

Copy the script from my github Intune/DUDE-AzureFunctions.ps1 at main · danielmoonpetri/Intune (github.com) ,paste it in “run.ps1” and hit “Save”

Select “Test/Run” and hit “Run”

Since we ran in debug mode we can review the output before moving this to production and making any changes

When we are happy with the results we can put this into production by going back to the application settings and change the “RunLevel” from “Debug” to “Prod” and it should look something like this:

Now the next function execution will proceed and make changes to the groups. We can wait for the timer to run or run it manually again. Let’s head back to the function again and run this manually

Select “Code + Test”, select “Test/Run” and hit “Run”

We can now see any changes made in the logs


After the function have executed according to our schedule or manually we can see the following results:

Device group members

Device Scope Tags


All actions will be logged in the audit logs

If we go to our function and check under monitor we will see status and runtime

If we open the invocation details we will get more information

The End

That’s it! We have now automated the device group assignments based on dynamic user groups and added scope tags. All we have to do now is to add more dynamic user groups, empty device group, assign scope tags and the function will take care of the rest.


Leave a Comment

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