Dynamic Device Renaming in Intune Using Group Tags and PowerShell

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.
  • You’re limited to 350 Autopilot profiles, which is not scalable if you have dozens of naming conventions.
  • Device names default to SerialNumber or Random, making them hard to read or organize.
  • Creating a profile for every naming scheme is neither efficient, feasible, nor sustainable.

🎯 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.

See the Script here DeviceRename.ps1

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

  1. Go to Azure Portal → Azure Active Directory → App registrations.
  2. Click New registration.
  3. Name it something like DeviceRenamer.

Step 2: Assign API Permissions

Under API permissions, add:

  • Device.Read.All (Application)
  • DeviceManagementServiceConfig.Read.All (Application)
  • User.Read (Delegated)

Grant admin consent for these permissions.

Step 3: Generate Client Credentials

Under Certificates & secrets:

  • Click New client secret
  • Store the Client ID, Tenant ID, and Secret securely

🧠 Script Overview: What It Does

Let’s break down the core logic of the script: 3.DeviceRename.ps1

🔐 1. Authentication

The script authenticates to Microsoft Graph using the Azure App credentials:

$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.

📡 3. Query Device Metadata

Using the 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

🧮 4. Calculate the New Name

The magic happens here. 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 limits

🖥️ 5. Rename the Device

If the device isn't already named correctly, it triggers the rename:

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.

🚀 Deployment Strategy

Here’s how you can use this at scale:

  1. Assign Group Tags to Autopilot devices in Intune (e.g., FINANCE, UK-HR, NYC-SALES).
  2. Use just a few deployment profiles (e.g., by region or OS version).
  3. Run this script during the provisioning process or as a scheduled task post-enrollment.
  4. The device auto-renames based on its tag and serial tail — clean, readable, and dynamic.

🔚 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.

<#
.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
}
Next
Next

Automate Intune Device Group Creation Based on Your OU Structure