A few months back, we decided that +- 80% of our company’s computers really needed an update. A lot of our users where still working on machines such as the Dell Dimension 4300 with a 1.6GHz P4 & 512MB of 133MHz SDRam… Like I said, time for a change ! We orderded a bunch of new computers with Intel E8400 processors, each equiped with 4GB of RAM… The real deal !

But then came the question all IT guys need to pose themselves at a certain moment in time… Such horsepower… Are we going to install Windows XP Pro on those machines ??? Nooooooo ! Let’s order Windows 7 Pro to go with that !

And that’s what this posting is all about. The pains, the sadness and the joy (in the end) of preparing a Windows 7 Pro master image ! With nothing more than the Windows AIK and some lovely tool called sysprep – yep, still the same tool, although it DID evolve quite a bit… It now works with…… XML files… (stylish éh)

So, let’s kick of by listing the things you need :

Now that you’ve got all that, start by installing the AIK. You will need this to use the xml editor for the sysprep configuration file. The AIK can safely be installed on machine running XP Pro, although Microsoft doesn’t list this OS as supported I had no problem in doing so.

Once the AIK is installed, make a copy of the contents of your Windows 7 DVD  to your hard drive. This isn’t necessary, but will allow you to work faster with the xml editor.

You’ll find a new folder in Start -> Programs, called “Microsoft Windows AIK”. Launch the program called “Windows System Image Manager”. If you need to know more about how this program works, please RTFM. Basically, you need to open the correct .wim file of your Windows 7 copy by clicking “Select a windows image or catalog file”. This will provide you with the building blocks needed to construct a valid xml-file,  tailored to your specific needs. Next, create a new answer file with the editor, by clicking on “Create or open an answer file”.

My Sysprep file : sysprep_xml

The above is a working sysprep.xml that configures numerous options, please take your time to discover all possibilities by using the building block provided in the editor. One thing : you should rename it to sysprep.xml and change some of the values inside to reflect your own situation and needs.

Some remarks :

  • Assigning a computer name during the OOBE wizard and joining the domain isn’t as simple as it seems. Sure, you can leave out the computer name for the xml, and yes, the OOBE will present you a nice window, asking for the name you wish to assign, BUT : the computer won’t join the domain with the nice name you’ve given him. No, you’ll find that the old, random generated temporary name has been used - really- your computer itself will have the name you’ve chosen, but it will have another name in Active Directory… How come ? Well it seems that the OOBE wizard asks for a computer name, AFTER joining the domain. Go Microsoft.. Sure, there are solutions for this, installing certain deployment products from Microsoft that should solve all these problem (so I have read), but hey, we don’t want all that, now do we ? Is there a solution for this ? Sure, read on :-)
  • Second problem : you can easily create a local admin account during setup and specify it’s password in the xml, it will be encrypted, this works just fine. But hey, you want those computers to auto-join the domain, don’t you. Well, try putting a domain account in the sysprep.xml with permission to join the computer to a domain… No password encryption here. This is an old problem and was also there at the time of XP, but it is still not fixed by Microsoft. Is this a problem ? Well, it depends, if you make your images in-house and you do the cloning yourself, this isn’t really much of a problem. But in our case, the cloning was done by a third party and I don’t want them to know the admin-pass (or other user used to join the domain). Again, there is a fix for this, so read on…
  • An third quirk : auto-joining the domain is a real pain in the ass. If this isn’t working, please read the sysprep logfiles ! (take a look around on the Internet to find out where they are located). In my case, all domain fields in the sysprep file could be in the simple, short netbios version, but it had to be the specified as FQDN between the “JoinDomain” tags in the UnattendedJoin section of the xml.

Now let’s fix those first two problems… After spending some precious time searching for the answer, I found a nice script on the Internet and a fine registry hack that allows you to modify some values in the xml file after sysprepping the machine and BEFORE the OOBE wizard uses the xml file.

The idea is quite simple, put some tags such as ReplaceMe1, ReplaceMe2 or equivalent in the xml file, and let them be replaced by a simple vbs script :

