Automating Computer Naming after Deploying Windows 10 Images

I was recently at a client planning on delivering a Windows 10 Pilot as normal.  However, during our kick off meeting a wrench was thrown into our standard practice.  The client didn’t have a working Configuration Manager or MDT environment and still used Ghost to deploy images.  Over all not a bad thing just not what I was expecting.  I haven’t touched Ghost in years and have been using MDT for image builds for some time now followed by ConfigMgr for image deployments.  Long story short, we helped design the Windows 10 image but had to be hands off on the Ghost part since this wasn’t part of our Windows 10 Pilot.  Even though using older technology the client had built up a pretty decent environment to deploy Windows 7 images with about 90% automation on the deployment piece.  The same practice they would use for deploying our Windows 10 image but of course with some draw backs.  Ghost can’t partition the BIOS using UEFI which means some of the security features are no available in Windows 10. Also, they used very thick images with everything installed and very little room for customization after the image or during the image deployment.

The only piece to the puzzle that they hadn’t been able to complete was getting their machines to automatically get named after imaging.  This is no issue with ConfigMgr or MDT but creating an automatic way to do this remotely would be interesting.  99% of these machines are all based in computer labs.  Which means they would wipe and load an entire lab remotely and still have to run up to that lab a few hours later to manually name each machine and join it to the domain.  The names would come from a txt file that had two columns, MAC address and Computer Name.  The MAC address would represent the MAC address in one of their many computer labs.  The computer name would be associated to that MAC address.  This way, the machine name would never change and the current way they managed their systems wouldn’t be effected.

Easy right?  Machine boots back up, auto logs on after image deployment, script runs and machine is renamed and joined to the domain.  Yes, that is what I had thought as well.  The issue we have is every one of these machine accounts are still active in Active Directory.  During the imaging process they didn’t disable or reset the machine accounts in Active Directory so when trying to join a machine and rename it to a name already in Active Directory we would get the account already exist in AD error and then well, nothing.  This can be done easily if you join the machine name manually, however, trying to use the Add-Computer Cmdlet, this is not allowed since it is trying to create a new object in Active Directory and it is being denied.  I tried the Join-Computer Cmdlet first, followed by the Add-Computer Cmdlet with the -NewComputer option but it would still fail with the error Account Already Exist error.

So this is my solution, it may not be the best solution but it worked for my client.  It includes three PowerShell scripts.  The first, Set-ComputerName.ps1 will query the ComputerList.txt file for a computer name associated to it’s MAC Address, then it will rename the computer.  If the computer doesn’t exist in the list, it will then pause and prompt for a computer name which will then rename the computer. Before the script reboots, it edits a few registry key entries to allow for autologon, giving it the local admin and password account and also creating a RunOnce key to point to the next PowerShell script, Set-JoinDomain.ps1 on logon.  You can see where I am going here?  The machine reboots, auto logs on as a local administrator account then launches the Set-JoinDomain.ps1 script with executive rights and admin rights.  The Set-JoinDomain.ps1 script then checks to see if the machine is on the domain, if so continues without joining the domain.  If not on the domain, it will than join the machine to the domain.  Before it reboots, the script adds a RunOnce value in the registry to start the last PowerShell script to clean up our scripts.  Why?  Because we didn’t encrypt the password and we don’t want existing scripts sitting around with user names and passwords in them.  On reboot, the computer logs on again, and starts the Cleanup.ps1 script.  This removes all our scripts and also removes the Unattend.xml file from previous Sysprep’s.  (I know, don’t ask.)  Before the script reboots for one last time, it then resets the Registry values back to default.  The machine reboots, and bingo, now has the correct name and is joined to the domain.  No interaction needed.

Here are my scripts and some basically explanation of what they did.  For those expert PowerShell guys/gals out there, yes I know it could be written different and more than likely better but hey, this works.

The three scripts are Set-ComputerName.ps1, Set-JoinDomain.ps1, and Cleanup.ps1.  Then the ComputerList.txt example as well.

 

Editable Variables

The following variables are configured to be editable and can change without effecting the scripts performance.

Set-ComputerName.ps1

# Editable Variables for script

$Domain = “NetBIOS Domain”

$DNSDomain = “FQDN”

$DomainUser = ‘DOMAINUSERHERE’

