WindowsAutoPilotIntune.psm1
#################################################### #region Initialization code #$m = Get-Module -Name Microsoft.Graph.Intune -ListAvailable #if (-not $m) #{ # Install-Module NuGet -Force # Install-Module Microsoft.Graph.Intune #} #Import-Module Microsoft.Graph.Intune -Global #endregion #################################################### #region Core methods Function Get-AutoPilotDevice(){ <# .SYNOPSIS Gets devices currently registered with Windows Autopilot. .DESCRIPTION The Get-AutoPilotDevice cmdlet retrieves either the full list of devices registered with Windows Autopilot for the current Azure AD tenant, or a specific device if the ID of the device is specified. .PARAMETER id Optionally specifies the ID (GUID) for a specific Windows Autopilot device (which is typically returned after importing a new device) .PARAMETER serial Optionally specifies the serial number of the specific Windows Autopilot device to retrieve .PARAMETER expand Expand the properties of the device to include the Autopilot profile information .EXAMPLE Get a list of all devices registered with Windows Autopilot Get-AutoPilotDevice #> [cmdletbinding()] param ( [Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$True)] $id, [Parameter(Mandatory=$false)] $serial, [Parameter(Mandatory=$false)] [Switch]$expand = $false ) Process { # Defining Variables $graphApiVersion = "beta" $Resource = "deviceManagement/windowsAutopilotDeviceIdentities" if ($id -and $expand) { $uri = "https://graph.microsoft.com/$graphApiVersion/$($Resource)/$($id)?`$expand=deploymentProfile,intendedDeploymentProfile" } elseif ($id) { $uri = "https://graph.microsoft.com/$graphApiVersion/$($Resource)/$id" } elseif ($serial) { $uri = "https://graph.microsoft.com/$graphApiVersion/$($Resource)?`$filter=contains(serialNumber,'$serial')" } else { $uri = "https://graph.microsoft.com/$graphApiVersion/$($Resource)" } try { $response = Invoke-MSGraphRequest -Url $uri -HttpMethod Get if ($id) { $response } else { $devices = $response.value $devicesNextLink = $response."@odata.nextLink" while ($devicesNextLink -ne $null){ $devicesResponse = (Invoke-MSGraphRequest -Url $devicesNextLink -HttpMethod Get) $devicesNextLink = $devicesResponse."@odata.nextLink" $devices += $devicesResponse.value } if ($expand) { $devices | Get-AutopilotDevice -Expand } else { $devices } } } catch { Write-Error $_.Exception break } } } Function Set-AutoPilotDevice(){ <# .SYNOPSIS Updates settings on an Autopilot device. .DESCRIPTION The Set-AutoPilotDevice cmdlet can be used to change the updatable properties on a Windows Autopilot device object. .PARAMETER id The Windows Autopilot device id (mandatory). .PARAMETER userPrincipalName The user principal name. .PARAMETER addressibleUserName The name to display during Windows Autopilot enrollment. If specified, the userPrincipalName must also be specified. .PARAMETER displayName The name (computer name) to be assigned to the device when it is deployed via Windows Autopilot. This is presently only supported with Azure AD Join scenarios. Note that names should not exceed 15 characters. After setting the name, you need to initiate a sync (Invoke-AutopilotSync) in order to see the name in the Intune object. .PARAMETER groupTag The group tag value to set for the device. .EXAMPLE Assign a user and a name to display during enrollment to a Windows Autopilot device. Set-AutoPilotDevice -id $id -userPrincipalName $userPrincipalName -addressableUserName "John Doe" -displayName "CONTOSO-0001" -groupTag "Testing" #> [cmdletbinding()] param ( [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$True)] $id, [Parameter(ParameterSetName = "Prop")] $userPrincipalName = $null, [Parameter(ParameterSetName = "Prop")] $addressableUserName = $null, [Parameter(ParameterSetName = "Prop")][Alias("ComputerName","CN","MachineName")] $displayName = $null, [Parameter(ParameterSetName = "Prop")] $groupTag = $null ) Process { # Defining Variables $graphApiVersion = "beta" $Resource = "deviceManagement/windowsAutopilotDeviceIdentities" $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource/$id/UpdateDeviceProperties" $json = "{" if ($userPrincipalName) { $json = $json + " userPrincipalName: `"$userPrincipalName`"," } if ($addressableUserName) { $json = $json + " addressableUserName: `"$addressableUserName`"," } if ($displayName) { $json = $json + " displayName: `"$displayName`"," } if ($groupTag) { $json = $json + " groupTag: `"$groupTag`"" } else { $json = $json.Trim(",") } $json = $json + " }" try { Invoke-MSGraphRequest -Url $uri -HttpMethod POST -Content $json } catch { Write-Error $_.Exception break } } } Function Remove-AutoPilotDevice(){ <# .SYNOPSIS Removes a specific device currently registered with Windows Autopilot. .DESCRIPTION The Remove-AutoPilotDevice cmdlet removes the specified device, identified by its ID, from the list of devices registered with Windows Autopilot for the current Azure AD tenant. .PARAMETER id Specifies the ID (GUID) for a specific Windows Autopilot device .EXAMPLE Remove all Windows Autopilot devices from the current Azure AD tenant Get-AutoPilotDevice | Remove-AutoPilotDevice #> [cmdletbinding()] param ( [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$True)] $id ) Process { # Defining Variables $graphApiVersion = "beta" $Resource = "deviceManagement/windowsAutopilotDeviceIdentities" $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource/$id" try { Write-Verbose "Removing device $id" Invoke-MSGraphRequest -Url $uri -HttpMethod DELETE } catch { Write-Error $_.Exception break } } } Function Get-AutoPilotImportedDevice(){ <# .SYNOPSIS Gets information about devices being imported into Windows Autopilot. .DESCRIPTION The Get-AutoPilotImportedDevice cmdlet retrieves either the full list of devices being imported into Windows Autopilot for the current Azure AD tenant, or information for a specific device if the ID of the device is specified. Once the import is complete, the information instance is expected to be deleted. .PARAMETER id Optionally specifies the ID (GUID) for a specific Windows Autopilot device being imported. .EXAMPLE Get a list of all devices being imported into Windows Autopilot for the current Azure AD tenant. Get-AutoPilotImportedDevice #> [cmdletbinding()] param ( [Parameter(Mandatory=$false)] $id ) # Defining Variables $graphApiVersion = "beta" $Resource = "deviceManagement/importedWindowsAutopilotDeviceIdentities" if ($id) { $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource/$id" } else { $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource" } try { $response = Invoke-MSGraphRequest -Url $uri -HttpMethod Get if ($id) { $response } else { $devices = $response.value $devicesNextLink = $response."@odata.nextLink" while ($devicesNextLink -ne $null){ $devicesResponse = (Invoke-MSGraphRequest -Url $devicesNextLink -HttpMethod Get) $devicesNextLink = $devicesResponse."@odata.nextLink" $devices += $devicesResponse.value } $devices } } catch { Write-Error $_.Exception break } } <# .SYNOPSIS Adds a new device to Windows Autopilot. .DESCRIPTION The Add-AutoPilotImportedDevice cmdlet adds the specified device to Windows Autopilot for the current Azure AD tenant. Note that a status object is returned when this cmdlet completes; the actual import process is performed as a background batch process by the Microsoft Intune service. .PARAMETER serialNumber The hardware serial number of the device being added (mandatory). .PARAMETER hardwareIdentifier The hardware hash (4K string) that uniquely identifies the device. .PARAMETER groupTag An optional identifier or tag that can be associated with this device, useful for grouping devices using Azure AD dynamic groups. .EXAMPLE Add a new device to Windows Autopilot for the current Azure AD tenant. Add-AutoPilotImportedDevice -serialNumber $serial -hardwareIdentifier $hash -groupTag "Kiosk" #> Function Add-AutoPilotImportedDevice(){ [cmdletbinding()] param ( [Parameter(Mandatory=$true)] $serialNumber, [Parameter(Mandatory=$true)] $hardwareIdentifier, [Parameter(Mandatory=$false)] [Alias("orderIdentifier")] $groupTag = "" ) # Defining Variables $graphApiVersion = "beta" $Resource = "deviceManagement/importedWindowsAutopilotDeviceIdentities" $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource" $json = @" { "@odata.type": "#microsoft.graph.importedWindowsAutopilotDeviceIdentity", "orderIdentifier": "$groupTag", "serialNumber": "$serialNumber", "productKey": "", "hardwareIdentifier": "$hardwareIdentifier", "state": { "@odata.type": "microsoft.graph.importedWindowsAutopilotDeviceIdentityState", "deviceImportStatus": "pending", "deviceRegistrationId": "", "deviceErrorCode": 0, "deviceErrorName": "" } } "@ try { Invoke-MSGraphRequest -Url $uri -HttpMethod Post -Content $json } catch { Write-Error $_.Exception break } } Function Remove-AutoPilotImportedDevice(){ <# .SYNOPSIS Removes the status information for a device being imported into Windows Autopilot. .DESCRIPTION The Remove-AutoPilotImportedDevice cmdlet cleans up the status information about a new device being imported into Windows Autopilot. This should be done regardless of whether the import was successful or not. .PARAMETER id The ID (GUID) of the imported device status information to be removed (mandatory). .EXAMPLE Remove the status information for a specified device. Remove-AutoPilotImportedDevice -id $id #> [cmdletbinding()] param ( [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$True)] $id ) Process { # Defining Variables $graphApiVersion = "beta" $Resource = "deviceManagement/importedWindowsAutopilotDeviceIdentities" $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource/$id" try { Write-Verbose "Removing imported device $id" Invoke-MSGraphRequest -Url $uri -HttpMethod DELETE } catch { Write-Error $_.Exception break } } } Function Get-AutoPilotProfile(){ <# .SYNOPSIS Gets Windows Autopilot profile details. .DESCRIPTION The Get-AutoPilotProfile cmdlet returns either a list of all Windows Autopilot profiles for the current Azure AD tenant, or information for the specific profile specified by its ID. .PARAMETER id Optionally, the ID (GUID) of the profile to be retrieved. .EXAMPLE Get a list of all Windows Autopilot profiles. Get-AutoPilotProfile #> [cmdletbinding()] param ( [Parameter(Mandatory=$false)] $id ) # Defining Variables $graphApiVersion = "beta" $Resource = "deviceManagement/windowsAutopilotDeploymentProfiles" if ($id) { $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource/$id" } else { $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource" } try { $response = Invoke-MSGraphRequest -Url $uri -HttpMethod Get if ($id) { $response } else { $devices = $response.value $devicesNextLink = $response."@odata.nextLink" while ($devicesNextLink -ne $null){ $devicesResponse = (Invoke-MSGraphRequest -Url $devicesNextLink -HttpMethod Get) $devicesNextLink = $devicesResponse."@odata.nextLink" $devices += $devicesResponse.value } $devices } } catch { Write-Error $_.Exception break } } Function Get-AutoPilotProfileAssignedDevice(){ <# .SYNOPSIS Gets the list of devices that are assigned to the specified Windows Autopilot profile. .DESCRIPTION The Get-AutoPilotProfileAssignedDevice cmdlet returns the list of Autopilot devices that have been assigned the specified Windows Autopilot profile. .PARAMETER id The ID (GUID) of the profile to be retrieved. .EXAMPLE Get a list of all Windows Autopilot profiles. Get-AutoPilotProfileAssignedDevices -id $id #> [cmdletbinding()] param ( [Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$True)] $id ) Process { # Defining Variables $graphApiVersion = "beta" $Resource = "deviceManagement/windowsAutopilotDeploymentProfiles" $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource/$id/assignedDevices" try { $response = Invoke-MSGraphRequest -Url $uri -HttpMethod Get $response.Value } catch { Write-Error $_.Exception break } } } Function ConvertTo-AutoPilotConfigurationJSON(){ <# .SYNOPSIS Converts the specified Windows Autopilot profile into a JSON format. .DESCRIPTION The ConvertTo-AutoPilotConfigurationJSON cmdlet converts the specified Windows Autopilot profile, as represented by a Microsoft Graph API object, into a JSON format. .PARAMETER profile A Windows Autopilot profile object, typically returned by Get-AutoPilotProfile .EXAMPLE Get the JSON representation of each Windows Autopilot profile in the current Azure AD tenant. Get-AutoPilotProfile | ConvertTo-AutoPilotConfigurationJSON #> [cmdletbinding()] param ( [Parameter(Mandatory=$true,ValueFromPipeline=$True)] [Object[]] $profile ) Process { $oobeSettings = $_.outOfBoxExperienceSettings # Build up properties $json = @{} $json.Add("Comment_File", "Profile $($_.displayName)") $json.Add("Version", 2049) $json.Add("ZtdCorrelationId", $_.id) if ($_."@odata.type" -eq "#microsoft.graph.activeDirectoryWindowsAutopilotDeploymentProfile") { $json.Add("CloudAssignedDomainJoinMethod", 1) } else { $json.Add("CloudAssignedDomainJoinMethod", 0) } if ($_.deviceNameTemplate) { $json.Add("CloudAssignedDeviceName", $_.deviceNameTemplate) } # Figure out config value $oobeConfig = 8 + 256 if ($oobeSettings.userType -eq 'standard') { $oobeConfig += 2 } if ($oobeSettings.hidePrivacySettings -eq $true) { $oobeConfig += 4 } if ($oobeSettings.hideEULA -eq $true) { $oobeConfig += 16 } if ($oobeSettings.skipKeyboardSelectionPage -eq $true) { $oobeConfig += 1024 if ($_.language) { $json.Add("CloudAssignedLanguage", $_.language) } } if ($oobeSettings.deviceUsageType -eq 'shared') { $oobeConfig += 32 + 64 } $json.Add("CloudAssignedOobeConfig", $oobeConfig) # Set the forced enrollment setting if ($oobeSettings.hideEscapeLink -eq $true) { $json.Add("CloudAssignedForcedEnrollment", 1) } else { $json.Add("CloudAssignedForcedEnrollment", 0) } # Set the org-related info $org = Get-Organization foreach ($domain in $org.VerifiedDomains) { if ($domain.isDefault) { $tenantDomain = $domain.name } } $json.Add("CloudAssignedTenantId", $org.id) $json.Add("CloudAssignedTenantDomain", $tenantDomain) $embedded = @{} $embedded.Add("CloudAssignedTenantDomain", $tenantDomain) $embedded.Add("CloudAssignedTenantUpn", "") if ($oobeSettings.hideEscapeLink -eq $true) { $embedded.Add("ForcedEnrollment", 1) } else { $embedded.Add("ForcedEnrollment", 0) } $ztc = @{} $ztc.Add("ZeroTouchConfig", $embedded) $json.Add("CloudAssignedAadServerData", (ConvertTo-JSON $ztc -Compress)) # Return the JSON ConvertTo-JSON $json } } Function Set-AutoPilotProfile(){ <# .SYNOPSIS Sets Windows Autopilot profile properties. .DESCRIPTION The Set-AutoPilotProfile cmdlet sets properties on an existing Autopilot profile. .PARAMETER id Type: Integer - The ID (GUID) of the profile to be updated. .PARAMETER language Type: String - The language identifier (e.g. "en-us") to be configured in the profile. .PARAMETER description Type: String - The description to be configured in the profile. .PARAMETER ConvertDeviceToAutopilot Type: Boolean - Configure the value "Convert all targeted devices to Autopilot" .PARAMETER OOBE_HideEULA Type: Boolean - Configure the OOBE option to hide or not the EULA .PARAMETER OOBE_EnableWhiteGlove Type: Boolean - Configure the OOBE option to allow or not White Glove OOBE .PARAMETER OOBE_hidePrivacySettings Type: Boolean - Configure the OOBE option to hide or not the privacy settings .PARAMETER OOBE_HideChangeAccountOpts Type: Boolean - Configure the OOBE option to hide or not the change account options .PARAMETER OOBE_userTypeAdmin Type: Switch - Configure the user account type as administrator. .PARAMETER OOBE_userTypeUser Type: Switch - Configure the user account type as standard. .PARAMETER OOBE_NameTemplate Type: String - Configure the OOBE option to apply a device name template .PARAMETER OOBE_SkipKeyboard Type: String - Configure the OOBE option to skip or not the keyboard selection page .EXAMPLE Get a list of all Windows Autopilot profiles. Set-AutoPilotProfile -ID <guid> -Language "en-us" Set-AutoPilotProfile -ID <guid> -Language "en-us" -displayname "My testing profile" -Description "Description of my profile" -OOBE_HideEULA $True -OOBE_hidePrivacySettings $True #> [cmdletbinding()] param ( [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$True)] $id, [string]$language, [string]$displayname, [string]$description, [bool]$ConvertDeviceToAutopilot, [bool]$OOBE_HideEULA, [bool]$OOBE_hidePrivacySettings, [bool]$OOBE_HideChangeAccountOpts, [Switch]$OOBE_userTypeAdmin, [Switch]$OOBE_userTypeUser, [string]$OOBE_NameTemplate, [bool]$OOBE_SkipKeyboard, [bool]$OOBE_EnableWhiteGlove ) # LIST EXISTING VALUES FOR THE SELECTING PROFILE # Default profile values $Profile_Values = Get-AutoPilotProfile -ID $id $Profile_DisplayName = $Profile_Values.displayName $Profile_Description = $Profile_Values.description $Profile_language = $Profile_Values.language $Profile_ConvertDeviceToAutopilot = $Profile_Values.extractHardwareHash $Profile_enableWhiteGlove = $Profile_Values.enableWhiteGlove $Profile_deviceType = $Profile_Values.deviceType $Profile_deviceNameTemplate = $Profile_Values.deviceNameTemplate # OOBE profile values $Profile_OOBE_NameTemplate = $Profile_Values.deviceNameTemplate $Profile_OOBE_HideEULA = $Profile_Values.outOfBoxExperienceSettings.hideEULA $Profile_OOBE_hidePrivacySettings = $Profile_Values.outOfBoxExperienceSettings.hidePrivacySettings $Profile_OOBE_userTypeAdmin = $Profile_Values.outOfBoxExperienceSettings.userType $Profile_OOBE_SkipKeyboard = $Profile_Values.outOfBoxExperienceSettings.skipKeyboardSelectionPage $Profile_OOBE_HideChangeAccountOpts = $Profile_Values.outOfBoxExperienceSettings.hideEscapeLink # If user has selected admin mode If($OOBE_userTypeAdmin) { $OOBE_userType = "administrator" } If($OOBE_userTypeUser) { $OOBE_userType = "standard" } If(($OOBE_userTypeAdmin) -and ($OOBE_userTypeUser)) { write-warning "Please select OOBE_userTypeAdmin OR OOBE_userTypeUser, not both !!!" break } If((!($OOBE_userTypeAdmin)) -and (!($OOBE_userTypeUser))) { $OOBE_userType = $Profile_OOBE_userTypeAdmin } If(($displayname -eq "")) # If user hasn't typed a display name { $displayname = $Profile_DisplayName # We will used the existing value } Else # If user has typed a display name { $displayname = $displayname # We will use the typed display name } If(($OOBE_NameTemplate -eq $null)) { $OOBE_NameTemplate = $Profile_deviceNameTemplate } ElseIf(($OOBE_NameTemplate -eq "")) { $OOBE_NameTemplate = "" } If(($language -eq "")) { $language = $Profile_language } If(($description -eq "")) { $description = $Profile_Description } If(($ConvertDeviceToAutopilot -eq $null)) { $ConvertDeviceToAutopilot = $Profile_ConvertDeviceToAutopilot } If(($OOBE_HideEULA -eq $null)) { $OOBE_HideEULA = $Profile_OOBE_HideEULA } If(($OOBE_hidePrivacySettings -eq $null)) { $OOBE_hidePrivacySettings = $Profile_OOBE_hidePrivacySettings } If(($OOBE_SkipKeyboard -eq "")) { $OOBE_SkipKeyboard = $Profile_OOBE_SkipKeyboard } If(($OOBE_HideChangeAccountOpts -eq $null)) { $OOBE_HideChangeAccountOpts = $Profile_OOBE_HideChangeAccountOpts } If(($OOBE_EnableWhiteGlove -eq $null)) { $OOBE_EnableWhiteGlove = $OOBE_EnableWhiteGlove } # Defining Variables $graphApiVersion = "beta" $Resource = "deviceManagement/windowsAutopilotDeploymentProfiles" $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource/$id" $json = @" { "@odata.type": "#microsoft.graph.azureADWindowsAutopilotDeploymentProfile", "displayName": "$displayname", "description": "$description", "language": "$language", "extractHardwareHash": "$ConvertDeviceToAutopilot", "deviceNameTemplate": "$OOBE_NameTemplate", "deviceType": "$Profile_deviceType", "enableWhiteGlove": "$OOBE_EnableWhiteGlove", "outOfBoxExperienceSettings": { "@odata.type": "microsoft.graph.outOfBoxExperienceSettings", "hidePrivacySettings": "$OOBE_hidePrivacySettings", "hideEULA": $OOBE_HideEULA, "userType": "$OOBE_userType", "deviceUsageType": "singleUser", "skipKeyboardSelectionPage": "$OOBE_SkipKeyboard", "hideEscapeLink": $OOBE_HideChangeAccountOpts } } "@ try { Invoke-MSGraphRequest -Url $uri -HttpMethod PATCH -Content $json } catch { Write-Error $_.Exception break } } Function Add-AutoPilotProfile(){ <# .SYNOPSIS Sets Windows Autopilot profile properties. .DESCRIPTION The Add-AutoPilotProfile cmdlet sets properties on an existing Autopilot profile. .PARAMETER id The ID (GUID) of the profile to be updated. .PARAMETER language Type: String - The language identifier (e.g. "en-us") to be configured in the profile. .PARAMETER description Type: String - The description to be configured in the profile. .PARAMETER ConvertDeviceToAutopilot Type: Boolean - Configure the value "Convert all targeted devices to Autopilot" .PARAMETER OOBE_HideEULA Type: Boolean - Configure the OOBE option to hide or not the EULA .PARAMETER OOBE_EnableWhiteGlove Type: Boolean - Configure the OOBE option to allow or not White Glove OOBE .PARAMETER OOBE_hidePrivacySettings Type: Boolean - Configure the OOBE option to hide or not the privacy settings .PARAMETER OOBE_HideChangeAccountOpts Type: Boolean - Configure the OOBE option to hide or not the change account options .PARAMETER OOBE_userTypeAdmin Type: Switch - Configure the user account type as administrator. .PARAMETER OOBE_userTypeUser Type: Switch - Configure the user account type as standard. .PARAMETER ModeUserDriven Type: Switch - Configure the deployment mode to user driven .PARAMETER ModeSelfDeploying Type: Switch - Configure the deployment mode to self deploying .PARAMETER OOBE_NameTemplate Type: String - Configure the OOBE option to apply a device name template .PARAMETER OOBE_SkipKeyboard Type: Boolean - Configure the OOBE option to skip or not the keyboard selection page .EXAMPLE Get a list of all Windows Autopilot profiles. Add-AutoPilotProfile -Language "en-us" -displayname "My testing profile" -Description "Description of my profile" -OOBE_HideEULA $True -OOBE_hidePrivacySettings $True #> [cmdletbinding()] param ( [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$True)][string]$displayname, [string]$language, [string]$description, [bool]$ConvertDeviceToAutopilot, [bool]$OOBE_HideEULA, [bool]$OOBE_EnableWhiteGlove, [bool]$OOBE_hidePrivacySettings, [bool]$OOBE_HideChangeAccountOpts, [Switch]$ModeUserDriven, [Switch]$ModeSelfDeploying, [Switch]$OOBE_userTypeAdmin, [Switch]$OOBE_userTypeUser, [string]$OOBE_NameTemplate ) # If user has selected admin mode If($OOBE_userTypeAdmin) { $OOBE_userType = "administrator" } If($OOBE_userTypeUser) { $OOBE_userType = "standard" } If(($OOBE_userTypeAdmin) -and ($OOBE_userTypeUser)) { write-warning "Please select OOBE_userTypeAdmin OR OOBE_userTypeUser, not both !!!" break } If((!($OOBE_userTypeAdmin)) -and (!($OOBE_userTypeUser))) { $OOBE_userType = "standard" } If($ModeUserDriven) { $Deployment_Mode = "singleUser" } If($OOBE_EnableWhiteGlove) { $OOBE_HideChangeAccountOpts = $True } If($ModeSelfDeploying) { $Deployment_Mode = "Shared" } If(($ModeUserDriven) -and ($ModeSelfDeploying)) { write-warning "Please select ModeUserDriven OR ModeSelfDeploying, not both !!!" break } If((!($ModeUserDriven)) -and (!($ModeSelfDeploying))) { $Deployment_Mode = "singleUser" } If(($displayname -eq "")) # If user hasn't typed a display name { $displayname = $Profile_DisplayName # We will used the existing value } Else # If user has typed a display name { $displayname = $displayname # We will use the typed display name } # Defining Variables $graphApiVersion = "beta" $Resource = "deviceManagement/windowsAutopilotDeploymentProfiles" $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource" $json = @" { "@odata.type": "#microsoft.graph.azureADWindowsAutopilotDeploymentProfile", "displayName": "$displayname", "description": "$description", "language": "$language", "extractHardwareHash": $ConvertDeviceToAutopilot, "deviceNameTemplate": "$OOBE_NameTemplate", "deviceType": "windowsPc", "enableWhiteGlove": $OOBE_EnableWhiteGlove, "outOfBoxExperienceSettings": { "hidePrivacySettings": $OOBE_hidePrivacySettings, "hideEULA": $OOBE_HideEULA, "userType": "$OOBE_userType", "deviceUsageType": "$Deployment_Mode", "skipKeyboardSelectionPage": false, "hideEscapeLink": $OOBE_HideChangeAccountOpts } } "@ $json = $json -replace "True", "true" try { Invoke-MSGraphRequest -Url $uri -HttpMethod POST -Content $json } catch { Write-Error $_.Exception break } } Function Remove-AutoPilotProfile(){ <# .SYNOPSIS Remove a Deployment Profile .DESCRIPTION The Remove-AutoPilotProfile allows you to remove a specific deployment profile .PARAMETER id Mandatory, the ID (GUID) of the profile to be removed. .EXAMPLE Remove-AutoPilotProfile -id $id #> [cmdletbinding()] param ( [Parameter(Mandatory=$True,ValueFromPipelineByPropertyName=$True)] $id ) Process { # Defining Variables $graphApiVersion = "beta" $Resource = "deviceManagement/windowsAutopilotDeploymentProfiles" $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource/$id" Try { Invoke-MSGraphRequest -Url $uri -HttpMethod DELETE } catch { Write-Error $_.Exception break } } } Function Get-AutoPilotProfileAssignments(){ <# .SYNOPSIS List all assigned devices for a specific profile ID .DESCRIPTION The Get-AutoPilotProfileAssignments cmdlet returns the list of groups that ae assigned to a spcific deployment profile .PARAMETER id Type: Integer - Mandatory, the ID (GUID) of the profile to be retrieved. .EXAMPLE Get-AutoPilotProfileAssignments -id $id #> [cmdletbinding()] param ( [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$True)] $id ) Process { # Defining Variables $graphApiVersion = "beta" $Resource = "deviceManagement/windowsAutopilotDeploymentProfiles" $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource/$id/assignments" try { $response = Invoke-MSGraphRequest -Url $uri -HttpMethod Get $Group_ID = $response.Value.target.groupId ForEach($Group in $Group_ID) { Try { Get-AzureADGroup | where {$_.ObjectId -like $Group} } Catch { $Group } } } catch { Write-Error $_.Exception break } } } Function Remove-AutoPilotProfileAssignments(){ <# .SYNOPSIS Removes a specific group assigntion for a specifc deployment profile .DESCRIPTION The Remove-AutoPilotProfileAssignments cmdlet allows you to remove a group assignation for a deployment profile .PARAMETER id Type: Integer - Mandatory, the ID (GUID) of the profile .PARAMETER groupid Type: Integer - Mandatory, the ID of the group .EXAMPLE Remove-AutoPilotProfileAssignments -id $id #> [cmdletbinding()] param ( [Parameter(Mandatory=$true)]$id, [Parameter(Mandatory=$true)]$groupid ) # Defining Variables $graphApiVersion = "beta" $Resource = "deviceManagement/windowsAutopilotDeploymentProfiles" $full_assignment_id = $id + "_" + $groupid + "_0" $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource/$id/assignments/$full_assignment_id" try { Invoke-MSGraphRequest -Url $uri -HttpMethod DELETE } catch { Write-Error $_.Exception break } } Function Set-AutoPilotProfileAssignedGroup(){ <# .SYNOPSIS Assigns a group to a Windows Autopilot profile. .DESCRIPTION The Set-AutoPilotProfileAssignedGroup cmdlet allows you to assign a specific group to a specific deployment profile .PARAMETER id Type: Integer - Mandatory, the ID (GUID) of the profile .PARAMETER groupid Type: Integer - Mandatory, the ID of the group .EXAMPLE Set-AutoPilotProfileAssignedGroup -id $id -groupid $groupid #> [cmdletbinding()] param ( [Parameter(Mandatory=$true)]$id, [Parameter(Mandatory=$true)]$groupid ) $full_assignment_id = $id + "_" + $groupid + "_0" # Defining Variables $graphApiVersion = "beta" $Resource = "deviceManagement/windowsAutopilotDeploymentProfiles" $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource/$id/assignments" $json = @" { "id": "$full_assignment_id", "target": { "@odata.type": "#microsoft.graph.groupAssignmentTarget", "groupId": "$groupid" } } "@ try { Invoke-MSGraphRequest -Url $uri -HttpMethod Post -Content $json } catch { Write-Error $_.Exception break } } Function Get-EnrollmentStatusPage(){ <# .SYNOPSIS List enrollment status page .DESCRIPTION The Get-EnrollmentStatusPage cmdlet returns available enrollment status page with their options .PARAMETER id The ID (GUID) of the status page (optional) .EXAMPLE Get-EnrollmentStatusPage #> [cmdletbinding()] param ( [Parameter()] $id ) # Defining Variables $graphApiVersion = "beta" $Resource = "deviceManagement/deviceEnrollmentConfigurations" if ($id) { $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource/$id" } else { $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource" } try { $response = Invoke-MSGraphRequest -Url $uri -HttpMethod Get if ($id) { $response } else { $response.Value | ? { $_.'@odata.type' -eq "#microsoft.graph.windows10EnrollmentCompletionPageConfiguration" } } } catch { Write-Error $_.Exception break } } Function Add-EnrollmentStatusPage(){ <# .SYNOPSIS Adds a new Windows Autopilot Enrollment Status Page. .DESCRIPTION The Add-EnrollmentStatusPage cmdlet sets properties on an existing Autopilot profile. .PARAMETER DisplayName Type: String - Configure the display name of the enrollment status page .PARAMETER description Type: String - Configure the description of the enrollment status page .PARAMETER HideProgress Type: Boolean - Configure the option: Show app and profile installation progress .PARAMETER AllowCollectLogs Type: Boolean - Configure the option: Allow users to collect logs about installation errors .PARAMETER Message Type: String - Configure the option: Show custom message when an error occurs .PARAMETER AllowUseOnFailure Type: Boolean - Configure the option: Allow users to use device if installation error occurs .PARAMETER AllowResetOnError Type: Boolean - Configure the option: Allow users to reset device if installation error occurs .PARAMETER BlockDeviceUntilComplete Type: Boolean - Configure the option: Block device use until all apps and profiles are installed .PARAMETER TimeoutInMinutes Type: Integer - Configure the option: Show error when installation takes longer than specified number of minutes .EXAMPLE Add-EnrollmentStatusPage -Message "Oops an error occured, please contact your support" -HideProgress $True -AllowResetOnError $True #> [cmdletbinding()] param ( [Parameter(Mandatory=$True)][string]$DisplayName, [string]$Description, [bool]$HideProgress, [bool]$AllowCollectLogs, [bool]$blockDeviceSetupRetryByUser, [string]$Message, [bool]$AllowUseOnFailure, [bool]$AllowResetOnError, [bool]$BlockDeviceUntilComplete, [Int]$TimeoutInMinutes ) If($HideProgress -eq $False) { $blockDeviceSetupRetryByUser = $true } If(($Description -eq $null)) { $Description = $EnrollmentPage_Description } If(($DisplayName -eq $null)) { $DisplayName = "" } If(($TimeoutInMinutes -eq "")) { $TimeoutInMinutes = "60" } # Defining Variables $graphApiVersion = "beta" $Resource = "deviceManagement/deviceEnrollmentConfigurations" $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource" $json = @" { "@odata.type": "#microsoft.graph.windows10EnrollmentCompletionPageConfiguration", "displayName": "$DisplayName", "description": "$description", "showInstallationProgress": "$hideprogress", "blockDeviceSetupRetryByUser": "$blockDeviceSetupRetryByUser", "allowDeviceResetOnInstallFailure": "$AllowResetOnError", "allowLogCollectionOnInstallFailure": "$AllowCollectLogs", "customErrorMessage": "$Message", "installProgressTimeoutInMinutes": "$TimeoutInMinutes", "allowDeviceUseOnInstallFailure": "$AllowUseOnFailure", } "@ try { Invoke-MSGraphRequest -Url $uri -HttpMethod Post -Content $json } catch { Write-Error $_.Exception break } } Function Set-EnrollmentStatusPage(){ <# .SYNOPSIS Sets Windows Autopilot Enrollment Status Page properties. .DESCRIPTION The Set-EnrollmentStatusPage cmdlet sets properties on an existing Autopilot profile. .PARAMETER id The ID (GUID) of the profile to be updated. .PARAMETER DisplayName Type: String - Configure the display name of the enrollment status page .PARAMETER description Type: String - Configure the description of the enrollment status page .PARAMETER HideProgress Type: Boolean - Configure the option: Show app and profile installation progress .PARAMETER AllowCollectLogs Type: Boolean - Configure the option: Allow users to collect logs about installation errors .PARAMETER Message Type: String - Configure the option: Show custom message when an error occurs .PARAMETER AllowUseOnFailure Type: Boolean - Configure the option: Allow users to use device if installation error occurs .PARAMETER AllowResetOnError Type: Boolean - Configure the option: Allow users to reset device if installation error occurs .PARAMETER BlockDeviceUntilComplete Type: Boolean - Configure the option: Block device use until all apps and profiles are installed .PARAMETER TimeoutInMinutes Type: Integer - Configure the option: Show error when installation takes longer than specified number of minutes .EXAMPLE Set-EnrollmentStatusPage -id $id -Message "Oops an error occured, please contact your support" -HideProgress $True -AllowResetOnError $True #> [cmdletbinding()] param ( [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$True)] $id, [string]$DisplayName, [string]$Description, [bool]$HideProgress, [bool]$AllowCollectLogs, [string]$Message, [bool]$AllowUseOnFailure, [bool]$AllowResetOnError, [bool]$AllowUseOnError, [bool]$BlockDeviceUntilComplete, [Int]$TimeoutInMinutes ) Process { # LIST EXISTING VALUES FOR THE SELECTING STAUS PAGE # Default profile values $EnrollmentPage_Values = Get-EnrollmentStatusPage -ID $id $EnrollmentPage_DisplayName = $EnrollmentPage_Values.displayName $EnrollmentPage_Description = $EnrollmentPage_Values.description $EnrollmentPage_showInstallationProgress = $EnrollmentPage_Values.showInstallationProgress $EnrollmentPage_blockDeviceSetupRetryByUser = $EnrollmentPage_Values.blockDeviceSetupRetryByUser $EnrollmentPage_allowDeviceResetOnInstallFailure = $EnrollmentPage_Values.allowDeviceResetOnInstallFailure $EnrollmentPage_allowLogCollectionOnInstallFailure = $EnrollmentPage_Values.allowLogCollectionOnInstallFailure $EnrollmentPage_customErrorMessage = $EnrollmentPage_Values.customErrorMessage $EnrollmentPage_installProgressTimeoutInMinutes = $EnrollmentPage_Values.installProgressTimeoutInMinutes $EnrollmentPage_allowDeviceUseOnInstallFailure = $EnrollmentPage_Values.allowDeviceUseOnInstallFailure If(!($HideProgress)) { $HideProgress = $EnrollmentPage_showInstallationProgress } If(!($BlockDeviceUntilComplete)) { $BlockDeviceUntilComplete = $EnrollmentPage_blockDeviceSetupRetryByUser } If(!($AllowCollectLogs)) { $AllowCollectLogs = $EnrollmentPage_allowLogCollectionOnInstallFailure } If(!($AllowUseOnFailure)) { $AllowUseOnFailure = $EnrollmentPage_allowDeviceUseOnInstallFailure } If(($Message -eq "")) { $Message = $EnrollmentPage_customErrorMessage } If(($Description -eq $null)) { $Description = $EnrollmentPage_Description } If(($DisplayName -eq $null)) { $DisplayName = $EnrollmentPage_DisplayName } If(!($AllowResetOnError)) { $AllowResetOnError = $EnrollmentPage_allowDeviceResetOnInstallFailure } If(($TimeoutInMinutes -eq "")) { $TimeoutInMinutes = $EnrollmentPage_installProgressTimeoutInMinutes } # Defining Variables $graphApiVersion = "beta" $Resource = "deviceManagement/deviceEnrollmentConfigurations" $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource/$id" $json = @" { "@odata.type": "#microsoft.graph.windows10EnrollmentCompletionPageConfiguration", "displayName": "$DisplayName", "description": "$description", "showInstallationProgress": "$HideProgress", "blockDeviceSetupRetryByUser": "$BlockDeviceUntilComplete", "allowDeviceResetOnInstallFailure": "$AllowResetOnError", "allowLogCollectionOnInstallFailure": "$AllowCollectLogs", "customErrorMessage": "$Message", "installProgressTimeoutInMinutes": "$TimeoutInMinutes", "allowDeviceUseOnInstallFailure": "$AllowUseOnFailure" } "@ try { Invoke-MSGraphRequest -Url $uri -HttpMethod PATCH -Content $json } catch { Write-Error $_.Exception break } } } Function Remove-EnrollmentStatusPage(){ <# .SYNOPSIS Remove a specific enrollment status page .DESCRIPTION The Remove-EnrollmentStatusPage allows you to remove a specific enrollment status page .PARAMETER id Mandatory, the ID (GUID) of the profile to be retrieved. .EXAMPLE Remove-EnrollmentStatusPage -id $id #> [cmdletbinding()] param ( [Parameter(Mandatory=$True,ValueFromPipelineByPropertyName=$True)] $id ) Process { # Defining Variables $graphApiVersion = "beta" $Resource = "deviceManagement/deviceEnrollmentConfigurations" $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource/$id" try { Invoke-MSGraphRequest -Url $uri -HttpMethod DELETE } catch { Write-Error $_.Exception break } } } Function Invoke-AutopilotSync(){ <# .SYNOPSIS Initiates a synchronization of Windows Autopilot devices between the Autopilot deployment service and Intune. .DESCRIPTION The Invoke-AutopilotSync cmdlet initiates a synchronization between the Autopilot deployment service and Intune. This can be done after importing new devices, to ensure that they appear in Intune in the list of registered Autopilot devices. See https://developer.microsoft.com/en-us/graph/docs/api-reference/beta/api/intune_enrollment_windowsautopilotsettings_sync for more information. .EXAMPLE Initiate a synchronization. Invoke-AutopilotSync #> [cmdletbinding()] param ( ) # Defining Variables $graphApiVersion = "beta" $Resource = "deviceManagement/windowsAutopilotSettings/sync" $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource" try { Invoke-MSGraphRequest -Url $uri -HttpMethod Post } catch { Write-Error $_.Exception break } } #endregion Function Import-AutoPilotCSV(){ <# .SYNOPSIS Adds a batch of new devices into Windows Autopilot. .DESCRIPTION The Import-AutoPilotCSV cmdlet processes a list of new devices (contained in a CSV file) using a several of the other cmdlets included in this module. It is a convenient wrapper to handle the details. After the devices have been added, the cmdlet will continue to check the status of the import process. Once all devices have been processed (successfully or not) the cmdlet will complete. This can take several minutes, as the devices are processed by Intune as a background batch process. .PARAMETER csvFile The file containing the list of devices to be added. .PARAMETER groupTag An optional identifier or tag that can be associated with this device, useful for grouping devices using Azure AD dynamic groups. This value overrides an Group Tag value specified in the CSV file. .EXAMPLE Add a batch of devices to Windows Autopilot for the current Azure AD tenant. Import-AutoPilotCSV -csvFile C:\Devices.csv #> [cmdletbinding()] param ( [Parameter(Mandatory=$true)] $csvFile, [Parameter(Mandatory=$false)] [Alias("orderIdentifier")] $groupTag = "" ) # Read CSV and process each device $devices = Import-CSV $csvFile foreach ($device in $devices) { if ($groupTag -ne "") { $o = $groupTag } elseif ($device.'Group Tag' -ne "") { $o = $device.'Group Tag' } else { $o = $device.'OrderID' } Add-AutoPilotImportedDevice -serialNumber $device.'Device Serial Number' -hardwareIdentifier $device.'Hardware Hash' -groupTag $o } # While we could keep a list of all the IDs that we added and then check each one, it is # easier to just loop through all of them $processingCount = 1 while ($processingCount -gt 0) { $deviceStatuses = @(Get-AutoPilotImportedDevice) $deviceCount = $deviceStatuses.Length # Check to see if any devices are still processing $processingCount = 0 foreach ($device in $deviceStatuses){ if ($device.state.deviceImportStatus -eq "unknown") { $processingCount = $processingCount + 1 } } Write-Host "Waiting for $processingCount of $deviceCount" # Still processing? Sleep before trying again. if ($processingCount -gt 0){ Start-Sleep 2 } } # Display the statuses $deviceStatuses | ForEach-Object { Write-Host "Serial number $($_.serialNumber): $($_.state.deviceImportStatus) $($_.state.deviceErrorCode) $($_.state.deviceErrorName)" } # Cleanup the imported device records $deviceStatuses | ForEach-Object { Remove-AutoPilotImportedDevice -id $_.id } } |