Wednesday, 8 August 2018

Changing the Windows ComputerName after installation (e.g. to contain the system Serial Number)

It is often the case that the System Admin wants the Windows ComputerName to reflect some aspect of the system itself, such as the system serial number or DELL Service Tag (7,10 or 11 characters) or perhaps the MAC address of the Ethernet adapter.

The main problem is that the Serial Number of the target system cannot be determined until after Setup (WinPE) has booted.

I wanted to try to alter the ComputerName during an automated SDI_CHOCO install using Easy2Boot and a Windows 10 ISO + XML file...


 Experiments...

My first thought was that I could modify the XML file during the WinPE pass (first boot stage of Setup - before the target hard disk is even formatted). However, this did not work because it seems that Setup reads the AutoUnattend.xml file from the USB drive (or from inside the boot.wim file) before the E2B LOADISONP.cmd script is run and then, after Setup copies the Windows source files onto the target hard drive, Setup writes the XML file to the C: drive from its cache in memory. i.e. even though I changed the ComputerName field in the \AutoUnattend.XML file when LOADISONP.CMD ran, the file that was copied to C:\Windows\Panther\Unattend.xml contained the original XML with the old ComputerName setting!

My next thought was that I could change the C:\Windows\Panther\Unattend.xml file on the next reboot during the Specialize pass (after the drive has been formatted and the Windows files copied over). However, I found that WMIC would not work in the Specialize pass, but even if I changed the file manually, it still did not change the ComputerName at this stage either!

So this left me with having to change the ComputerName during the OOBE phase which is after the ComputerName has already been set. So I added the following code to the MyStartup.cmd file in my SDI_CHOCO configuration file. It seems to do the trick.

If you try it, look at the log file afterwards at C:\Temp\MyStartup.log to see the zz* variables to decide which one you want to use for the new ComputerName.

Note that setting a computername of longer than 15 characters will fail, and some characters are not allowed. Do not use any of these characters when naming Windows computers: (space) / \ * , . " @.

Also, it is recommended that you do not use lowercase letters for the ComputerName because some older operating systems apparently don't like seeing computers on a network with lowercase letters in their computer names.

The zz* variables will contain various values which have been extracted from the system.

If you want to use a prefix (e.g. NEW-) you can use something like
set NEWPC=NEW-%zzbiosserial%

If NEWPC is longer than 15 characters then the last few characters will always be removed by the script.

So you should ensure that the NEWPC value is always set to 15 characters or less.
You can use:
set NEWPC=%NEWPC:~-15%
if you want to only use the last 15 characters of the string instead of the first 15 characters.


Example .cmd script to change the ComputerName

This example uses only the BIOS serial number as the ComputerName (shortened to the first 15 characters if required).

Change the line in red to whatever format you want for your computers.

MyStartup.cmd

REM -----  CHANGE COMPUTERNAME ------

REM get serial numbers, etc.
for /F "skip=2 tokens=2 delims=," %%A in ('wmic bios get serialnumber /FORMAT:csv') do (set "zzbiosserial=%%A")
echo biosserial="%zzbiosserial%"
for /F "skip=2 tokens=2 delims=," %%A in ('wmic systemenclosure get serialnumber /FORMAT:csv') do (set "zzserial=%%A")
echo serial="%zzserial%"
for /F "skip=2 tokens=2 delims=," %%A in ('wmic csproduct get name /FORMAT:csv') do (set "zzprodname=%%A")
echo prodname="%zzprodname%"
for /F "skip=2 tokens=2 delims=," %%A in ('wmic csproduct get vendor /FORMAT:csv') do (set "zzprodvendor=%%A")
echo prodvendor="%zzprodvendor%"
for /F "skip=2 tokens=2 delims=," %%A in ('wmic baseboard get product /FORMAT:csv') do (set "zzboardprod=%%A")
echo boardprod="%zzboardprod%"
for /F "skip=2 tokens=2 delims=," %%A in ('wmic baseboard get version /FORMAT:csv') do (set "zzboardver=%%A")
echo boardver="%zzboardver%"
for /F "skip=2 tokens=2 delims=," %%A in ('wmic baseboard get SerialNumber /FORMAT:csv') do (set "zzboardserial=%%A")
echo boardserial="%zzboardserial%"
for /F "skip=2 tokens=2 delims=," %%A in ('wmic systemenclosure get ChassisTypes /FORMAT:csv') do (set "zztyperaw=%%A")
set zztype=PC
if "%zztyperaw:~1,1%"=="9"  set zztype=NB
if "%zztyperaw:~1,2%"=="10" set zztype=NB
if "%zztyperaw:~1,2%"=="14" set zztype=NB
if "%zztyperaw:~1,2%"=="25" set zztype=NB
echo zztype="%zztype%"
REM Get Mainboard UUID - e.g. 25168B60-D7FE-11DD-9D38-BCEE7B876D92  - the last part is often (but not always) the mainboard MAC address
for /F "skip=2 tokens=2 delims=," %%A in ('wmic csproduct get UUID /FORMAT:csv') do (set "zzuuid=%%A")
set zzmbmac=%zzuuid:-12%
echo UUID="%zzuuid%"  MAC="%zzmbmac%" (??)

