Windows Autopilot lifecycle automation with Logic Apps – Part2

About a year ago I wrote this article regarding a Logic Apps flow that I created to delegate some permissions to local IT to perform lifecycle management on Autopilot registered devices.

By using a SharePoint List, local IT can delete Autopilot device registrations (in case of a repair or retirement of the device) or change the Group TAG (which changes the deployment profile based on a dynamic AAD group). For the retire part of the flow, it removes the device object in Intune and after that, it deletes the Autopilot registration. What it did not do, was clean up Azure AD (AAD) by also removing the device object from AAD. I did not implement that part as a delete action via Graph API does not support application permissions and application permissions are what my HTTP actions use to perform several Graph queries. But since that time, I learned how to use Managed Identities for my HTTP actions (which still uses applications permissions), but thanks to some great community members #CommunityRocks I also learned that we can assign (custom) Azure AD roles to a Managed Identity. And if that is possible, we can use a Graph call to delete the device object in Azure AD with a Logic Apps flow!

Solution and requirements

On the solution and requirements, we can be short, these are the same as described in part 1, with one additional permission (Azure AD role), to delete Azure AD Devices.

The biggest difference is that I switched from an Azure App registration to a Managed Identity (yes, still need to describe that further). So if you have implemented the first part of the flow, but didn’t change authentication to a Managed Identity yet, you should first do that.

Assigning an Azure AD role to a Managed Identity works the exact same way as we assign the permission to a normal user account (not using PIM).
We can assign a built-in role, such as the Cloud device administrator role, but that role also holds other permissions.
We can also create a custom Azure AD role, which only holds the microsoft.directory/devices/delete permission.

As you can see we can just search on the name of our Managed Identity to assign the role to the Managed Identity.

Expand our Logic Apps flow

Sign in to the Azure portal and open the Logic App service. I suggest cloning your existing Logic App, so you can leave that up and running, while you implement the new actions.

If you followed my previous blog post, you have a case for the retirement of devices. Under this case, we have a case for (Intune) enrolled devices and devices which are not enrolled (not contacted). Under both of these cases, we will add additional actions to query via Graph if a device exists in Azure AD or not. If we don’t first determine if a device exists (sometimes an Autopilot registration shows no associated device object), but immediately perform a delete action, the flow will fail when the object does not exist.

We start with the enrolled case. We add a new HTTP Action between the second HTTP Delete and SharePoint Get Item actions.

Choose GET as Method.
As URI enter:

https://graph.microsoft.com/v1.0/devices?$search="deviceId:[azureAdDeviceId]"&$select=displayName,id

Replace [azureAdDeviceId] with the azureAdDeviceId from the Dynamic content list.

As Header enter:
ConsistencyLevel eventual

Add the Managed Identity under Authentication.

Next, we add a Parse JSON action.
As content add Body from the HTTP Action. As Schema add:

{
    "properties": {
        "@@odata.context": {
            "type": "string"
        },
        "value": {
            "items": {
                "properties": {
                    "displayName": {
                        "type": "string"
                    },
                    "id": {
                        "type": "string"
                    }
                },
                "required": [
                    "displayName",
                    "id"
                ],
                "type": "object"
            },
            "type": "array"
        }
    },
    "type": "object"
}

We use a Condition action with an expression that checks the length of the value. If no AAD device object is found, the value returned is empty (and length is 0) and the condition is false. If an AAD device object is found, the condition is true, under which we perform the HTTP Delete action.

Add a Condition and in the left text box enter this value: as Expression

length(body('Parse_JSON_GET_AAD_Device_enrolled')?['value'])

Note Parse_JSON_GET_AAD_Device_enrolled in the expression is the name of the previous Parse JSON action, with underscores between the words.

Choose is not equal to from the drop-down list and enter 0 in the right text box.

Under True, we add an HTTP action.
Choose DELETE as Method.
As URI enter:

https://graph.microsoft.com/v1.0/devices/[ID]

Replace [ID] with the ID from the Dynamic content list (from the last Parse JSON action).
This will add the HTTP action in a For each action.

This is what our enrolled case now looks like with the additional actions to delete the device object.

We need to add the exact same actions in the not contacted case.
Add the HTTP action between the HTTP delete and SharePoint Get Item action.

The HTTP Action is followed by a Parse JSON action and Condition.

As Expression add:

length(body('Parse_JSON_GET_AAD_Device_notContacted')?['value'])

And under True we add the HTTP action to delete de AAD Device object.

And that is all for expanding our existing Logic App.

Thanks for reading and if you have any questions, leave a comment below.

1 Comment

Leave a Reply

Your email address will not be published.


*