Forum Discussion
Bulk update of AutoPilot group tags via Powershell
As the title says, I want to use a command to customize the group tags of many AutoPilot devices. However, I don't want to use a file as a basis first, as described in many tutorials, but access directly the AutoPilot devices in Intune.
In other words, change all devices with a group tag named "A" to a new tag named "B".
Do you guys have a solution on how I can do this? I've only read something about the Graph API so far?
Thanks a lot!
4 Replies
That's possible. Check out Bulk Update Windows Autopilot entities (github.com) for more info.
- Andrew_BeardCopper Contributor
I found this method stopped working for me around the end of September 2023. Before that it worked fine for me to use a script to automatically add Group Tags to Autopilot devices in Intune based on their on-prem AD OU placement.
I am happy to share the full script I was using that has stopped working if anyone is interested. I have reached out to the author of the original script to see if he has any ideas. I think personally that some Beta feature of the previous MSGraph scripting has been changed and no longer works as it used to.
I have also attempted to use the PowerShell module https://www.powershellgallery.com/packages/WindowsAutoPilotIntune/5.6
but that also has no success at least how I have tried when using MSGraph direct login (without registered app ID and secret etc.).
If anyone has any help to offer I would be most grateful as I do this type of thing many times whilst working as a contract senior IT technician for many different companies on the same cloud enabled Hybrid-Join journey.- Andrew_BeardCopper Contributor
# GroupTagBulkListWinAutopilotDevices-v4.ps1 # Run this script with local admin rights, preferably on a Windows server. CLS $ErrorActionPreference = "SilentlyContinue" ## Trust scripts downloaded from the PSGallery Set-PSRepository -Name 'PSGallery' -InstallationPolicy Trusted ## Update Nuget Package and PowerShellGet Module Install-PackageProvider NuGet -Scope CurrentUser -Force # Install the required PowerShellGet module if not already installed if (-not (Get-Module -ListAvailable -Name PowerShellGet)) { Install-Module PowerShellGet -Scope CurrentUser -Force -AllowClobber } ## Remove old modules from existing session Remove-Module PowerShellGet,PackageManagement -Force -ErrorAction Ignore ## Import updated module Import-Module PowerShellGet -MinimumVersion 2.0 -Force Import-PackageProvider PowerShellGet -MinimumVersion 2.0 -Force ## MSAL is used with a registered MsalClientApplication in Azure for MSGraph Authentication and requires a -ClientId and -ClientSecret or Certificate ## See https://github.com/AzureAD/MSAL.PS # Install the required MSAL.PS module if not already installed (Not supported by Microsoft) if (-not (Get-Module -ListAvailable -Name "MSAL.PS")) { Install-Module -Name "MSAL.PS" -SkipPublisherCheck -Force -AllowClobber } # Install the required AzureAD module if not already installed if (-not (Get-Module -ListAvailable -Name AzureAD)) { Install-Module -Name AzureAD -Force -AllowClobber } # Install the required Graph.Intune module if not already installed if (-not (Get-Module -ListAvailable -Name Microsoft.Graph.Intune)) { Install-Module -Name Microsoft.Graph.Intune -Force -AllowClobber } # Check if the OS is a client version $isClientOS = (Get-CimInstance Win32_OperatingSystem).ProductType -eq 1 # If it is a client OS if ($isClientOS) { # Check if RSAT is installed for Windows 10 or 11 client OS $feature = Get-WindowsCapability -Online | Where-Object { $_.Name -like 'Rsat*' } if ($feature.Count -gt 0 -and $feature[0].State -ne 'Installed') { # Install RSAT tools Add-WindowsCapability -Online -Name $feature[0].Name } } # If it is not a client OS if (-not $isClientOS) { # Check if RSAT-AD-PowerShell feature is installed (ONLY WORKS ON SERVER OS) $featureInstalled = Get-WindowsFeature RSAT-AD-PowerShell -ErrorAction SilentlyContinue # If not installed, install the feature (ONLY WORKS ON SERVER OS) if ($featureInstalled -eq $null) { Install-WindowsFeature RSAT-AD-PowerShell -IncludeAllSubFeature -IncludeManagementTools } } # Install the required ActiveDirectory module if not already installed if (-not (Get-Module -ListAvailable -Name ActiveDirectory)) { Install-Module -Name ActiveDirectory -Force -AllowClobber } # Install the required WindowsAutoPilotIntune module if not already installed if (-not (Get-Module -ListAvailable -Name WindowsAutoPilotIntune)) { Install-Module -Name WindowsAutoPilotIntune -Force -AllowClobber } ## Import Modules that are not loaded for the current session # Check if AzureAD module is already imported if (-not (Get-Module -Name AzureAD -ListAvailable)) { Import-Module -Name AzureAD -Force } # Check if ActiveDirectory module is already imported if (-not (Get-Module -Name ActiveDirectory -ListAvailable)) { Import-Module -Name ActiveDirectory -Force } # Check if WindowsAutoPilotIntune module is already imported if (-not (Get-Module -Name WindowsAutoPilotIntune -ListAvailable)) { Import-Module -Name WindowsAutoPilotIntune -Force } # Check if Microsoft.Graph.Intune module is already imported if (-not (Get-Module -Name Microsoft.Graph.Intune -ListAvailable)) { Import-Module -Name Microsoft.Graph.Intune -Force } Connect-MSGraph Update-MSGraphEnvironment -SchemaVersion "Beta" -Quiet # Set-MgEnvironment -GraphEndpoint "https://graph.microsoft.com/v1.0" -SchemaVersion "beta" Connect-MSGraph -Quiet CLS # Define parameters for AD retrieval of computer objects from an OU so that they can be tagged the same. # $OUpath = 'OU=HybridJoin,OU=Laptop,OU=Workstations,OU=Contoso,DC=com' # $GrpTag = "Ltop" # $OUpath = 'OU=HybridJoin,OU=Conference,OU=Workstations,OU=Contoso,DC=com' # $GrpTag = "Conf" $OUpath = 'OU=HybridJoin,OU=Desktop,OU=Workstations,OU=Contoso,DC=com' $GrpTag = "Dtop" $ExportPath = 'c:\temp\computers_in_ou.csv' Get-ADComputer -Filter * -SearchBase $OUpath | Select-object Name | Export-Csv -NoType $ExportPath -Force # Define the input file path $InputFilePath = 'c:\temp\computers_in_ou.csv' # Fetch all devices from Intune $intuneDevices = Invoke-MSGraphRequest -HttpMethod GET -Url "deviceManagement/managedDevices" | Get-MSGraphAllPages # Load computer names from the input file $computerNames = Get-Content -Path $InputFilePath # Define an array to store results $results = @() foreach ($computer in $computerNames) { Write-Output "==============================================================================" Write-Output "A Computer was found named: $computer" $PC = $computer.Trim('"') # Find a matching device in Intune based on computer name Write-Output "Trying to match " $_.deviceName " and $PC" $matchedDevice = $intuneDevices | Where-Object { $_.deviceName -eq $PC } if (-not $matchedDevice) { Write-Output "Matching Failed" } if ($matchedDevice) { Write-Output "Matching Success" $results += [PSCustomObject]@{ ComputerName = $PC SerialNumber = $matchedDevice.serialNumber } $computerSerial = $matchedDevice.serialNumber Write-Output "SN: $computerSerial" # Get all autopilot devices for Invoke-MSGraphRequest method $autopilotDevices = Invoke-MSGraphRequest -HttpMethod GET -Url "deviceManagement/windowsAutopilotDeviceIdentities" | Get-MSGraphAllPages # Single out the autopilot device we are dealing with that has a name matching the serial number of the Intune/AD device. $matchedDevice2 = $autopilotDevices | Where-Object { $_.serialNumber -eq $computerSerial } if ($matchedDevice2) { $matchedDevice2.groupTag = $GrpTag # Request Body required for Invoke-MSGraphRequest parameter. $requestBody = @" { groupTag: "`"$($matchedDevice2.groupTag)`"", } "@ # Quoted Group Tag required for Set-AutopilotDevice command parameter. $QuotedGrpTag = '"' + $GrpTag + '"' Write-Output "Updating entity: $($matchedDevice2.id) | groupTag: $($matchedDevice2.groupTag)" # Attempt 2 different methods to set the Group Tag for the Serial Number Autopilot object Set-AutopilotDevice -id $computerSerial -groupTag $QuotedGrpTag Invoke-MSGraphRequest -HttpMethod POST -Content $requestBody -Url "deviceManagement/windowsAutopilotDeviceIdentities/$($matchedDevice2.id)/UpdateDeviceProperties" } } } # Invoke an autopilot service sync Invoke-MSGraphRequest -HttpMethod POST -Url "deviceManagement/windowsAutopilotSettings/sync" # Remove all values from used variables $OUpath = $null $GrpTag = $null $QuotedGrpTag = $null $ExportPath = $null $InputFilePath = $null $intuneDevices = $null $computerNames = $null $results = $null $computer = $null $PC = $null $matchedDevice = $null $computerSerial = $null $autopilotDevices = $null $matchedDevice2 = $null $requestBody = $null # Delete the input file Remove-Item -Path $InputFilePath -Force