Update-3: Added example for using the GetCMFirstAvailableNameSequence() function.
Update-2: fixed spelling of Nickolaj. Changed coffee brand. Moved lawn rake.
Updated-1 11/6: Corrected a few bone-headed mistakes. (1) ConfigMgrWebService author is Nickolaj Andersen (sorry about that), but I still need to let Maurice finish his dinner. (2) There is a function provided for querying the next available incremental name in a numbered sequence, from CM not AD, GetCMFirstAvailableNameSequence. So at least some of this post still holds up. Geez, this coffee just isn’t strong enough anymore.
As if there aren’t enough types of paint to inhale already, much like the wide variety of methods for naming devices, here’s one that was interesting and fun to automate. This is for environments where devices need to be named in an numerical incremental fashion.
Background
- Devices use a standard prefix based on form-factor (e.g. Chassis Type) such as “WS”, and “LT”.
- Unique portion is appended as an incremental value (e.g. 001, 002, …)
- Examples: “WS001”, “LT003”
Challenge
- How to determine the next available name in the Active Directory domain, during an OSD task sequence, provided only with the prefix portion such as “WS”.
- Solution should “fill-in” missing gaps in names found in AD, such as 001, 002, 004 (should return 003 as next available).
Approach
- Obtain device characteristics from WMI using PowerShell
- Obtain the next available account in AD by querying the ConfigMgrWebService using PowerShell.
I’ve seen quite a few ways to address this, from importing modules and using ADSI queries, etc., all of which involve PowerShell (and why not?!).
I’ve spent the better part of the last year helping customer move to “Modern Driver Management” using SCConfigMgr’s solution set (click here for more details), so I remembered ConfigMgrWebService also provides more query functions besides GetCMDrivePackageByModel.
The GetADComputer function looks closest to what I wanted, but it only returns one result per query (ask for a computer, get back one computer). No option that I could see for getting a list, much less a filtered list, of computer names in AD. I could have just bothered Maurice for like the 42nd time, but the poor guy needs to enjoy dinner in peace too. And there’s a very easy way to leverage that function as-is.
The example (below) takes the web service URI, the web service “secret key”, and naming pattern parameters, and loops through AD starting with a base index name of 1 (or 001). I set an arbitrary limit of 100 instances per prefix, but this can all be modified to whatever is needed.
[CmdletBinding()]
param (
[parameter(Mandatory)][ValidateNotNullOrEmpty()][string] $URI,
[parameter(Mandatory)][ValidateNotNullOrEmpty()][string] $SecretKey,
[parameter(Mandatory)][ValidateNotNullOrEmpty()][string] $Prefix,
[parameter()][ValidateRange(3,15)][int] $NameLength = 4
)
try {
Write-Verbose "connecting to web service at $URI"
$ws = New-WebServiceProxy -Uri $URI -ErrorAction 'stop'
for ($index = 1; $index -lt 100; $index++) {
$nextname = $Prefix + $([string]$index).PadLeft($NameLength - $($Prefix.Length), "0")
Write-Verbose "checking name: $nextname"
$found = ($ws.GetADComputer($SecretKey, $nextname)).SamAccountName
if (![string]::IsNullOrEmpty($found)) {
Write-Verbose "name exists: $nextname"
}
else {
return $nextname
}
}
Write-Output "no names for this prefix available from 1 to 100"
}
catch {
Write-Error $_.Exception.Message
}
The -NameLength parameter controls the overall length of the names to check and return value. Again, I set an arbitrary range of 3 to 15 characters (example: “WS1” to “WS0000000000001”). Here’s the results when I run this against my AD domain which already has devices WS01, WS02, WS03, WS09 and WS10…

It’s pretty quick. In my tests it runs about 20 to 30 names per second.
(updated) Using the built-in GetCMFirstAvailableNameSequence() function, it would be like the following…
try {
Write-Verbose "connecting to web service at $URI"
$ws = New-WebServiceProxy -Uri $URI -ErrorAction 'stop'
$nextSuffix = $ws.GetCMFirstAvailableNameSequence($SecretKey, $NameLength, $Prefix)
$nextname = "$Prefix$nextSuffix"
Write-Verbose "checking name: $nextname"
return $nextname
}
catch {
Write-Error $_.Exception.Message
}
To directly assign the output to a task sequence variable, like OSDComputerName, just wrap the code in a function block (i.e. Get-NextADDeviceName), and append a few more lines to assign the output…
$newname = Get-NextADDeviceName
try {
$tsenv = New-Object -COMObject Microsoft.SMS.TSEnvironment
$tsenv.Value("OSDComputerName") = $newname
}
catch {
Write-Warning "not running in a task sequence at the moment"
}
Putting all this together it looks like the following, but I’m sure you will see it can be improved a great deal…
[CmdletBinding()]
param (
[parameter(Mandatory)][ValidateNotNullOrEmpty()][string] $URI,
[parameter(Mandatory)][ValidateNotNullOrEmpty()][string] $SecretKey,
[parameter(Mandatory)][ValidateNotNullOrEmpty()][string] $Prefix,
[parameter()][ValidateRange(3,15)][int] $NameLength = 4
)
fuction Get-NextADDeviceName {
try {
Write-Verbose "connecting to web service at $URI"
$ws = New-WebServiceProxy -Uri $URI -ErrorAction 'stop'
for ($index = 1; $index -lt 100; $index++) {
$nextname = $Prefix + $([string]$index).PadLeft($NameLength - $($Prefix.Length), "0")
Write-Verbose "checking name: $nextname"
$found = ($ws.GetADComputer($SecretKey, $nextname)).SamAccountName
if (![string]::IsNullOrEmpty($found)) {
Write-Verbose "name exists: $nextname"
}
else {
return $nextname
}
}
Write-Output "no names for this prefix available from 1 to 100"
}
catch {
Write-Error $_.Exception.Message
}
}
# call the function and get the next available name
$newname = Get-NextADDeviceName
Write-Verbose $newname
try {
$tsenv = New-Object -COMObject Microsoft.SMS.TSEnvironment
$tsenv.Value("OSDComputerName") = $newname
}
catch {
Write-Warning "not running in a task sequence at the moment"
}
From here, it’s simply a matter of adding it to the task sequence, using Run PowerShell Script. If you need an example for querying the chassis type, check out my earlier post on computer naming.
Cheers!