Automated Windows Server 2008R2 installation from a Linux server without machine imaging

This example uses ‘bootsrv.example.com’ running Fedora 14 and ‘dev1.vc.example.com’ in a virtual machine.
It is a fully automated install that doesn’t involve machine imaging and doesn’t require you to access the target server’s console.

Install tftp+dhcp+samba RPMs:

yum install tftp
yum install tftp-server
yum install dhcp
yum install samba

Configure tftpd
Edit /etc/xinetd.d/tftp to add “-m /etc/tftpd.map” to server_args

echo 'rg \\ /' > /etc/tftpd.map

Configure Samba

mkdir /data
chown 777 /data

Create /etc/samba/smb.conf

[global]
workgroup = VC
server string = Samba Server Version %v
log file = /var/log/samba/log.%m
max log size = 50
security = share
guest account = nobody

[data]
path = /data
guest ok = yes
writable = yes
browsable = yes
printable = no

Configure dhcpd
Create /etc/dhcp/dhcpd.conf

authoritative;
allow booting;
allow bootp;

option domain-name "example.com";
option subnet-mask 255.255.255.0;
option domain-name-servers 10.233.0.1;

shared-network vc {
  subnet 10.233.0.0 netmask 255.255.254.0 {
    range 10.233.0.10 10.233.0.99;
    option routers 10.233.0.1;
  }
}
group {
  next-server 10.233.0.9;
  filename "\\Boot\\pxeboot.n12";
  host dev1.vc.example.com { hardware ethernet 52:54:00:f4:2f:20; }
}

Modify the “host” entry to match the MAC address of the target server

Install Windows AIK on the Technician computer

Copy boot files to the PXE server
Start the Deployment Tools Command Prompt
Create the WinPE directory structure:

c:\>copype.cmd amd64 c:\winpe_amd64

Mount the WinPE image:

c:\winpe_amd64>dism /mount-wim /wimfile:winpe.wim /mountdir:mount /index:1

Install the setup packages:

c:\winpe_amd64>dism /image:mount /add-package /packagepath:"c:\program files\windows aik\tools\petools\amd64\winpe_fps\winpe-setup.cab"
c:\winpe_amd64>dism /image:mount /add-package /packagepath:"c:\program files\windows aik\tools\petools\amd64\winpe_fps\winpe-setup-server.cab"
c:\winpe_amd64>dism /image:mount /add-package /packagepath:"c:\program files\windows aik\tools\petools\amd64\winpe_fps\en-us\winpe-setup_en-us.cab"
c:\winpe_amd64>dism /image:mount /add-package /packagepath:"c:\program files\windows aik\tools\petools\amd64\winpe_fps\en-us\winpe-setup-server_en-us.cab"

Rebuild lang.ini:

c:\winpe_amd64>dism /image:mount /gen-langini /distribution:mount

Create winpeshl.ini (to prevent winpe launching setup.exe immediately):

c:\winpe_amd64\mount>cd winpe_amd64\mount\windows\system32
c:\winpe_amd64\mount\Windows\System32>notepad winpeshl.ini

Insert the text below into winpeshl.ini:

[LaunchApp]
AppPath = %SystemRoot%\system32\startnet.cmd

Edit startnet.cmd (prevents the builtin setup.exe from using WDS):

C:\data\winpe_amd64\mount\Windows\System32>notepad startnet.cmd

Insert the text below into startnet.cmd:

wpeinit
reg delete HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\PXE /f
x:\setup.exe /unattend:bootsrv.example.com\data\autounattend.xml

Copy the PXE boot files to bootsrv.example.com:

c:\winpe_amd64>net use n: bootsrv.example.com\data
c:\winpe_amd64>mkdir n:\Boot
c:\winpe_amd64>copy mount\windows\boot\pxe\*.* n:\Boot
c:\winpe_amd64>copy "c:\program files\windows aik\tools\petools\amd64\boot\boot.sdi" n:\boot

Unmount the WinPE image (ensure all explorer windows are closed):

c:\winpe_amd64\mount\Windows\System32>cd winpe_amd64
c:\winpe_amd64>dism /unmount-wim /mountdir:mount /commit

Copy the image to bootsrv.example.com:

c:\winpe_amd64>copy winpe.wim n:\Boot\boot.wim

Configure BCD Store:

