Un PXE pour les unir, tous et dans la lumière les installer…

Logo SysLinux

1. Présentation

1.1. Principes de fonctionnement

PXE représente l’agrégation de trois protocoles différents : BOOTP, DHCP, TFTP. De nos jours la couche BOOTP peut-être remplacé par UEFI. Son but est de démarrer un système d’exploitation depuis le réseau, le plus souvent dans le but d’opérer une installation. Coté client, le seul pré-requis est la présence d’un contrôleur réseau capable d’opérer un démarrage PXE. Coté du serveur, les services DHCP et TFTP doivent être configurés correctement, éventuellement sur deux serveurs différents. BOOTP est pris en charge directement par le serveur DHCP. L’opération se déroule ainsi :

  • Le BIOS ou le système UEFI de la machine passe la main au logiciel de la carte réseau ;
  • Ce logiciel fait une requête DHCP ;
  • Le serveur DHCP répond avec une configuration IP, masque, route par défaut, résolution DNS et l’adresse du fichier sur le TFTP ;
  • Le logiciel de la carte réseau télécharge le fichier, le place dans sa propre RAM, puis l’exécute.

C’est au programme contenu dans ce fichier qu’incombera le reste du démarrage en fonction de ses possibilités.

1.2. Prérequis

Ce tutoriel ne traite pas à proprement parler de l’installation et de la configuration d’un serveur DHCP. Un serveur DHCP de l’ISC fonctionnel est présuposé dans le reste de l’article. Un minimum de connaissance de la ligne de commande Linux sera également supposé.

2. Briques logicielles mise en œuvre

2.1. PXELinux

PXELinux est un sous-projet d’un projet ensemble beaucoup plus vaste consistant à fournir une large palette de bootloaders pour des usages variés. Ce projet, appelé SYSLinux, fondé en 1994 comme une alternative à LiLo, est supporté par la fondation Linux et est hébergé sur le site « kernel.org », qui héberge le noyau Linux. Il inclus également les sous-projets ISOLinux (démarrage CD/DVD et clé USB) et EXTLinux (démarrage sur disque dur formaté en EXT2/3/4). SYSLinux lui-même s’occupe du démarrage depuis des disques formatés en FAT ou NTFS. Les fichiers de configuration et les modules sont totalement inter-opérables entre PXELinux, ISOLinux, EXTLinux et SYSLinux.

Le choix de SYSLinux s’impose à mes yeux pour plusieurs raisons :

  • Une très large capacité à booter à peu près n’importe quoi à travers un système modulaire ;
  • Il est très bien documenté, et on peut facilement trouver nombres d’exemples et de ressources, pour peut qu’on soit un tantinet anglophone ;
  • C’est le bootloader de quasiment 100 % des CD, clés USB et PXE des distributions Linux (en fait je n’ai pas trouvé de contre exemple dans le monde Linux) ;
  • La compatibilité des fichiers de configuration et de menu avec de nombreux supports de démarrage (pour produire un boot CD, par exemple) ;
  • Projet à la fois actif et mature, toujours soutenu par son fondateur et dictateur bienveillant, H. Peter Anvin, par ailleurs un important développeur du noyau Linuxv même si on peut noter un net ralentissement depuis 2016.

PXELinux est modulaire, il est capable d’utiliser des fichiers dits « com32 » de manière semblable à un système de modules d’extension. Dans leur version de démarrage traditionnel par le BIOS, il s’agit d’images mémoire en mode réel, semblables aux fichiers « com » qu’utilisaient autrefois les systèmes DOS (ceux qui on connu voit très bien de quoi je parle), mais en 32 bits. Les versions UEFI de ces fichiers fonctionnent en mode protégé, soit en 32 bits soit en 64 bits. Les binaires 64 bits UEFI ne seront pas capable d’exécuter des modules 32 bits. Pour des raisons de compatibilité, l’extension c32 est maintenu sur toute les architechtures.

2.2. iPXE

iPXE est un projet concurrent de PXELinux, bien plus jeune mais toutefois relativement mature. Il n’a pas été retenu dans le choix final du fait de son orientation qui le spécialise dans les systèmes UEFI, et de sa plus grande complexité de mise en œuvre qui ne nous apporte pas d’avantage significatif. Par ailleurs, PXELinux a depuis largement rattrapé son retard sur iPXE concernant le support UEFI.

En revanche, iPXE propose, lui aussi, différents sous-projets et l’un d’entre eux va particulièrement nous intéresser. Ce sous-projet étant compatible avec PXELinux, nous allons pouvoir l’utiliser moyennant une petite astuce.

Il s’agit de WimBoot qui propose une solution spécialisée de démarrage en réseau de systèmes Windows. La particularité intéressante de WimBoot est qu’il simule complètement le système de démarrage propriétaire de Microsoft et crée lui-même un ramdisk utilisable directement à chaud par l’environnement d’installation Windows.

D’autres méthodes existent pour amorcer Windows en PXE, mais WimBoot est définitivement le système le plus abouti, à la fois simple à mettre en œuvre et le seul à ma connaissance à permettre le boot de plusieurs images Windows différentes.

2.3. DHCP de l’ISC et TFTP HPA

L’association des implémentations ISC de DHCP et HPA pour ce qui est de TFTP est de loin la plus documentée et recommandée par l’ensemble des sites Internet traitant du sujet. Par ailleurs, des tests avec d’autres serveurs TFTP, comme atftpd, ont montré des difficultés dans nos tests pour démarrer des systèmes non Linux.

Par ailleurs, le HPA du nom du serveur TFTP signifie H. Peter Anvin, nom du développeur de cette version du serveur, le même développeur principal que celui de PXELinux, ce qui laisse deviner une forte optimisation pour ce dernier et une certaine cohérence dans leurs fonctionnements respectifs.