REM Get Ethernet MAC address - e.g. zzMAC=BCEE7B876D33  (12 characters)
set zzMAC=
if "%zzMAC%"=="" for /f "usebackq tokens=3 delims=," %%a in (`getmac /fo csv /v ^| find """Ethernet"""`) do set zzMAC=%%~a
if "%zzMAC%"=="" for /f "usebackq tokens=3 delims=," %%a in (`getmac /fo csv /v ^| find "Ethernet 1"`) do set zzMAC=%%~a
if "%zzMAC%"=="" for /f "usebackq tokens=3 delims=," %%a in (`getmac /fo csv /v ^| find "Ethernet 2"`) do set zzMAC=%%~a
REM Remove all hyphens from string
set zzMAC=%zzMAC:-=%
echo MAC=%zzMAC%
setlocal EnableDelayedExpansion
set zzmac1=
set N=0
for /F %%A in ('wmic NIC get Macaddress ^| find ":"') do (
  set /a N += 1
  set "zzmac!N!=%%A"
)
endlocal & set zzmac1=%zzmac1% & set zzmac2=%zzmac2% & set zzmac3=%zzmac3% & set zzmac4=%zzmac4%
REM remove :  from BC:EE:7B:87:6D:74
set zzmac1=%zzmac1::=%
set zzmac2=%zzmac2::=%
set zzmac3=%zzmac3::=%
set zzmac4=%zzmac4::=%
echo MAC1="%zzmac1%"
echo MAC2="%zzmac2%"
echo MAC3="%zzmac3%"
echo MAC4="%zzmac4%"


REM set the new computername as NEWPC   -  *** CHANGE THIS NEXT LINE AS REQUIRED ***
set "NEWPC=%zzbiosserial%"

REM Remove illegal characters / \ , . " @  (cannot easily remove *)
set NEWPC=%NEWPC:/=%
set NEWPC=%NEWPC:\=%
set NEWPC=%NEWPC:,=%
set NEWPC=%NEWPC:.=%
set NEWPC=%NEWPC:"=%
set NEWPC=%NEWPC:@=%
set NEWPC=%NEWPC: =%
REM Remove * from NEWPC
setlocal EnableDelayedExpansion
:loop
For /F "tokens=1,2* delims=*" %%x In ("%NEWPC%") Do (
   Set "str=!str!%%x%%y"
   Set "NEWPC=%%z"
)
If not "%NEWPC%"=="" GoTo:loop
endlocal & set NEWPC=%str%


