Skip to content

Exclusive Computer Renaming with Intune and Azure

During an engagement with a customer, there was a demand to have all computers in Endpoint Manager/Intune renamed. They wanted a naming standard including the two-character ISO country code from the device owner followed by the serial number of the device. Let me explain how this was solved by Graph API from a PowerShell script running in an Azure Runbook.

The Mission

The mission is to have all Windows devices in Microsoft Endpoint Manager follow a specified naming standard giving the device a unique name consisting of a country code and the device serial. This could look like this for a computer used by a Norwegian user NO-132435465768. The solution must address existing and new devices.

The challenge with this design is related to compiling a device name consisting of the country code found at the user owning the device and the serial found on the device it self. I have found examples online for renaming endpoints, but these did not get hold of the country codes from the user to use as part of the new device name. Some of these examples include:

New devices and autopilot profiles

During the initial phase of this project, I did design a configuration for Autopilot, allowing the devices to start out with the correct device name upon the initial onboarding. This was based on several group tags matched with corresponding AutoPilot profiles. A specialized menu was built in order to ease the hash collection and, at the same time, have the group tag specified.

The menu used for selecting country code when getting the hardware hash code for AutoPilot

This did work as expected for new computers. The hash got a Grouptag specified pr. device based on the operators choice when collecting the hash. When uploaded to Intune, the Grouptag did match with an Azure dynamic device group which in turn was targeted towards the corresponding autopilot profile setting the correct name on the device. Magic!

Although this was a full-blown technical solution, it didn’t meet the expectations of easy implementation from the first-line helpdesk. The setup was therefore reversed, leaving one common autopilot profile for each and every Windows device in the tenant.

Existing devices and renaming with script

Initially, this was thought as a one-shot run to rename existing devices. As the first phase of naming new machines during Autopilot was neglected, the challenge is somewhat extended to renaming devices on a regular basis. This has led to a PowerShell script running in an Azure Runbook on a schedule once pr. day.

Pseudo Code

The script has a hash table with current countries. The script will recure the country list selecting all users belonging to each country, and further on list each device belonging to those users.

Attributes from the user give access to information about the country, while attributes from the device give information about the serial number.

The script considers the maximum length of 15 characters for computer names. This gives the fundaments for renaming the computer to the given naming standard. A rename will be initiated if the existing computer name differs from the standard.

Azure App Registration

The script authenticates through an Azure App Registration which has the following Microsoft Graph API application permissions:

  • DeviceManagementManagedDevices.PrivilegedOperations.All
  • DeviceManagementManagedDevices.ReadWrite.All
  • Directory.Read.All
  • User.Read

The app secret for the app registration is created with PowerShell in order to have extra life time:

$startDate = Get-Date
$endDate = $startDate.AddYears(9)
$ObjectID = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'
$aadAppsecret01 = New-AzureADApplicationPasswordCredential -ObjectId $ObjectID -StartDate $startDate -EndDate $endDate
($aadAppSecret01).Value
PowerShell

Azure Runbook

The TenantID, ClientID and ClientSecret from the app registration are stored as encrypted variables in the Azure Runbook.

Encrypted variables stored in the runbook

The runbook does have most of the modules loaded already, except for the Microsoft.Graph.Authentication module, which has to be added from the Gallery.

The script can now be added, published, and linked to a schedule in the runbook. The script is available on my Github and has some comments throughout the code describing the process.

<#
  .NOTES
  ===========================================================================
   Created on:   	09.05.2022
   Created by:   	Simon Skotheimsvik
   Filename:     	MEM-ChangeOfComputerNames-Runbook.ps1
   Instructions:    https://skotheimsvik.no/rename-computers-with-countrycode-in-intune
  ===========================================================================
  
  .DESCRIPTION
    This script uses the Graph API to bulk rename Windows devices. It can
    for example be used in a scenario where autopilot default naming has
    been used and a new standardised naming convention has been agreed upon.
    This Script will use the Country Code from the owning users 
    Azure Account. It can be modified to use other user variables as well.

    The script is designed to run unattended in an Azure Runbook.

    Prerequisits:
    - Az.Storage
    
  .EXAMPLE
    MEM-ChangeOfComputerNames-Runbook.ps1 
#>

$GLOBAL:DebugPreference = "Continue"

$Countries = @{
    Norway    = "NO"
    Vietnam   = "VN"
    Brazil    = "BR"
    Chile     = "CL"
    Croatia   = "HR"
    India     = "IN"
    Italy     = "IT"
    Poland    = "PL"
    Romania   = "RO"
    Singapore = "SG"
    Canada    = "CA"
}

# CONNECT TO GRAPH WITH AZURE APP-REGISTRATION
$TenantId = Get-AutomationVariable -Name 'Computer_Rename_TenantID'
$ClientId = Get-AutomationVariable -Name 'Computer_Rename_ClientID'
$ClientSecret = Get-AutomationVariable -Name 'Computer_Rename_ClientSecret'

# Create a hashtable for the body, the data needed for the token request
# The variables used are explained above
$Body = @{
    'tenant'        = $TenantId
    'client_id'     = $ClientId
    'scope'         = 'https://graph.microsoft.com/.default'
    'client_secret' = $ClientSecret
    'grant_type'    = 'client_credentials'
}