$DomainPass = “DOMAINPASSWORDHERE”

$LocalAdmin = “Administrator”

$LocalPass = “LOCALPASSWORD”

$Timeout = “30”

$FileName = “ComputerList.txt”

$Share = ‘\\servername\$secure’

$NetworkDrive = “W:\1. SYSPREP\NameList\”

 

$Domain is the NetBIOS Domain Name.

$DNSDomain name is the Fully Qualified Domain Name.

$DomainUser is the user account that has correct AD rights to join a machine to the domain. $DomainPass is the password for the domain account used to join a machine to the domain. $LocalAdmin is the local administrator account used to log a machine on when rebooted.

$LocalPass is the local administrator account password used to log a machine on when rebooted.

$TimeOut is the seconds the script will wait. This is not needed but will stay in the script for now.

$FileName is the name of the file that the script will check for computer names and existing MAC addresses.

$Share is the location of the filename.

$NetworkDrive is the drive letter that will be mapped when the script maps a network share.

 

Set-JoinDomain.ps1

# Editable Variables for script

$Domain = “NetBIOS domain”

$DNSDomain = “fqdn”

$DomainUser = ‘DOMAINUSERHERE’

$DomainPass = “DOMAINPASSWORDHERE”

$Timeout = “30”

 

$Domain is the NetBIOS Domain Name.

$DNSDomain name is the Fully Qualified Domain Name.

$DomainUser is the user account that has correct AD rights to join a machine to the domain. $DomainPass is the password for the domain account used to join a machine to the domain.

 

Cleanup.ps1

# Editable Variables for script

$ScriptDir = “C:\Windows\Setup\Scripts\*”

$UnAttend = “C:\Windows\System32\sysprep\unattend.xml”

 

$ScriptDir is the location of the scripts that need to be removed during cleanup.

$UnAttend is the location of the unattended.xml file that needs to be removed.

Non-Editable Variables

The following variables are not to be edited. If so it can affect the scripts performance.

Set-ComputerName.ps1

# Set Variables. Do not edit.

$ScriptDir = Split-Path $script:MyInvocation.MyCommand.Path

$ComputerMAC = Get-WmiObject win32_networkadapterconfiguration -Filter ‘ipenabled = “true”‘ | select MACAddress

$cred = New-Object System.Management.Automation.PsCredential(“$domain\$DomainUser”, (ConvertTo-SecureString “$DomainPass” -AsPlainText -Force))

New-PSDrive -Name “W” -PSProvider “FileSystem” -Root “$Share” -Credential $Cred

$ComputerList = Import-Csv -Path “$Networkdrive\$FileName”

 

Set-JoinDomain.ps1

# Set Variables. Do not edit.

$cred = New-Object System.Management.Automation.PsCredential(“$domain\$DomainUser”, (ConvertTo-SecureString “$DomainPass” -AsPlainText -Force))

$ComputerName = Hostname

$ScriptDir = Split-Path $script:MyInvocation.MyCommand.Path

 

$RunOnceKey = “HKLM:\Software\Microsoft\Windows\CurrentVersion\RunOnce”

set-itemproperty $RunOnceKey “ConfigureComputer” (“C:\Windows\System32\WindowsPowerShell\v1.0\Powershell.exe -NoExit -executionPolicy Bypass -File $ScriptDir\Cleanup.ps1”)

 

Cleanup.ps1

# Set Variables. Do not edit.

$ComputerName = Hostname

 

The Computer List

The computer list is a basic comma separated text file. It includes two columns with headers.

MAC,CN
34:17:b:cc:44:eb,MachineName
34:17:eb:b3:63:e0,MachineName

 

 

The Set-ComputerName.ps1 Full Script

 

# —————————————————————————–

# Script: Set-ComputerName

# Author: Kris Turner

# Date:   1/20/2017

# Keywords:

# comments:

# v6 Updates:

# Changed location where script looks for ComputerList.txt from local drive to a shared network drive.

# —————————————————————————–

 

# Editable Variables for script

$Domain = “NETBIOS”

$DNSDomain = “FQDN”

$DomainUser = ‘DOMAINUSERHERE’

$DomainPass = “DOMAINPASSWORDHERE”

$LocalAdmin = “Administrator”