Here is the script : EditUnattend_vbs

Please, DO NOT CHANGE the location of the unattend file (line 4), this is where the sysprep command always copies the file for use by the OOBE wizard. I repeat, DO NOT CHANGE THIS, this hasn’t anything to do with the location where you put your own xml file ! Everything else in the script can be changed as needed.

In my version, the script asks for a computer name and the domain-admin password. Two variables that are afterwards used to replace the text in the placeholders in the xml file.

So now you have a sysprep.xml and a vbs script to change it before the OOBE wizard start, but how will this thing be started ? Well, that’s where the registry hack comes in. Put the following code in a batch file and run it, after sysprepping the machine (change the path of the vbs script if needed)

reg add HKLM\System\Setup /v CmdLine /t REG_SZ /d "cmd /c cscript //nologo C:\windows\system32\sysprep\EditUnattend.vbs" /f

As I said, run this reg-hack AFTER sysprepping the machine. How ? Sysprep has a commandline option that tells it not to shutdown or reboot but to just quit after running. This is what you should use :

c:\windows\system32\sysprep\sysprep /quit /generalize /oobe /unattend:yourxmlfile.xml

And run the reg-hack when the above command finishes.

If all goes well, you should be ready to go !

Just one final hint : Windows 7 features Aero… But to activate Aero, your computer needs to calculate it’s performance score. Do you want to do that on each and every machine ? No, well, if all machines have the same hardware, run this before syspreping your master-image :

winsat prepop

This will calculate the performance index and put it on your machine in xml-format. If the OOBE wizard finds these xml file, and the hardware hasn’t changed, it uses the pre-populate values and Aero works out of the box ! Enjoy !

UPDATES

  • Take a look at this article at MS Support : How to customize default user profiles in Windows 7 and in Windows Server 2008 R2. It explains the CopyProfile switch that you should use to change the default user profile for new users. In fact, I did all customisations (start menu, icons, desktop, settings for IE etc…) to the master image with the local admin user (you have to enable it manually) and then used the CopyProfile switch to copy all settings to the default user profile. This brings us to the next remark…
  • As Todd and Tim pointed out in their comments, the reg-hack apparently needs to be added using the local admin account. As I did all customisations using the local admin, this might very well be true.
  • The sysprep file offered for download in this articles is for 32bit installations only. Users installing the 64bit version of Windows 7 will need to change all instances of processorArchitecture=”x86″ to processorArchitecture=”amd64″.
 

