Windows XP network install
This is a useful technique if you don't have an XP installation CD and need to install Windows XP on an old system which supports PXE. I've found that USB installation is unreliable.
How everything fits together
There are quite a few moving parts in the Windows XP network install process:
- PXE:
- Use DHCP to get an IP address, the name of the TFTP server (
next-server
) and the name of the boot file. - Get the boot file (
pxelinux.0
) from the TFTP server using TFTP and chain it
pxelinux.0
:- Get
ldlinux.c32
using TFTP and start it - Get the configuration file via TFTP
- First try using the MAC address (e.g.
pxelinux.cfg/00-11-22-33-44-55-66
) - If that fails, convert the IP address to hex (e.g. 10.0.240.239 becomes
0A00F0E6
) then request e.g.pxelinux.cfg/0A00F0E6
. - Remove a character from the end of the name and try again. Repeat until either there is success, or the name is null.
- Finally, request
pxelinux.cfg/default
- The configuration file may specify a user interface (e.g.
menu.c32
) which will be downloaded at this stage - The user selects the
Windows XP Netinstall
option from the menu (or types it)- Syslinux gets
startrom.0
(the renamedstartrom.n12
) via TFTP and chainloads it.
startrom.0
– Windows XP stage-0 boot:- Request
ntldr
,BOOTFONT.BIN
(optional),ntdetect.com
andwinnt.sif
- Read configuration from
winnt.sif
.- Use the
SetupSourceDevice
in the[SetupData]
section to obtain the TFTP and SMB relative path from root.
- Request around 120 bootstrap files from the TFTP server
- These are listed in the appendix, and are all in the
i386
directory.
- The Windows XP loading screen appears
- It takes a few minutes for Windows to load.
- Windows XP Setup requests the rest of the files it needs using SMB, from the
SetupSourceDevice
path inwinnt.sif
.
- Machine reboots from the hard disk to run the graphical setup wizard.
- Files are again downloaded over SMB.
- The
OriSrc
parameter in the[data]
section ofwinnt.sif
specifies where Windows will look for install files (e.g. drivers) after it has been installed.
Preparation
Download the following:
- A clean Windows XP installation ISO
- You can validate your image using the hash values here: https://msfn.org/board/topic/173057-how-to-obtain-authentic-microsoft-xp-isos/
Samba setup
Create the share directory and copy the Windows XP CD contents into it:
sudo zfs create zpool/risinstall cd /mnt/zfs/risinstall mkdir winxp_32bit cd winxp_32bit # Unpack the CD. Can also use 'cp -r /media/WINXP/* .' 7z x /media/WINXP.ISO # Fix permissions and convert filenames to lower case find -type d -exec chmod 755 {} \; find -type f -exec chmod 644 {} \; find . -depth -exec rename 's!([^/]*\Z)!lc($1)!e' {} + # Change names of files which stage-0 TFTP requests as uppercase, back to uppercase for i in KDCOM.DL_ BOOTVID.dl_ SETUPREG.HI_ SETUPREG.HIV SPDDLANG.SY_ WMILIB.SY_ OPRGHDLR.SY_ 1394BUS.SY_ PCIIDEX.SY_ USBPORT.SY_ USBD.SY_ HIDCLASS.SY_ HIDPARSE.SY_ VIDEOPRT.SY_ SCSIPORT.SY_ CLASSPNP.SY_ TDI.SY_ ; do mv i386/`echo $i | tr '[:upper:]' '[:lower:]'` i386/$i done # Make the system files needed for Setup executable (required by Samba 4, see manpage https://www.samba.org/samba/docs/current/man-html/smb.conf.5.html#ACLALLOWEXECUTEALWAYS) chmod 755 i386/system32/* i386/*.dll i386/*.exe i386/*.com
Edit /etc/samba/smb.conf
to add the share:
[risinstall] comment = Unattended Windows XP install path = /mnt/zfs/risinstall guest ok = yes browseable = no writeable = yes locking = no
Restart Samba (sudo service smbd restart
).
DNSmasq configuration (advertising a remote TFTP server)
Add these lines to /etc/dnsmasq.d/pxe.conf
, replacing the XX
'ed MAC address with the target PC's MAC address, and TFTP-SERVER
with the hostname or IP address of the TFTP server.
; Change the MAC address to that of the PC you want to netboot dhcp-host=XX:XX:XX:XX:XX:XX,set:netbootwxp ; Windows XP Netinstall for dhcp-boot=tag:netbootwxp,pxelinux.0,TFTP-SERVER,TFTP-SERVER
TFTP server setup
Install the TFTP server, PXELinux and Syslinux:
sudo apt install pxelinux syslinux-efi tftpd-hpa
Windows XP requests files from TFTP using Windows naming conventions, so we need to use a TFTP map file to convert these names to Unix
# Convert Windows naming conventions to Linux (backslashes to forward-slashes) rg \\ / # Convert non-absolute files to absolute. r ^[^/] /srv/tftp/\0 # Convert relative paths to their absolute position r ^/syslinux/ /srv/tftp\0 r ^/pxelinux.cfg/ /srv/tftp\0 r ^/winxp_32bit/ /srv/tftp\0 # Add the remote IP address as a folder on the front of all requests. # This can be useful for sending different winnt.sif's to different machines. #r ^ \i/
And edit /etc/default/tftpd-hpa
to set:
# /etc/default/tftpd-hpa TFTP_USERNAME="tftp" TFTP_DIRECTORY="/srv/tftp" TFTP_ADDRESS=":69" #TFTP_OPTIONS="--secure -vvv -m /etc/tftpd-hpa.rules" TFTP_OPTIONS="-vvv -m /etc/tftpd-hpa.rules"
Note that secure mode is disabled - this is deliberate. In secure mode, tftpd-hpa
runs in a chroot
inside the TFTP directory, which prevents it from following symlinks outside the TFTP root.
Next set up PXELinux:
cd /srv/tftp sudo cp /usr/lib/PXELINUX/pxelinux.0 . sudo cp /usr/lib/SYSLINUX.EFI/efi64/syslinux.efi . sudo mkdir syslinux for i in ldlinux.c32 libutil.c32 menu.c32; do sudo cp /usr/lib/syslinux/modules/bios/$i syslinux/; done mkdir pxelinux.cfg cat <<EOF >pxelinux.cfg/default timeout 0 prompt 1 ui menu.c32 label xp32_netinst kernel startrom.0
Prepare the Windows XP installation files:
cp /mnt/zfs/risinstall/winxp_32bit/i386/ntdetect.com . cp /mnt/zfs/risinstall/winxp_32bit/i386/setupldr.bin ntldr # Decompress startrom.n12 as startrom.0 7z x /mnt/zfs/risinstall/winxp_32bit/i386/startrom.n1_ mv startrom.n12 startrom.0 # Convert SETUPLDR.BIN into NTLDR fixloader.py ntldr
Appendix: fixloader.py, Python 3 version
- fixloader.py
#!/usr/bin/env python3 # -*- Mode: Python; tab-width: 4 -*- # # Fix for setuploader # # Copyright (C) 2005-2006 Gianluigi Tiesi <sherpya@netfarm.it> # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # ====================================================================== from sys import argv, exit as sys_exit if __name__ == '__main__': if len(argv) < 2: print('Usage: fixloader.py ntldr') sys_exit() data = open(argv[1], 'rb').read() if data.find(b'setupldr.exe')==-1: print('Wrong file') sys_exit() if data[:2] == b'MZ': print('Loader already fixed') sys_exit() data = b'MZ' + data.split(b'MZ', 1).pop() open(argv[1], 'wb').write(data) print('Loader fixed')
Creating the setup information file
Create a file called winnt.sif
in the TFTP root. The one below is an example.
Replace FILESERVER
with the SMB name of the file server, and RISINSTALL
with the share name.
OriSrc
should point to the i386
directory as it's used if Windows needs extra files after it's been installed.
SetupSourceDevice
is the SMB path in the form of the device, and should point to what is effectively the root directory, one level up from the i386
directory.
[data] floppyless = "1" msdosinitiated = "1" ; Needed for second stage -- this is used as the installation path for Windows itself (if it needs things later) OriSrc = "\\FILESERVER\RISINSTALL\winxp_32bit\i386" OriTyp = "4" LocalSourceOnCD = 1 DisableAdminAccountOnDomainJoin = 1 ; ;;;;;;;;;;;;; ; Copy the [data] section from your nLite i386/WINNT.SIF file into the area below. ; ;;;;;;;;;;;;; AutomaticUpdates="Yes" Autopartition=0 MsDosInitiated=0 UnattendedInstall="Yes" ; ;;;;;;;;;;;;; ; End nLite area ; ;;;;;;;;;;;;; [SetupData] OsLoadOptions = "/fastdetect" ; Needed for first stage SetupSourceDevice="\Device\LanmanRedirector\FILESERVER\RISInstall\winxp_32bit" [RemoteInstall] ; Avoid automatic format/repartition Repartition = No UseWholeDisk = No [UserData] ; Samba will see this as an underscore ComputerName = * ProductID=XXXXX-XXXXX-XXXXX-XXXXX-XXXXX ; ;;;;;;;;;;;;; ; Copy your nLite i386/WINNT.SIF file (except the [data] section) below. ; ;;;;;;;;;;;;;
Network drivers and BINL
BINL is used to convert a network card identity (PCI ID) into a device driver name. It requires a server on the local network, and a directory of INF files. The SYS file is retrieved via TFTP.
If you need an Ethernet driver which isn't included with Windows XP, download and unpack it. For this example I'll be using the Marvell Yukon driver.
First we create the BINL support directories and unpack the Windows XP standard driver descriptions:
mkdir -p /mnt/zfs/risinstall/binl/tmp cd /mnt/zfs/risinstall/binl/tmp cabextract /mnt/zfs/risinstall/winxp_32bit/I386/*.IN_ cabextract /mnt/zfs/risinstall/winxp_32bit/I386/DRIVER.CAB
Next we copy the Marvell Yukon INF file into the BINL input directory, and the driver into the Windows i386 directory:
cp /mnt/zfs/risinstall/Drivers/yukon/XP32/*.inf /mnt/zfs/risinstall/binl/tmp cp /mnt/zfs/risinstall/Drivers/yukon/XP32/*.sys /mnt/zfs/risinstall/winxp_32bit/i386
And the same for the Realtek RTL811E drivers:
cp /mnt/zfs/risinstall/Drivers/rtl8111e/WINXP/*.inf /mnt/zfs/risinstall/binl/tmp cp /mnt/zfs/risinstall/Drivers/rtl8111e/WINXP/*.sys /mnt/zfs/risinstall/winxp_32bit/i386
Now run nLite and use it to integrate the network drivers into the installer. If you don't do this, then the network drivers will only be used for the setup process, and will not actually be installed on the system.
Finally we create the BINL cache and start the server:
# Create BINL cache cd /mnt/zfs/risinstall/binl ../ris-linux-0.4/infparser.py tmp # Start BINL server gcc -o binlsrv ../ris-linux-0.4/binlsrv.c ./binlsrv # Alternatively use the Python BINL server ../ris-linux-0.4/binlsrv.py
I've found that the Python BINL server doesn't always find the driver correctly (e.g. on the Intel D525MW), but the C version is quite reliable.
Booting the target system
Now the TFTP, SMB and BINL servers should be running.
Configure the target system for PXE network boot, and trigger a netboot. On the Asus Rampage Formula system I used for testing, this is done by enabling the LAN Boot ROM, then hitting F8 for the boot menu, and selecting the Marvell Yukon PXE entry.
If you see NT_STATUS_ACCESS_DENIED
errors from Samba (or STATUS_ACCESS_DENIED
in Wireshark decoded SMB protocol traces), then check whether the file being requested is executable. If so, and the client expects to execute it, then it may need to be chmod +x
'd.
Post-installation steps
This more or less boils down to installing the applications and drivers you need. I usually put these in a subdirectory of the RISInstall
share directory, then run them over the network.
I've yet to find a good way to pre-install applications automatically. I imagine something could be done with a RunOnce
modification in nLite, but that's something I need to look into.
The main applications you'll want to install are:
- 7-Zip, surprisingly the latest version (as of April 2024) still supports Windows XP
- Firefox – you'll need to search around and find the last Windows XP-compatible version.
- You may not want to install this: it's not a stellar idea to use a massively outdated Windows XP system to browse the Internet…
Next steps
nLite
nLite can be used to integrate service packs and drivers. Generally this is most useful for network and RAID/AHCI drivers as everything else can usually be loaded after the installation has completed.
Note that some filenames will need to be fixed after nLite has built the image:
mv TXTSETUP.SIF txtsetup.sif
mv IASTOR.SY_ iaStor.sy_
(Intel ICH9R RAID drivers)
Other files may need to be renamed; these will be visible when the setup is first started from the nLite'd image directory.
Useful changes to make with nLite
These are starting from a Windows XP SP3 CD.
- Hotfixes, add-ons and update packs
- Windows XP Unofficial Service Pack 4: https://archive.org/details/windows-xp-usp-4-v-3.1b-x-86-enu.-7z
- Drivers – as needed.
- Generally I integrate the drivers for whichever boards I'm using; this is usually the ASUS Rampage Formula and Intel D525MW.
- As a minimum, include the AHCI drivers for your SATA controller, and the network drivers.
- Remove components – disabled
- Unattended
- General tab:
- Product Key: set to your product key
- Misc
- Skip OOBE (skips post-install setup)
- System restore service
- Turn Off
- Users tab:
- Set default Administrator password if desired
- Add users if desired
- Owner and Network ID tab: (this skips the user registration page in Setup)
- Full name:
BUILD
- Organization:
BUILD
- Workgroup:
Workgroup
(or your system workgroup)
- Regional: (this skips the region settings page)
- Language: English UK
- Use language type
- Timezone: GMT London
- Desktop themes tab:
- Options:
- Default theme: Windows Classic
- Colour scheme: Windows Classic style
- Classic Start Menu: checked
- Automatic updates:
- Download and install
- Elevate non-admins: checked
- RunOnce tab:
- TBD. Could use this to install drivers and applications after installation.
- Options
- High compression enabled (saves disk space and speeds up installation over the network)
- Tweaks
- Boot and Shutdown-Logon Page-Classic
- Desktop-Internet Explorer icon-Hide
- Desktop-My Computer icon-Show
- Desktop-My Documents icon-Show
- Desktop-My Network Places icon-Show
- Desktop-Recycle Bin icon-Show
- Explorer-Add 'Command Prompt' to folder context menu
- Explorer-Advanced Search: preconfigure options
- Explorer-Associate additional file types with Notepad
- Explorer-Classic Control Panel
- Explorer-Disable Accessibility keyboard shortcuts
- Explorer-Disable Autorun
- Explorer-Disable Search Assistant
- Explorer-Display the contents of system folders
- Explorer-Launch folder windows in a separate process
- Explorer-Show extensions of known file-types
- Explorer-Show hidden files and folders
- Explorer-Show protected operating system files
- Explorer-Show the full path in the Address Bar
- Internet Explorer-Disable Internet Explorer link creation
- Internet Explorer-Disable Market Place bookmark
- Internet Explorer-Disable Media Player 6.4 created bookmarks
- Internet Explorer-Disable Outlook Express link creation
- Internet Explorer-Disable Password-Caching
- Internet Explorer-Disable sound when popup is blocked
- Internet Explorer-Enable Google URL-Search
- Network-Disable Simple File Sharing
- Privacy-Disable Driver Update Internet prompt
- Privacy-Disable Error Reporting
- Privacy-Remove Alexa
- Security-Disable Web Open With prompt
- Start Menu-Do not use Personalized Menus
- Taskbar-Disable Windows Tour popup
Multiple Windows XP ''SIF'' files
Sometimes it's necessary to have several different winnt.sif
files, to accommodate different deployment images.
The easiest way to achieve this is to modify the TFTP server rules
file to remap requests for winnt.sif
to winnt_\i.sif
. This will select the SIF file based on the IP address of the requesting machine.
Sometimes it's preferable to have multiple images which can be selected from the menu. This can be achieved by patching the loaders, as documented by Jui-Nan Lin:
- Modify the name of the loader from
NTLDR
toXPLDR
:sed -i -e 's/NTLDR/XPLDR/gi' startrom.n12
- Move the modified pxe loader to tftpd root, and call it
winxp.0
- Modify the name of the response file from
winnt.sif
towinxp.sif
- Extract the setuploader, using cabextract:
cabextract /i386/SETUPLDR.EX_
sed -i -e 's/winnt\.sif/winxp\.sif/gi' setupldr.exe
- Modify the name of
ntdetect
fromntdetect.com
tontdetect.wxp
:sed -i -e 's/ntdetect\.com/ntdetect\.wxp/gi' setupldr.exe
- Move the modified setuploader to tftpd root, and call it
xpldr
The modified loader is referenced in the PXELinux configuration as winxp.0
. With the above modifications, the load order changes to:
winxp.0
(modified startrom
) → XPLDR
(modified ntldr
) → ntdetect.wxp
, winxp.sif
→ (install)
While this process works, it's imperfect:
- There are three almost-identical files on the TFTP share, for each different
sif
file variant. - The new filename must be the same length as the old one, which limits the options available.
Troubleshooting
Product Key is in WINNT.SIF, but Setup still asks for it -- or Product Key is rejected
Per KB950722 and this thread on MSFN, this is usually caused by slipstreaming an XP Service Pack into an installation under Windows Server 2003 or Windows 7.
To resolve this, you'll have to recreate your nLite-d install image using Windows XP.
Identifying image type (matching product keys)
Windows XP images generally require a product key for the specific type of Windows in use. There are two ways to identify the image type.
SETUPP.INI
: The last three digits of thePid
field identifies the image type.270
: VLK335
: RetailOEM
: OEM000
: can be one of several; the full MPC/CID code will need to be looked up on Lunarsoft's list of valid product IDs.- The Lunarsoft list also explains how to decode a product ID as shown in the System Properties (Windows key + Break, or right click My Computer, select Properties).
- Setup appearance: The “Enter Product Key” screen (during the first part of Setup) changes depending on the edition:
- OEM: Shows a green Certificate of Authenticity, and asks for the key from it.
- Retail: Shows a yellow Product Key sticker, and asks for the key from it.
- VLK: Shows no stickers, and requests a Volume License product key.
- Screenshots are available here: http://www.thetechguide.com/misc/winxp.html
These both assume the image hasn't been monkeyed with: changing the Pid will generally not work to change a VLK installation into a Retail one, per the comments on this MyDigitalLife post.
Appendices
Appendix: Files requested over TFTP before starting Setup
These files are requested by the text-mode version of the Windows XP setup utility.
All these files are in the i386
directory.
txtsetup.si_ txtsetup.sif biosinfo.in_ biosinfo.inf drvmain.sd_ drvmain.sdb migrate.in_ migrate.inf unsupdrv.in_ unsupdrv.inf halmacpi.dl_ ntkrnlmp.ex_ KDCOM.DL_ BOOTVID.dl_ SETUPREG.HI_ SETUPREG.HIV vgaoem.fo_ c_1252.nl_ c_437.nl_ l_intl.nl_ c_1252.nl_ c_437.nl_ l_intl.nl_ setupdd.sy_ SPDDLANG.SY_ pci.sy_ acpi.sy_ WMILIB.SY_ isapnp.sy_ acpiec.sy_ OPRGHDLR.SY_ ohci1394.sy_ 1394BUS.SY_ pcmcia.sy_ pciide.sy_ PCIIDEX.SY_ intelide.sy_ viaide.sy_ cmdide.sy_ toside.sy_ aliide.sy_ mountmgr.sy_ ftdisk.sy_ partmgr.sy_ fdc.sy_ dmload.sy_ dmio.sy_ sbp2port.sy_ lbrtfdc.sy_ usbehci.sy_ USBPORT.SY_ usbohci.sy_ usbuhci.sy_ usbhub.sy_ USBD.SY_ usbccgp.sy_ hidusb.sy_ HIDCLASS.SY_ HIDPARSE.SY_ serial.sy_ serenum.sy_ usbstor.sy_ vga.sy_ VIDEOPRT.SY_ i8042prt.sy_ kbdhid.sy_ kbdclass.sy_ SCSIPORT.SY_ cpqarray.sy_ atapi.sy_ aha154x.sy_ sparrow.sy_ symc810.sy_ aic78xx.sy_ i2omp.sy_ dac960nt.sy_ ql10wnt.sy_ amsint.sy_ asc.sy_ asc3550.sy_ mraid35x.sy_ ini910u.sy_ ql1240.sy_ aic78u2.sy_ symc8xx.sy_ sym_hi.sy_ sym_u3.sy_ asc3350p.sy_ abp480n5.sy_ cd20xrnt.sy_ ultra.sy_ adpu160m.sy_ dpti2o.sy_ ql1080.sy_ ql1280.sy_ ql12160.sy_ perc2.sy_ hpn.sy_ cbidf2k.sy_ dac2w2k.sy_ dmboot.sy_ cdrom.sy_ CLASSPNP.SY_ disk.sy_ sfloppy.sy_ ramdisk.sy_ ksecdd.sy_ ksecdd.sys fastfat.sy_ ntfs.sy_ ntfs.sys cdfs.sy_ ndis.sy_ ipsec.sy_ tcpip.sy_ TDI.SY_ ipnat.sy_ netbt.sy_ rdbss.sy_ mup.sy_ mrxsmb.sy_
Note that the network driver is also requested from TFTP, after its name has been obtained using BINL.
Appendix: TFTP remapping rules to convert filenames to lowercase
These are useful for debugging the stage-zero (TFTP bootstrapping) phase.
Source: https://www.syslinux.org/archives/2004-August/003883.html
Making them exclusive to WinXP is a bit tricky, see: https://www.syslinux.org/archives/2004-August/003884.html
rg A a # lower case rg B b # lower case rg C c # lower case rg D d # lower case rg E e # lower case rg F f # lower case rg G g # lower case rg H h # lower case rg I i # lower case rg J j # lower case rg K k # lower case rg L l # lower case rg M m # lower case rg N n # lower case rg O o # lower case rg P p # lower case rg Q q # lower case rg R r # lower case rg S s # lower case rg T t # lower case rg U u # lower case rg V v # lower case rg W w # lower case rg X x # lower case rg Y y # lower case rg Z z # lower case