En revanche des expériences menés avec DNSMasq, on montré des résultat plutôt satisfaisant et peuvent être explorés si le cœur vous en dit. Pour ma part, je ne suis pas fan des serveurs qui mélangent plusieurs services, c’est pourquoi je ne souhaite pas l’utiliser.

3. Mise en place des serveurs

3.1. Arborescence PXE du serveur TFTP

PXELinux permet une organisation sous forme de répertoires assez flexible. Seul un petit nombre de fichiers doivent obligatoirement figurer à la racine (voir les détails en section 3.3). L’arborescence sera organisé de la manière suivante :

  • /menus : contient notre structure de menus ;
  • /bios : contient les fichiers binaires pour un démarrage en mode bios ;
  • /efi32 : contient les fichiers binaires pour un démarrage en mode UEFI 32 bits ;
  • /efi64 : contient les fichiers binaires pour un démarrage en mode UEFI 64 bits ;
  • /images : contient les fichiers spécifiques au systèmes cibles ;
  • /etc : contient de la configuration et un fichier spécifique à OpenBSD.

Chaque répertoire binaire (bios, efi32 et efi64) contient un répertoire « pxelinux.cfg » qui est le seul à être imposé par PXELinux. Il devra contenir le ou les fichiers de configuration principaux bien qu’un système d’include nous permettra de mettre en commun la quasi-totalité des paramètres. Cette arborescence peut-être placé à la racine ou dans un sous répertoire de l’arborescence du serveur TFTP.

Chaque répertoire de binaires contiendra un fichier « pxelinux.0 », « syslnx32.efi » ou « syslnx64.efi »  respectivement dans « bios », « efi32 » et « efi64 ». Chacun de ces fichiers est un point d’entrée exécutable. Une fois chargé, le programme contenu dans ce point d’entrée se met à la recherche de son fichier de configuration principal. Attention : si vous n’avez pas placé le point d’entrée à la racine de l’arborescence TFTP, il faudra bien faire attention à ce que l’ensemble des chemins utiles à PXELinux soient relatifs à l’emplacement de ce point d’entrée. Autrement dit, dans tous les fichiers de menu et de configuration de PXELinux, la racine pour tous les chemins n’est pas la racine de l’arborescence TFTP mais toujours le répertoire ou se trouve le point d’entrée.

Enfin, il ne faut jamais préciser le répertoire racine dans les fichiers de configuration ou de menu de PXELinux. Autrement dit, nous n’écrirons jamais quelque chose comme « /config/menu.cfg » mais toujours « config/menu.cfg ».

3.2. Configuration des DHCP et TFTP

Chaque configuration DHCP peut avoir ses spécificités et détailler son fonctionnement sort du cadre de ce document. Ces lignes sont à ajouter dans la section de votre choix du fichier de configuration de DHCP (traditionnellement une section subnet) :

if option arch = 00:06 {
        filename "/la_ou_vous_voulez/efi32/syslnx32.efi";
} else if option arch = 00:07 {
        filename "/la_ou_vous_voulez/efi64/syslnx64.efi";
} else if option arch = 00:09 {
        filename "/la_ou_vous_voulez/efi64/syslnx64.efi";
} else {
       filename "/la_ou_vous_voulez/bios/pxelinux.0";
}

Évidemment, remplacez « <la_ou_vous_voulez> » par l’emplacement du fichier relativement à la racine de votre arborescence TFTP.

Si votre serveur TFTP n’a pour seule utilité que le boot PXE, il n’y a pas de raison de placer tous ces fichiers ailleurs qu’à sa racine.

Pour le serveur TFTP, il existe très peu d’option indispensable à paramétrer. Dans notre cas seule la ligne définissant l’emplacement de la racine du service TFTP est importante :

TFTP_DIRECTORY="/srv/tftp/"

Libre à vous de changer ce chemin, tout ce document n’y faisant pas référence, les chemins fournis pour PXE seront toujours relatif à ce répertoire. Pour le reste, les options par défaut de la distribution conviendront la plupart du temps et ne changeront pas le comportement de cette implémentation.

3.3. Installation de PXELinux

PXELinux est disponible dans les archives sources de SYSLinux. Aucune compilation n’est cependant nécessaire pour obtenir les fichiers requis. Les archives sources sont disponibles à l’adresse suivante : https://www.kernel.org/pub/linux/utils/boot/syslinux. Il n’y a pas de raison à préférer une autre version que la dernière. Par ailleurs, le contenu de ce document n’est plus valable pour toute version inférieure à la 6.00.

3.3.1. Partie BIOS

Les fichiers absolument nécessaires sont les suivants, relativement au répertoire principal de l’archive :

  • bios/core/pxelinux.0
  • bios/com32/elflink/ldlinux/ldlinux.c32
  • bios/com32/lib/libcom32.c32
  • bios/com32/libutil/libutil.c32

Tous ces fichiers doivent obligatoirement se trouver le répertoire « bios » de notre arborescence, à coté de « pxelinux.0 ». Toutefois, des liens symboliques sont possibles si vous ne souhaitez pas que les fichiers s’y trouve physiquement.

Un autre fichier est indispensable, celui qui permettra d’afficher effectivement le menu. Celui-ci est proposé sous forme de deux alternatives, qu’on peut utiliser indistinctement avec les même options de configuration :

  • bios/com32/menu/menu.c32 : Affichage texte ;
  • bios/com32/menu/vesamenu.c32 : Affichage graphique.

On peut passer de l’un à l’autre à chaud à l’intérieur des menu, même si ça n’a pas tellement de sens. L’ensemble des options inapplicables au mode texte sont simplement ignoré lorsqu’elles sont rencontrées.