77 Responses to Windows 7 Sysprep – Tips & tricks

  1. Jason says:

    found it…. I think it had something to do with the CopyProfile set to “true” Set it to false and made it through its first successful install. Thanks for throwing this out there!

  2. Martin says:

    Anyone who has had the same problem?

    After I run sysprep with /generalize /oobe /quit with unattend sysprep_xml I am unable then run anything that needs administrative rights. This is definitely to do with running the sysprep before. I get C:\Windows\regedit.exe (cmd.exe, whatever I run) The device is not ready. I am unable to run the hack.bat that executes editunattend.vbs as I need the admin rights. I run this as a local admin, etc. anyone any ideas why this is happening? can I run the hack before I sysprep it?
    Thank you…

  3. Joe A says:

    Hi,

    I’ve been trying your work around to have setup prompt for a computer name and password, but sysprep hangs and I get an error 1326 on DomainJoin. I looked it up and it says that the domain logon credentials might be incorrect. I’m really lost on this one, because those are the same credentials that I use for manually joining machines to the domain. Is there a particular format that I need to put the domain credentials in?

    Please help!!!

    Thanks in advance!

    Joe.

  4. Joe A says:

    Just to add, I’m doing Windows 7 Pro 64-bit.

    Thanks,
    Joe.

  5. Alex says:

    Martin,

    I was having the same problem you were. This may sound like a pain but you have to find a way to login with the Administrator account. Once you login with the Administrator account not your domain admin account it should work.

    Joe A.

    It is not your credentials it is actually your sysprep.xml file. You will see line
    OU=PCs,OU=Accounts,DC=YourDomain,DC=local and change it to . Only down fall for this is that you will have to move the computer in AD to what OU you want maually which to me is fine.

    Try that out and let me know guys.

  6. Alex says:

    Sorry Joe for some reasy it did not show the rest of what i wanted to say.

    It is not your credentials it is actually your sysprep.xml file. You will see line (OU=PCs,OU=Accounts,DC=YourDomain,DC=local) and change it to () . Only down fall for this is that you will have to move the computer in AD to what OU you want maually which to me is fine.

  7. John says:

    I’ve tried doing this with a slight modification to the script (which I have tested and it works just fine), but after I sysprep the machine It loads some settings and then goes to a login screen and because it hasn’t run through the unattend file and the administrator account is disabled I can’t log into the machine to have any scripts kick off….I’m not sure what I’m doing wrong with this but I’d love some help if anyone can spare the time.

  8. John says:

    Ok…so after looking at it I figured out part of my issue and I actually got the script to run finally. However, the script doesn’t seem to be going all of the way through. Here is the script that I have running.

    Option Explicit
    Dim answer, answer2, answer3, response, SiteCode, DeptCode, strComputer, objWMIService, colBIOS, objBIOS, ServiceTag, computername, domainUser, domainPass, unattendFile, WshShell, fso, unattendFileObject, strContents

    unattendFile = “C:\Windows\Panther\unattend.xml”

    Set WshShell = WScript.CreateObject(“WScript.Shell”)
    Set fso = CreateObject(“Scripting.FileSystemObject”)

    ‘Prompt for Site Code
    response=”"
    Do While Len(response)=0
    response = InputBox(“Enter Site Code: ” & vbCRLF & vbCRLF & _
    “[ie: SJO or SJF]“,”Site Code”)
    Loop
    SiteCode = response

    ‘Prompt for Department Code
    response=”"
    Do While Len(response)=0
    response = InputBox(“Enter Department Code: ” & vbCRLF & vbCRLF & _
    “[ie: 3N or 2MAIN]“,”Department Code”)
    Loop
    DeptCode = response

    strComputer = “.”
    Set objWMIService = GetObject(“winmgmts:” _
    & “{impersonationLevel=impersonate}!\\” & strComputer & “\root\cimv2″)
    Set colBIOS = objWMIService.ExecQuery _
    (“Select * from Win32_BIOS”)
    For each objBIOS in colBIOS
    ServiceTag = objBIOS.SerialNumber
    Next

    ‘Set Computer name
    computername = SiteCode & “-” & DeptCode & “-” & ServiceTag

    ‘Prompt for Domain Username
    response=”"
    Do While Len(response)=0
    response = InputBox(“Enter Your Domain Username:”, “Domain Username”)
    domainUser = response
    Loop

    ‘Prompt for Domain Password
    response=”"
    Do While Len(response)=0
    response = InputBox(“Enter Your Domain Password:”, “Domain Password”)
    domainPass = response
    Loop

    If fso.FileExists(unattendFile) = False Then
    wscript.echo “ERROR: Could not find the unattend file”
    Else
    ‘Read the unattend file in and replace apprpriate variables
    Set unattendFileObject = fso.OpenTextFile(unattendFile, 1)
    strContents = unattendFileObject.ReadAll
    strContents = Replace(strContents, “ReplaceMe1″, computerName)
    strContents = Replace(strContents, “ReplaceMe2″, domainUser)
    strContents = Replace(strContents, “ReplaceMe3″, domainPass)
    unattendFileObject.Close

    ‘Write the updated contents back to the unattend file
    Set unattendFileObject = fso.OpenTextFile(unattendFile, 2)
    unattendFileObject.Write(strContents)
    unattendFileObject.Close
    End If

    ‘ Launch setup (will use the modified unattend.xml)
    WScript.Sleep 5000
    WshShell.Run “%WINDIR%\System32\oobe\windeploy.exe”, 0, True

    The script prompts for a Site Code, then a department code and then it is supposed to read the BIOS for the serial number and concatenate all of that together for the PC name (that’s the naming convention here). Afterwards it prompts for a domain username and password. It then passes each of the variable over to the unattend.xml file in the same method shown in the walkthru. I’ve tested the script on a Windows 7 Ent. x64 machine and it runs perfectly. However, when it runs after a sysprep it prompts for the site code and the department code and then it never prompts for the username and password. I was able to boot to a WinPE environment and check the unattend.xml file in the c:\windows\panther directory and none of the variables passed through, which tells me that it didn’t like something in reading the BIOS portion. Does anyone out there happen to know what could be hanging this script from completing? I would like to get this portion of the script working instead of having to type the serial number out for each machine. Any help would be appreciated.

  9. Moose says:

    Rick
    How did you resolve the problem with the domain admin getting disabled?

  10. Joe A. says:

    Alex:

    Thanks for the tip.

    I actually found out that my issue was all isolated to the domain credentials I provided.

    Apparently, I needed to append my username with @domain.com and also append my domain with .com.

    The example .xml provided above has the following format:

    YourDomain
    ReplaceMe2
    administrator

    Instead, it should be:

    YourDomain.com
    ReplaceMe2
    administrator@YourDomain.com

    At least, that’s what worked for me. Can’t even tell you how long it took me to isolate that issue!

    Thanks anyway for your help.

    Joe.

  11. [...] confused after reading some tutorials that talk about using Windows Automated Installation Kit, or hacks with the registry and custom-build batch files. This process seems overly complex to me: I did something similar 10+ years ago, and and [...]

  12. [...] I also recommend reading this article, “Windows 7 Sysprep – Tips & tricks.” [...]

  13. Gary Hicks says:

    I am creating an answer file for a 64bit intel system, (core i7). Do the amd64_ choices under components apply to both Intel and AMD 64bit systems or is this exclusively for amd processor based 64bit systems?

    thanks,
    gary

  14. admin says:

    amd64 platform stands for both Intel and AMD 64bit processors – the reason why it is called amd64 is a historical question – just Google it if you want to know some more about it…

  15. DTEGuy says:

    This answer is simple. x86-64 specification was created by AMD: After launching the architecture under the “x86-64″ name, AMD renamed it AMD64 in 2003; Intel initially used the names IA-32e and EM64T before finally settling on Intel 64 for their implementation. The x86-64 specification is distinct from the Intel Itanium (formerly IA-64) architecture, which is not compatible on the native instruction set level with the x86 architecture. So in other words AMD crated the first hybrid processor and the industry like it, supported it and forced Intel to adopt it.

  16. Ricky says:

    Author,
    Good info on the prepop. I didn’t know about that.

    John,
    As per the “serial” extraction. I know this site references Dell, but it may be related. Thinking about doing this myself.

    http://djseppie.wordpress.com/2010/07/19/show-dell-asset-tag-part-number-serial-number-using-vb-script/

    Also add msgbox dialogs or echos all over your script to give indication where the script is timing out (which is probably what is happening). Really am interested if you get it to work. BTW, What brand of computer?

    For those interested in enabling the local admin acct.
    Add to the Deployment Component to your Specialize Pass in your custom unattend file. Add a synchronous Command (order 1) with “net user administrator /active:yes”
    I’ve seen other sites suggest putting it in the oobe pass, with 5 autologins. Dumb. Don’t do it – Put it in the specialize pass.

    Ex…

    false

    net user administrator /active:yes
    1
    Open local admin account

    For those that install in alternate win directories.
    Add to vbscript:

    base = Wshshell.ExpandEnvironmentStrings("%SystemRoot%")
    unattendFile = base & "\Panther\unattend.xml"

    Other notes:
    Credit wasn’t given to the original author of this script. See here for original posting for Vista back in ’07.
    http://social.technet.microsoft.com/Forums/en/itprovistadeployment/thread/2d03e17d-c2ea-4d19-bf32-7db2e9975251

  17. Ricky says:

    I tried hiding the xml syntax in [code] brackets. But it came out as
    false, and some other junk.
    "Open local admin account" was the description of the synchronous command in the unattend file.

    If you have a directory where all this sysprep stuff is kept, then you can make yourself a .cmd (or batch file for the legacy folk) file to automate the process. Idea from... well, I couldn't find it. Run it from the "to-be-imaged" workstation. Right-click and run as administrator if UAC is still enabled on your image. It pauses to mamke sure files were copied, and for any last regrets to be cancelled (you cancel by clicking the X).

    copy /Y "%~dp0MainCorporate.xml" "%SystemRoot%\system32\sysprep\unattend.xml"
    copy /Y "%~dp0EditUnattend.vbs" "%SystemRoot%\system32\sysprep\EditUnattend.vbs"
    echo Last chance. Press any key to continue SysPrep...
    pause
    %SystemRoot%\system32\sysprep\sysprep.exe /generalize /oobe /quit /unattend:%Systemroot%\system32\sysprep\unattend.xml
    reg add HKLM\System\Setup /v CmdLine /t REG_SZ /d "cmd /c cscript //nologo C:\Windows\System32\Sysprep\EditUnattend.vbs" /f
    Shutdown /p /d p:2:4

    Be sure to replace your source unattend file over the name of mine "MainCorporate.xml".
    The characters "%~dp0" is a dos method of obtaining the location of the current running batch file (or cmd file in our case). It returns the backslash, is why we don't have one to seperate it from the file name.

  18. Ricky says:

    John,
    It appears to kill over at the For loop. I tried testing the objBIOS var for IsNull(), and the entire script bombed. But I got msgbox dialogs to appear just before the For loop. I also placed one as the first statement in the For loop, and it never showed. The reboot was instantaneous, thus no additional Specialize Pass instructions from the unattend.xml file were processed.

    Good luck. Hope you can comment back if you happen to find a solution. This would be an extreme no-touch startup.

  19. James says:

    Bit of a programming newbie here. Does anyone have an example of how to input the vbscript to the xml file please?

  20. Niall says:

    We investigated using this solution however as we ran into problems with getting it to gather the systems serial number as WMI is not active when the script runs.

    We eventually settled on creating series of scripts utilizing imagex and Windows PE in order to deploy our image (Rather than WDS) as it provided greater flexibility and we could utilize WMI to get a serial number and dump it into our unattend file.

  21. anointminus says:

    reg add HKLM\System\Setup /v CmdLine /t REG_SZ /d “mshta C:\Windows\System32\Sysprep\EditUnattend.hta” /f

    Computer Deployment

    Set WshShell = CreateObject("Wscript.Shell")

    Sub Window_onLoad
    window.resizeTo 450,400

    'turn off setup flag in registry so we can query wmi
    WshShell.RegWrite "HKLM\SYSTEM\Setup\SystemSetupInProgress", 0, "REG_DWORD"

    'query wmi for serial number
    Const wbemFlagReturnImmediately = &h10
    Const wbemFlagForwardOnly = &h20
    strComputer = "."
    Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\CIMV2")
    Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_BIOS", "WQL", _
    wbemFlagReturnImmediately + wbemFlagForwardOnly)

    For Each objItem In colItems
    serialNumber = objItem.SerialNumber
    Next

    'turn setup flag back on
    WshShell.RegWrite "HKLM\SYSTEM\Setup\SystemSetupInProgress", 1, "REG_DWORD"

    'put the serial number that was retrieved in the textbox
    ComputerNameArea.Value = serialNumber

    End Sub

    Sub modUnattend

    run_button.Disabled = True

    Set fso = CreateObject("Scripting.FileSystemObject")

    base = Wshshell.ExpandEnvironmentStrings("%SystemRoot%")
    unattendFile = base & "\Panther\unattend.xml"

    computerName = ComputerNameArea.Value
    domainName = DomainNameArea.Value
    userName = UserNameArea.Value
    domainAdminPass = PasswordArea.Value
    OUName = OUNameArea.Value

    Set xmlDoc = CreateObject("Microsoft.XMLDOM")
    xmlDoc.load unattendFile

    'Iterate through Unattend.xml searching for nodes and properties to replace
    Set oNodes = xmlDoc.documentElement.selectNodes("/unattend/settings/component/ComputerName")
    For each n in oNodes
    n.text = computerName
    xmlDoc.save unattendFile
    Next

    Set oNodes = xmlDoc.documentElement.selectNodes("/unattend/settings/component/Identification/Credentials/Domain")
    For each n in oNodes
    n.text = domainName
    xmlDoc.save unattendFile
    Next

    Set oNodes = xmlDoc.documentElement.selectNodes("/unattend/settings/component/Identification/Credentials/Password")
    For each n in oNodes
    n.text = domainAdminPass
    xmlDoc.save unattendFile
    Next

    Set oNodes = xmlDoc.documentElement.selectNodes("/unattend/settings/component/Identification/Credentials/Username")
    For each n in oNodes
    n.text = userName
    xmlDoc.save unattendFile
    Next

    Set oNodes = xmlDoc.documentElement.selectNodes("/unattend/settings/component/Identification/JoinDomain")
    For each n in oNodes
    n.text = domainName
    xmlDoc.save unattendFile
    Next

    Set oNodes = xmlDoc.documentElement.selectNodes("/unattend/settings/component/Identification/MachineObjectOU")
    For each n in oNodes
    n.text = OUName
    xmlDoc.save unattendFile
    Next

    'launch the continuation of setup in a hidden window and wait for return
    'if we dont wait, closing mshta, closes windeploy.exe
    WshShell.Run "%WINDIR%\System32\oobe\windeploy.exe", 0, True
    idTimer = window.setTimeout("closeHTA", 5000, "VBScript")
    End Sub

    Sub closeHTA
    window.close
    End Sub

    Sub commandLine
    WshShell.Run "%WINDIR%\System32\cmd.exe", 1, True
    End Sub

    Computer Name:

    Domain Name:

    Container OU:

    Desktops
    Laptops

    User Name:

    Password:

    Note: The following characters are invalid for use in the computer name: " `~!@#$%^&*()=+[]{}\|;:'",/?. "
    You will not recieve any warning regarding incorrectly supplied parameters during setup. If any of them are incorrect, setup completion
    may take a long time.

  22. anointminus says:

    That last post was an HTA file, the tags didnt work at this site stripped out all the tags. The post can be viewed in a better format at http://social.technet.microsoft.com/Forums/en-US/itprovistadeployment/thread/2d03e17d-c2ea-4d19-bf32-7db2e9975251/

    Look for string objCompDeploy

  23. Dane says:

    Howdy,

    Great script! Works awesome! I am just curious if there is a way to have the Domain Password field show as asteriks or some other character when you type it rather than plain text or will this cause issues when it writes the data to the unattend file?

    Specifically, put in the (or some variant as needed):

    Private Sub Form_Load()
    Text1.PasswordChar = “*” ‘ :wave:
    End Sub

    That possible?

  24. Dane says:

    Well, I decided to try the hta file instead and with a bit of tweaking, it is glorious. Thanks anointminus!

  25. I accidentally the vbs says:

    Did something change for SP1? It fails to continue setup after “Microsoft-Windows-Shell-Setup”.

    Company Name
    false
    Central Standard Time
    false
    Company Name
    ReplaceMe1
    true

  26. I accidentally the vbs says:

    The error was detected while processing settings for component [Microsoft-Windows-Shell-Setup].

  27. I accidentally the vbs says:

    Found the fix. I had a profile other than the admin account and it got confused.

    http://social.technet.microsoft.com/Forums/en/w7itproinstall/thread/2aa9466d-a203-4f3e-80d9-f1ae6d11f6c5

Leave a Reply

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

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>