c:\winpe_amd64>bcdedit -createstore BCD
c:\winpe_amd64>bcdedit -store BCD -create {ramdiskoptions} /d "Ramdisk Options"
c:\winpe_amd64>bcdedit -store BCD -set {ramdiskoptions} ramdisksdidevice boot
c:\winpe_amd64>bcdedit -store BCD -set {ramdiskoptions} ramdisksdipath \Boot\boot.sdi
c:\winpe_amd64>bcdedit -store BCD -create /d "WinPE Boot Image" /application osloader

Use the GUID returned from this command in place of {GUID} in the following commands:

c:\winpe_amd64>bcdedit -store BCD -set {GUID} systemroot \Windows
c:\winpe_amd64>bcdedit -store BCD -set {GUID} detecthal Yes
c:\winpe_amd64>bcdedit -store BCD -set {GUID} winpe Yes
c:\winpe_amd64>bcdedit -store BCD -set {GUID} osdevice ramdisk=[boot]\Boot\boot.wim,{ramdiskoptions}
c:\winpe_amd64>bcdedit -store BCD -set {GUID} device ramdisk=[boot]\Boot\boot.wim,{ramdiskoptions}
c:\winpe_amd64>bcdedit -store BCD -create {bootmgr} /d "Windows Boot Manager"
c:\winpe_amd64>bcdedit -store BCD -set {bootmgr} timeout 30
c:\winpe_amd64>bcdedit -store BCD -displayorder {GUID}
c:\winpe_amd64>copy BCD n:\Boot

Move /data/Boot to /var/lib/tftpboot/Boot on bootsrv.example.com:

[root@bootsrv ~]# mv /data/Boot /var/lib/tftpboot/Boot

Copy the DVD install.wim to bootsrv.example.com:

c:\winpe_amd64>copy e:\sources\install.wim n:\win2008r2.wim

Create the unattended xml file in /data/autounattend.xml. This example can be edited with the Windows System Image Manager. It will perform these actions:

  • Create two partitions (system and windows)
  • Install Windows Server 2008R2 Datacenter Server (use the value Windows Server 2008 R2 SERVERDATACENTERCORE in the XML to get Server Core)
  • Name the server ‘dev1’
  • Join the domain ‘VC’ using the username ‘djoin’ and password ‘djoin’ in the OU ou=application servers,dc=vc,dc=example,dc=com
  • Set the local administrator password to ‘password1’

Product key should be changed from ZZZZZ-ZZZZZ-ZZZZZ-ZZZZZ-ZZZZZ

<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
<servicing></servicing>
<settings pass="windowsPE">
<component name="Microsoft-Windows-International-Core-WinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SetupUILanguage>
<UILanguage>en-US</UILanguage>
<WillShowUI>OnError</WillShowUI>
</SetupUILanguage>
<InputLocale>en-US</InputLocale>
<SystemLocale>en-US</SystemLocale>
<UILanguage>en-US</UILanguage>
<UserLocale>en-US</UserLocale>
</component>
<component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<DiskConfiguration>
<Disk wcm:action="add">
<CreatePartitions>
<CreatePartition wcm:action="add">
<Order>1</Order>
<Size>200</Size>
<Type>Primary</Type>
</CreatePartition>
<CreatePartition wcm:action="add">
<Order>2</Order>
<Extend>true</Extend>
<Type>Primary</Type>
</CreatePartition>
</CreatePartitions>
<ModifyPartitions>
<ModifyPartition wcm:action="add">
<Active>true</Active>
<Format>NTFS</Format>
<Label>System</Label>
<Order>1</Order>
<PartitionID>1</PartitionID>
</ModifyPartition>
<ModifyPartition wcm:action="add">
<Format>NTFS</Format>
<Label>Windows</Label>
<PartitionID>2</PartitionID>
<Order>2</Order>
</ModifyPartition>
</ModifyPartitions>
<DiskID>0</DiskID>
<WillWipeDisk>true</WillWipeDisk>
</Disk>
</DiskConfiguration>
<ImageInstall>
<OSImage>
<InstallFrom>
<Path>\\bootsrv.example.com\data\windows\win2008r2sp1.wim</Path>
<Credentials>
<Username></Username>
</Credentials>
<MetaData wcm:action="add">
<Value>Windows Server 2008 R2 SERVERDATACENTER</Value>
<Key>/IMAGE/NAME</Key>
</MetaData>
</InstallFrom>
<InstallTo>
<DiskID>0</DiskID>
<PartitionID>2</PartitionID>
</InstallTo>
</OSImage>
</ImageInstall>
<UserData>
<AcceptEula>true</AcceptEula>
</UserData>
</component>
</settings>
<settings pass="specialize">
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ProductKey>ZZZZZ-ZZZZZ-ZZZZZ-ZZZZZ-ZZZZZ</ProductKey>
<ComputerName>dev1</ComputerName>
<TimeZone>UTC</TimeZone>
</component>
<component name="Microsoft-Windows-UnattendedJoin" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Identification>
<Credentials>
<Domain>vc</Domain>
<Password>djoin</Password>
<Username>djoin</Username>
</Credentials>
<JoinDomain>vc</JoinDomain>
<MachineObjectOU>ou=application servers,dc=vc,dc=example,dc=com</MachineObjectOU>
</Identification>
</component>
</settings>
<settings pass="oobeSystem">
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<UserAccounts>
<AdministratorPassword>
<Value>cABhAHMAcwB3AG8AcgBkADEAQQBkAG0AaQBuAGkAcwB0AHIAYQB0AG8AcgBQAGEAcwBzAHcAbwByAGQA</Value>
<PlainText>false</PlainText>
</AdministratorPassword>
</UserAccounts>
</component>
</settings>
<settings pass="offlineServicing">
<component name="Microsoft-Windows-PnpCustomizationsNonWinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="NonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<DriverPaths>
<PathAndCredentials wcm:action="add" wcm:keyValue="1">
<Path>\\bootsrv.example.com\data\windows\drivers</Path>
</PathAndCredentials>
</DriverPaths>
</component>
</settings>
<cpi:offlineImage cpi:source="wim:c:/data/deploy/windows2008r2sp1-x64-msdn.wim#Windows Server 2008 R2 SERVERDATACENTER" xmlns:cpi="urn:schemas-microsoft-com:cpi" />
</unattend>

