I know it is possible to set the computer name before you start the task sequence by adding the OSDComputerName variable to a collection – usually used in the Unknown Computers collection. I know as well how to generate it based on the serial number of the workstation or laptop. Well, this was not enough for me and I decided that it should be possible to auto-assign computer names during Task Sequence based on the current active directory names. To make it even more fun I was determined to get the next available computer name based on domain naming convention (will shorten this to DNC), but only for computers above 1000. Please, do not ask me why I did this to myself. So let’s start. With the drawbacks and how to deal with them.
Drawback Number One – Active Directory Modules are missing in Windows PE and there is no easy way to add them.
Drawback Number 2 – I want to take the name with PowerShell because I know PowerShell and it is so convenient to use it. I know, I know it is easier with LDAP, but I said PowerShell and that’s it. To be honest, I am considering changing it to LDAP, but more on this later.
Infrastructure Involved – MECM version 2207 installed on Server 2016. MDT installed as well.
With all that said I pulled my sleeves and started. The easy part – get the name.
#Get List Of All Computer Names with filtering to exclude some computers
$worstations = Get-ADComputer -Filter {name -like "whatever*" -and name -notlike "*this*" } `
| sort name | select -ExpandProperty name
#Create empty array for computer numbers
$numbers = @()
#Loop computers and get last four only, that's what I need.
#Little logic for numbers above 1000 implemented #as well
foreach ($w in $worstations ){
$getnum = $w.substring($w.length - 4, 4)
if($getnum -gt 1000){
$numbers +=$getnum
}
}
#Make the strings numbers again
$a = [int[]]$numbers
#Loop again and break if the diffidence between two numbers is greater than 1
#[int[]]$numbers = $workstations-replace '\D+'
for ($i = 0; $i -lt $a.Count; $i++) {
if($a[$i + 1] - $a[$i] -gt 1) {
$OSDComputerName= 'DNC{0:00}' -f ($a[$i]+1); break
}
}
#Line 1 goes here
#Print the name so we can see it in task Sequence Monitor and know that it works.
$OSDComputerNameCode language: PHP (php)The above script works perfectly fine in PowerShell, however, not so perfectly in a Task Sequence. To make it work there this line (let’s name it Line 1) should be added, before printing Computer Name is good.
(New-Object -COMObject Microsoft.SMS.TSEnvironment).Value('OSDComputerName') = $OSDComputerName
With that done I moved to Drawback Number 1. To make a long story short I’ll skip the 100 boring tests I did and jump right to the solution. The only reasonable and stable way to do this was to create a package containing AD modules and copy it during the task sequence. In this way, they will stay persistent as long as you are in WinPE. I’ll attach the modules to this post if you want to create one yourself keep the directories structure, it is way easier to copy the modules this way. Thanks to this guy for pointing me in the right direction. Copy command is:
xcopy "ADModules\*.*" "X:\Windows" /D /E /C /I /Q /H /R /Y /SCode language: JavaScript (javascript)
It was time to test, so I set up a task sequence and happily watched how it….. fails. It failed because you cannot browse Active Directory anonymously, you need a user for that. Since we are in WinPe we cannot use “Run this step as the following account” the only way I could figure out was to put the username and password inside the PowerShell script, but this is not the best security approach because the password is exposed in clear text. You know that you have to switch off F8 in your production boot images, right? That’s why I’m considering changing everything to LDAP, but this is a story for another day. Clear text passwords are a big no-no. To remove it from the script I did the following:
- Created a collection variable for the collection in question – All Unknown Computers
- When creating the variable choose name that fits you (mine is named NAPWD) and select “Do not Display this value in Configuration Manager” – this will hide the password. This variable cannot be read-only (the ones starting with underscore _) if you use complex passwords
- In the script add
$tspass = New-Object -ComObject Microsoft.SMS.TSEnvironment
$username = "domain\domainjoinaccount"
$pass = $tspass.Value("NAPWD")
$password = ConvertTo-SecureString -AsPlainText $pass -Force
$Cred = New-Object System.Management.Automation.PSCredential $psername,$password
$worstations = Get-ADComputer -Filter {name -like "whatever*" -and name -notlike "*morewhatever*" } -Server yourdomaincontroller -Credential $Cred | sort name | select -ExpandProperty name | Sort-Object name | Select-Object -ExpandProperty name
This works, however, it leads to a new Drawback – how to ensure that computer names are not overwritten if you are imaging multiple workstations at once? The only solution I see is to add the computer to the active directory immediately after the name is calculated. With this, our final script looks like that:
Import-Module activedirectory | Out-Null
$tspass = New-Object -ComObject Microsoft.SMS.TSEnvironment
$username = "domain\username"
$pass = $tspass.Value("NAPWD")
$password = ConvertTo-SecureString -AsPlainText $pass -Force
$Cred = New-Object System.Management.Automation.PSCredential $Username,$Password
$wst = Get-ADComputer -Filter {name -like "whatever*" -and name -notlike "*morewhatever*"} -Server domaincontroller -Credential $Cred | Sort-Object name | Select-Object -ExpandProperty name
$numbers = @()
foreach ($w in $wst){
$getnum = $w.substring($w.length - 4, 4)
if($getnum -gt 1000){
$numbers +=$getnum
}
}
$a = [int[]]$numbers
#[int[]]$numbers = $wst -replace '\D+'
for ($i = 0; $i -lt $a.Count; $i++) {
if($a[$i + 1] - $a[$i] -gt 1) {
$OSDComputerName = 'DNC{0:00}' -f ($a[$i]+1); break
}
}
(New-Object -COMObject Microsoft.SMS.TSEnvironment).Value('OSDComputerName') = $OSDComputerName
New-ADComputer -Name $OSDComputerName -SamAccountName $OSDComputerName -Path "OU=Windows 10,OU=Workstations,OU=CONTOSO,DC=DOMAIN,DC=COM" `
-Enabled $True -DOMAINCONTROLLER -Credential $Cred
$OSDComputerName
Don’t forget to change the username, domain name, and OU PATH also adapt filters to your needs. AD modules are here. I copy them in the beginning of the task sequence. Set Computer name step I put between Apply Windows Setting and Apply Network Settings, seems the best location.
Hope it helps someone, if you have any questions leave me a comment.
Hi Thanks for sharing this, regarding the ADModule, where should i add the zip file? I’m confused a little bit
Hello Ahmed,
First, apologies for the significantly delayed reply. To make this work, you must unzip the files and create a package with source files. Then, in the task sequence, you add the run command line step with the copy command and your newly created package. After that, run the script to name it in the “Run PowerShell Script” step. I do this before the “Apply Operating System” step. If you still need help with something, leave me another comment; I will try to be faster this time 🙂
Would you know how to name the computer based on locations we have set to a 3 digit number then a single letter set through a variable then a 2 or 3 digit number string at the end. We currently do this with MDT Integrated which allows also to only use a name that is not in use. We are curerntly removing MDT and trying to mimic the same from native MECM. Thanks for any advice
Hi John,
seems possible with an additional variable. Which part of the name is unique and what you set manually?
Hi there, thanks for the reply, Currently we name computers with an X at the start then a 4 digit code based on location e.g. X2041 = Liverpool. We use the TSGui which has all the locations in a dropdown list. if I select a site like 2041, it generates a variable for 2041 = VAR_2041 and same if I select in another dropdown list Desktop it creates a variable for desktop “VAR_D” or “VAR_L” for laptop and finally 2 x number at the end from 00 to 99. Trying to figure out how to check AD or SQL DB for an unused name and then use the variables ideally to populate the osdcomputername or something 🙂
Hi Ivan thanks again for getting back to me, I did comment more 20 mins ago, but the comment seems to have disappeared from here, maybe just till approved or something. I will mention again here incase the previous comment is awol. We have devices named as follows X2041D21 Prefix is always X then the 4 digits e.g. 2041 = site in Liverpool as an example, then the D for desktop and then the last 2 digits e.g. 21 is just any number between 00 – 99. We use TSGui and at the start of the build it pops up with sites and roles etc, so each site has the 4 digit code specific and selecting the site will create a variable e.g. VAR_2041 (in this case). Then also we can select in a drop down Desktop/Laptop/Tablet which again produces another variable e.g. VAR_D. Was trying to figure out a way to populate the name accordingly and if its a new unknown build then check AD for the available name, basically the last 2 digits of any selected site. Some of our build engineers have no access to AD to check if a name exists already before they could manually name the new PC with a new name, Currently I have just removed MDT from MECM and created a new native MECM build sequence, only thing our company was very dependant on MDT especially for Roles and auto naming devices according to site and role etc. MECM doesn’t have this same functionality by default it seems.. Not sure hoe to query the CM DB like what happens with MDT to auto get a name for anew computer, hope this makes sense. I will copy this comment before posting incase it disappears :). Cheers again for any advice/help you can give..
Twice I’ve commented but both don’t show here now, hope you got the additional comments??
Good Morning, John,
I wasn’t in front of the computer yesterday. My example automates the naming completely, but can be adapted to do something different. I am simplifying here to give an idea of how this could be done. Let’s say that you have two variables in the “All Unknown Computers” collection:
OSDComputerName – which gives the name of the computer
NAPWD – containing the password of the domain join account, hidden.
By default, Active Directory adds all newly joined computers to a specific OU. My domain join account has rights to create computers there, but not to delete them, as a mechanism to prevent overwriting. When you start the task sequence, you add, for example, a desktop named X2041D to the OSDComputerName variable. What you write is just for checking where it belongs, it will be overwritten later. Then the rest goes as usual until it reaches the naming step. Do not forget to copy the ad modules first! Then we put a little logic in the script, something like
if($tsCompName -contains “X2041d”){
$wst = Get-ADComputer -searchbase “OU=Liverpool,DC=contost,DC=com” -filter * -Server yourDCFQDN -Credential $Cred | Sort-Object name | Select-Object -ExpandProperty name
}
You’ll need an if/else for all of your locations/cases.
For two digits only, the next part of the script will be:
foreach ($w in $wst){
$getnum = $w.substring($w.length – 2, 2)
$numbers +=$getnum
}
#Create an array
$a = [int[]]$numbers
#Loop until you find a free computer name
for ($i = 0; $i -lt $a.Count; $i++) {
if($a[$i + 1] – $a[$i] -gt 1) {
$OSDComputerName = ‘$($tsCompName){0:00}’ -f ($a[$i]+1); break
}
}
$tsCompName = $OSDComputerName
$tscn.value(“OSDComputerName”) = $tsCompName
#Add the computer with the generated name
New-Adcomputer -Name $tsCompName -Server YourDcFQDN -Credential $Cred -Description $desc
#print the name so you can see it in the ts monitoring for troubleshooting
$tscn.value(“OSDComputerName”)
I hope you get the idea. This is quick and dirty, and it will likely fail somewhere along the way. I have no time to test it. Try to do it yourself and if you get stuck ping me, I’ll try to help you if I have time.