Getting Windows 7 to boot from Debian Linux PXE boot, round 439…

The guide that I found, Ultimate Deployment didn’t work straight away. I ran into a bug generating the BCD file, probably because the winpe.wim that I generated is corrupt. So maybe it is difficult to get this working after all. But I’m not ready to give up yet; wimlib contains an implementation of the Windows IMage manipulation tool, imagex.

The first step in the Ultimate Deployment guide is to set up the DHCP server and TFTP server. I already did that for Debian and Fedora (see my previous posts here, and here. Rather than scrap what I had before, I will remove everything which I know doesn’t work. Here’s my current, broken Windows PE setup:


.
├── boot
│   ├── bcd
│   └── fonts
│       ├── chs_boot.ttf
│       ├── cht_boot.ttf
│       ├── jpn_boot.ttf
│       ├── kor_boot.ttf
│       └── wgl4_boot.ttf
├── bootmgr.exe
├── debian
│   ├── debian.menu.bak
│   ├── menu.cfg
│   ├── sid
│   │   ├── amd64
│   │   └── i386
│   ├── splash.png
│   └── wheezy
│       └── amd64
├── fedora
│   ├── 18
│   │   ├── initrd.img
│   │   └── vmlinuz
│   ├── menu.cfg
│   └── splash.png
├── hiberfil.sys
├── pxeboot.com
├── pxelinux.0
├── pxelinux.cfg
│   ├── default
│   ├── logo.png
│   ├── main.png
│   ├── pxe.conf
│   └── vesamenu.c32
├── wdsnbp.com
└── windows
    ├── 7.x64
    │   ├── __boot_metadata__
    │   ├── bootmgr.exe
    │   ├── boot.sdi
    │   ├── install.cmd
    │   ├── pxeboot.com
    │   ├── wdsnbp.0
    │   ├── winpeshl.ini
    │   └── winpe.wim
    ├── __boot_metadata__
    ├── menu.cfg
    ├── pxeboot.com
    ├── remap
    ├── splash.png
    ├── wdsnbp.com
    └── XP

I will remove everything from the windows/7.x64 directory, as well as all the /boot and windws related files in the TFTP root (/srv/tftp). One thing I want to make sure, is that WIM and BCD files (and any related helpers), are regenerated. Now just the windows/menu.cfg and splash image exist.

Next step is to set up the Samba share (which I’ve already done, but will go over again). The deployment guide suggests /work/sambashare as the path; I chose /var/spool/mirror/windows. The Windows 7 ISO I have is mounted oun /var/spool/mirror/windows/win7.x64.sp1/. The “smbclient –no-pass –list localhost” command confirms that REMINST is a known share. After some tribulation with midnight-commander (Debian does not compile SMB VFS support into mc by default), I was able to connect and browse the shares on my home workstation. I even created a symlink from “win7” to “win7.x64.sp1”, the former of which is the directory the deployment guide suggests to put in the Samba share root.

The guide has the administrator enable a log monitoring tool called “binl”. This will be mostly useless unless we set it to the tftp log (which on Debian is /var/log/daemon.log). I also had to ensure that a very verbose option was set in /etc/default/tftpd-hpa, adding “-vvv” to the TFTP_OPTIONS variable.

Part 3 of the deployment guide is where I decided to diverge. Rather than use the decidedly-closed source, yet still buggy tools they provided, I will use wimlibs’ imagex. The first step is to mount the image(s) in the Windows ISO root:/sources/boot.wim. Since there are two images within the boot.wim (Windows PE, and Windows Setup), I mounted both (at /mnt/win and /mnt/win.2, respectively. The first task is to find and extract the following files:


//windows/boot/pxe/pxeboot.n12
//windows/boot/pxe/bootmgr.exe
//windows/boot/pxe/wdsnbp.com

The Windows PE installation process expects these files to be in the TFTP root (/srv/tftp). So I placed them there. It looks like much of the deployment guide sets up is an unattended installation procedure. That’s not my goal right now; I’m just trying to launch a typical, attended Windows 7 Professional install, all from PXE. I’ll go with the stock boot.wim and see what happens… Looks like it’s a success! At least, I’ve gotten farther than I have ever with this Win7 attempt. I’m now at the Windows 7 “Setup is starting…” screen, I have a rotating blue “wait” ring… positive signs! Hrmm, it doesn’t work, the WDS client can’t connect to my TFTP server.

First thing I’m going to do is remap everything so the Windows files aren’t littering my TFTP root. Simple enough. I won’t worry about the files conflicting with any other Windows installs I want to put on here (since that list is probably effectively nil). Now it boots, but the installer can’t find the Windows Deployment Service (WDS), because I don’t have one. I will continue with the instructions from Ultimate Deployment, starting with section 3…

And I got lost. I stopped making notes. I ended up using the install.cmd. Rather than post the contents here (since it’s rather large), I’ve linked to it here: install.cmd. Since I was using the stock bcd file, it didn’t have the hive keys in it that the original install.cmd references. I hard coded my internal IP address, and had it call setup.exe on the mounted ISO.

Now, all I need to do is find a valid Windows 7 x64 Professional registration key, and I’ll be able to test the entire setup!

Adding Windows 7 to my PXE boot server…

I would have thought this would be difficult, but I found this Install Windows 7 over PXE from Linux without WAIK guide. I will document what I had to do differently (since that guide is designed for CentOS 5.3).

The first major change I needed to make was in the /etc/init.d/binl script; it called some things (e.g. /etc/sysconfig/network) which just doesn’t exist in Debian. I had to rip out all of the CentOS/Red Hat bits, and replace them with Debian ones. I also had to edit the binlsrv2.py file, since it had the tftp root path hardcoded in it.

Since tftpd-hpa was already set up (see my previous posts on the PXE boot subject), I just needed to add a remap file to /srv/tftp/windows/remap. This will cause tftpd-hpa to remap backslashes (‘\’) to slashes (‘/’). Setting up samba was pretty simple. I created the [REMINST] share as instructed, and mounted the Windows 7 x64 ISO to that share.

Importing the default boot files was straightforward, just used the wimextract tool found in the win7pxelinux.tgz distributed by the author of the ultimatedeployment.org site. I placed all of the executable files in /usr/local/bin, so I wouldn’t have to adjust my $PATH variable. I ran into an issue generating the winpe.wim Windows image (kept giving me an error that //windows/system32 couldn’t be found). To work around this problem, I added a “mkdir //windows/system32” command to the actionfile.txt, and it worked. Well, at least it didn’t give me an error.

The next step was to run a Perl script called bcdedit.pl. For this I had to install libhivex-bin, so I could run hivexsh (executed by bcdedit.pl). There was a problem, though. The hivexsh script generated a large number of errors. As far as I could figure out, hivexsh is slightly different between the Red Hat way and Debian way. In Debian, the -w option does not take an argument, whereas in Red Hat/CentOS the argument is the hive (Windows registry) file. Correcting this in bcdedit.pl was just a matter of moving the $bcd variable to the end of the command, rather than directly after the -w option.

Now was time to test it out. It looks like it launches, but it can’t seem to pull the files it needs from TFTP. It looks like it’s trying, just can’t find the files it wants:

…after some trial and error I notice that the WinPE client can’t find ‘hiberfil.sys’, a file created by Windows 7 when it hibernates. Thus the installation halts. Just touching the file isn’t enough. I can’t even make one in my Windows 7 virtual machine, since the guest firmware doesn’t support hibernation (not that it really needs to). So I’m stuck trying to figure out where I can grab that file from. I think it’s in the BCD I generated, but I don’t know where. Using the wimextract command from the toolset requires you to know where it is in the path. wimlib, which comes with an implementation of Windows’ imagex. I will have to start a new blog post for that, since I’ll have to start from scratch.

Adding Fedora 18 to my PXE boot server…

I covered setting up a Debian PXE boot server, and how to set up multiple OSes (well, multiple versions of Debian). This time I added Fedora 18 to the mix. Here’s my pxelinux.cfg/default menu file as it stands now:

default pxelinux.cfg/vesamenu.c32 menu background pxelinux.cfg/main.png prompt 0 timeout 0 ontimeout BootLocal noescape 1 label BootLocal localboot 0 text help Boot to local hard disk endtext menu begin Debian menu title Debian label Previous text help Return to previous menu endtext menu exit menu separator menu include debian/menu.cfg menu end menu begin Fedora menu title Fedora label Previous text help Return to previous menu endtext menu exit menu separator menu include fedora/menu.cfg menu end

All I did was copy the Debian section, and replace “Debian” with “Fedora.” I created the /srv/tftp/fedora/18 directory hierarchy, and pulled the vmlinuz and initrd.img from the linux/releases/18/Fedora/x86_64/iso/isolinux/ directory of the Fedora 18 netinst ISO. I created the /srv/tftp/fedora/menu.cfg file:

menu background fedora/splash.png label fedora18 menu label Fedora 18 - Install or Upgrade kernel fedora/18/vmlinuz append initrd=fedora/18/initrd.img repo=http://shevek.ceti/fedora/linux/releases/18/Fedora/x86_64/iso/ \ stage2=http://dl.fedoraproject.org/pub/fedora/linux/releases/18/Fedora/x86_64/os/ label fedora18vesa menu label Fedora 18 - Install or Upgrade (basic video driver) kernel fedora/18/vmlinuz append initrd=fedora/18/initrd.img xdriver=vesa nomodeset repo=http://shevek.ceti/fedora/linux/releases/18/Fedora/x86_64/iso/ \ stage2=http://dl.fedoraproject.org/pub/fedora/linux/releases/18/Fedora/x86_64/os/

(shevek.ceti is my workstation/PXE boot server). At first I just used the public mirror (repo only, not stage2), but since I was hosting the netinst image, I decided to use the stage2 install. My test VM is currently installing Fedora 18, I’d consider it a success!

Adding multiple Linux OSes to PXE boot…

In a followup to this post, I figured out how to add other versions of Debian to my PXE boot server. I followed two guides for doing so (PXE install on Debian Lenny, and Ubuntu Help’s Multi-Distro PXE Install Guide).

  1. After getting the single-distro (Debian Sid) working, I renamed the debian-installer directory (in /srv/tftp) to ‘sid’, created the ‘debian’ directory, and moved the ‘sid’ directory into ‘debian’:
    
    cd /srv/tftp
    mv debian-installer sid
    mkdir debian
    mv sid debian/
    
    
  2. Next, I needed to edit /srv/tftp/debian/sid/amd64/boot-screens/menu.cfg, and replace all instances of ‘debian-installer’ with ‘debian/sid’. I used vim to do it, but this simple sed command should also have done the trick:
    
    sed -i 's,debian-installer,debian/sid,g' /srv/tftp/debian/sid/amd64/boot-screens/menu.cfg
    
    

    Note that I will repeat this process for each Linux distro and arch added.

  3. I then added my next distro, Debian Wheezy amd64:
    
    cp -R /var/spool/mirror/dists/wheezy/main/installer-amd64/current/images/netboot/debian-installer/* /srv/tftp/debian/wheezy
    
    

    I made the same change as (2) above, changing ‘debian-installer’ in menu.cfg to ‘debian/wheezy’.

  4. Next I modified /srv/tftp/pxelinux.cfg/default:
    
    default pxelinux.cfg/vesamenu.c32
    prompt 0
    timeout 0
    ontimeout BootLocal
    noescape 1
    
    label BootLocal
            localboot 0
            text help
            Boot to local hard disk
            endtext
    
    menu begin Debian
    menu title Debian
            label Previous
            text help
            Return to previous menu
            endtext
            menu exit
            menu separator
            menu include debian/menu.cfg
    menu end
    
    
  5. I copied the syslinux file vesamenu.c32 to the pxelinux.cfg/ directory,

    cp /var/spool/mirror/dists/sid/main/installer-amd64/current/images/netboot/debian-installer/amd64/boot-screens/vesamenu.c32 /srv/tftp/pxelinux.cfg/

  6. Next, I created the file /srv/tftp/debian/menu.cfg
    
    menu background debian/splash.png
    menu begin Sid (amd64)
    menu title Sid (amd64)
            label Previous
            text help
            Return to previous menu
            endtext
            menu exit
            menu separator
            menu include debian/sid/amd64/boot-screens/menu.cfg
    menu end
    
    menu begin Sid (i386)
    menu title Sid (i386)
            label Previous
            text help
            Return to previous menu
            endtext
            menu exit
            menu separator
            menu include debian/sid/i386/boot-screens/menu.cfg
    menu end
    
    menu begin Wheezy (amd64)
    menu title Wheezy (amd64)
            label Previous
            text help
            Return to previous menu
            endtext
            menu exit
            menu separator
            menu include debian/wheezy/amd64/boot-screens/menu.cfg
    menu end
    
    
    
  7. I copied sid’s dists/sid/main/installer-amd64/current/images/netboot/debian-installer/amd64/boot-screens/splash.png to /srv/tftp/splash.png. That way, each distro family can have its own splash image!

After that, I added the other Sid distro (i386), following the same procedure. Here are some screenshots of the process (taken from my hosting workstation):

Next steps:

  • Add a foreign distro to the mix (e.g. Fedora 18, Arch)
  • Figure out how to boot and install a Windows image from this setup (probably very difficult).
    • Start with an old copy of Windows XP
    • Then go with Windows 7 (if I even have an ISO for it).