REM check we have a value
if "%NEWPC%"=="" echo no serial number! & pause
if "%NEWPC%"=="""" echo no serial number! & pause

REM pre-fix with 'PC-' or 'NB-'
set NEWPC=%zztype%-%NEWPC%

REM uncomment line below if you want to use a prefix + serial number
::set "NEWPC=NEW-%zzbiosserial%"
REM uncomment line below if you want to use the *last* 15 characters only
::set "NEWPC=%NEWPC:~-15%"

REM Use first 15 chars max - otherwise we will get an error!
set NEWPC=%NEWPC:~0,15%

start /wait %systemdrive%\DRIVERS\nircmd speak text "Changing computer name - reboot is required"
REM Record system info variables
if "%log%"=="" set log=C:\temp\%~n0.log
set zz >> %log%
set NEWPC >> %log%
set CN=
WMIC computersystem where caption='%COMPUTERNAME%' rename "%NEWPC%" || echo ERROR: COMPUTERNAME WAS NOT CHANGED! && set CN=1 && pause
if "%CN%"=="" echo COMPUTERNAME %COMPUTERNAME% will be changed to "%NEWPC%" on reboot & echo COMPUTERNAME %COMPUTERNAME% will be changed to "%NEWPC%" on reboot >> %log%

REM ----------- END OF COMPUTERNAME CHANGE --------

This sample code will be included in the Sample_MyStartup.cmd file in SDI_CHOCO in the next version of E2B.

Tip: You can re-run this cmd file after an installation has completed and test changes by editing and running C:\DRIVERS\MyStartup.cmd. When it is working correctly update MyStartup.cmd on the E2B USB flash drive.

Tip: This subroutine can be called to make convert the value of a variable to uppercase:

:ToUpper
REM Returns variable %1 as UpCase in variable %2
REM Usage: call :ToUpper %myvar% myvar
FOR /F "tokens=2 delims=-" %%A IN ('FIND "" "%~1" 2^>^&1') DO SET UpCase=%%A
set %2=%UpCase:~1,99%
goto :EOF


Recording serial number, etc.

If you add the code below to \_ISO\e2b\firadisk\LOADISONP.cmd, it is executed just as Setup is first run. It creates a BIOSINFO.CMD file on the root of the E2B drive which you may like to later run and use.

If you do want to use this code for some reason, you should make your own version of LOADISONP.cmd so that it is not overwritten when you update E2B. You will then need to change your XML file so that it uses the modified .cmd file.


REM Save SYSTEM INFO to USB drive
if exist %~d0\BIOSINFO.cmd del %~d0\BIOSINFO.CMD
echo set biosserial=none> %~d0\BIOSINFO.CMD
REM get serial number
for /F "skip=2 tokens=2 delims=," %%A in ('wmic bios get serialnumber /FORMAT:csv') do (set "biosserial=%%A")
echo biosserial="%biosserial%"
for /F "skip=2 tokens=2 delims=," %%A in ('wmic systemenclosure get serialnumber /FORMAT:csv') do (set "serial=%%A")
echo serial="%serial%"
for /F "skip=2 tokens=2 delims=," %%A in ('wmic csproduct get name /FORMAT:csv') do (set "prodname=%%A")
echo prodname="%prodname%"
for /F "skip=2 tokens=2 delims=," %%A in ('wmic csproduct get vendor /FORMAT:csv') do (set "prodvendor=%%A")
echo prodvendor="%prodvendor%"
for /F "skip=2 tokens=2 delims=," %%A in ('wmic baseboard get product /FORMAT:csv') do (set "boardprod=%%A")
echo boardprod="%boardprod%"
for /F "skip=2 tokens=2 delims=," %%A in ('wmic baseboard get version /FORMAT:csv') do (set "boardver=%%A")
echo boardver="%boardver%"
for /F "skip=2 tokens=2 delims=," %%A in ('wmic baseboard get SerialNumber /FORMAT:csv') do (set "boardserial=%%A")
echo boardserial="%boardserial%"
REM Write settings to USB drive
echo set biosserial=%biosserial%> %~d0\BIOSINFO.CMD
echo set serial=%serial%>> %~d0\BIOSINFO.CMD
echo set prodname=%prodname%>> %~d0\BIOSINFO.CMD
echo set prodvendor=%prodvendor%>> %~d0\BIOSINFO.CMD
echo set boardprod=%boardprod%>> %~d0\BIOSINFO.CMD
echo set boardver=%boardver%>> %~d0\BIOSINFO.CMD
echo set boardserial=%boardserial%>> %~d0\BIOSINFO.CMD


Example \BIOSINFO.cmd
set biosserial=4CZ0231XR1
set serial=Chassis Serial Number
set prodname=HP G62 Notebook PC              
set prodvendor=Hewlett-Packard
set boardprod=143B
set boardver=62.3E
set boardserial=

Note: If you change the > sign to >> in the 7th from last line, then the BIOSINFO.cmd file will have a record of all the systems that you have run a Windows install on.

Summary

Changing the ComputerName is not ideal and may cause problems (especially after joining a Domain!). Let me know if you use a better way...