Account Protection Local Group Membership Management Automation with Azure Function
This automation is implemented as an Azure Function (PowerShell) that creates device-specific Account Protection policies in Microsoft Intune (via Microsoft Graph) to grant specific users local administrator rights on specific devices. It was built to provide exceptions to a global account protection policy for targeted device-user pairs.
Prerequisites & Resources
Azure Resources
This automation is deployed as an Azure Function. At minimum, you need the following resources:
-
Resource Group – to contain all components.
- Function App (PowerShell) – hosts the scripts. Use Consumption or Premium plan.
-
Storage Account – required for Function state and triggers. Is created automatically while deploying an Azure Function App.
-
Application Insights – for telemetry and monitoring (not required but recommended).
-
Managed Identity – for secure authentication to Microsoft Graph. For permissions view next chapter.
Graph API Permissions
Your Bearer access token for the Microsoft Graph API needs at least the following scopes. If you are deploying the solution with the recommended approach using a managed identity, then grant the following permissions:
- Device.Read.All
-
Group.ReadWrite.All
-
DeviceManagementManagedDevices.Read.All
When you want to use the solution with multiple tenants and/or delegated permissions, you can also use an existing access token while calling the API endpoint. More on that approach below.
Azure Functions
In an Azure Function app we have to deploy two Azure Functions. One PowerShell code is to create the groups, devices, assignments, exclusions, and policies (Automation-LocalAdminGrant.ps1
). The second function is responsible for revoking the access and reverting the steps that the grant automation is doing (<a href="https://github.com/lucanoahcaprez/lnc-docs-resources/blob/main/microsoft-intune/Automation-LocalAdminRevoke.ps1">Automation-LocalAdminRevoke.ps1</a>
). All the code is provided in the Github repository of LNC DOCS.
-
Automation-LocalAdminGrant.ps1
: Automation for granting and creating the permission policies. -
Automation-LocalAdminRevoke.ps1
: Second automation for reverting the steps (removing the permissions through policy change).
Workflow & Architecture
This chapter describes the workflow and architecture of the two parts (grant & revoke) of the solution. The automation enables per-device exceptions to a global account protection policy which handles local admin rights on Windows clients. It does so by creating device-specific Entra ID groups, updating Intune configuration policies, and managing membership in a global exclusion group.
HighAutomation Level Workflowprocess
This is how the automation processes your request. Between "Grant" and "Revoke" part, the automation is almost similar. The main difference is, that the automation creates or deletes the objects/memberships according to existing environment and requests.
-
Input validation
- When the Function receives an HTTP request (POST) with parameters UserPrincipalName and DeviceName it validates the provided JSON object.
- If the validation is rejecting the input, the automation returns 400 codes.
-
Authentication (choose token source)
- If a parameter with the name
MicrosoftEntraIDAccessToken
is provided in the JSON body of the POST request, this token is used for authentication. - Another option is to optain a token from the Managed Identity via IMDS (Azure Instance Metadata Service). This needs to be configured correctly.
- If a parameter with the name
-
Resolve device
- Next the automation queries the Intune managed devices with a filter on DeviceName (prefix match).
- It ensures that there is an exact match. It aborts on zero or multiple responses.
-
Resolve Entra ID device
- Afterwards it queries the Microsoft Entra ID devices using the Intune device's AzureADDeviceId.
-
Prepare naming and resources
- Then it builds policy and group names from device serial (e.g. Windows-COPE-LUSRMGR-
for Account Protection policy and MEID-INT-Windows-LUSRMGR- for Entra ID group). - Resolves ExclusionGroupID for excluding the device from the global Account Protection policy.
- Then it builds policy and group names from device serial (e.g. Windows-COPE-LUSRMGR-
-
Create/Ensure resources
- It creates a device-specific Entra ID security group if not present.
- Then it adds the device to the previously created/verified group.
- In the end it adds the device to the global exclusion group.
-
Create/Update account protection policy
- First it checks if a policy with the constructed name already exists.
- If not present, the automation creates a configuration policy that grants the specified user local admin (via AzureAD<UserPrincipalName> reference) on the target device group.
- If the policyname is already present, the policy members are updated if needed.
-
Final validation
- Last but not least it verifies that the device is in the correct groups and the policy is assigned.
- The Azure Function returns success (200) or a helpful error message describing which step failed.
-
Revoke path (Automation-LocalAdminRevoke)
- To reverse the actions you can call the "revoke" automation. It remove the user from the policy, removes the policy if empty, removes the device from the exclusion group and deletes the device-specific group if it is empty.
Usage & Implementation
API Request using HTTP
- Endpoint:
POST /api/Automation-LocalAdminGrant
- Content-Type:
application/json
- Body parameters:
-
UserPrincipalName
(string) — required -
DeviceName
(string) — required (prefix match) -
MicrosoftEntraIDAccessToken
(string) — optional; usesManaged Identity
if not provided
-
- Success response: HTTP 200 with body
"FINAL CHECK: SUCCESS"
- Failure responses: HTTP 400/401/500 with appropriate diagnostic messages
Example POST
$body = @{
UserPrincipalName = 'user@example.com'
DeviceName = 'LAPTOP-1234'
} | ConvertTo-Json
Invoke-RestMethod -Uri 'https://<func-app>.azurewebsites.net/api/Automation-LocalAdminGrant' -Method Post -Body $body -ContentType 'application/json'
Authentication (Token handling)
- Preferred: Managed Identity (system-assigned or user-assigned) enabled on the Function App.
- The function will request a token from the IMDS endpoint:
http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://graph.microsoft.com/
- The function will request a token from the IMDS endpoint:
- Alternative: include an Access Token in the request body as
MicrosoftEntraIDAccessToken
(Bearer token). The function will use this token directly.
Implementation details & notable behaviours
-
CheckGroupMember
accepts either a group name or GUID. It resolves names to IDs when needed and enumerates members across paginated results. - The policy creation uses Graph's
beta/deviceManagement/configurationPolicies
endpoints (beta). This is required for the specific configuration policy templates used. - The function may create up to three groups per device: device-specific group, device-assignment group, and an exclusion group addition (global exclusion group is pre-configured ID).
- The function performs idempotent checks before creating groups or policies.
Error modes & troubleshooting
- "Resource not found" when removing members: often caused by using an array object incorrectly. Ensure device lookups use the correct element index (e.g.,
$EntraIDDevice[0].id
). - 401 Unauthorized: ensure managed identity has required Graph app permissions and admin consent is granted, or provide a valid Bearer token in the request.
- Rate limiting: Graph API limits may require retry/backoff behavior — consider adding exponential backoff for production.
Example: Local testing with a token
- Acquire a token with required scopes (admin):
# Use Azure AD app registration with client credentials
$tenantId = '<tenant>'
$clientId = '<appclientid>'
$clientSecret = '<clientsecret>'
$body = @{
client_id = $clientId
scope = 'https://graph.microsoft.com/.default'
client_secret = $clientSecret
grant_type = 'client_credentials'
}
$token = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token" -Method Post -Body $body -ContentType 'application/x-www-form-urlencoded'
$token.access_token
- Call the function with the token:
$body = @{UserPrincipalName='user@example.com'; DeviceName='LAPTOP-1234'; MicrosoftEntraIDAccessToken = "Bearer $($token.access_token)"} | ConvertTo-Json
Invoke-RestMethod -Method Post -Uri 'https://<func>.azurewebsites.net/api/Automation-LocalAdminGrant' -Body $body -ContentType 'application/json'
Deployment & Permissions (Detailed)
1) Deploy the PowerShell Azure Function
- Create a Function App (PowerShell) in your target subscription and resource group.
- Use ZIP deploy, VS Code deployment, or GitHub Actions to deploy the function code. Ensure the file
Automation-LocalAdminGrant.ps1
is placed in the function folder andfunction.json
is configured for HTTP trigger.
2) Enable Managed Identity
- In the Azure Portal, go to your Function App -> Identity -> System assigned -> On -> Save.
- Note down the object id (service principal) of the managed identity.
3) Grant Microsoft Graph application permissions to the managed identity
- Open the Microsoft Entra admin center -> Enterprise applications.
- Find the managed identity service principal by the Function App name.
- Under
Permissions
(or API permissions) add the following Application permissions for Microsoft Graph:-
Group.ReadWrite.All
-
Directory.ReadWrite.All
-
Device.ReadWrite.All
-
DeviceManagementManagedDevices.ReadWrite.All
-
DeviceManagementConfiguration.ReadWrite.All
-
- Click Grant admin consent (requires an administrator account).
- Alternatively, you can grant the permissions programmatically via Microsoft Graph API or Azure AD PowerShell, but admin consent is still required.
4) Verify permissions
- Use Microsoft Graph Explorer or Microsoft.Graph PowerShell to check that the service principal can call endpoints such as
GET https://graph.microsoft.com/v1.0/groups
andGET https://graph.microsoft.com/beta/deviceManagement/configurationPolicies
using an app-only token.
5) App Registration alternative (optional)
If you prefer not to use Managed Identity, create an App Registration and grant the same set of Application permissions to that app. Use client credentials to obtain a token and pass it to the function.
6) Function App settings
- Review
WEBSITE_RUN_FROM_PACKAGE
and other deployment settings. - Consider enabling Application Insights for rich telemetry.
7) Monitoring and logging
- Enable Application Insights and verify request traces and exceptions.
- Add diagnostic logging inside the function (Write-Output, Write-Error) for key steps like token acquisition, group creation, and policy assignment.