Src/Private/Get-AbrIntuneEnrollmentRestrictions.ps1
|
# Helper: map MDM/WIP policy appliesTo field to human-readable scope string # The scope field is 'appliesTo' on policies/ but 'appliesToGroups'+'isDefaultPolicy' on mobilityManagementPolicies function Get-MdmScopeString ($policy) { if (-not $policy) { return 'None' } if ($policy.PSObject.Properties['appliesTo']) { $val = $policy.appliesTo if ($val -eq 'all') { return 'All' } if ($val -eq 'selected') { return 'Selected' } if ($val -eq 'none') { return 'None' } if ($val) { return $val } return 'None' } if ($policy.PSObject.Properties['appliesToGroups']) { if ($policy.appliesToGroups -and @($policy.appliesToGroups).Count -gt 0) { return 'Selected' } if ($policy.isDefaultPolicy -eq $true) { return 'All' } } return 'None' } function Get-AbrIntuneEnrollmentRestrictions { <# .SYNOPSIS Documents Intune Device Enrollment Restrictions and configuration. .DESCRIPTION Collects and reports on: - Enrollment Restrictions (device type and limit) - Device Enrollment (Windows Automatic MDM / WIP) - Deployment Profiles (Windows Autopilot) - Autopilot Device Preparation V2 - Enrollment Status Pages (ESP) .NOTES Version: 0.1.0 Author: Pai Wei Sing #> [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory)] [string]$TenantId ) begin { Write-PScriboMessage -Message "Collecting Intune Enrollment Restrictions for $TenantId." Show-AbrDebugExecutionTime -Start -TitleMessage 'Enrollment Restrictions' } process { Section -Style Heading2 'Enrollment Restrictions' { Paragraph "The following section documents Device Enrollment configuration for tenant $TenantId." BlankLine $TotalEnrollmentRestrictions = 0 $TotalAutopilotProfiles = 0 $TotalESPProfiles = 0 #region Device Type Restrictions try { Write-Host " - Retrieving device type restrictions..." $TypeRestResp = Invoke-MgGraphRequest -Method GET ` -Uri "$($script:GraphEndpoint)/v1.0/deviceManagement/deviceEnrollmentConfigurations?`$expand=assignments" ` -ErrorAction SilentlyContinue $AllRestrictions = $TypeRestResp.value $null = ($TotalEnrollmentRestrictions = @($AllRestrictions).Count) if ($AllRestrictions -and @($AllRestrictions).Count -gt 0) { # Device Type Restrictions $TypeRestrictions = $AllRestrictions | Where-Object { $_.'@odata.type' -like '*deviceEnrollmentPlatformRestrictionsConfiguration*' } if ($TypeRestrictions) { Section -Style Heading3 'Device Type Restrictions' { BlankLine foreach ($Restriction in ($TypeRestrictions | Sort-Object priority)) { $assignResolved = Resolve-IntuneAssignments -Assignments $Restriction.assignments $AssignedTo = if ($assignResolved.AssignmentSummary -ne 'Not assigned') { $assignResolved.AssignmentSummary } else { 'Default (All Users)' } $RestObj = [System.Collections.ArrayList]::new() $restInObj = [ordered] @{ 'Restriction Name' = $Restriction.displayName 'Priority' = $Restriction.priority 'Assignments' = $AssignedTo } # Platform-level settings $Platforms = @('androidRestriction', 'androidForWorkRestriction', 'iosRestriction', 'macOSRestriction', 'windowsRestriction', 'windowsMobileRestriction') foreach ($PlatKey in $Platforms) { if ($Restriction.$PlatKey) { $PlatLabel = $PlatKey -replace 'Restriction', '' -replace 'androidForWork', 'Android Work Profile' ` -replace 'android', 'Android' -replace 'ios', 'iOS' -replace 'macOS', 'macOS' ` -replace 'windows$', 'Windows' -replace 'windowsMobile', 'Windows Mobile' $PlatData = $Restriction.$PlatKey $restInObj["$PlatLabel - Platform Blocked"] = $PlatData.platformBlocked $restInObj["$PlatLabel - Personal Blocked"] = $PlatData.personalDeviceEnrollmentBlocked if ($PlatData.osMinimumVersion) { $restInObj["$PlatLabel - Min OS"] = $PlatData.osMinimumVersion } if ($PlatData.osMaximumVersion) { $restInObj["$PlatLabel - Max OS"] = $PlatData.osMaximumVersion } } } $RestObj.Add([pscustomobject](ConvertTo-HashToYN $restInObj)) | Out-Null $RestTableParams = @{ Name = "Type Restriction - $($Restriction.displayName)"; List = $true; ColumnWidths = 45, 55 } $RestObj | Table @RestTableParams BlankLine } } } # Device Limit Restrictions $LimitRestrictions = $AllRestrictions | Where-Object { $_.'@odata.type' -like '*deviceEnrollmentLimitConfiguration*' } if ($LimitRestrictions) { Section -Style Heading3 'Device Limit Restrictions' { BlankLine $LimObj = [System.Collections.ArrayList]::new() foreach ($Lim in ($LimitRestrictions | Sort-Object priority)) { $assignResolved = Resolve-IntuneAssignments -Assignments $Lim.assignments $AssignedTo = if ($assignResolved.AssignmentSummary -ne 'Not assigned') { $assignResolved.AssignmentSummary } else { 'Default (All Users)' } $limInObj = [ordered] @{ 'Restriction Name' = $Lim.displayName 'Priority' = $Lim.priority 'Device Limit' = $Lim.limit 'Assignments' = $AssignedTo } $LimObj.Add([pscustomobject]$limInObj) | Out-Null } $LimTableParams = @{ Name = "Device Limit Restrictions - $TenantId"; ColumnWidths = 35, 15, 20, 30 } if ($Report.ShowTableCaptions) { $LimTableParams['Caption'] = "- $($LimTableParams.Name)" } $LimObj | Table @LimTableParams } } if (Get-IntuneBackupSectionEnabled -SectionKey 'EnrollmentRestrictions') { $script:BackupData['EnrollmentRestrictions'] = $AllRestrictions } if (Get-IntuneExcelSheetEnabled -SheetKey 'EnrollmentRestrictions') { $AllRestrictionsExcel = $AllRestrictions | ForEach-Object { [pscustomobject]@{ 'Name' = $_.displayName 'Type' = $_.'@odata.type' -replace '#microsoft.graph.', '' 'Priority' = $_.priority } } $script:ExcelSheets['Enrollment Restrictions'] = $AllRestrictionsExcel } #region InfoLevel 2 -- per-restriction Heading4 detail if ($InfoLevel.EnrollmentRestrictions -ge 2) { $TypeRestrictions = $AllRestrictions | Where-Object { $_.'@odata.type' -like '*deviceEnrollmentPlatformRestrictions*' } | Sort-Object priority foreach ($Restriction in $TypeRestrictions) { $assignResolved = Resolve-IntuneAssignments -Assignments $Restriction.assignments Section -Style Heading4 $Restriction.displayName { BlankLine $ovObj = [System.Collections.ArrayList]::new() $ovObj.Add([pscustomobject]@{ Setting = 'Restriction Name'; Value = $Restriction.displayName }) | Out-Null $ovObj.Add([pscustomobject]@{ Setting = 'Priority'; Value = "$($Restriction.priority)" }) | Out-Null $ovObj.Add([pscustomobject]@{ Setting = 'Included Groups'; Value = $assignResolved.IncludedGroups }) | Out-Null $ovObj.Add([pscustomobject]@{ Setting = 'Excluded Groups'; Value = $assignResolved.ExcludedGroups }) | Out-Null $OvParams = @{ Name = "Overview - $($Restriction.displayName)"; ColumnWidths = 30, 70 } if ($Report.ShowTableCaptions) { $OvParams['Caption'] = "- $($OvParams.Name)" } $ovObj | Table @OvParams if ($Restriction.platformRestrictions) { BlankLine Paragraph 'Platform Settings:' BlankLine $platRows = [System.Collections.ArrayList]::new() $platMap = @{ 'windows' = 'Windows' 'windowsMobile' = 'Windows Mobile' 'ios' = 'iOS / iPadOS' 'android' = 'Android' 'androidForWork' = 'Android Enterprise' 'mac' = 'macOS' } foreach ($key in $platMap.Keys) { $platData = $Restriction.platformRestrictions.$key if ($platData) { $platRows.Add([pscustomobject]([ordered]@{ 'Platform' = $platMap[$key] 'Platform Blocked' = if ($platData.platformBlocked) { 'Yes' } else { 'No' } 'Personal Blocked' = if ($platData.personalDeviceEnrollmentBlocked) { 'Yes' } else { 'No' } 'Min OS' = if ($platData.osMinimumVersion) { $platData.osMinimumVersion } else { '--' } 'Max OS' = if ($platData.osMaximumVersion) { $platData.osMaximumVersion } else { '--' } })) | Out-Null } } if ($platRows.Count -gt 0) { $PlatParams = @{ Name = "Platform Restrictions - $($Restriction.displayName)"; ColumnWidths = 22, 18, 18, 21, 21 } if ($Report.ShowTableCaptions) { $PlatParams['Caption'] = "- $($PlatParams.Name)" } $platRows | Table @PlatParams } } } } } #endregion } else { Paragraph "No Enrollment Restrictions found in tenant $TenantId." } } catch { if (Test-AbrGraphForbidden -ErrorRecord $_) { Write-AbrPermissionError -Section 'Enrollment Restrictions' -RequiredRole 'Intune Service Administrator or Global Administrator' } else { Write-AbrSectionError -Section 'Enrollment Restrictions' -Message "$($_.Exception.Message)" } } #endregion #region Device Enrollment (Windows Automatic MDM Enrollment) try { Write-Host " - Retrieving Windows Automatic MDM Enrollment settings..." $MdmPolicy = $null $WipPolicy = $null try { $MdmMobResp = Invoke-MgGraphRequest -Method GET ` -Uri "$($script:GraphEndpoint)/beta/deviceManagement/mobilityManagementPolicies?`$filter=managedDeviceType ne 'unknown'" ` -ErrorAction Stop if ($MdmMobResp.value) { $MdmPolicy = $MdmMobResp.value | Where-Object { $_.displayName -like '*Intune*' -or $_.isDefaultPolicy -eq $true } | Select-Object -First 1 if (-not $MdmPolicy) { $MdmPolicy = $MdmMobResp.value | Select-Object -First 1 } } } catch { $MdmPoliciesResp = Invoke-MgGraphRequest -Method GET ` -Uri "$($script:GraphEndpoint)/beta/policies/mobileDeviceManagementPolicies" ` -ErrorAction SilentlyContinue $MdmPolicy = if ($MdmPoliciesResp.value) { $MdmPoliciesResp.value | Select-Object -First 1 } else { $null } } try { $WipMobResp = Invoke-MgGraphRequest -Method GET ` -Uri "$($script:GraphEndpoint)/beta/deviceManagement/mobilityManagementPolicies?`$filter=managedDeviceType eq 'unknown'" ` -ErrorAction Stop $WipPolicy = if ($WipMobResp.value) { $WipMobResp.value | Select-Object -First 1 } else { $null } } catch { $WipPoliciesResp = Invoke-MgGraphRequest -Method GET ` -Uri "$($script:GraphEndpoint)/beta/policies/mobileAppManagementPolicies" ` -ErrorAction SilentlyContinue $WipPolicy = if ($WipPoliciesResp.value) { $WipPoliciesResp.value | Select-Object -First 1 } else { $null } } $mdmScopeStr = Get-MdmScopeString $MdmPolicy $wipScopeStr = Get-MdmScopeString $WipPolicy Section -Style Heading2 'Device Enrollment' { Paragraph "The following table documents the Windows automatic MDM and WIP enrollment configuration for tenant $TenantId." BlankLine $AutoEnrollRows = [System.Collections.ArrayList]::new() $AutoEnrollRows.Add([pscustomobject]@{ Setting = 'MDM'; Value = '' }) | Out-Null $AutoEnrollRows.Add([pscustomobject]@{ Setting = 'MDM User Scope'; Value = $mdmScopeStr }) | Out-Null $AutoEnrollRows.Add([pscustomobject]@{ Setting = 'MDM Terms of Use URL'; Value = if ($MdmPolicy.termsOfUseUrl) { $MdmPolicy.termsOfUseUrl } else { 'https://portal.manage.microsoft.com/TermsofUse.aspx (Default)' } }) | Out-Null $AutoEnrollRows.Add([pscustomobject]@{ Setting = 'MDM Discovery URL'; Value = if ($MdmPolicy.discoveryUrl) { $MdmPolicy.discoveryUrl } else { 'https://enrollment.manage.microsoft.com/enrollmentserver/discovery.svc (Default)' } }) | Out-Null $AutoEnrollRows.Add([pscustomobject]@{ Setting = 'MDM Compliance URL'; Value = if ($MdmPolicy.complianceUrl) { $MdmPolicy.complianceUrl } else { 'https://portal.manage.microsoft.com/?portalAction=Compliance (Default)' } }) | Out-Null $disableMdm = if ($mdmScopeStr -eq 'None') { 'Yes' } else { 'No' } $AutoEnrollRows.Add([pscustomobject]@{ Setting = 'Disable MDM Enrollment When Adding Work or School Account'; Value = $disableMdm }) | Out-Null $AutoEnrollRows.Add([pscustomobject]@{ Setting = 'Windows Information Protection (WIP)'; Value = '' }) | Out-Null $AutoEnrollRows.Add([pscustomobject]@{ Setting = 'WIP User Scope'; Value = $wipScopeStr }) | Out-Null $AutoEnrollRows.Add([pscustomobject]@{ Setting = 'WIP Terms of Use URL'; Value = if ($WipPolicy.termsOfUseUrl) { $WipPolicy.termsOfUseUrl } else { 'Default' } }) | Out-Null $AutoEnrollRows.Add([pscustomobject]@{ Setting = 'WIP Discovery URL'; Value = if ($WipPolicy.discoveryUrl) { $WipPolicy.discoveryUrl } else { 'Default' } }) | Out-Null $AutoEnrollRows.Add([pscustomobject]@{ Setting = 'WIP Compliance URL'; Value = if ($WipPolicy.complianceUrl) { $WipPolicy.complianceUrl } else { 'Default' } }) | Out-Null $mdmWipHeaders = @('MDM', 'Windows Information Protection (WIP)') $null = ($AutoEnrollRows | Where-Object { $_.Setting -in $mdmWipHeaders } | Set-Style -Style TableDefaultHeading) $AutoEnrollParams = @{ Name = "Windows Automatic MDM Enrollment - $TenantId"; ColumnWidths = 50, 50 } if ($Report.ShowTableCaptions) { $AutoEnrollParams['Caption'] = "- $($AutoEnrollParams.Name)" } $AutoEnrollRows | Table @AutoEnrollParams } } catch { if (Test-AbrGraphForbidden -ErrorRecord $_) { Write-AbrPermissionError -Section 'Device Enrollment' -RequiredRole 'DeviceManagementServiceConfig.Read.All or Policy.Read.All' } else { Write-AbrSectionError -Section 'Device Enrollment' -Message "$($_.Exception.Message)" } } #endregion #region Windows Autopilot Deployment Profiles try { Write-Host " - Retrieving Windows Autopilot profiles..." # /beta required -- windowsAutopilotDeploymentProfiles is not supported in v1.0 $AutopilotResp = Invoke-MgGraphRequest -Method GET ` -Uri "$($script:GraphEndpoint)/beta/deviceManagement/windowsAutopilotDeploymentProfiles?`$expand=assignments" ` -ErrorAction SilentlyContinue $AutopilotProfiles = $AutopilotResp.value $TotalAutopilotProfiles = if ($AutopilotProfiles) { @($AutopilotProfiles).Count } else { 0 } if ($TotalAutopilotProfiles -gt 0) { Section -Style Heading2 'Deployment Profiles' { Paragraph "The following section documents the Windows Autopilot Deployment Profiles configured in tenant $TenantId." BlankLine # ── Summary table ────────────────────────────────────────────────── $APObj = [System.Collections.ArrayList]::new() foreach ($APProfile in ($AutopilotProfiles | Sort-Object displayName)) { $assignResolved = Resolve-IntuneAssignments -Assignments $APProfile.assignments -CheckMemberCount:$script:CheckEmptyGroups $AssignedTo = $assignResolved.AssignmentSummary # Determine Join Type from odata type and hybrid flag $JoinType = if ($APProfile.'@odata.type' -like '*hybrid*' -or $null -ne $APProfile.hybridAzureADJoinSkipConnectivityCheck) { 'Microsoft Entra Hybrid Joined' } else { 'Microsoft Entra Joined' } # Deployment mode: check explicit property first, fall back to @odata.type encoding # azureADWindowsAutopilotDeploymentProfile = User-Driven (Entra joined) # activeDirectoryWindowsAutopilotDeploymentProfile = User-Driven (Hybrid) # selfDeploying in either property = Self-Deploying $odataType = $APProfile.'@odata.type' $dmRaw = $APProfile.deploymentMode if ($dmRaw -eq 'userDriven' -or $dmRaw -eq 'user_driven') { $DeployMode = 'User-Driven' } elseif ($dmRaw -eq 'selfDeploying' -or $dmRaw -eq 'self_deploying') { $DeployMode = 'Self-Deploying' } elseif ($odataType -like '*selfDeploying*') { $DeployMode = 'Self-Deploying' } elseif ($odataType -like '*azureAD*' -or $odataType -like '*activeDirectory*') { $DeployMode = 'User-Driven' } elseif ($dmRaw) { $DeployMode = $dmRaw } else { $DeployMode = 'User-Driven' } # User account type — Graph returns 'outOfBoxExperienceSettings' (plural) for # azureADWindowsAutopilotDeploymentProfile and 'outOfBoxExperienceSetting' (singular) for hybrid $oobeObj = if ($APProfile.outOfBoxExperienceSettings) { $APProfile.outOfBoxExperienceSettings } else { $APProfile.outOfBoxExperienceSetting } $utVal = if ($oobeObj) { $oobeObj.userType } else { $null } if ($utVal -eq 'administrator') { $SumUserType = 'Administrator' } elseif ($utVal -eq 'standard') { $SumUserType = 'Standard' } elseif ($utVal) { $SumUserType = $utVal } else { $SumUserType = '--' } $apInObj = [ordered] @{ 'Profile Name' = $APProfile.displayName 'Deployment Mode' = $DeployMode 'Join Type' = $JoinType 'User Account Type' = $SumUserType 'Device Name Template'= if ($APProfile.deviceNameTemplate) { $APProfile.deviceNameTemplate } else { 'Not configured' } 'Assignments' = $AssignedTo 'Last Modified' = if ($APProfile.lastModifiedDateTime) { ([datetime]$APProfile.lastModifiedDateTime).ToString('yyyy-MM-dd') } else { '--' } } $APObj.Add([pscustomobject]$apInObj) | Out-Null } $null = (& { if ($HealthCheck.Intune.EnrollmentRestrictions) { $null = ($APObj | Where-Object { $_.'Assignments' -eq 'Not assigned' } | Set-Style -Style Warning | Out-Null) } }) $APTableParams = @{ Name = "Autopilot Deployment Profiles - $TenantId"; ColumnWidths = 24, 14, 20, 12, 16, 7, 7 } if ($Report.ShowTableCaptions) { $APTableParams['Caption'] = "- $($APTableParams.Name)" } $APObj | Table @APTableParams if (Get-IntuneExcelSheetEnabled -SheetKey 'AutopilotProfiles') { $script:ExcelSheets['Autopilot Profiles'] = $APObj } if (Get-IntuneBackupSectionEnabled -SectionKey 'AutopilotProfiles') { $script:BackupData['AutopilotProfiles'] = $AutopilotProfiles } # ── Per-profile detail sections (all InfoLevel) ──────────────────── foreach ($APProfile in ($AutopilotProfiles | Sort-Object displayName)) { $assignResolved = Resolve-IntuneAssignments -Assignments $APProfile.assignments -CheckMemberCount:$script:CheckEmptyGroups # Derive values $JoinType = if ($APProfile.'@odata.type' -like '*hybrid*' -or $null -ne $APProfile.hybridAzureADJoinSkipConnectivityCheck) { 'Microsoft Entra Hybrid Joined' } else { 'Microsoft Entra Joined' } $DeployMode = $null $odataType2 = $APProfile.'@odata.type' $dmRaw2 = $APProfile.deploymentMode if ($dmRaw2 -eq 'userDriven' -or $dmRaw2 -eq 'user_driven') { $DeployMode = 'User-Driven' } elseif ($dmRaw2 -eq 'selfDeploying' -or $dmRaw2 -eq 'self_deploying') { $DeployMode = 'Self-Deploying' } elseif ($odataType2 -like '*selfDeploying*') { $DeployMode = 'Self-Deploying' } elseif ($odataType2 -like '*azureAD*' -or $odataType2 -like '*activeDirectory*') { $DeployMode = 'User-Driven' } elseif ($dmRaw2) { $DeployMode = $dmRaw2 } else { $DeployMode = 'User-Driven' } # Graph returns 'outOfBoxExperienceSettings' (plural) for Entra joined profiles # and 'outOfBoxExperienceSetting' (singular) for hybrid profiles $OOBE = if ($APProfile.outOfBoxExperienceSettings) { $APProfile.outOfBoxExperienceSettings } else { $APProfile.outOfBoxExperienceSetting } $UserAccountType = $null $utVal2 = if ($OOBE) { $OOBE.userType } else { $null } if ($utVal2 -eq 'administrator') { $UserAccountType = 'Administrator' } elseif ($utVal2 -eq 'standard') { $UserAccountType = 'Standard' } elseif ($utVal2) { $UserAccountType = $utVal2 } else { $UserAccountType = '--' } $HideShow = { param($boolVal) if ($boolVal) { 'Hide' } else { 'Show' } } Section -Style Heading4 $APProfile.displayName { BlankLine # ── Overview table ── $APDetailObj = [System.Collections.ArrayList]::new() $APDetailObj.Add([pscustomobject]@{ Setting = 'Profile Name'; Value = $APProfile.displayName }) | Out-Null $APDetailObj.Add([pscustomobject]@{ Setting = 'Description'; Value = if ($APProfile.description) { $APProfile.description } else { '--' } }) | Out-Null $APDetailObj.Add([pscustomobject]@{ Setting = 'Assigned'; Value = if ($assignResolved.AssignmentSummary -ne 'Not assigned') { 'Yes' } else { 'No' } }) | Out-Null $APDetailObj.Add([pscustomobject]@{ Setting = 'Assignments'; Value = $assignResolved.AssignmentSummary }) | Out-Null $APDetailObj.Add([pscustomobject]@{ Setting = 'Created'; Value = if ($APProfile.createdDateTime) { ([datetime]$APProfile.createdDateTime).ToString('yyyy-MM-dd') } else { '--' } }) | Out-Null $APDetailObj.Add([pscustomobject]@{ Setting = 'Last Modified'; Value = if ($APProfile.lastModifiedDateTime) { ([datetime]$APProfile.lastModifiedDateTime).ToString('yyyy-MM-dd') } else { '--' } }) | Out-Null $APDetailObj.Add([pscustomobject]@{ Setting = 'Deployment Mode'; Value = $DeployMode }) | Out-Null $APDetailObj.Add([pscustomobject]@{ Setting = 'Join to Microsoft Entra ID as'; Value = $JoinType }) | Out-Null # Hybrid-only: skip AD connectivity check if ($null -ne $APProfile.hybridAzureADJoinSkipConnectivityCheck) { $APDetailObj.Add([pscustomobject]@{ Setting = 'Skip AD Connectivity Check'; Value = if ($APProfile.hybridAzureADJoinSkipConnectivityCheck) { 'Yes' } else { 'No' } }) | Out-Null } # Convert all targeted devices to Autopilot if ($null -ne $APProfile.extractHardwareKey) { # extractHardwareKey = $true means "convert all targeted devices to Autopilot" $APDetailObj.Add([pscustomobject]@{ Setting = 'Convert All Targeted Devices to Autopilot'; Value = if ($APProfile.extractHardwareKey) { 'Yes' } else { 'No' } }) | Out-Null } # OOBE settings if ($OOBE) { $APDetailObj.Add([pscustomobject]@{ Setting = 'Microsoft Software License Terms'; Value = (& $HideShow ($OOBE.eulaHidden)) }) | Out-Null $APDetailObj.Add([pscustomobject]@{ Setting = 'Privacy Settings'; Value = (& $HideShow ($OOBE.privacySettingsHidden)) }) | Out-Null $APDetailObj.Add([pscustomobject]@{ Setting = 'Hide Change Account Options'; Value = (& $HideShow ($OOBE.escapeLinkHidden)) }) | Out-Null $APDetailObj.Add([pscustomobject]@{ Setting = 'User Account Type'; Value = $UserAccountType }) | Out-Null } # Allow pre-provisioned deployment (White Glove) if ($null -ne $APProfile.enableWhiteGlove) { $APDetailObj.Add([pscustomobject]@{ Setting = 'Allow Pre-Provisioned Deployment'; Value = if ($APProfile.enableWhiteGlove) { 'Yes' } else { 'No' } }) | Out-Null } # Language / keyboard $APDetailObj.Add([pscustomobject]@{ Setting = 'Language (Region)'; Value = if ($APProfile.language) { $APProfile.language } else { 'Operating System Default' } }) | Out-Null if ($null -ne $APProfile.keyboardSelectionPageSkipped) { $APDetailObj.Add([pscustomobject]@{ Setting = 'Automatically Configure Keyboard'; Value = if ($APProfile.keyboardSelectionPageSkipped) { 'Yes' } else { 'No' } }) | Out-Null } # Device name template $APDetailObj.Add([pscustomobject]@{ Setting = 'Apply Device Name Template'; Value = if ($APProfile.deviceNameTemplate) { $APProfile.deviceNameTemplate } else { 'Not configured' } }) | Out-Null $APDetailTableParams = @{ Name = "Profile Overview - $($APProfile.displayName)"; ColumnWidths = 45, 55 } if ($Report.ShowTableCaptions) { $APDetailTableParams['Caption'] = "- $($APDetailTableParams.Name)" } $APDetailObj | Table @APDetailTableParams } } } } } catch { if (Test-AbrGraphForbidden -ErrorRecord $_) { Write-AbrPermissionError -Section 'Autopilot Deployment Profiles' -RequiredRole 'Intune Service Administrator or Global Administrator' } else { Write-AbrSectionError -Section 'Autopilot Deployment Profiles' -Message "$($_.Exception.Message)" } } #endregion #region Windows Autopilot Device Preparation (V2) try { Write-Host " - Retrieving Windows Autopilot Device Preparation (V2) profiles..." $APDPV2Profiles = @() try { $APDPV2Resp = Invoke-MgGraphRequest -Method GET ` -Uri "$($script:GraphEndpoint)/beta/deviceManagement/windowsAutopilotDevicePreparationPolicies?`$expand=assignments" ` -ErrorAction Stop $APDPV2Profiles = if ($APDPV2Resp.value) { $APDPV2Resp.value } else { @() } } catch { # BadRequest/404 = feature not provisioned on this tenant — skip silently Write-AbrDebugLog "Autopilot V2 not available on this tenant: $($_.Exception.Message)" 'INFO' 'AutopilotV2' } if (@($APDPV2Profiles).Count -gt 0) { Section -Style Heading2 'Autopilot Device Preparation (V2)' { Paragraph "Windows Autopilot Device Preparation (V2) is the next-generation Autopilot enrollment flow using Entra ID Enrollment Time Grouping. The following documents V2 profiles configured in tenant $TenantId." BlankLine # Summary table $V2SumObj = [System.Collections.ArrayList]::new() foreach ($V2Prof in ($APDPV2Profiles | Sort-Object displayName)) { $assignResolved = Resolve-IntuneAssignments -Assignments $V2Prof.assignments -CheckMemberCount:$script:CheckEmptyGroups $V2SumObj.Add([pscustomobject]([ordered]@{ 'Profile Name' = $V2Prof.displayName 'Account Type' = if ($V2Prof.accountType) { switch ($V2Prof.accountType) { 'administrator' { 'Administrator' } 'standard' { 'Standard User' } default { $V2Prof.accountType } } } else { '--' } 'Assignments' = $assignResolved.AssignmentSummary 'Last Modified' = if ($V2Prof.lastModifiedDateTime) { ([datetime]$V2Prof.lastModifiedDateTime).ToString('yyyy-MM-dd') } else { '--' } })) | Out-Null } $null = (& { if ($HealthCheck.Intune.EnrollmentRestrictions) { $null = ($V2SumObj | Where-Object { $_.'Assignments' -eq 'Not assigned' } | Set-Style -Style Warning | Out-Null) } }) $V2TableParams = @{ Name = "Autopilot Device Preparation V2 Profiles - $TenantId"; ColumnWidths = 30, 20, 35, 15 } if ($Report.ShowTableCaptions) { $V2TableParams['Caption'] = "- $($V2TableParams.Name)" } $V2SumObj | Table @V2TableParams # Per-profile detail foreach ($V2Prof in ($APDPV2Profiles | Sort-Object displayName)) { $assignResolved = Resolve-IntuneAssignments -Assignments $V2Prof.assignments -CheckMemberCount:$script:CheckEmptyGroups Section -Style Heading4 $V2Prof.displayName { BlankLine $V2DetailObj = [System.Collections.ArrayList]::new() $V2DetailObj.Add([pscustomobject]@{ Setting = 'Profile Name'; Value = $V2Prof.displayName }) | Out-Null $V2DetailObj.Add([pscustomobject]@{ Setting = 'Description'; Value = if ($V2Prof.description) { $V2Prof.description } else { '--' } }) | Out-Null $V2DetailObj.Add([pscustomobject]@{ Setting = 'Assignments'; Value = $assignResolved.AssignmentSummary }) | Out-Null $V2DetailObj.Add([pscustomobject]@{ Setting = 'Created'; Value = if ($V2Prof.createdDateTime) { ([datetime]$V2Prof.createdDateTime).ToString('yyyy-MM-dd') } else { '--' } }) | Out-Null $V2DetailObj.Add([pscustomobject]@{ Setting = 'Last Modified'; Value = if ($V2Prof.lastModifiedDateTime) { ([datetime]$V2Prof.lastModifiedDateTime).ToString('yyyy-MM-dd') } else { '--' } }) | Out-Null if ($V2Prof.accountType) { $acctType = switch ($V2Prof.accountType) { 'administrator' { 'Administrator' } 'standard' { 'Standard User' } default { $V2Prof.accountType } } $V2DetailObj.Add([pscustomobject]@{ Setting = 'User Account Type'; Value = $acctType }) | Out-Null } if ($null -ne $V2Prof.deviceSecurityGroupId) { $grpName = Resolve-IntuneGroupName -GroupId $V2Prof.deviceSecurityGroupId $V2DetailObj.Add([pscustomobject]@{ Setting = 'Enrollment Time Device Group'; Value = if ($grpName) { $grpName } else { $V2Prof.deviceSecurityGroupId } }) | Out-Null } if ($null -ne $V2Prof.managedDeviceGroupId) { $grpName = Resolve-IntuneGroupName -GroupId $V2Prof.managedDeviceGroupId $V2DetailObj.Add([pscustomobject]@{ Setting = 'Device Security Group'; Value = if ($grpName) { $grpName } else { $V2Prof.managedDeviceGroupId } }) | Out-Null } if ($null -ne $V2Prof.allowedDeviceTypes) { $V2DetailObj.Add([pscustomobject]@{ Setting = 'Allowed Device Types'; Value = ($V2Prof.allowedDeviceTypes -join ', ') }) | Out-Null } if ($null -ne $V2Prof.deploymentTimeout) { $V2DetailObj.Add([pscustomobject]@{ Setting = 'Deployment Timeout (mins)'; Value = "$($V2Prof.deploymentTimeout)" }) | Out-Null } $V2DetailParams = @{ Name = "V2 Profile - $($V2Prof.displayName)"; ColumnWidths = 45, 55 } if ($Report.ShowTableCaptions) { $V2DetailParams['Caption'] = "- $($V2DetailParams.Name)" } $V2DetailObj | Table @V2DetailParams } } } } } catch { if (Test-AbrGraphForbidden -ErrorRecord $_) { Write-AbrPermissionError -Section 'Autopilot Device Preparation V2' -RequiredRole 'DeviceManagementServiceConfig.Read.All' } else { Write-AbrSectionError -Section 'Autopilot Device Preparation V2' -Message "$($_.Exception.Message)" } } #endregion #region Enrollment Status Pages try { $ESPProfiles = if ($AllRestrictions) { @($AllRestrictions | Where-Object { $_.'@odata.type' -like '*windows10EnrollmentCompletionPageConfiguration*' }) } else { @() } if ($ESPProfiles.Count -gt 0) { Section -Style Heading2 'Enrollment Status Pages' { Paragraph "The Enrollment Status Page (ESP) displays the provisioning progress to end users during device setup. The following documents ESP profiles configured in tenant $TenantId." BlankLine $EspObj = [System.Collections.ArrayList]::new() foreach ($ESP in ($ESPProfiles | Sort-Object priority)) { $assignResolved = Resolve-IntuneAssignments -Assignments $ESP.assignments $AssignedTo = if ($assignResolved.AssignmentSummary -ne 'Not assigned') { $assignResolved.AssignmentSummary } else { 'Default (All Devices)' } $BoolLabel = { param($v) if ($null -eq $v) { 'Not Configured' } elseif ($v) { 'Yes' } else { 'No' } } $espInObj = [ordered] @{ 'ESP Profile Name' = $ESP.displayName 'Priority' = $ESP.priority 'Show Progress to End User' = (& $BoolLabel $ESP.showInstallationProgress) 'Block Device Until Provisioning' = (& $BoolLabel $ESP.blockDeviceSetupRetryByUser) 'Allow Reset if Installation Fails' = (& $BoolLabel $ESP.allowDeviceResetOnInstallFailure) 'Allow Use of Device Before Profile' = (& $BoolLabel $ESP.allowDeviceUseOnInstallFailure) 'Tracking Error Timeout (minutes)' = if ($ESP.installProgressTimeoutInMinutes) { $ESP.installProgressTimeoutInMinutes } else { 'Default (60)' } 'Assignments' = $AssignedTo } $EspObj.Add([pscustomobject]$espInObj) | Out-Null } $EspTableParams = @{ Name = "Enrollment Status Page Profiles - $TenantId"; List = $true; ColumnWidths = 50, 50 } if ($Report.ShowTableCaptions) { $EspTableParams['Caption'] = "- $($EspTableParams.Name)" } $EspObj | Table @EspTableParams } } } catch { if (Test-AbrGraphForbidden -ErrorRecord $_) { Write-AbrPermissionError -Section 'Enrollment Status Pages' -RequiredRole 'Intune Service Administrator or Global Administrator' } else { Write-AbrSectionError -Section 'Enrollment Status Pages' -Message "$($_.Exception.Message)" } } #endregion #region ACSC E8 Assessment if ($script:IncludeACSCe8) { BlankLine Paragraph "ACSC Essential Eight Maturity Level Assessment -- Enrollment Restrictions:" BlankLine try { $_v = @{ TotalEnrollmentRestrictions = $TotalEnrollmentRestrictions TotalAutopilotProfiles = $TotalAutopilotProfiles TotalESPProfiles = $TotalESPProfiles } $E8Checks = Build-AbrIntuneComplianceChecks -Definitions (Get-AbrIntuneE8Checks -Section 'EnrollmentRestrictions') -Framework E8 -CallerVariables $_v New-AbrIntuneE8AssessmentTable -Checks $E8Checks -Name 'Enrollment Restrictions' -TenantId $TenantId if ($E8Checks) { $null = $script:E8AllChecks.AddRange([object[]](@($E8Checks | Select-Object @{N='Section';E={'EnrollmentRestrictions'}}, ML, Control, Status, Detail))) } } catch { Write-AbrSectionError -Section 'E8 Enrollment Assessment' -Message "$($_.Exception.Message)" } } #endregion #region CIS Assessment if ($script:IncludeCISBaseline) { BlankLine Paragraph "CIS Microsoft 365 Foundations Benchmark Assessment -- Enrollment Restrictions:" BlankLine try { $_v = @{ TotalEnrollmentRestrictions = $TotalEnrollmentRestrictions TotalESPProfiles = $TotalESPProfiles } $CISChecks = Build-AbrIntuneComplianceChecks -Definitions (Get-AbrIntuneCISChecks -Section 'EnrollmentRestrictions') -Framework CIS -CallerVariables $_v New-AbrIntuneCISAssessmentTable -Checks $CISChecks -Name 'Enrollment Restrictions' -TenantId $TenantId if ($CISChecks) { $null = $script:CISAllChecks.AddRange([object[]](@($CISChecks | Select-Object @{N='Section';E={'EnrollmentRestrictions'}}, CISControl, Level, Status, Detail))) } } catch { Write-AbrSectionError -Section 'CIS Enrollment Assessment' -Message "$($_.Exception.Message)" } } #endregion } } end { Show-AbrDebugExecutionTime -End -TitleMessage 'Enrollment Restrictions' } } |