Pour ces deux fichiers, on peut spécifier le chemin mais il n’y a pas de raison dans ce tutoriel de les mettre ailleurs. Dans cette implémentation, j’ai choisi la version graphique, plus agréable, mais aussi capable d’afficher bien davantage d’éléments que ce que permet le mode texte, limité à un affichage de 80×25.

Il existe aussi un fichier « bios/memdisk/memdisk » qui permet de charger un fichier en mémoire, de manière brute, et de le booter. Il permet par conséquent de booter en théorie n’importe quelle image de disquette, CD ou DVD bootable, sans avoir à la manipuler. Lui aussi sera placé dans notre répertoire /lib.

Attention toutefois avec l’usage de « memdisk ». Si ce système peut sembler pratique et simple à mettre en œuvre et être une solution universelle pour booter n’importe quoi, son utilisation est très loin d’être privilégiée, notamment avec les images ISO. En effet, il faut disposer de beaucoup de RAM pour pouvoir y stocker l’image dans son intégralité, incluant son éventuel espace libre, et le système une fois démarré. Par conséquent, le chargement d’une image ISO de 2 Go, indépendamment de son très long temps de téléchargement en RAM, va rapidement nécessiter plus de 3 Go de RAM, si on se lance dans une installation graphique. Par ailleurs, memdisk est indisponible en mode UEFI car il repose sur les interruptions 13h et 15h du BIOS.

3.3.3. Partie UEFI

Les deux arboressances efi32 et efi64 de l’archive sont identiques et les fichiers iront dans nos répertoires efi32 et efi64 respectivement :

  • efi{32,64}/efi/syslinux.efi renomé en syslnx32.efi et syslnx64.efi
  • efi32/com32/elflink/ldlinux/ldlinux.e32 ou efi64/com32/elflink/ldlinux/ldlinux.e64
  • efi{32,64}/com32/lib/libcom32.c32
  • efi{32,64}/com32/libutil/libutil.c32

Comme pour le BIOS, les fichiers qui correspondent au menus :

  • efi{32,64}/com32/menu/menu.c32
  • efi{32,64}/com32/menu/vesamenu.c32

3.3.3. Autres modules intéressants

D’autres fichiers sont potentiellement intéressants si on veut ajouter des fonctionnalités supplémentaires au menu. J’ai retenu les suivants :

  • {bios,efi{32,64}}/com32/modules/poweroff.c32 : permet l’extinction de la machine ;
  • {bios,efi{32,64}}/com32/modules/reboot.c32 : permet le redémarrage ;
  • {bios,efi{32,64}}/com32/modules/linux.c32 : simule un noyau Linux (voir la partie Windows) ;
  • {bios,efi{32,64}}/com32/hdt/hdt.c32 : outils d’informations sur le matériel (qui dépend d’autres fichier c32, à voir plus bas) ;
  • {bios,efi{32,64}}/com32/chain/chain.c32 : permet de chaîner le démarrage sur un autre bootloader ;
  • {bios,efi{32,64}}/com32/modules/pxechn.c32 : permet de chaîner le démarrage sur un autre serveur PXE.

D’autres fichiers au format com32 sont disponibles dans l’archive source pour enrichir les possibilités offertes par le menu. Leur utilisation sera abordée en section 6.1 de cet article.

3.3.4. Liens symboliques

Afin que les répertoires « menus », « images » et « etc » soient disponibles pour chaque architecture des liens symboliques sont créés dans les répertoires de chaque architecture :

  • {bios,efi{32,64}}/etc pointe sur ../etc
  • {bios,efi{32,64}}/menus pointe sur ../menus
  • {bios,efi{32,64}}/images pointe sur ../images

3.4. Principes de boot d’un OS

Dans le cas d’un démarrage en réseau on retrouve des principes de base qui sont communs à la totalité des systèmes. Tout d’abord, l’absence de support physique rend absolument nécessaire l’usage de ramdisk. Il s’agit d’unités de lecture virtuelles créées en RAM qui contiendront le système de fichiers nécessaire au fonctionnement de l’OS. Voici les étapes de démarrage :

  • PXELinux, qui se comporte comme n’importe quel bootloader du point de vue d’un noyau, télécharge en RAM le noyau à booter puis l’exécute. À ce stade, il n’y a aucune notion de système de fichiers ou d’unité de lecture.
  • Le noyau exécuté s’initialise et monte son système de fichiers racine, à savoir le ramdisk. Ce noyau peut être complet et tout à fait semblable à celui d’un système installé comme avec Linux ou BSD qui supportent nativement l’exécution en PXE, soit être un embryon minimaliste qui n’a que pour rôle d’effectuer ce montage pour passer la main à quelque chose de plus complexe dans le cas de Windows. En effet un noyau Windows ne gérera pas lui même le démarrage en PXE et devra, dans ce cas, être encapsulé. Pour illustrer, un « memdisk » est lui-aussi une méthode d’encapsulation.

4. Obtention des fichiers

4.1. Fichiers de boot Linux

Toutes les distributions Linux ont besoin de deux fichiers vitaux pour démarrer en PXE : le noyau, souvent appelé « vmlinuz » (mais pas forcément) et le ramdisk qui lui est associé, souvent appelé « initrd.XX », où XX est l’extension du format de compression utilisé. Le plus simple est habituellement de télécharger une archive contenant ces fichiers spécialement préparés pour le démarrage en PXE. Voici des liens de téléchargement pour les distributions que nous allons manipuler, dans lesquels vous remplacerez par l’architecture cible (par exemple, amd64, i686 ou i386) et par la version à mettre en œuvre (par exemple, jessie pour Debian ou 6.7 pour CentOS) :

  • Debian : http://ftp.fr.debian.org/debian/dists/<version>/main/installer-<arch>/current/images/
  • CentOS : http://vault.centos.org/<version>/os/<arch>/images/pxeboot/
  • Suse : http://download.opensuse.org/factory/repo/oss/boot/<arch>/loader/