Boot the VM
It should boot WinPE, install, and the last reboot will bring it up as a domain joined server
The domain group policies will automatically apply (eventually), so if you have Remote Desktop enabled then you’ll be able to RDP into the server at this point. Otherwise you can log into the machine’s console and run “gpupdate /boot /sync” to get the policies to apply asap.

Comments

  • Great tutorial! I have been using pxelinux for a while now, and gave this a try. I get to the Windows Boot Manager and get the following error:

    File: \Boot\BCD
    Status: 0x000000f
    Info: An error occurred while attempting to read the boot configuration data.

    /var/log/messages is looking for boot.ini and says that the file is not found.

    Any ideas?

  • Well it’s trying to get boot.ini because the BCD either wasn’t readable, or was damaged, so once the BCD is fixed that should go away.
    It gets the pxeboot.n12 bootloader, so your tftp server is working. I think your BCD must be bad. Try just “bcdedit -store BCD” on your BCD, and compare it to this one:

    C:\data\winpe_amd64>bcdedit -store BCD

    Windows Boot Manager
    ——————–
    identifier {bootmgr}
    description Windows BootManager
    debugtype Serial
    debugport 1
    baudrate 115200
    bootdebug Yes
    displayorder {f26e3cc3-40e1-11e0-9683-001c42e9b3e9}
    timeout 30

    Windows Boot Loader
    ——————-
    identifier {f26e3cc3-40e1-11e0-9683-001c42e9b3e9}
    device ramdisk=[boot]\Boot\boot.wim,{ramdiskoptions}
    description WinPE Boot Image
    locale en-US
    osdevice ramdisk=[boot]\Boot\boot.wim,{ramdiskoptions}
    systemroot \Windows
    detecthal Yes
    winpe Yes
    sos No
    debug No

    If you get it working, post back what you did and I’ll update the howto. It might be a copy/paste problem caused by the bad line-wrapping of the blocks.

  • I recreaded the BCD 3 times, and this is the what bcedit -store BCD reports:

    c:\winpe_amd64>bcdedit -store BCD

    Windows Boot Manager
    ——————–
    identifier {bootmgr}
    description Windows Boot Manager
    displayorder {a20dd1b1-c44d-11e0-b7cc-0050568f00ac}
    timeout 30

    Windows Boot Loader
    ——————-
    identifier {a20dd1b1-c44d-11e0-b7cc-0050568f00ac}
    device ramdisk=[boot]\Boot\boot.wim,{ramdiskoptions}
    description WinPE Boot Image
    osdevice ramdisk=[boot]\Boot\boot.wim,{ramdiskoptions}
    systemroot \Windows
    detecthal Yes
    winpe Yes

    c:\winpe_amd64>

  • This could also be the tftpd.map thing, we need to map \ to /.

    imac:/Users/chrisl/ 7$ tftp bootsrv
    tftp> get \Boot\BCD
    Received 16418 bytes in 0.1 seconds
    tftp>

    Do you download the BCD if you do that same operation? If not the map file might be broken or not loaded.

  • Everything works good now. The BCD file was in the wrong location on my tftp server. Now I get an error regarding an invalid product key. The key is valid, I have used it on all my servers here. I am wondering if its having trouble finding the correct version (DATACENTER) to apply the key to?

    This is from my answer file:




    Windows Server 2008 R2 SERVERDATACENTER
    /IMAGE/NAME

  • The MSDN DVD I was using has all the distributions (server core, datacenter etc.) as separate images on the disk, so I need that <MetaData> to make the installer choose the right one. If you have a normal DVD with a single distribution on it then you can probably delete the whole <MetaData> section to make it work.

  • Alright! Getting there. Now I am getting errors that its missing a necessary CD/DVD driver.

  • I cant figure out why it keeps failing at the cd/dvd driver level. Are there certain drivers I have to have in the image for it to proceed?

  • I typically install into virtual machines that don’t have CD drives, but I can’t see why having a drive defined (or installed in a physical server) would cause any problems. What exactly is the error?

  • A required CD/DVD drive device driver is missing. If you have a driver floppy disk, CD, DVD, or USB flash drive, please insert it now.

    Note: If the Windows installation media is in the CD/DVD drive, you can safely remove it for this step.

    I am also installing into virtual machines.

  • I think that even though it’s saying “CD/DVD drive device driver” it’s confused and it means a hard disk storage controller driver. AFAICR the “If the Windows installation media” error is from WinPE so it must be at the stage where it’s loading real device drivers instead of the generic ones where possible. Are you using VirtIO on QEMU-KVM or a VMware SCSI controller that Windows doesn’t have built-in drivers for? Can you switch your hard disks to use something really generic like IDE? (not that you’d have to leave them as IDE, the issue can be fixed, just to check that this is what the issue is)

  • We are using the VMware SCSI driver. I have tried the other options for SCSI with no luck. We are now going to try to switch to IDE. So the problem you think is the driver built into the wim file not being compatible with VMware’s SCSI driver? Is there a way we can put that driver into the install wim?

  • Yep, I wrote a separate post about including third party drivers in the WIM here: http://dice.neko-san.net/2011/05/unattended-windows-2008-r2-installation-on-qemu-kvm-using-virtio/ VMware should work just the same.

  • \\bootsrv.example.com\data\windows\drivers

    Are the driver files supposed to be in that data\windows\driver? That folder isn’t even there. I am thinking that file didn’t get copied to the pxe server.

  • No, you have to create that folder structure. Any drivers that you want to be available to the OS on first boot should be put in there. The setup process only installs drivers from the WinPE image into the OS that are critical to the boot process (like disk controllers), it doesn’t copy ones that aren’t (like network drivers) unless they’re in that directory. Setup doesn’t actually install the drivers in that directory, the first boot installs them if they’re needed.

  • Excellent. Got it all working. Thank you for your help on this!

    One quick last question….do you know if I can add a couple msi’s to be installed during initial setup? I have a 2 programs that are *.msi that need installed.

  • If you’ve got software packaged as MSIs then I would install those post-deployment using a Group Policy, or via System Center Configuration Manager if you have that available.

  • Hi Chrisl,

    Can I try your guide to unattend install Windows 2K8 using PXElinux installed on a RHEL5?

    I haved used a winpe.iso guide to deploy but it not works.

    default linux
    label PXElinux
    localboot 0
    timeout 300
    default menu.c32

    menu title Boot Menu DEMOLAB

    label RHEL 5.5 64bit Script
    menu label 1) RHEL-5.5-^64bit Script
    kernel RHEL5.5_64bit/vmlinuz
    append initrd=RHEL5.5_64bit/initrd.img method=ftp://10.84.9.249/RHEL/5.5_64bit/Content-dvd-RHEL5.5/ ks=ftp://10.84.9.249/ks-64bit.cfg

    label RHEL 5.5 32bit Script
    menu label 2) RHEL-5.5-^32bit Script
    kernel RHEL5.5_32bit/vmlinuz
    append initrd=RHEL5.5_32bit/initrd.img method=ftp://10.84.9.249/RHEL/5.5_32bit/Content-dvd-RHEL5.5/ ks=ftp://10.84.9.249/ks-32bit.cfg

    label Windows 2k8 64bit
    menu label 3) ^Windows-DC-EE-SE-Web-R2-2K8-64bit
    kernel memdisk
    initrd winpe/winpe.iso
    append iso initrd=winpe/winpe.iso raw

  • Leave a comment