$LocalPass = “LOCALPASSWORD”

$Timeout = “30”

$FileName = “ComputerList.txt”

$Share = ‘\\SERVERNAME\$secure’

$NetworkDrive = “W:\1. SYSPREP\NameList\”

 

# Set Variables. Do not edit.

$ScriptDir = Split-Path $script:MyInvocation.MyCommand.Path

$ComputerMAC = Get-WmiObject win32_networkadapterconfiguration -Filter ‘ipenabled = “true”‘ | select MACAddress

$cred = New-Object System.Management.Automation.PsCredential(“$domain\$DomainUser”, (ConvertTo-SecureString “$DomainPass” -AsPlainText -Force))

New-PSDrive -Name “W” -PSProvider “FileSystem” -Root “$Share” -Credential $Cred

$ComputerList = Import-Csv -Path “$Networkdrive\$FileName”

 

# Timeout period if needed. Can remove section.

# This section was placed in here for issues we had needed a 30-minute timeout period.

cls

Write-Host “Waiting $TimeOut Seconds”

Start-Sleep -Seconds $Timeout

cls

 

 

# Checks list for MAC Address and Computer Name

ForEach ($Computer in $ComputerList)

{

$FileComputerName = $Computer.CN

$FileComputerMAC = $Computer.MAC

 

If ($ComputerMAC -match $FileComputerMAC)

{

Write-Host $FileComputerName matches the localhost MAC Address: $ComputerMAC

$NewComputerName = $FileComputerName

}

}

 

# If computer isn’t on list the script will prompt for computer name to continue.

If ($NewComputerName -eq $Null)

{

Write-Host “Computer is not found in computer list. Please check that this machines MAC Address and computer name is on the list.” -ForegroundColor Red

Write-Host “Please manually rename computer and join it to domain at this time.” -ForegroundColor Yellow

Start-Sleep -Seconds 5

cls

 

# Prompt for computer name to manually join to domain.

$PromptComputerName = Read-Host -Prompt ‘Please enter desired computer name then hit enter. (Example: coe-lab-e333) ‘

Write-Host “Computer will be renamed to $PromptComputerName then rebooted. Then joined to the $DNSDomain domain and rebooted.” -ForegroundColor Yellow

Rename-Computer -NewName $PromptComputerName -Force -Verbose

 

 

# Adds RunOnce line to registry for HKLM and reboot machine.

 

Set-ItemProperty -Path “HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon” -Name DefaultUserName -Value “$LocalAdmin”

Set-ItemProperty -Path “HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon” -Name DefaultPassword -Value “$LocalPass”

#Set-ItemProperty -Path “HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon” -Name DefaultDomainName -Value “$PromptComputerName”

Set-ItemProperty -Path “HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon” -Name AutoAdminLogon -Value “1”

Set-ItemProperty -Path “HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon” -Name ForceAutoLogon -Value “1”

 

$RunOnceKey = “HKLM:\Software\Microsoft\Windows\CurrentVersion\RunOnce”

set-itemproperty $RunOnceKey “ConfigureComputer” (“C:\Windows\System32\WindowsPowerShell\v1.0\Powershell.exe -NoExit -executionPolicy Bypass -File $ScriptDir\Set-JoinDomain.ps1”)

 

 

Write-Host “$PromptComputerName will reboot in 30 seconds.” -ForegroundColor Yellow

Start-Sleep -Seconds 30

Restart-Computer

 

}

Else

{

Write-Host “This new computer name will be: $NewComputerName” -ForeGroundColor Green

}

 

# Will rename computer and then reboot system and start the join-domain script.

Write-Host “Computer will be renamed to $NewComputerName then rebooted. Then $NewComputerName will be joined to the $DNSDomain domain.” -ForegroundColor Yellow

Rename-Computer -NewName $NewComputerName -Force -Verbose

 

Set-ItemProperty -Path “HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon” -Name DefaultUserName -Value “$LocalAdmin”

Set-ItemProperty -Path “HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon” -Name DefaultPassword -Value “$LocalPass”

Set-ItemProperty -Path “HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon” -Name DefaultDomainName -Value “$NewComputerName”

Set-ItemProperty -Path “HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon” -Name AutoAdminLogon -Value “1”

