Windows Autopilot

Windows Autopilot health check: An experiment in Graph API scripting

We have talked to a number of customers over the past months who have run into challenges with Windows Autopilot – sometimes these were simple configuration issues, other times they were self-inflicted pains (e.g. deleting Azure AD device objects associated with a registered Windows Autopilot device).  But as we learn more about the types of challenges encountered, we get better at detecting those issues (and eventually we’ll try to prevent them from happening).

To help with the detection process, I’ve published a new script called AutopilotHealthCheck.ps1 to the PowerShell Gallery.  You can install it using PowerShell quite easily, along with its pre-requisite modules:


For those that don’t like to type, you can copy and paste:

Install-Module AzureAD
Install-Module Microsoft.Graph.Intune
Install-Module WindowsAutopilotIntune
Install-Script AutopilotHealthCheck

You can then run the script just by typing its name:


It will prompt for authentication twice, once for querying Intune and a second time for Azure AD; typically you will want to specify the same credentials for both.  (The AzureAD and Microsoft.Graph.Intune modules can’t share credentials, hence the need to authenticate to each one separately.)

The script will then perform several checks:

  • Device registration status.  All registered Autopilot devices will be checked to ensure that they have an assigned Autopilot profile.  A list of those that don’t will be provided.
  • Azure AD device object status.  Each Autopilot device will be checked to ensure that there is an associated Azure AD object.  A list of those that don’t will be provided.  (Some scenarios, e.g. self-deploying, white glove, will fail if this object doesn’t exist.  Don’t delete it.  If you need to put it back, you will need to re-register the device with Windows Autopilot.)
  • Intune managed device status.  This is mostly informational, just showing how many Autopilot devices have an associated Intune device object (a good indication that they were enrolled at least once), how many don’t (never enrolled), and how many reference an Intune device object that no longer exists (a good indication that the Intune device object was deleted or archived).
  • Autopilot devices by profile type.  Another informational one, showing how many devices have a user-driven Azure AD profile, user-driven Hybrid Azure AD profile, or a self-deploying profile.
  • Hybrid Azure AD Join domain join profile check.  This one is much more involved, checking each Autopilot device that has a Hybrid Azure AD Join profile assigned to it, making sure that it has a Domain Join profile assigned to it.  If you have assigned one to “All devices” then this is easy; if you have assigned it to an Azure AD device group then it is more involved.  Basically, if you have a device that doesn’t have an associated Domain Join profile, it won’t successfully complete the offline domain join (ODJ) process if it were ever reset.  (See the notes at the bottom of my previous blog on this one.)  To pull this off, you have to follow the chain from Intune to Azure AD, then find an Autopilot device that corresponds to the same Azure AD device.  (I hope I got that one right, it’s messy.)

Here’s an example report from my environment:


So I have a few items that I should address:

  • There are two Autopilot devices that don’t have profiles assigned.
  • There are four Autopilot devices that don’t have associated Azure AD objects, which could cause issues.
  • There are some Autopilot devices that don’t have associated Intune devices – some of which reference an Intune object that doesn’t exist, either because it has been deleted or automatically cleaned up.  (This is more of a hygiene item.)
  • There are a number of Autopilot devices that don’t have a Domain Join profile targeted to them because I have targeted “All Autopilot Devices” (a dynamic group) which won’t work for Hybrid Azure AD devices that have already been deployed (Intune switched from the Azure AD device object to the Hybrid AADJ device object).

Try it out and let me know if it works in your environment.  (I’m concerned what will happen with larger sets of devices, due to Graph API and RAM limitations  – the only efficient way to check this stuff is by pulling all of the objects into PowerShell.)  Also, if you can think of any other useful information that should be checked, I’m open to suggestions.

Categories: Windows Autopilot

5 replies »

  1. Great resource Mike.

    Think you can pull the device name into the output?.. SN is a bit hard to identify with in larger deployments.

    If the fix is to reimage a device, it would be great to know the hostname.


    • I submitted version 1.1 to the PowerShell Gallery with this change for the last table (displaying two different names, for the AAD device and the Intune device – they don’t always match).


  2. I noticed that all our Hybrid AADJ devices were returning with no domain join profile assigned – which definitely isn’t true. Checking the script, it’s just because the Get-IntuneManagedDevice cmdlet returns a max 1000 objects. The following update fixes it:

    $intuneDevices = Get-IntuneManagedDevice | Get-MSGraphAllPages


  3. Hello Michael,
    I try your script, but get an error:
    PS C:\> AutopilotHealthCheck.ps1
    Response content:
    “error”: {
    “code”: “InvalidAuthenticationToken”,
    “message”: “Access token is empty.”,
    “innerError”: {
    “request-id”: “xxxxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxx”,
    “date”: “2019-11-16T23:14:22”
    Get-AutopilotDevice : Request to failed with HTTP Status Unauthorized Unauthorized
    In C:\Program Files\WindowsPowerShell\Scripts\AutopilotHealthCheck.ps1:53 Zeichen:21
    + $autopilotDevices = Get-AutopilotDevice | Get-MSGraphAllPages
    + ~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Get-AutoPilotDevice
    Try it with 2 different tenant admins. The login screen appears 2 times.
    Thanks for help.