Certaines distributions ne fournissent pas de version spécifique du noyau et du ramdisk pour le démarrage en PXE. Dans ce cas, il est possible de récupérer ces fichiers dans l’image ISO de leur support d’installation. Cependant, le fonctionnement n’est pas assuré dans cette situation. Une solution consiste alors à générer le ramdisk nécessaire avec les outils proposés par la distribution.

Si la distribution que l’ont veut démarrer n’a pas de possibilité d’être démarrée en PXE, et que la génération du ramdisk adéquat n’est pas envisageable, il reste possible d’utiliser memdisk avec une image ISO la plus légère possible.

4.2. Fichiers OpenBSD

Nous aurons besoin de deux fichiers fournis par OpenBSD pour pouvoir démarrer ce système, à savoir l’image de la disquette de démarrage et le ramdisk :

  • Disquette : http://ftp.openbsd.org/pub/OpenBSD/<version>/<arch>/floppy<version>.fs
  • Ramdisk : http://ftp.openbsd.org/pub/OpenBSD/<version>/<arch>/bsd.rd

Cette section ne couvre pas les autres BSD. OpenBSD est très spécifique, là ou NetBSD et FreeBSD se comportent de manière comparable.

4.3. Fichiers de boot Windows

Contrairement aux systèmes déjà abordés, Microsoft ne fournit pas de fichiers directement utilisables pour un démarrage PXE. Par ailleurs, nous devrons également aborder le problème des pilotes nécessaires au démarrage en PXE.

En conséquence, il existe un nombre nettement plus important d’étapes pour réaliser une image de boot Windows. Il faut préparer l’image, écrire un script d’initialisation permettant de fournir la source et de démarrer le programme d’installation, puis installer tout le nécessaire dans notre arborescence PXE et sur un partage CIFS.

4.3.1. Preparation de l’image

Windows est capable de démarrer en réseau un environnement d’exécution, appelé Windows PE, qui est assez peu dépendant de la version à installer. Par conséquent, un certain nombre de fichiers, ainsi que la procédure de démarrage, sont communs à l’ensemble des versions installables de ce système. Dans un premier temps, il faudra installer sur un poste Windows quelconque, le pack « Windows Automated Installation Kit », souvent abrévié « WAIK », qui se base sur les versions de Windows Vista et 7. Il est disponible ici : https://www.microsoft.com/fr-fr/download/details.aspx?id=5753. Les droits d’administration seront nécessaires sur ce poste.

Concernant les différents kits de déploiement Microsoft, qui ont la fâcheuse tendance à changer de nom à chaque version de Windows, on peut noter que pour une version donnée de Windows, toutes les versions précédentes supportées au moment de sa sortie seront installables avec. L’inverse peut être vrai mais n’est pas garanti.

Pour Windows 8 et 8.1 on parlera du « Automated Deployment Kit » (ADK), et enfin pour Windows 10 nous nous intéresserons à « Microsoft Deployment Toolkit » (MDT), qui ne propose plus d’interface en ligne de commande mais des outils graphiques de type Management Console (MMC) ne permettant plus de scripter la génération de l’image de boot comme je propose de le faire. Toutefois un ADK pour Windows 10 a finallement vu le jour. L’ADK est téléchargeable par ce lien : https://docs.microsoft.com/fr-fr/windows-hardware/get-started/adk-install.

Une fois le kit de déploiement installé, on crée l’environnement nécessaire à notre travail :

copype.cmd amd64 d:\winpe_amd64
mkdir d:\winpe_amd64\mount

Remplacez les « amd64 » par des « x86 » si vous êtes en 32 bits. Cet environnement se compose d’une arborescence contenant une image de boot (« d:\winpe_amd64\winpe.wim ») et le nécessaire à la création d’un fichier ISO qui dans notre cas ne sera pas utilisé en tant que tel.

Attention, en aucun cas, « d:\winpe_amd64 » ne peut être sur un chemin réseau ou un lecteur amovible. Par ailleurs, le système de fichier doit obligatoirement être en NTFS.

Nous devrons ensuite monter l’image de boot :

mkdir d:\winpe_amd64\mount
dism /Mount-Wim /WimFile:d:\winpe_amd64\winpe.wim /index:1 /MountDir:d:\winpe_amd64\mount
dism /image:d:\winpe_amd64\mount /Set-AllIntl:fr-FR

La dernière ligne nous permet de forcer la langue française à la fois pour la langue de l’installateur et pour la langue à installer sur le système cible.

4.3.2. Ajout des pilotes à l’image

Il est rare que l’image standard Microsoft fonctionne correctement sur des machines modernes notamment par manque de pilotes. Il est capital de disposer d’une image de boot qui contient au moins tous les pilotes réseau possibles de votre parc. Pour ce faire, vous devez créer un répertoire qui sera votre répertoire de stockage des pilotes pour WAIK ou ADK et vous assurer de les y placer non compressés.

Les pilotes doivent être composés d’un fichier d’information « .inf » et de tous les fichiers que ce dernier référencera (on trouvera surtout des « .sys » et des « .dll »). Les programmes d’installation seront, eux, inutilisables tels qu’ils sont faits. Dans la suite de ce document nous considérerons les pilotes sous « D:\drivers\<arch>\ » ou <arch> représente l’architecture cible (« x86 » ou « amd64 »).

Nous ajoutons les pilotes à l’image de boot ainsi :

mkdir d:\winpe_amd64\mount
dism /image:d:\winpe_amd64\mount /Add-Driver /Driver:d:\drivers\amd64 /Recurse /ForceUnsigned

Ceci ajoute récursivement tous les pilotes qui seront trouvés dans « d:\drivers\amd64 ».

4.3.3. Processus de boot de Windows