Set-ItemProperty -Path “HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon” -Name ForceAutoLogon -Value “1”

 

$RunOnceKey = “HKLM:\Software\Microsoft\Windows\CurrentVersion\RunOnce”

set-itemproperty $RunOnceKey “ConfigureComputer” (“C:\Windows\System32\WindowsPowerShell\v1.0\Powershell.exe -NoExit -executionPolicy Bypass -File $ScriptDir\Set-JoinDomain.ps1”)

 

# Restarting Computer

Write-Host “$NewComputerName will reboot in 30 seconds.” -ForegroundColor Yellow

start-sleep -Seconds 30

Restart-Computer

 

 

The Set-JoinDomain.ps1 Full Script

 

# —————————————————————————–

# Script: Set-JoinDomain

# Author: Kris Turner

# Date:   1/20/2017

# Keywords:

# comments: This script depends on the Set-ComputerName.ps1 script to have ran and rebooted the machine.

#

# —————————————————————————–

 

 

# Editable Variables for script

$Domain = “NetBIOS DOMAIN”

$DNSDomain = “FQDN”

$DomainUser = ‘DOMAINUSERHERE’

$DomainPass = “DOMAINPASSWORDHERE”

$Timeout = “30”

 

 

# Set Variables. Do not edit.

$cred = New-Object System.Management.Automation.PsCredential(“$domain\$DomainUser”, (ConvertTo-SecureString “$DomainPass” -AsPlainText -Force))

$ComputerName = Hostname

$ScriptDir = Split-Path $script:MyInvocation.MyCommand.Path

 

$RunOnceKey = “HKLM:\Software\Microsoft\Windows\CurrentVersion\RunOnce”

set-itemproperty $RunOnceKey “ConfigureComputer” (“C:\Windows\System32\WindowsPowerShell\v1.0\Powershell.exe -NoExit -executionPolicy Bypass -File $ScriptDir\Cleanup.ps1”)

 

 

# Checks to see if machine is domain joined already. If domain joined will restart computer.

If ((Get-WmiObject Win32_Computersystem).partofdomain -eq $true)

{

Write-Host -ForegroundColor Red “This computer is a domain joined computer!”

Start-Sleep -Seconds 5

Write-Host “$ComputerName will reboot in 30 seconds.” -ForegroundColor Yellow

Start-Sleep -Seconds 30

Restart-Computer

}

Else

{

Write-Host -ForegroundColor Green “This computer is not domain joined. Will now continue to join computer to the domain.”

}

 

# Joins domain and restarts computer

Add-Computer -DomainName “$DNSDomain” -Credential $cred -Restart -Force -Verbose

 

 

The Cleanup.ps1 Full Script

 

# —————————————————————————–

# Script: Cleanup.ps1

# Author: Kris Turner

# Date:   1/25/2017

# Keywords:

# comments: To be used to cleanup scripts after running. This script is dependant on Set-JoinDomain.ps1 script.

#

# —————————————————————————–

 

# Editable Variables for script

$ScriptDir = “C:\Windows\Setup\Scripts\*”

$UnAttend = “C:\Windows\System32\sysprep\unattend.xml”

 

# Set Variables. Do not edit.

$ComputerName = Hostname

 

 

# Remove the runonce

Write-Host “Resetting AutoAdminLogon Registry settings”

Set-ItemProperty -Path “HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon” -Name AutoAdminLogon -Value “0”

Set-ItemProperty -Path “HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon” -Name ForceAutoLogon -Value “0”

 

# Deleting Scripts and Unattended File.

Write-Host “Deleting all files in the Setup directory and the Sysprep Unattended File”

Remove-Item $ScriptDir

Remove-Item $UnAttend

New-Item C:\Windows\Setup\Scripts\autonamecomplete.txt -ItemType File -Value “Auto Name Script Complete!” -Force

 

# Restarting Computer

Write-Host “$ComputerName will reboot in 30 seconds.” -ForegroundColor Yellow

start-sleep -Seconds 30

Restart-Computer

 

 

 

 

 

 

 

Advertisements
Tagged with: , , , , ,
Posted in Active Directory, OSD, PowerShell, Windows 10

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow Kristopher Jon Turner on WordPress.com
Archives
%d bloggers like this: