AutopilotHealthCheck.ps1

<#PSScriptInfo
 
.VERSION 1.0
 
.GUID 3101c38e-4843-4582-b85b-a2e8cf565220
 
.AUTHOR Michael Niehaus
 
.COMPANYNAME Microsoft
 
.COPYRIGHT
 
.TAGS Windows AutoPilot
 
.LICENSEURI
 
.PROJECTURI
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
Version 1.0: Original published version.
 
#>


<#
.SYNOPSIS
Checks all devices registered with Windows Autopilot for common issues.
.DESCRIPTION
This script uses the Graph API to check for a variety of common issues with devices that are registered with Windows Autopilot. It leverages
the WindowsAutopilotIntune, Microsoft.Graph.Intune, and AzureAD modules which should be installed (using "Install-Module") before running this script.
It will be necessary to sign in twice, once to MSGraph (for access to Intune and Autopilot objects) and once to Azure AD (for additional Azure AD objects).
This script does not change anything, it only reads info from the Graph and displays a simple report based on what it finds.
 
Due to the amount of data this will retrieve, it is possible this won't work for large tenants due to Graph API throttling.
.EXAMPLE
.\AutopilotHealthCheck.ps1
 
#>


Import-Module WindowsAutopilotIntune -Scope Global
Import-Module AzureAD -Scope Global
$intuneId = Connect-MSGraph
$aadId = Connect-AzureAD

# Data gathering
$autopilotDevices = Get-AutopilotDevice
$autopilotProfiles = Get-AutopilotProfile
$aadDevices = Get-AzureADDevice -All $true
$intuneDevices = Get-IntuneManagedDevice
$intuneDJProfiles = (Invoke-MSGraphRequest -Url 'https://graph.microsoft.com/beta/deviceManagement/deviceConfigurations').Value | ? {$_.'@odata.type' -eq '#microsoft.graph.windowsDomainJoinConfiguration'}

# STEP 1: Report on overall status
Write-Host " "
Write-Host "Overall Windows Autopilot device registration status:" -ForeGroundColor Yellow
Write-Host " "
$autopilotDevices | Group-Object deploymentProfileAssignmentStatus | % {
    Write-Host "$($_.Name) : $($_.Count)"
}
Write-Host " "
Write-Host "List of Autopilot devices with Autopilot profile assignment issues:"
Write-Host " "
$autopilotDevices | ? {-not ($_.deploymentProfileAssignmentStatus -eq 'assignedUnkownSyncState')} | Select serialNumber, deploymentProfileAssignmentStatus | Out-Host

# STEP 2: Check device links
$emptyGuid = "00000000-0000-0000-0000-000000000000"
$autopilotDevices | % {
    $a = $_

    # See if the AAD device can be found
    $found = $aadDevices | ? {$_.DeviceId -eq $a.azureActiveDirectoryDeviceId}
    if ($found) {
        $a | Add-Member -NotePropertyName AADStatus -NotePropertyValue Found
    }
    else
    {
        $a | Add-Member -NotePropertyName AADStatus -NotePropertyValue NotFound
    }

    # See if the Intune device can be found
    if ($a.managedDeviceId -eq $emptyGuid) {
            $a | Add-Member -NotePropertyName IntuneStatus -NotePropertyValue NeverEnrolled
    }
    else
    {
        $found = $intuneDevices | ? {$_.id -eq $a.managedDeviceId}
        if ($found) {
            $a | Add-Member -NotePropertyName IntuneStatus -NotePropertyValue Found
        }
        else
        {
            $a | Add-Member -NotePropertyName IntuneStatus -NotePropertyValue NotFound
        }
    }
}

Write-Host " "
Write-Host "Azure AD device object status:" -ForeGroundColor Yellow
Write-Host " "
$autopilotDevices | Group-Object AADStatus | % {
    Write-Host "$($_.Name) : $($_.Count)"
}
Write-Host " "
Write-Host "List of Autopilot devices with no corresponding Azure AD device object:"
Write-Host " "
$autopilotDevices | ? {$_.AADStatus -eq 'NotFound'} | Select serialNumber | Out-Host

Write-Host " "
Write-Host "Intune managed device object status:" -ForeGroundColor Yellow
Write-Host " "
$autopilotDevices | Group-Object IntuneStatus | % {
    Write-Host "$($_.Name) : $($_.Count)"
}

# STEP 3: Check profiles
$autopilotProfiles | % {
    $type = 'Unknown'
    $profileName = $_.displayName
    if ($_.'@odata.type' -eq '#microsoft.graph.azureADWindowsAutopilotDeploymentProfile')
    {
        if ($_.outOfBoxExperienceSettings.deviceUsageType -eq 'shared')
        {
            $type = 'SelfDeploying'
        }
        else
        {
            $type = 'UserDrivenAAD'
        }
    }
    elseif ($_.'@odata.type' -eq '#microsoft.graph.activeDirectoryWindowsAutopilotDeploymentProfile')
    {
            $type = 'UserDrivenAD'
    }
    $_ | Get-AutopilotProfileAssignedDevice | % {
        $assignedDevice = $_
        $autopilotDevices | ? {$_.id -eq $assignedDevice.id} | % {
            $_ | Add-Member -NotePropertyName ProfileType -NotePropertyValue $type
            $_ | Add-Member -NotePropertyName ProfileName -NotePropertyValue $profileName
        }
    }
}
Write-Host " "
Write-Host "Autopilot devices by profile type:" -ForeGroundColor Yellow
Write-Host " "
$autopilotDevices | ? {$_.ProfileType} | Group-Object ProfileType | % {
    Write-Host "$($_.Name) : $($_.Count)"
}

# STEP 4: Check if AD devices have a domain join profile
$autopilotDevices | % {
    $_ | Add-Member -NotePropertyName HasDJProfile -NotePropertyValue $false
}
$intuneDJProfiles | % {
    $dj = $_
    (Get-IntuneDeviceConfigurationPolicyAssignment -deviceConfigurationId $_.id).target | % {
        if ($_.'@odata.type' -eq '#microsoft.graph.allDevicesAssignmentTarget') {
            $autopilotDevices | % {
                $_.HasDJProfile = $true
            }
        }
        else
        {
            $devices = Invoke-MSGraphRequest -Url "https://graph.microsoft.com/beta/deviceManagement/deviceConfigurations/$($dj.id)/deviceStatuses"
            $devices.value | % {
                $managedDeviceId = $_.id.Substring(74)
                $intuneDevices | ? {$_.id -eq $managedDeviceId } | % {
                    $aadId = $_.azureADDeviceId
                    $autopilotDevices | ? {$_.azureActiveDirectoryDeviceId -eq $aadId} | % {
                        $_.HasDJProfile = $true
                    }
                }
            }
        }
    }
}
Write-Host " "
Write-Host "Autopilot Hybrid AADJ domain join profile check:" -ForeGroundColor Yellow
Write-Host " "
$result = $autopilotDevices | ? {$_.ProfileType -eq 'UserDrivenAD'} | Group-Object HasDJProfile
$result | % {
    Write-Host "$($_.Name) : $($_.Count)"
}

Write-Host " "
Write-Host "List of Autopilot Hybrid AADJ devices with no domain join profile:"
Write-Host " "
$result | ? {$_.Name -eq $false} | % { $_.Group } | Select serialNumber, azureActiveDirectoryDeviceId, managedDeviceId, enrollmentState | Out-Host