Quand l’environnement Windows PE boot, un certain nombre de tâche d’initialisation doivent être menées. Si ce démarrage s’effectue grâce au supports d’installations officiels de Microsoft, ces tâches sont opérées automatiquement, mais supposent une certaine invariance. Ces tâches sont l’initialisation du matériel et le montage éventuel du système de fichier d’installation. Ceci abouti au lancement du programme d’installation.

Notre situation est différente puisque le boot réseau nous prive de l’accès à certaines ressources requise par l’installateur de Microsoft. Parmi les ressources possibles la source d’installation qui contient tous les fichiers à installer ainsi que le nécessaire pour initialiser base de registre et autres configuration et pilotes liés au matériel est essentielle. Cette source s’appelle « install.wim ». Pour des raisons pratiques il faudra proposer cette source sur un montage CIFS accessible anonymement. Nous allons donc devoir prévoir un partage CIFS adapté à l’installation de Windows que nous monterons grâce à un script. Ce script devra effectuer les étapes préalables de préparation de l’environnement (initialisation du matériel et mise en œuvre de l’accès à la source d’installation) puis devra lancer avec des paramètres corrects le programme d’installation.

4.3.4. Script d’initialisation

Nous allons supposer qu’un partage CIFS est correctement configuré. Ce partage doit pouvoir être accessible en lecture mais l’écriture n’est pas nécessaire. Dans ce document le partage que nous utiliserons sera situé sous « \\cifs\install\win7 ». Dans ce partage, le seul fichier vital sera « install.wim », récupéré depuis le DVD d’installation dans le répertoire « \sources\ ». Nous placerons ce fichier (environ 4,5 Go, plus ou moins suivant les éditions) dans notre partage CIFS à l’emplacement indiqué plus tôt.

Notre script d’initialisation doit être déclaré dans un fichier de configuration situé dans le répertoire « d:\winpe_amd64\mount\windows\system32 » (dans l’arborescence du fichier « winpe.wim »). Ce fichier de configuration se nommera « winpeshl.ini » et contient :

[LaunchApps]
%SYSTEMDRIVE%\sources\install.cmd
%SYSTEMDRIVE%\windows\system32\cmd.exe

On crée ensuite le répertoire d’accueil pour notre script d’initialisation (qui peut être placé ailleurs du moment que l’information dans « winpeshl.ini » correspond) :

md d:\winpe_amd64\mount\sources

Ce répertoire contiendra le script « install.cmd » listé ci-dessous :

rem Lancement de l'initialisation:
wpeinit
rem Montage du partage d'installation:
net use V: \\cifs\install\win7 /USER:nobody
rem Lancement du programme d'installation:
setup.exe /installfrom:V:\install.wim

En premier lieu, nous initialisons Windows PE, notamment pour qu’il puisse utiliser le réseau, puisque notre script prend le pas sur le mécanisme classique d’initialisation de Windows PE. Nous continuons avec le montage de notre partage sur le lecteur « V:\ ». Si vous utilisez une autre lettre de lecteur, assurez vous qu’elle ne puisse entrer en conflit avec les lecteurs physiques de la machine (à partir de « C:\ ») et le lecteur correspondant à notre ramdisk nécessaire pendant l’installation, c’est-à-dire « X:\ ».

La dernière ligne de notre script d’initialisation consistera à lancer effectivement le programme d’installation. Cette ligne doit être la dernière : tout code placé à la suite, ne sera pas exécuté, sauf éventuel échec de « setup.exe ».

4.3.5. Fermeture de l’image et copie des fichiers

Une fois l’image prête nous en extrayons le bootloader PXE de Microsoft puis nous pouvons enregistrer nos modifications et la démonter :

copy d:\winpe_amd64\mount\Windows\Boot\PXE\bootmgr.exe d:\winpe_amd64\
dism /Unmount-Wim /MountDir:C:\winpe_amd64\mount /Commit

En cas d’erreur ou pour toute autre raison, vous pouvez annuler vos modifications en utilisant le switch « /Discard » au lieu du switch « /Commit ». Veuillez noter que l’usage d’un de ces deux switchs est obligatoire quand on utilise « /Unmount-Wim ».

Maintenant que notre « winpe.wim » est complet, les fichiers suivants de l’arborescence devront être ajoutés dans celle du serveur PXE (chemins relatifs à « d:\winpe_amd64 ») :

  • ISO\boot\bcd qui doit être renommé « BCD » (en majuscule)
  • ISO\boot\boot.sdi
  • bootmgr.exe
  • winpe.wim

4.3.6 Installation de WimBoot

Une fois tout cela en place, il faut s’occuper d’ajouter WimBoot dans l’arborescence PXE, le bootloader pour Windows que nous avons choisi.

WimBoot n’ayant pas été conçu, à la base, pour PXELinux, nous devrons utiliser le com32 « linux.c32 » qui se comporte comme un noyaux Linux et qui prend comme unique paramètre un ramdisk. Ce ramdisk sera WimBoot.

On peut obtenir les différentes versions de WimBoot à partir de ce répertoire : https://github.com/ipxe/wimboot/releases. Le fichier « wimboot.i386 » sera renommé en « wimboot » dans « efi32 ». WimBoot est considéré comme un module de PXELinux.

5. Mise en œuvre

5.1. Pré-requis

À partir de maintenant nous considérerons que les serveurs DHCP et TFTP sont correctement configurés et sont fonctionnels.

Pour terminer, le serveur DHCP et le serveur TFTP n’ont pas besoin d’être dans la même machine. Toutefois la configuration sera légèrement plus simple si tel est le cas et les nombreux exemples fournis sur Internet supposent presque toujours cette situation.

Une aide à la configuration de ces services en vue de l’utilisation de PXELinux est disponible à l’adresse suivante : http://www.syslinux.org/wiki/index.php/PXELINUX (en anglais).

5.2. Fichier de configuration principal

