Dynamic Device Renaming in Intune Using Group Tags and PowerShell
Automate device renaming in Microsoft Intune using Group Tags and PowerShell, avoiding the 350 Autopilot profile limit while maintaining clean, readable device names that comply with NetBIOS naming constraints.
Managing device names in Microsoft Intune at scale can become a messy, manual burden, especially when you have multiple naming standards across regions, departments, or user types.
While Intune allows you to use Autopilot deployment profiles to assign naming conventions, this model breaks down fast:
๐ฉ The Real-World Challenges
-
Intune device names are capped at 15 characters - This is a NetBIOS naming limitation that affects all Windows devices.
-
You're limited to 350 Autopilot profiles - As documented in Windows Autopilot deployment limits, this constraint makes it impossible to create a profile for every naming scheme.
-
Device names default to SerialNumber or Random - Without proper configuration, devices end up with unreadable names that make organization difficult.
-
Creating a profile for every naming scheme is neither efficient, feasible, nor sustainable - This approach doesn't scale with organizational growth.
๐ฏ The Smarter Solution
Instead of tying your naming conventions to deployment profiles, use Group Tags to define personas or functions and let a PowerShell script handle the renaming post-deployment.
By leveraging Intune's dynamic group tagging and Microsoft Graph API, you can:
- Apply only a few general deployment profiles
- Automatically rename devices based on their Group Tag + a shortened serial tail
- Stay well within Intune limits while keeping device names clean and meaningful
๐ Prerequisites
Step 1: Create an Azure App Registration
- Go to Azure Portal โ Azure Active Directory โ App registrations.
- Click New registration.
- Name it something like
DeviceRenamer. - For detailed guidance, see Register an application with the Microsoft identity platform.
Step 2: Assign API Permissions
Under API permissions, add the following Microsoft Graph permissions:
- Device.Read.All (Application) - Required to read device information
- DeviceManagementServiceConfig.Read.All (Application) - Required for Autopilot device queries
- User.Read (Delegated) - Optional, for user context if needed
Important: Grant admin consent for these permissions. Learn more about permission types and consent.
Step 3: Generate Client Credentials
- Under Certificates & secrets:
- Click New client secret
- Store the Client ID, Tenant ID, and Secret securely
For more information on app authentication, see Microsoft identity platform application authentication.
๐ง Script Overview: What It Does
Let's break down the core logic of the script:
๐ 1. Authentication
The script authenticates to Microsoft Graph using the Azure App credentials via the OAuth 2.0 client credentials flow:
$TenantId = '...'
$ClientId = '...'
$ClientSecret = '...'
It requests an access token to call Graph API endpoints securely.
๐ 2. Get Serial Number
It retrieves the local BIOS serial number:
$Serial = (Get-CimInstance Win32_BIOS).SerialNumber.Trim()
This is used to match the device record in Graph. Learn more about querying device information with WMI.
๐ก 3. Query Device Metadata
Using the Microsoft Graph API, the script pulls the device's full Autopilot profile, including its Group Tag:
$Device = $AllDevices.value | Where-Object { $_.serialNumber -eq $Serial }
$GroupTag = $Device.groupTag
The script queries the Windows Autopilot device identities endpoint.
๐งฎ 4. Calculate the New Name
The script constructs a new name that fits Intune's 15-character limit:
$BaseLen = $GroupTag.Length + 1 # +1 for hyphen
$AvailLen = 15 - $BaseLen
$SerialTail = if ($SerialClean.Length -le $AvailLen) {
$SerialClean
} else {
$SerialClean.Substring($SerialClean.Length - $AvailLen, $AvailLen)
}
$NewName = "$GroupTag-$SerialTail"
So if the Group Tag is 6 characters, the last 8 characters of the serial will be used. It dynamically adjusts.
โ This guarantees:
- Maximum readability
- Unique identifiers
- Compliance with Intune's NetBIOS naming limits
๐ฅ๏ธ 5. Rename the Device
If the device isn't already named correctly, it triggers the rename using PowerShell's Rename-Computer cmdlet:
Rename-Computer -NewName $NewName -Force
It also logs success or failure and schedules a reboot.
๐ Logging
All operations are logged to:
C:\ProgramData\IntuneDeviceRenamer\logs\
This helps with troubleshooting and auditability. For best practices on PowerShell logging, see PowerShell logging and auditing.
๐ Deployment Strategy
Here's how you can use this at scale:
-
Assign Group Tags to Autopilot devices in Intune (e.g., FINANCE, UK-HR, NYC-SALES). Learn how in Add Group Tags to Autopilot devices.
-
Use just a few deployment profiles (e.g., by region or OS version). See Create and assign Autopilot deployment profiles.
-
Run this script during the provisioning process or as a scheduled task post-enrollment. For deploying PowerShell scripts via Intune, see Add PowerShell scripts to Microsoft Intune.
The device auto-renames based on its tag and serial tail โ clean, readable, and dynamic.
๐ Additional Resources
- Windows Autopilot overview
- Microsoft Graph API for Intune
- PowerShell scripting with Microsoft Graph
- Intune device naming best practices
๐ Final Thoughts
This approach offers the best of both worlds:
โ
Clean, human-readable names
โ
Dynamic device group alignment
โ
Minimal deployment profiles
โ
Fully automated and scalable
You don't have to choose between flexibility and manageability โ you can have both.
Full PowerShell Script
<#
.Author
AliAlame - CYBERSYSTEM
.SYNOPSIS
Renames an AAD-joined Intune device to "<OrderID>-<SerialTail>" (โค15 chars)
โwith verbose console output for troubleshooting.
.NOTES
โข Requires Graph application permission Device.Read.All (app registration)
โข Fill in $TenantId $ClientId $ClientSecret below
โข Logs + console: C:\ProgramData\IntuneDeviceRenamer\logs\
#>
#Device.Read.All (Application)
#DeviceManagementServiceConfig.Read.All (Application)
#User.Read (Delegated)
# ========= 0. SETTINGS =========
$TenantId = 'XXXXXXXXXXXXXXXXXXXXXXX'
$ClientId = 'XXXXXXXXXXXXXXXXXXXXXXX'
$ClientSecret = 'XXXXXXXXXXXXXXXXXXXXXXX'
$DebugMode = $false # true = no rename, no reboot, prints extra
# === 1. Logging ===
$LogDir = 'C:\ProgramData\IntuneDeviceRenamer\logs'
if (-not (Test-Path $LogDir)) { New-Item -ItemType Directory -Path $LogDir -Force | Out-Null }
$LogFile = Join-Path $LogDir ("Rename_{0:yyyyMMdd_HHmmss}.log" -f (Get-Date))
function Log { param($m, $l='INFO'); ("{0:o} [{1}] {2}" -f (Get-Date), $l, $m) | Tee-Object -FilePath $LogFile -Append }
Log "=== Rename-From-GroupTag START ==="
# === 2. BIOS Serial (RAW) ===
$Serial = (Get-CimInstance Win32_BIOS).SerialNumber.Trim()
if (-not $Serial) { Log 'ERR: BIOS serial empty.' 'ERROR'; exit 1 }
Log "Serial (raw) = $Serial"
# === 3. Graph Token ===
try {
$Body = "client_id=$ClientId" +
"&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default" +
"&client_secret=$([uri]::EscapeDataString($ClientSecret))" +
"&grant_type=client_credentials"
$AccessToken = (Invoke-RestMethod -Method POST `
-Uri "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token" `
-Body $Body -ContentType 'application/x-www-form-urlencoded' `
-Verbose:$DebugMode).access_token
Log "Token OK (len=$($AccessToken.Length))"
} catch {
Log "ERR: Token request failed. $_" 'ERROR'; exit 1
}
# === 4. Query Autopilot Devices (NO $filter) ===
$Uri = "https://graph.microsoft.com/beta/deviceManagement/windowsAutopilotDeviceIdentities"
try {
$AllDevices = Invoke-RestMethod -Uri $Uri -Headers @{Authorization="Bearer $AccessToken"} -Method GET -Verbose:$DebugMode
$Device = $AllDevices.value | Where-Object { $_.serialNumber -eq $Serial }
if (-not $Device) { Log "ERR: No Autopilot record found for serial $Serial" 'ERROR'; exit 1 }
$GroupTag = $Device.groupTag
Log "Found GroupTag = $GroupTag"
} catch {
Log "ERR: Graph query failed. $_" 'ERROR'; exit 1
}
if (-not $GroupTag) { Log "ERR: GroupTag is empty." 'ERROR'; exit 1 }
# === 5. Build New Name ===
# Clean serial for naming
$SerialClean = ($Serial -replace '[^0-9A-Za-z]', '')
Log "Serial (cleaned) = $SerialClean"
$MaxLen = 15
$BaseLen = $GroupTag.Length + 1 # +1 for hyphen
$AvailLen = $MaxLen - $BaseLen
if ($AvailLen -le 0) { Log "ERR: GroupTag too long for NetBIOS limit." 'ERROR'; exit 1 }
# Use cleaned serial for SerialTail
$SerialTail = if ($SerialClean.Length -le $AvailLen) { $SerialClean }
else { $SerialClean.Substring($SerialClean.Length - $AvailLen, $AvailLen) }
$NewName = "$GroupTag-$SerialTail"
Log "Proposed new name = $NewName"
# === 6. Rename Computer ===
if ($env:COMPUTERNAME -ieq $NewName) {
Log "Already correctly named. EXIT."
exit 0
}
try {
Rename-Computer -NewName $NewName -Force -ErrorAction Stop
Log "Rename-Computer succeeded."
} catch {
Log "ERR: Rename-Computer failed. $_" 'ERROR'; exit 1
}
# === 7. Handle Reboot ===
$Cs = Get-CimInstance Win32_ComputerSystem
if ($Cs.UserName -match 'defaultUser') {
Log "In ESP/OOBE โ Exiting 1641 for forced reboot"
exit 1641
} else {
try {
Add-Type -AssemblyName PresentationFramework
[System.Windows.MessageBox]::Show(
"Device name was updated to:`n$NewName`n`nThe system will reboot automatically in 10 minutes, or you can reboot manually now.",
"Device Renamed",
"OK",
"Info"
) | Out-Null
shutdown.exe /g /t 600 /f /c "Restarting after device rename to $NewName."
} catch {
Log "Fallback: shutdown command triggered."
shutdown.exe /g /t 600 /f /c "Restarting after device rename to $NewName."
}
exit 0
}