From 39baaa67e6fba9377c15678f4ed7f99c318a9adb Mon Sep 17 00:00:00 2001 From: nocode Date: Wed, 8 Jul 2026 23:56:56 +0200 Subject: [PATCH] feat(releng): add fws-windows-bcdfix script for windows bcd repair Add new script to make Windows bootable by executing bcdboot in WinPE launched once via BootNext after FWS installation. The script: 1. Stages bootable WinPE from ISO (bootmgr + BCD + boot.wim) to ESP 2. Injects automation (winpeshl.ini + fwspe.cmd) into boot.wim boot image - WinPE finds Windows drive and ESP partition - Executes bcdboot and reboots 3. Creates UEFI entry with one-shot BootNext to WinPE Note: Not validated on real hardware. Recommended path: bcdboot writes correct BCD with one automatic WinPE reboot before returning to FWS. --- .../airootfs/usr/local/bin/fws-windows-bcdfix | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 configs/releng/airootfs/usr/local/bin/fws-windows-bcdfix diff --git a/configs/releng/airootfs/usr/local/bin/fws-windows-bcdfix b/configs/releng/airootfs/usr/local/bin/fws-windows-bcdfix new file mode 100644 index 0000000..2ddf426 --- /dev/null +++ b/configs/releng/airootfs/usr/local/bin/fws-windows-bcdfix @@ -0,0 +1,85 @@ +#!/bin/bash +# ============================================================ +# fws-windows-bcdfix — rend Windows bootable en exécutant le VRAI `bcdboot` +# dans une WinPE lancée UNE FOIS (BootNext), juste après l'install FWS. +# +# ⚠ NON VALIDÉ SUR MATÉRIEL RÉEL. Voie RECOMMANDÉE par défaut : bcdboot écrit un +# BCD correct. Coût : 1 reboot automatique en WinPE, puis retour à FWS +# (BootOrder[0]=FWS réasserté par fws-windows-deploy + fws-gameboot-bootfix). +# +# Mécanique : +# 1. Copier la WinPE bootable de l'ISO (bootmgr + BCD WinPE + boot.wim) sur l'ESP. +# 2. Injecter winpeshl.ini + fwspe.cmd DANS l'image AMORÇABLE de boot.wim +# (Boot Index, typiquement 2 « Setup », + index 1 en ceinture) : au démarrage, +# WinPE lance fwspe.cmd → trouve le lecteur Windows (\Windows\System32\ +# winload.efi) et l'ESP (label WINESP via diskpart) → bcdboot → wpeutil reboot. +# 3. Poser une entrée UEFI + BootNext one-shot vers cette WinPE. +# +# Args : +# ============================================================ +set -u +ISO="${1:-}"; ESP="${2:-}"; WIN_DISK="${3:-}"; ESP_PN="${4:-1}" +log(){ printf '\e[36m[bcdfix]\e[0m %s\n' "$*"; } +die(){ printf '\e[31m[bcdfix] ERREUR : %s\e[0m\n' "$*" >&2; exit 1; } +[ -d "$ISO" ] && [ -d "$ESP" ] && [ -b "$WIN_DISK" ] || die "args invalides" +command -v wimlib-imagex >/dev/null 2>&1 || die "wimlib absent" + +# 1) Structure de boot WinPE depuis l'ISO (bootmgr + BCD WinPE prêts). +log "Staging de la WinPE de l'ISO sur l'ESP…" +mkdir -p "$ESP/EFI/Microsoft/Boot" "$ESP/sources" +cp -rf "$ISO"/efi/microsoft/boot/. "$ESP/EFI/Microsoft/Boot/" 2>/dev/null || true +[ -f "$ESP/EFI/Microsoft/Boot/bootmgfw.efi" ] \ + || cp -f "$ISO/efi/boot/bootx64.efi" "$ESP/EFI/Microsoft/Boot/bootmgfw.efi" 2>/dev/null \ + || die "bootmgfw.efi WinPE introuvable dans l'ISO" + +# 2) Injecter l'automation dans l'image AMORÇABLE de boot.wim. +TMP="$(mktemp -d)" +cp -f "$ISO/sources/boot.wim" "$TMP/boot.wim" || die "boot.wim introuvable dans l'ISO" +cat > "$TMP/winpeshl.ini" <<'INI' +[LaunchApps] +"cmd.exe", "/c X:\fwspe.cmd" +INI +# ⚠ NON VALIDÉ. bcdboot dans WinPE : trouver le lecteur Windows par présence de +# winload.efi (NTFS auto-monté), et l'ESP par son label WINESP via diskpart. +cat > "$TMP/fwspe.cmd" <<'CMD' +@echo off +set WIN= +for %%D in (C D E F G H I J K L M N O P) do if exist %%D:\Windows\System32\winload.efi set WIN=%%D: +echo list volume > X:\dp.txt +diskpart /s X:\dp.txt > X:\vol.txt +for /f "tokens=2" %%V in ('findstr /i "WINESP" X:\vol.txt') do ( + echo select volume %%V > X:\dp2.txt + echo assign letter=S >> X:\dp2.txt + diskpart /s X:\dp2.txt +) +if not defined WIN goto reboot +if exist S:\ ( bcdboot %WIN%\Windows /s S: /f UEFI ) else ( bcdboot %WIN%\Windows /f UEFI ) +:reboot +wpeutil reboot +CMD +# Image amorcée = « Boot Index » (typiquement 2) ; on injecte aussi l'index 1 en ceinture. +BOOTIDX="$(wimlib-imagex info "$TMP/boot.wim" 2>/dev/null | sed -n 's/^Boot Index:[[:space:]]*//p' | head -1)" +[ -n "$BOOTIDX" ] || BOOTIDX=2 +INJECTED=0 +for i in $BOOTIDX 1; do + wimlib-imagex update "$TMP/boot.wim" "$i" \ + --command="add '$TMP/winpeshl.ini' /Windows/System32/winpeshl.ini" 2>/dev/null \ + && wimlib-imagex update "$TMP/boot.wim" "$i" \ + --command="add '$TMP/fwspe.cmd' /fwspe.cmd" 2>/dev/null \ + && INJECTED=1 +done +[ "$INJECTED" = 1 ] || die "injection winpeshl/fwspe dans boot.wim échouée" +cp -f "$TMP/boot.wim" "$ESP/sources/boot.wim" || die "copie boot.wim → ESP échouée" +rm -rf "$TMP" + +# 3) Entrée UEFI one-shot vers la WinPE stagée. +log "Création de l'entrée UEFI WinPE (one-shot BootNext)…" +efibootmgr -c -d "$WIN_DISK" -p "$ESP_PN" -L 'FWS WinPE (bcdboot)' \ + -l '\EFI\Microsoft\Boot\bootmgfw.efi' >/dev/null 2>&1 \ + || die "création de l'entrée UEFI WinPE échouée" +PE_BN="$(efibootmgr 2>/dev/null | sed -n "s/^Boot\([0-9A-Fa-f]\{4\}\)\*\? *FWS WinPE.*/\1/p" | head -1)" +[ -n "$PE_BN" ] || die "numéro de boot WinPE introuvable" +efibootmgr -n "$PE_BN" >/dev/null || die "BootNext WinPE non armé" +log "WinPE armée en BootNext (Boot$PE_BN). Au 1er reboot : bcdboot puis retour FWS." +log "⚠ NON VALIDÉ sur matériel — à tester (assignation lettres WinPE, index boot.wim)." +exit 0