Le fichier de configuration principal de PXELinux est auto-suffisant et permet d’intégrer des structure complexe dans un unique fichier de configuration. Ceci dit, on peut vite arriver à des fichiers très long est illisible. C’est pourquoi nous allons massivement utiliser le système d’inclusion disponible. Ce système insère le fichier inclus, à l’endroit ou l’inclusion est déclaré, récursivement quand un fichier inclus en appel lui-même d’autres. Dans notre cas, cela sous entend que notre structure de menu complète est intégralement chargée quand le menu principal est affiché.

Pendant les phases de développement, il peut être utile de recharger la configuration et les menus. Ceci est possible simplement en appuyant sur la touche « Echap » quand on se trouve dans nôtre menu principal. Dans tous les autres cas, « Echap » permet de sortir d’un sous menu.

Voici nôtre fichier « pxelinux.cfg/default », pour chaque architecture :

# Inclus un fichier unique pour toute les archis:
path bios
include etc/common.cfg

Pour chaque architecture le champ « bios » de la variable path doit être replacé par « efi32 » et « efi64 » respectivement. Ce champ doit être préfixé par votre répertoire d’accueil si votre arborescence PXE ne se trouve pas à la racine de l’arborescence TFTP.

Toute la magie, vous le devinerez se trouve dans ce fichier « etc/common.cfg », dont les détails sont expliqués en commentaire :

# Ajoute le module permettant un affichage graphique et le menu en lui même
# Pour le mode texte, utiliser menu.c32 à la place
default vesamenu.c32

# Définit la résolution (si possible, sinon continue en mode texte)
# La résolution graphique par défaut est 640x480
menu resolution 800 600

# Définit le titre du menu et l'image de fond (doit être en 800x600)
menu title Menu d'installation et dépannage PXE
menu background etc/smoke.jpg

# Positionne le menu selon une grille correspondant à la taille d'un caractère
menu hshift 16
menu vshift 3
menu width  66
menu margin 3 # Nombre de caractère entre le bord du cadre et les entrées

# Définit les couleurs au format GRVB (Gamma, Rouge, Vert, Bleu)
#                    Attributs Foreground Background Ombre
menu color border    *         #76a1d0ff  #00000000  none # Fond du menu et cadre
menu color title     *         #ffffff00             *    # Titre
menu color sel       *         #ffffffff  #76a1d0ff  *    # Sélection
menu color hotsel    1;7;37;40 #ffffffff  #76a1d0ff  *    # Racourci sélectionné
menu color tabmsg    *         #ff00ff00  #00000000  *    # Message d'instruction
menu color help      37;40     #ffddddff  #00000000  *    # Message d'aide
menu color pwdborder *         #76a1d0ff  #00000000  none # Fond de la boite mot de passe
menu color pwdheader *         #ffffff00             *    # Titre de la boite mot de passe
menu color pwdentry  *         #ffffffff             *    # Zone de saisie du mot de passe

# Position des zones de texte supplémentaire
menu helpmsgrow 24    # 1ère ligne d'aide
menu cmdlinerow 24    # Ligne de commande
menu timeoutrow 21    # Compte à rebour si pertinant
menu tabmsgrow 20     # Message d'instruction
menu tabmsg Choisissez le systeme, utilisez TAB pour editer la ligne de boot.

prompt 0 # Affiche un promp supplémentaire avnt le boot si 1
timeout 0 # Timeout en secondes sélectionnant le choix par défaut, 0 pour désactiver

noescape 1 # Désactive l'échappement, on ne peut pas rendre la main à la carte mère
allowoptions 1 # Permet de passer des arguments dans la ligne KERNEL, sinon interdit

# Mot de passe d'accès ou de modification des entrées du menu
#menu master passwd 
#menu passprompt Mot de passe requis

# On place le menu dans une structure de répertoire reflétant sa hiérarchie
include menus/main.cfg

PXELinux ne gère pas les jeux de caractères étendus de type « Unicode ». L’accès aux caractères accentués est possible mais peu simple car il nécessite la conversion des fichiers à la table OEM850 (c’est celle du BIOS).

Une liste relativement exhaustive des paramètres possibles, à la fois pour le menu en lui-même et son apparence, est disponible à l’adresse suivante : http://www.syslinux.org/wiki/index.php/Comboot/menu.c32. Notez que bon nombre de ces paramètres peuvent être surchargés à l’intérieur du menu (c’est à dire, dans les fichiers inclus, dans notre cas). En d’autres termes, si on veut changer l’apparence ou le papier peint pour chaque sous-menu, on peut.

Les fichiers de configuration principaux sont soient nommés « default » pour la configuration par défaut, soit nommé à partir de l’adresse MAC d’une machine en majuscule, ou du début commun de l’adresse MAC d’un groupe de machine. Par exemple, si nous avons cinq machines dont les adresses MAC commencent toutes par « AC-21-D0 », alors il est possible de créer un fichier « AC21D0 », qui contiendra les paramètres spécifiques pour ce groupe de machines. La priorité la plus forte ira aux adresses MAC les plus complètes pour se terminer avec le fichier « default ».

5.3. Structure de menu

La structure de menu suit un système d’inclusion en arbre hiérarchique semblable à ceci :

	Menu principal (répertoire config)
		+---- menu.cfg
		+---- Outils
		|	+---- menu.cfg
		|	+---- Catégorie 1
		|	|	+---- menu.cfg
		|	+---- Catégorie 2
		|		+---- menu.cfg
		+---- Système 1
		|	+---- menu.cfg
		|	+---- Version 1
		|	|	+---- menu.cfg
		|	+---- Version 2
		|	|	+---- menu.cfg
		|	+---- Version 3
		|		+---- menu.cfg
		+---- Système 2
			+---- menu.cfg
			+---- Version 1
			|	+---- menu.cfg
			+---- Version 2
				+---- menu.cfg

