AutopilotHealthCheck.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
<#PSScriptInfo
 
.VERSION 1.1
 
.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 | Get-MSGraphAllPages
$autopilotProfiles = Get-AutopilotProfile
$aadDevices = Get-AzureADDevice -All $true
$intuneDevices = Get-IntuneManagedDevice -Filter "contains(operatingsystem, 'Windows')" | Get-MSGraphAllPages
$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
        $a | Add-Member -NotePropertyName AADDeviceName -NotePropertyValue $found.DisplayName
    }
    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
            $a | Add-Member -NotePropertyName IntuneDeviceName -NotePropertyValue $found.deviceName
        }
        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, AADDeviceName, managedDeviceId, IntuneDeviceName, enrollmentState | Format-Table | Out-Host