# Assemble a hashtable for splatting parameters, for readability
# The tenant id is used in the uri of the request as well as the body
$Params = @{
    'Uri'         = "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token"
    'Method'      = 'Post'
    'Body'        = $Body
    'ContentType' = 'application/x-www-form-urlencoded'
}

$AuthResponse = Invoke-RestMethod @Params

$Headers = @{
    'Authorization' = "Bearer $($AuthResponse.access_token)"
}

# Connect-MgGraph with Token in order to be able to post a computer renaming
$connection = Invoke-RestMethod `
    -Uri https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token `
    -Method POST `
    -Body $body
 
$token = $connection.access_token
Connect-MgGraph -AccessToken $token

write-output "Authentication finished"

############################################################
# ROUTINE FOR RENAMING USERS AUTOPILOT DEVICES
############################################################

foreach ($CountryCode in $Countries.keys) {
    write-output "Working on country $CountryCode"
    $Country = $CountryCode
    $CountryCode = $($Countries[$Country])
    $MaxSerialLength = (15 - $CountryCode.get_Length()) - 1 #Max 15 characters allowed in devicename. Calculate length of serial# part.
    $userList = $Null

    # Get all users with the current country code. Use paging in order to get more than 999 which is max pr query
    $UsersURL = 'https://graph.microsoft.com/v1.0/users?$filter=startswith(country,''' + $Country + ''')&$top=999'
    While ($UsersURL -ne $Null) {
        $data = (Invoke-WebRequest -Headers $Headers -Uri $UsersURL -UseBasicParsing) | ConvertFrom-Json
        $userList += $data.Value
        $UsersURL = $data.'@Odata.NextLink'    
    }

    # Get all managed devices for each user
    foreach ($User in $UserList) {
        $upn = $User.userPrincipalName
        write-output "- Focus on user $upn"
        $DeviceList = $Null
        $deviceURL = 'https://graph.microsoft.com/v1.0/users/' + $User.userPrincipalName + '/managedDevices?$filter=startswith(operatingSystem,''Windows'')'
        $DeviceList = (Invoke-RestMethod -Uri $deviceURL -Headers $Headers).value
        $NoOfDevices = $DeviceList.Count
        write-output "- $NoOfDevices device(s) found"

        foreach ($Device in $DeviceList) {
            $CurrentDeviceName = $Device.deviceName
            write-output "--- Focus on device $CurrentDeviceName"
            $OS = $Device.operatingSystem
            $DeviceID = $Device.id
            $FullSerial = $Device.serialNumber

            # Max 15 characters allowed in devicename - Some devices have to long serialnumber
            if ($FullSerial.get_Length() -gt $MaxSerialLength) {
                $DeviceSerial = $FullSerial.substring($FullSerial.get_Length() - $MaxSerialLength)
                write-output "---- Serial too long - shortened!"
            }
            else {
                $DeviceSerial = $FullSerial
            }
            # Calculates new devicename in format NO-12345678
            $CalculatedDeviceName = $CountryCode.ToUpper() + '-' + $DeviceSerial
            
            # Virtual computers have the text "SerialNumber" as serialnumber...
            if (($CurrentDeviceName -ne $CalculatedDeviceName) -and ($DeviceSerial -ne "SerialNumber")) {
                write-warning "---- Device $CurrentDeviceName needs to be renamed to $CalculatedDeviceName"
                # Calculate graph api url's
                $Resource = "deviceManagement/managedDevices/$DeviceID/setDeviceName"
                $GraphApiVersion = "beta"
                $URI = "https://graph.microsoft.com/$GraphApiVersion/$($Resource)"

                $JSONPayload = @{
                    "deviceName" = $CalculatedDeviceName
                }

                $convertedJSONPayLoad = $JSONPayload | ConvertTo-Json
                
                #Send change to Graph.
                Invoke-MgGraphRequest -Uri $URI -Method POST -Body $convertedJSONPayLoad -Verbose -ErrorAction Continue
            }
            else {
                write-output "---- $CurrentDeviceName will not be renamed"
            }
        }
    }
}

PowerShell

Verify the results

When running the script, all outputs can be found in the logs, and all renamed computers are logged as warnings:

Feedback from the script with renamed computers found as warnings

This is reflected on the device in the Microsoft Intune:

Device waiting to be renamed

As with other renaming requests in Microsoft Intune, it requires the device to reboot before all registers (AzureAD, Intune, AutoPilot, Device) are up to date.

Device rename confirmed in the Intune portal

Summary

This routine will effectively and automatically rename devices on a given schedule as long as the app secret is valid. The script can be easily altered to mix and match variables from user and device in order to create the corresponding device name for your naming convention. You can, for example, use information from the user like department, company, region, postalcode as a part of the computername.

No extra charge for the mistakes – solution shared as it is – use it at your own risk.

Thanks for reading – please share and comment.

Published inAutomationAzureGraphAPIIntuneMEMMicrosoft 365PowershellScriptWindows

3 Comments

  1. […] If you have missed this point on a bunch of devices and feel the need to change existing computer names, you should take a look at my earlier blog post regarding renaming existing enrolled endpoints: Simon does… Exclusive Computer Renaming with Intune and Azure (skotheimsvik.no) […]

  2. […] tags when registering devices for Autopilot. This was first briefly mentioned in my post covering Exclusive Computer Renaming with Intune and Azure and more details have since been requested by the […]

Leave a Reply

Your email address will not be published. Required fields are marked *