Comme on peut le voir, nous allons différencier deux types de fichiers de menu : ceux qui permettent d’ouvrir un sous-menu et ceux, en bout de chaîne, qui lancent effectivement un installateur ou un outil.

Cette hiérarchie est également reportée, pour plus de cohérence, sur la structure de répertoires qui va abriter les noyaux, ramdisk et autres fichiers nécessaires au boot des différents éléments présents dans les menus. Pour résumer, dans notre implémentation, la racine des fichiers de menu se trouve dans le répertoire « menus » et les programmes à lancer dans le répertoire « images ». Ces deux répertoires respecteront strictement la même structure.

5.4. Déclaration de sous-menu

On utilise le code suivant pour créer un sous menu :

menu begin diagnostic
    # Titre du sous menu (pas racourci)
    menu title Outils de diagnostic
    # Entrée de menu, avec support des racourcis
    menu label ^Outils de diagnostic
    include menus/diag/menu.cfg
menu end

# On ajoute un séparateur qui consiste en une ligne vide :
menu separator

menu begin debian
    menu title Debian
    menu label ^Debian
    include menus/debian/menu.cfg
menu end

Le nom du menu (suivi par « begin ») n’est affiché qu’en l’absence de la ligne « menu title ». Ce nom est un identifiant qui peut être utilisé si on utilise la commande « goto ». Dans la mesure ou nous ne l’utiliserons pas, inutile de détailler cette possibilité. Pour le reste, rien de particulier à ajouter, le fonctionnement est limpide.

À l’intérieur d’un menu on pourra trouver l’entrée suivante pour revenir au menu parent :

label mainmenu
    menu label ^ESC - Retour...
    menu exit

5.5. Déclaration d’un menu Linux

Chaque distribution possède ses spécificités et il est impossible de lister toutes les options disponibles ni toutes les procédures de démarrage. En revanche, tous les Linux possèdent des points communs que nous pouvons évoquer ici et qui seront suffisant pour un démarrage basique de n’importe quelle distribution, c’est-à-dire au moins en runlevel 1 (mono-utilisateur). Voici à quoi ça ressemble dans le cas d’une Debian Jessie :

label deb-buster
        menu label Debian ^Buster (64 bits)
        kernel images/debian/buster/x86_64/linux
        append vga=788 initrd=images/debian/buster/x86_64/initrd.gz netcfg/choose_interface=auto ramdisk_size=10275 root=/dev/ram rw lang=fr debian-installer/locale=fr_FR keymap=fr(latin9) qla2xxx.blacklist=yes –

Jusqu’à la ligne « menu », rien d’extraordinaire. On fourni ensuite à PXELinux le chemin du noyau à démarrer (ligne « kernel »). La ligne « append » est celle qui va varier d’une distribution à une autre, même si un des paramètres doit toujours apparaître et que les autres sont rarement vitaux. C’est le paramètre « initrd » qui est absolument obligatoire. Il s’agit de la structure du ramdisk qui sera utilisé par le noyau, et qui contient notamment ses modules mais aussi le système d’init et d’autres éléments vitaux.

Tous les paramètres sont passés au noyau puis, ceux qu’il ne connait pas sont passés à « init » qui les propage généralement dans l’environnement, pour qu’ils soient disponibles à l’ensemble des programmes de la procédure de démarrage. Ici nous utilisons la possibilité de choisir automatiquement l’interface réseau en prenant le premier qui a une configuration DHCP fonctionnelle et configurer le français des le démarrage de l’installeur Debian.

Le cas des systèmes Linux Live est légèrement différent dans la mesure ou ils font parfois référence à un système de fichier supplémentaire (qui correspond généralement à /usr), séparé du ramdisk :

label sysresccd64
    menu label Recovery CD 64 bits (^SysRescCD 4.7.1)
    kernel images/diag/dist/sysresccd/rescue64
    append scandelay=5 initrd=images/diag/dist/sysresccd/initram.igz boottftp=tftp://10.1.1.254/images/diag/dist/sysresccd/sysrcd.dat setkeymap=fr

label rescatux64
    menu label ^RescaTux 0.40b5 x86_64
    kernel images/diag/dist/rescatux/vmlinuz1
    append initrd=images/diag/dist/rescatux/initrd1.img boot=live config noswap fetch=tftp://10.1.1.254/images/diag/dist/rescatux/filesystem.squashfs noquiet setkeymap=fr 

On voit que la ligne « append » fait référence au dit système de fichier à travers l’adresse de ce fichier sur le serveur TFTP. Prenez donc garde à remplacer ces références par l’adresse correcte de votre serveur TFTP, soit en y plaçant son adresse IP, soit son nom d’hôte (nete : les noms DNS ne fonctionnent pas avec RescaTux).

On peut également observer que notre structure PXE se trouve dans un sous-répertoire « pxe » du TFTP qui est cette fois explicitement mentionné. Ce lien sera en effet utilisé bien après le début du boot à un moment ou toute trace de PXELinux aura disparue en mémoire.

5.6. Déclaration d’un menu (Open)BSD

Cette procédure ne fonctionnera, à priori, qu’avec OpenBSD. Un module spécifique appelé « mboot.c32 » est disponible pour FreeBSD et NetBSD.

PXELinux n’est pas conçu à la base pour démarrer un OpenBSD. Ceci dit, le kernel « memdisk » fourni avec, permet de démarrer n’importe quel support de type disquette et/ou autre image de périphérique bootable (notamment ISO), pour peu que la mémoire soit suffisante pour abriter à la fois l’image dans son intégralité (y compris son éventuel espace libre) et le système une fois démarré.

OpenBSD fournissant toujours des disquettes de démarrage, c’est la méthode que nous avons choisi :

