Files
pxe-server/playbook/startnet.cmd
cproudlock 7be5518fd7 Fix v2 imaging: copy common/ at imaging time + use $setupDir not $PSScriptRoot
Two bugs that have been silently masking GE-Enforce registration since
Stage 2a landed 2026-04-22, surfaced when v1 enforcers were retired
(commit 0badfc1) and could no longer cover for the missing v2 registration.

Bug 1: startnet.cmd at imaging time only xcopied Shopfloor\ and the
PCTYPE-specific dir from the imaging share to W:\Enrollment\shopfloor-setup\.
common\ was never copied. v1 dispatchers lived per-pctype and rode in via
the %PCTYPE% xcopy, so this was never noticed. v2's GE-Enforce.ps1 +
Register-GEEnforce.ps1 + lib\Install-FromManifest.ps1 all live in common\
and got skipped at imaging entirely.

Fix: add a third xcopy block for common\, mirroring the Shopfloor\ block
above it. Applies to playbook/startnet.cmd and startnet-template.cmd.

Bug 2: Run-ShopfloorSetup.ps1 line 288 set $commonSetupDir via
'Join-Path $PSScriptRoot common'. Run-ShopfloorSetup.ps1 lives at
C:\Enrollment\Run-ShopfloorSetup.ps1 (xcopied by startnet.cmd), so
$PSScriptRoot resolves to C:\Enrollment, and $commonSetupDir resolved
to C:\Enrollment\common - which is NOT where common\ lives even after
the bug 1 fix (correct path is C:\Enrollment\shopfloor-setup\common\).
The Test-Path -LiteralPath check on Register-GEEnforce.ps1 returned
false silently and GE-Enforce never registered.

Same bug existed for Register-MapSfldShare on line 321.

Fix: $PSScriptRoot -> $setupDir for both. $setupDir was already defined
on line 51 as Join-Path $enrollDir "shopfloor-setup", which is the path
the rest of the script uses consistently.

Pre-v1-cleanup, v1's per-pctype enforcer registrations on lines 322-357
(now deleted) ran independently and covered the gap, so PCs ended up
with v1 enforcers and the user thought v2 was running. Post-cleanup,
this bug means nothing gets registered.

PXE server has been patched directly: boot.wim re-baked with the new
startnet.cmd, /srv/samba/enrollment/shopfloor-setup/Run-ShopfloorSetup.ps1
replaced. New PXE-imaged PCs from this point forward will register
GE-Enforce correctly.

For PCs imaged before this fix: run Deploy-GEEnforce.ps1 from the SFLD
share's _meta/runtime/ to retrofit. Same one-liner used for promoting
v1 PCs to v2.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 14:31:15 -04:00

382 lines
13 KiB
Batchfile

