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 exists to provide exceptions to a global account protection policy for targeted device-user pairs.
Prerequisites
Azure Resources
This automation is deployed as an Azure Function. At minimum, you need the following resources:
Resource Group – to contain all components.
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:
Azure Functions
Automation-LocalAdminGrant.ps1 - Main Azure Function implementation (PowerShell run.ps1)
Automation-LocalAdminRevoke.ps1 - Revoke function to remove the policy, group and membership
High-level Workflow
- Receive HTTP request (POST) with JSON body containing
UserPrincipalNameandDeviceName. - Obtain Microsoft Graph access token — prefer supplied token in request body, fallback to the Function's Managed Identity via IMDS.
- Query Intune for managed devices matching
DeviceName(prefix match) and select the first match. - Query Azure AD (Entra ID) for the device object representing the Intune device by
azureADDeviceId. - Create an Entra ID security group for the device, add the device to this group, and add the device to the global exclusion group.
- Create or update a configuration policy (Account Protection) in Intune with the user (and optional default admin group SID) as a member.
- Assign the configuration policy to the device group.
- Return success/failure diagnostics.
Files
Automation-LocalAdminGrant.ps1 - Main Azure Function implementation (PowerShell run.ps1)
Automation-LocalAdminRevoke.ps1 - Revoke function to remove the policy, group and membership
API Contract (HTTP)
POST /api/Automation-LocalAdminGrant
Content-Type: application/json
Body parameters:
UserPrincipalName (string) — required
DeviceName (string) — required (prefix match)
MicrosoftEntraIDAccessToken (string) — optional; uses Managed 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)
http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://graph.microsoft.com/
Alternative: include an Access Token in the request body as MicrosoftEntraIDAccessToken (Bearer token). The function will use this token directly.
Required Microsoft Graph permissions (application-level)
Group.ReadWrite.All
Directory.ReadWrite.All
Device.ReadWrite.All
DeviceManagementManagedDevices.ReadWrite.All
DeviceManagementConfiguration.ReadWrite.All
Note: These are application permissions and require admin consent. The managed identity's service principal must be granted these permissions.
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
$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.
Deployment steps (Azure CLI)
az functionapp identity assign -g <rg> -n <functionapp-name>
Configure Graph API permissions on the function's service principal (admin consent required). You can do this via an App Registration used by the function or directly for the managed identity service principal using PowerShell/AzureAD.
Example: Grant Graph permissions via Microsoft Graph PowerShell (admin)
# Requires Microsoft.Graph PowerShell modules and admin privileges
Connect-MgGraph -Scopes 'Application.ReadWrite.OwnedBy'
$sp = Get-MgServicePrincipal -Filter "displayName eq '<function-app-name>'"
# ... assign required AppRoleAssignments or update oauth2PermissionGrants ... (admin tasks)
Example: Local testing with a token
# 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
$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'
Logging & validation
Next steps / Enhancements
Deployment & Permissions (Detailed)
1) Deploy the PowerShell Azure Function
Automation-LocalAdminGrant.ps1 is placed in the function folder and function.json is configured for HTTP trigger.
2) Enable Managed Identity
3) Grant Microsoft Graph application permissions to the managed identity
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
GET https://graph.microsoft.com/v1.0/groups and GET 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
WEBSITE_RUN_FROM_PACKAGE and other deployment settings.
Consider enabling Application Insights for rich telemetry.
7) Monitoring and logging
Troubleshooting checklist
401 Unauthorized: ensure admin consent was granted for application permissions to the managed identity or app registration. "Resource not found" when adding/removing members: verify that the Entra ID device id is correctly extracted (e.g.$EntraIDDevice[0].id).
Policy creation fails: check Graph beta availability and that the service principal has DeviceManagementConfiguration.ReadWrite.All permission.
Throttling: add exponential backoff and log 429 responses.
Documentation generated on $(Get-Date) by automation helper.