label bsd68
    menu label OpenBSD 6.8 (64 bits)
    kernel memdisk
    append initrd=images/openbsd/6.8/floppy68.fs

Cette image de type floppy est trop petite pour contenir un OpenBSD suffisant pour pratiquer une installation. Elle contient le noyau et un init suffisant pour aller chercher des ressources complémentaires. En particulier, elle va récupérer les éléments manquant dans un fichier « bsd.rd ». Le chemin d’accès à ce fichier est fourni dans « etc/boot.conf » à la racine du PXE. Voici le nôtre :

boot images/openbsd/6.8/bsd.rd

Comme on peut le voir ce fichier est extrêmement simple mais impose une certaine limitation : il n’est pas possible avec cette méthode de proposer plusieurs version d’OpenBSD.

Malheureusement cette méthode ne fonctionnera pas en UEFI. Des recherches supplémentaires devraient permettre de trouver un autre moyen.

5.7. Déclaration d’un menu Windows

WimBoot n’ayant pas été conçu, à la base, pour PXELinux, nous allons utiliser le com32 « linux.c32 » qui se comporte comme un noyaux Linux et qui prend comme unique paramètre un ramdisk. Ce ramdisk n’est autre que WimBoot :

label win7
    menu label ^Windows 7
    com32 linux.c32
    append wimboot gui initrdfile=images/windows/win7/bootmgr.exe,images/windows/win7/BCD,images/windows/win7/boot.sdi,images/windows/win7/winpe.wim

label win2008r2
    menu label ^Windows Server 2008r2
    com32 lib/linux.c32
    append lib/wimboot gui initrdfile=images/windows/win2008r2/bootmgr.exe,images/windows/win2008r2/BCD,images/windows/win2008r2/boot.sdi,images/windows/win2008r2/winpe.wim

Une fois WimBoot chargé, il intercepte la liste des fichiers dans le paramètre « initrdfile », détecte automatiquement leur rôle à partir de leur contenu et charge ces fichiers correctement en simulant un ramdisk couvrant la plupart des cas de figure. Par exemple, « boot.sdi » sera visible à la racine du ramdisk mais également dans plusieurs sous répertoire de recherche possible des différentes version de Windows. Voici la structure du ramdisk de WimBoot dans lequel chaque fichier est répliqué :

\
\Boot
\Boot\Fonts
\Boot\Resources
\Sources
\EFI
\EFI\Boot
\EFI\Microsoft
\EFI\Microsoft\Boot

6. Outils

6.1. Exécuter un fichiers com32

Les fichiers com32 sont des modules de SYSLinux. Certains proposent des fonctionnalités supplémentaires (par exemple, la possibilité de menus conditionnels en fonction de l’architecture), d’autres peuvent être démarrés comme de micro systèmes d’exploitation. Toutefois, une fois leur exécution terminée nous pouvons retourner au menu PXE sans redémarrage, à moins que leur fonctionnement ne s’y oppose.

label reboot
    menu label ^Redemarrer l'ordinateur
    kernel reboot.c32

label poweroff
    menu label ^Eteindre l'ordinateur
    kernel poweroff.c32

Ces deux com32 sont appelés indifféremment avec le mot clé « kernel », ou le mot clé « com32 » dans la mesure ou le résultat est toujours le même.

label localhdd
    menu label ^Disque dur local
    kernel chain.c32
    append hd0 0
    text help
Vous pouvez editer la ligne de boot pour specifier quel disque et/ou quelle partition demarrer, en la modifiant comme suit :

      >  chain.c32 hdX Y

X represente alors le disque et Y la partition. Attention, ce mecanisme ne fonctionne qu'avec des tables de partition DOS ou GPT.
endtext

Ce module est également l’occasion de montrer comment on peut afficher un texte d’aide supplémentaire. Chaque entrée de menu et de sous-menu peut en avoir un. Là encore, le mot clé « kernel » est préféré.

label hdt
    menu label Hardware Detection Tools 6.03
    com32 hdt.c32

Pour cette entrée de menu, nous utilisons le mot-clé « com32 ». Dans ce cas, quitter HDT permet de retourner au menu PXE. Si nous avions utilisé le mot clé « kernel » la machine aurait redémarré en quittant HDT.

La liste détaillée des com32 fournis avec l’ensemble SYSLinux est disponible à cette adresse : http://www.syslinux.org/wiki/index.php/Library_modules (en anglais). Certains ne sont malheureusement pas encore documentés.

7. Conclusion

Grace à ces resources vous disposez de nombreuses possibilité pour booter par le réseau un grand nombre de systèmes. Combiné à des fichiers de préconfiguration d’installation (préseed chez Debian, kickstart dans la famille Red Had, etc), cette solution vous permettra rapidement d’installer un système d’exploitation rapidement et de manière automatisé.

N’hésitez pas à utiliser les commentaires pour relever les problème, fôte d’aurthograffe ou éléments qu’il serait pertinant d’ajouter !

Partagez éthiquement

11 thoughts on “Un PXE pour les unir, tous et dans la lumière les installer…”

  1. Lu en diagonale. Bravo pour ce travail !
    Ca me rappelle le boot des terminaux X (X11R6) dans les années 80…
    cmic, sysadmin à la retraite

  2. Assez touffus, mais assez complet pour se lancer, merci.
    Une petite typo au passage (3.3.4) : “sont crés dna s”

  3. Je n’ai pas très bien compris ( ou je suis idiot ) sur le : Que doit contenir tel ou tel répertoire … Mais comme j’ ai déjà fait quelques essais auparavant je vais voir à cela !!!

  4. Pour ceux que cela intéresserait j’ utilise OpenWrt . La version 19.07.5 gère le SMB2 ce qui ne posera pas de problème avec Windows contrairement à la version 18.06 qui oblige à “bricoler” le WinPE pour qu’il gère le SMB1 …

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.