@echo off
echo Please wait while 'WinPE' is being processed. This may take a few seconds.
wpeinit
powercfg /s 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c
REM --- Wait for network (DHCP may take a moment after wpeinit) ---
echo Waiting for network...
:wait_net
ping -n 2 10.9.100.1 >NUL 2>&1
if errorlevel 1 goto wait_net
echo Network ready.
REM --- BIOS update check (runs before imaging menu) ---
REM Mounts [winpeapps_bios] share. CRITICAL: do NOT call check-bios.cmd
REM inside an `if exist (...)` parens block - CMD's variable scoping for
REM CALLed scripts inside parens does not propagate BIOS_STATUS back to
REM this script reliably. Use goto-flow instead so the CALL runs at the
REM top scope and BIOS_STATUS persists.
set BIOS_STATUS=No BIOS check (share unavailable)
net use B: \\10.9.100.1\winpeapps_bios /user:pxe-upload pxe /persistent:no 2>NUL
if not exist B:\check-bios.cmd goto :bios_check_done
echo.
echo Checking for BIOS updates...
call B:\check-bios.cmd
:bios_check_done
net use B: /delete 2>NUL
:menu
cls
echo.
echo ========================================
echo WinPE Setup Menu
echo ========================================
echo Firmware: %BIOS_STATUS%
echo.
echo Please select an option:
echo.
echo 1. GEA Standard
echo 2. GEA Engineer
echo 3. GEA Shopfloor
echo 4. GE Standard
echo 5. GE Engineer
echo 6. GE Shopfloor Lockdown
echo 7. GE Shopfloor MCE
echo.
echo ========================================
echo.
set /p choice=Enter your choice (1-7):
REM --- Only shopfloor images (3,6,7) need GCCH enrollment ---
set PPKG=
if "%choice%"=="3" goto enroll_menu
if "%choice%"=="6" goto enroll_menu
if "%choice%"=="7" goto enroll_menu
goto enroll_staged
:enroll_menu
cls
echo.
echo ========================================
echo GCCH Enrollment Profile
echo ========================================
echo.
echo 1. No Office
echo 2. Standard Office (x86)
echo 3. Standard Office (x64)
echo 4. Pro Plus Office (x86) with Access
echo 5. Pro Plus Office (x64) with Access
echo 6. Skip enrollment
echo.
set /p enroll=Enter your choice (1-6):
REM --- PPKG configuration (constructed at menu time, see docs) ---
REM Vendor ships one source PPKG; we construct the BPRT-tagged filename
REM by filling in Office, Region, Expiry, Version on the target copy.
REM Update SOURCE_PPKG + PPKG_VER when a new PPKG is released.
set SOURCE_PPKG=GCCH_Prod_SFLD_v4.12.ppkg
set PPKG_VER=v4.12
set PPKG_EXP=20260831
set REGION=US
set OFFICE=
if "%enroll%"=="1" set OFFICE=NoOffice
if "%enroll%"=="2" set OFFICE=StdOffice-x86
if "%enroll%"=="3" set OFFICE=StdOffice-x64
if "%enroll%"=="4" set OFFICE=ProPlusOffice-x86
if "%enroll%"=="5" set OFFICE=ProPlusOffice-x64
if "%enroll%"=="6" set OFFICE=
if "%enroll%"=="" goto enroll_menu
set PPKG=
if not "%OFFICE%"=="" set PPKG=GCCH_Prod_SFLD_%OFFICE%_%REGION%_Exp_%PPKG_EXP%_%PPKG_VER%.ppkg
:pctype_menu
cls
echo.
echo ========================================
echo Shopfloor PC Type
echo ========================================
echo.
echo 1. CMM
echo 2. Wax and Trace
echo 3. Keyence
echo 4. Genspect
echo 5. Display
echo 6. Standard
echo 7. Lab
echo.
set PCTYPE=
set /p pctype_choice=Enter your choice (1-7):
if "%pctype_choice%"=="1" set PCTYPE=CMM
if "%pctype_choice%"=="2" set PCTYPE=WaxAndTrace
if "%pctype_choice%"=="3" set PCTYPE=Keyence
if "%pctype_choice%"=="4" set PCTYPE=Genspect
if "%pctype_choice%"=="5" set PCTYPE=Display
if "%pctype_choice%"=="6" set PCTYPE=Standard
if "%pctype_choice%"=="7" set PCTYPE=Lab
if "%PCTYPE%"=="" goto pctype_menu
REM --- Sub-type selection menus ---
REM PCSUBTYPE is written to pc-subtype.txt alongside pc-type.txt.
REM Scripts read it to look up the right profile in site-config.json.
set PCSUBTYPE=
set DISPLAYTYPE=
REM --- Standard sub-type ---
if not "%PCTYPE%"=="Standard" goto skip_standard_menu
:standard_menu
cls
echo.
echo ========================================
echo Standard PC Sub-Type
echo ========================================
echo.
echo 1. Machine (WJ Shopfloor, Plant Apps, eDNC, UDC)
echo 2. Timeclock (WJ Shopfloor only)
echo.
set /p standard_choice=Enter your choice (1-2):
if "%standard_choice%"=="1" set PCSUBTYPE=Machine
if "%standard_choice%"=="2" set PCSUBTYPE=Timeclock
if "%PCSUBTYPE%"=="" goto standard_menu
REM --- Machine number (Standard-Machine only; Timeclock PCs do not use one) ---
set MACHINENUM=9999
if "%PCSUBTYPE%"=="Timeclock" goto skip_standard_menu
echo.
set /p MACHINENUM=Enter machine number (digits, or Enter for 9999):
if "%MACHINENUM%"=="" set MACHINENUM=9999
echo Machine number: %MACHINENUM%
:skip_standard_menu
REM --- Display sub-type ---
if not "%PCTYPE%"=="Display" goto skip_display_menu
:display_menu
cls
echo.
echo ========================================
echo Display Type
echo ========================================
echo.
echo 1. Dashboard
echo 2. Lobby Display
echo.
set /p display_choice=Enter your choice (1-2):
if "%display_choice%"=="1" set DISPLAYTYPE=Dashboard
if "%display_choice%"=="1" set PCSUBTYPE=Dashboard
if "%display_choice%"=="2" set DISPLAYTYPE=Lobby
if "%display_choice%"=="2" set PCSUBTYPE=Lobby
if "%PCSUBTYPE%"=="" goto display_menu
:skip_display_menu
REM --- Map enrollment share early (kept open for copy after imaging) ---
set NEED_ENROLL=0
if not "%PPKG%"=="" set NEED_ENROLL=1
if not "%PCTYPE%"=="" set NEED_ENROLL=1
if "%NEED_ENROLL%"=="0" goto enroll_staged
net use Y: \\10.9.100.1\enrollment /user:pxe-upload pxe /persistent:no
if "%PPKG%"=="" goto enroll_staged
if not exist "Y:\ppkgs\%SOURCE_PPKG%" (
echo WARNING: %SOURCE_PPKG% not found on server. Enrollment will be skipped.
set PPKG=
)
:enroll_staged
echo. > X:\Boot.tag
if "%choice%"=="1" goto gea-standard
if "%choice%"=="2" goto gea-engineer
if "%choice%"=="3" goto gea-shopfloor
if "%choice%"=="4" goto ge-standard
if "%choice%"=="5" goto ge-engineer
if "%choice%"=="6" goto ge-shopfloor-lockdown
if "%choice%"=="7" goto ge-shopfloor-mce
echo Invalid choice. Please try again.
pause
goto menu
:gea-standard
echo.
echo Starting GEA Standard setup...
start "FlatApp" %SYSTEMDRIVE%\GESetup\FlatSetupLoader.exe
for /l %%i in (1,1,2000000) do rem
net use Z: \\10.9.100.1\winpeapps\gea-standard /user:pxe-upload pxe /persistent:no
goto end
:gea-engineer
echo.
echo Starting GEA Engineer setup...
start "FlatApp" %SYSTEMDRIVE%\GESetup\FlatSetupLoader.exe
for /l %%i in (1,1,2000000) do rem
net use Z: \\10.9.100.1\winpeapps\gea-engineer /user:pxe-upload pxe /persistent:no
goto end
:gea-shopfloor
echo.
echo Starting GEA Shopfloor setup...
start "FlatApp" %SYSTEMDRIVE%\GESetup\FlatSetupLoader.exe
for /l %%i in (1,1,2000000) do rem
net use Z: \\10.9.100.1\winpeapps\gea-shopfloor /user:pxe-upload pxe /persistent:no
goto end
:ge-standard
echo.
echo Starting GE Standard setup...
start "FlatApp" %SYSTEMDRIVE%\GESetup\FlatSetupLoader.exe
for /l %%i in (1,1,2000000) do rem
net use Z: \\10.9.100.1\winpeapps\ge-standard /user:pxe-upload pxe /persistent:no
goto end
:ge-engineer
echo.
echo Starting GE Engineer setup...
start "FlatApp" %SYSTEMDRIVE%\GESetup\FlatSetupLoader.exe
for /l %%i in (1,1,2000000) do rem
net use Z: \\10.9.100.1\winpeapps\ge-engineer /user:pxe-upload pxe /persistent:no
goto end
:ge-shopfloor-lockdown
echo.
echo Starting GE Shopfloor Lockdown setup...
start "FlatApp" %SYSTEMDRIVE%\GESetup\FlatSetupLoader.exe
for /l %%i in (1,1,2000000) do rem
net use Z: \\10.9.100.1\winpeapps\ge-shopfloor-lockdown /user:pxe-upload pxe /persistent:no
goto end
:ge-shopfloor-mce
echo.
echo Starting GE Shopfloor MCE setup...
start "FlatApp" %SYSTEMDRIVE%\GESetup\FlatSetupLoader.exe
for /l %%i in (1,1,2000000) do rem
net use Z: \\10.9.100.1\winpeapps\ge-shopfloor-mce /user:pxe-upload pxe /persistent:no
goto end
:end
echo.
echo Waiting for PESetup.exe to start...
:wait_start
ping -n 3 127.0.0.1 >NUL
wmic process where "name='PESetup.exe'" get name 2>NUL | find /I "PESetup" >NUL
if errorlevel 1 goto wait_start
echo PESetup.exe is running. Waiting for imaging to complete...
REM --- Copy enrollment package and shopfloor setup as soon as Windows partition appears ---
if "%PPKG%"=="" if "%PCTYPE%"=="" goto wait_finish
echo Waiting for Windows partition at W: ...
:wait_enroll
ping -n 11 127.0.0.1 >NUL
if not exist W:\Windows\System32\config\system goto wait_enroll
echo Found Windows at W:
mkdir W:\Enrollment 2>NUL
REM --- Copy site config (drives site-specific values in all setup scripts) ---
if exist "Y:\config\site-config.json" (
copy /Y "Y:\config\site-config.json" "W:\Enrollment\site-config.json"
echo Copied site-config.json.
) else (
echo WARNING: site-config.json not found on enrollment share.
)
REM --- Copy PPKG if selected (renames from SOURCE to BPRT-tagged filename) ---
if "%PPKG%"=="" goto copy_pctype
copy /Y "Y:\ppkgs\%SOURCE_PPKG%" "W:\Enrollment\%PPKG%"
if errorlevel 1 (
echo WARNING: Failed to copy enrollment package.
goto copy_pctype
)
copy /Y "Y:\scripts\run-enrollment.ps1" "W:\Enrollment\run-enrollment.ps1"
copy /Y "Y:\scripts\wait-for-internet.ps1" "W:\Enrollment\wait-for-internet.ps1"
copy /Y "Y:\scripts\migrate-to-wifi.ps1" "W:\Enrollment\migrate-to-wifi.ps1"
REM --- Create enroll.cmd at drive root as manual fallback ---
> W:\enroll.cmd (
echo @echo off
echo echo Waiting for network...
echo :waitnet
echo ping -n 2 8.8.8.8 ^>NUL 2^>^&1
echo if errorlevel 1 goto waitnet
echo echo Network connected. Running enrollment...
echo powershell.exe -ExecutionPolicy Bypass -File "C:\run-enrollment.ps1"
)
echo Manual fallback created at W:\enroll.cmd
:copy_pctype
REM --- Copy shopfloor PC type setup scripts ---
if "%PCTYPE%"=="" goto cleanup_enroll
echo %PCTYPE%> W:\Enrollment\pc-type.txt
if not "%DISPLAYTYPE%"=="" echo %DISPLAYTYPE%> W:\Enrollment\display-type.txt
if not "%PCSUBTYPE%"=="" echo %PCSUBTYPE%> W:\Enrollment\pc-subtype.txt
if not "%MACHINENUM%"=="" echo %MACHINENUM%> W:\Enrollment\machine-number.txt
copy /Y "Y:\shopfloor-setup\Run-ShopfloorSetup.ps1" "W:\Enrollment\Run-ShopfloorSetup.ps1"
REM --- Always copy Shopfloor baseline scripts ---
mkdir W:\Enrollment\shopfloor-setup 2>NUL
copy /Y "Y:\shopfloor-setup\backup_lockdown.bat" "W:\Enrollment\shopfloor-setup\backup_lockdown.bat"
if exist "Y:\shopfloor-setup\Shopfloor" (
mkdir W:\Enrollment\shopfloor-setup\Shopfloor 2>NUL
xcopy /E /Y /I "Y:\shopfloor-setup\Shopfloor" "W:\Enrollment\shopfloor-setup\Shopfloor\"
echo Copied Shopfloor baseline setup files.
)
REM --- Always copy common/ (cross-PC-type GE-Enforce dispatcher + lib live here post-v2) ---
if exist "Y:\shopfloor-setup\common" (
mkdir W:\Enrollment\shopfloor-setup\common 2>NUL
xcopy /E /Y /I "Y:\shopfloor-setup\common" "W:\Enrollment\shopfloor-setup\common\"
echo Copied common setup files.
)
REM --- Copy type-specific scripts on top of baseline ---
if exist "Y:\shopfloor-setup\%PCTYPE%" (
mkdir "W:\Enrollment\shopfloor-setup\%PCTYPE%" 2>NUL
xcopy /E /Y /I "Y:\shopfloor-setup\%PCTYPE%" "W:\Enrollment\shopfloor-setup\%PCTYPE%\"
echo Copied %PCTYPE% setup files.
) else (
echo WARNING: No setup files found for PC type %PCTYPE%.
)
REM --- Stage preinstall bundle (apps installed locally to save Azure bandwidth) ---
if exist "Y:\pre-install\preinstall.json" (
mkdir W:\PreInstall 2>NUL
mkdir W:\PreInstall\installers 2>NUL
copy /Y "Y:\pre-install\preinstall.json" "W:\PreInstall\preinstall.json"
if exist "Y:\pre-install\installers" (
xcopy /E /Y /I "Y:\pre-install\installers" "W:\PreInstall\installers\"
echo Staged preinstall bundle to W:\PreInstall.
) else (
echo WARNING: Y:\pre-install\installers not found - preinstall.json staged without installers.
)
if exist "Y:\pre-install\udc-backups" (
xcopy /E /Y /I "Y:\pre-install\udc-backups" "W:\PreInstall\udc-backups\"
echo Staged UDC settings backups to W:\PreInstall\udc-backups.
)
) else (
echo No preinstall bundle on PXE server - skipping.
)
REM --- Stage CMM bootstrap bundle (CMM-type PCs only) ---
REM Copies the Hexagon installer bundle (~1.9 GB) from the PXE server enrollment
REM share onto the target disk so 09-Setup-CMM.ps1 can install from local disk.
REM The tsgwp00525 SFLD share that holds the canonical copy is not yet reachable
REM during shopfloor-setup (Azure DSC provisions those creds later), so this
REM bootstrap exists to get the first-install through. Post-imaging, the
REM unified GE-Enforce dispatcher takes over from the share for ongoing updates.
if /i not "%PCTYPE%"=="CMM" goto skip_cmm_stage
if exist "Y:\installers-post\cmm\cmm-manifest.json" (
mkdir W:\CMM-Install 2>NUL
xcopy /E /Y /I "Y:\installers-post\cmm" "W:\CMM-Install\"
echo Staged CMM bootstrap to W:\CMM-Install.
) else (
echo WARNING: Y:\cmm-installers not found - CMM PC cannot install Hexagon apps at imaging time.
)
:skip_cmm_stage
:pctype_done
:cleanup_enroll
net use Y: /delete 2>NUL
:wait_finish
ping -n 11 127.0.0.1 >NUL
wmic process where "name='PESetup.exe'" get name 2>NUL | find /I "PESetup" >NUL
if not errorlevel 1 goto wait_finish
echo.
echo Imaging complete. Rebooting in 15 seconds...
echo Press Ctrl+C to cancel.
ping -n 16 127.0.0.1 >NUL
wpeutil reboot