@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 172.16.9.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: \\172.16.9.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 (sub-menu) echo. echo ======================================== echo. set /p choice=Enter your choice (1-3): REM --- Shopfloor images (3,6,7) need GCCH enrollment + (for 3) PC-type sub-menu. REM Choice 3 = GEA Shopfloor: drill into sub-menu first to pick the gea-shopfloor-* REM sub-category, THEN the office menu, THEN machine number for collections+nocollections. set PPKG= if "%choice%"=="3" goto gea_shopfloor_submenu if "%choice%"=="6" goto enroll_menu if "%choice%"=="7" goto enroll_menu goto enroll_staged :gea_shopfloor_submenu cls set PCTYPE= REM Data-driven PC-type menu: the PXE webapp maintains menu.json on the REM enrollment share; select-shopfloor-type.ps1 renders it and writes the REM chosen PCTYPE to X:\pctype.txt. Falls back to the baked-in menu below if REM the share or the picker is unavailable (mirrors the CMM bay picker). net use Y: \\172.16.9.1\enrollment /user:pxe-upload pxe /persistent:no >NUL 2>NUL del X:\pctype.txt 2>NUL if exist "Y:\shopfloor-setup\select-shopfloor-type.ps1" powershell.exe -NoProfile -ExecutionPolicy Bypass -File "Y:\shopfloor-setup\select-shopfloor-type.ps1" -MenuJson "Y:\shopfloor-setup\menu.json" -OutFile "X:\pctype.txt" if exist X:\pctype.txt set /p PCTYPE=NUL 2>NUL del X:\cmm-bay.txt 2>NUL set CMMID= set CMMVARIANT=standard if not exist "Y:\installers-post\cmm\select-cmm-bay.ps1" goto cmm_picker_skip powershell.exe -NoProfile -ExecutionPolicy Bypass -File "Y:\installers-post\cmm\select-cmm-bay.ps1" -ConfigPath "Y:\installers-post\cmm\cmm-bay-config.csv" -OutFile "X:\cmm-bay.txt" :cmm_picker_skip if exist X:\cmm-bay.txt set /p CMMID=nul 2>&1 set SOURCE_PPKG= set PPKG_VER= set PPKG_EXP= if exist "Y:\ppkg.conf" ( for /f "usebackq tokens=1,* delims==" %%A in ("Y:\ppkg.conf") do ( if /i "%%A"=="SOURCE_PPKG" set "SOURCE_PPKG=%%B" if /i "%%A"=="PPKG_VER" set "PPKG_VER=%%B" if /i "%%A"=="PPKG_EXP" set "PPKG_EXP=%%B" ) ) if "%SOURCE_PPKG%"=="" set SOURCE_PPKG=GCCH_Prod_SFLD_v4.16.ppkg if "%PPKG_VER%"=="" set PPKG_VER=v4.16 if "%PPKG_EXP%"=="" 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 REM --- 2026-05-04 rename reorg: PCTYPE is set by gea_shopfloor_submenu above REM (single string, e.g. gea-shopfloor-collections). pc-subtype.txt is no REM longer written. DISPLAYTYPE IS still written (display-type.txt) when REM PCTYPE=gea-shopfloor-display because Install-KioskApp.cmd needs Lobby REM vs Dashboard to choose installer + Get-PCProfile builds Display-{type} REM profile key. set PCSUBTYPE= REM --- Machine number / asset tag (only PC types that key per-machine config) --- REM collections + nocollections = 4-digit machine number for shopfloor identification. REM waxtrace = asset tag like WJRP2335 used to match per-machine cal ISO during REM 09-Setup-WaxAndTrace.ps1. Cal ISO files are named REM CAL-{asset_tag}_serial-*_probe-*.iso. set MACHINENUM=9999 if /i "%PCTYPE%"=="gea-shopfloor-collections" goto prompt_machinenum if /i "%PCTYPE%"=="gea-shopfloor-nocollections" goto prompt_machinenum if /i "%PCTYPE%"=="gea-shopfloor-heattreat" goto prompt_machinenum if /i "%PCTYPE%"=="gea-shopfloor-waxtrace" goto prompt_waxtrace_asset if /i "%PCTYPE%"=="gea-shopfloor-cmm" goto skip_machinenum goto skip_machinenum :prompt_machinenum echo. set /p MACHINENUM=Enter machine number (digits, or Enter for 9999): if "%MACHINENUM%"=="" set MACHINENUM=9999 echo Machine number: %MACHINENUM% goto skip_machinenum :prompt_waxtrace_asset echo. echo Loading Wax/Trace bay list from PXE share... REM Mount enrollment share early so the picker can read INDEX.csv. Later REM net use Y: will be a no-op if Y: is already mapped. net use Y: \\172.16.9.1\enrollment /user:pxe-upload pxe /persistent:no >NUL 2>NUL del X:\waxtrace-asset.txt 2>NUL if not exist "Y:\installers-post\waxtrace\select-waxtrace-asset.ps1" goto waxtrace_picker_skip powershell.exe -NoProfile -ExecutionPolicy Bypass -File "Y:\installers-post\waxtrace\select-waxtrace-asset.ps1" -IndexPath "Y:\installers-post\waxtrace\bay-config.csv" -OutFile "X:\waxtrace-asset.txt" :waxtrace_picker_skip set MACHINENUM= if exist X:\waxtrace-asset.txt set /p MACHINENUM= X:\Boot.tag if "%choice%"=="1" goto gea-standard if "%choice%"=="2" goto gea-engineer if "%choice%"=="3" goto gea-shopfloor 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: \\172.16.9.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: \\172.16.9.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 REM --- Per-PCTYPE media view ----------------------------------------------- REM PESetup's CopyPackages copies the WHOLE of \Deploy\Applications to REM the target, recursively, with no filtering and no manifest (see REM docs/PESETUP-INTERNALS.md). One shared shopfloor media therefore hands REM every shopfloor payload to every bay whatever its type. REM _media\ is that same media rebuilt out of symlinks by REM scripts/build-pctype-media.py, carrying only this type's payload. It is REM built once, server-side, and never mutated per session: bays image REM concurrently and CopyPackages is fail-fast, so changing a path mid-copy REM would fail some OTHER bay's imaging. if "%PCTYPE%"=="" goto gea_shopfloor_media_shared REM Free Z: first. A leftover mapping makes net use fail with "device already REM in use" and the probe below would then pass against the OLD media. net use Z: /delete /y >NUL 2>&1 net use Z: \\172.16.9.1\winpeapps\_media\%PCTYPE% /user:pxe-upload pxe /persistent:no >NUL 2>&1 REM Probe a file that only resolves when the view exists AND its symlinks are REM intact. A dangling view must not image silently off a half-mapped drive. if exist "Z:\Deploy\Control\HardwareDriver.json" goto end echo. echo WARNING: no usable per-type media at _media\%PCTYPE%. echo Falling back to the shared shopfloor media, so EVERY shopfloor echo payload will be staged on this bay, not just this type's. echo Imaging is otherwise unaffected. Tell the PXE admin. echo. net use Z: /delete /y >NUL 2>&1 :gea_shopfloor_media_shared net use Z: \\172.16.9.1\winpeapps\gea-shopfloor /user:pxe-upload pxe /persistent:no goto end :end echo. REM --- Push initial "WinPE staging" status to PXE webapp --- REM Externalized to Y:\scripts\winpe-status-push.ps1 so future edits don't REM require a boot.wim rebuild. Best-effort; the script logs to REM X:\Windows\Temp\winpe-status-push.log and swallows all errors. if exist "Y:\scripts\winpe-status-push.ps1" ( powershell -NoProfile -ExecutionPolicy Bypass -File "Y:\scripts\winpe-status-push.ps1" ) 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 Log all copy operations to a file that persists on the target disk. REM Tech can check C:\Enrollment\winpe-staging.log post-imaging. REM Each echo in the copy block below also appends to this file via REM the >> redirect after the screen echo. robocopy /LOG+ appends its REM own output directly. set STAGELOG=W:\Enrollment\winpe-staging.log echo [%DATE% %TIME%] WinPE staging started >> "%STAGELOG%" echo PCTYPE=%PCTYPE% PPKG=%PPKG% MACHINENUM=%MACHINENUM% CMMID=%CMMID% >> "%STAGELOG%" REM --- Copy site config (drives site-specific values in all setup scripts) --- if exist "Y:\config\site-config.json" ( robocopy "Y:\config" "W:\Enrollment" "site-config.json" /R:1 /W:1 /NFL /NDL /NJH /NJS echo Copied site-config.json. echo [%TIME%] Copied site-config.json >> "%STAGELOG%" ) else ( echo WARNING: site-config.json not found on enrollment share. echo [%TIME%] WARNING: site-config.json not found >> "%STAGELOG%" ) REM --- Copy PPKG if selected (renames from SOURCE to BPRT-tagged filename) --- if "%PPKG%"=="" goto copy_pctype robocopy "Y:\ppkgs" "W:\Enrollment" "%SOURCE_PPKG%" /R:1 /W:1 /NFL /NDL /NJH /NJS REM robocopy exit codes: 0-7 = success, 8+ = failure (inverse of copy's 0/1). if errorlevel 8 ( echo WARNING: Failed to copy enrollment package. echo [%TIME%] WARNING: Failed to copy PPKG %SOURCE_PPKG% >> "%STAGELOG%" goto copy_pctype ) REM robocopy keeps the source name; rename to the BPRT-tagged target name. if not "%SOURCE_PPKG%"=="%PPKG%" ren "W:\Enrollment\%SOURCE_PPKG%" "%PPKG%" echo [%TIME%] Copied PPKG %SOURCE_PPKG% as %PPKG% >> "%STAGELOG%" robocopy "Y:\scripts" "W:\Enrollment" "run-enrollment.ps1" "wait-for-internet.ps1" "migrate-to-wifi.ps1" /R:1 /W:1 /NFL /NDL /NJH /NJS echo [%TIME%] Copied enrollment scripts >> "%STAGELOG%" 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 REM 2026-05-04 rename reorg: pc-subtype.txt no longer written. REM display-type.txt IS still written for gea-shopfloor-display because REM Install-KioskApp.cmd reads it to pick Lobby vs Dashboard installer REM and Get-PCProfile.ps1 reads it to build the Display-{type} profile key. if not "%DISPLAYTYPE%"=="" echo %DISPLAYTYPE%> W:\Enrollment\display-type.txt if not "%MACHINENUM%"=="" echo %MACHINENUM%> W:\Enrollment\machine-number.txt REM Keyence model goes to BOTH keyence-model.txt (read by 09-Setup-Keyence) AND REM pc-subtype.txt (read by GE-Enforce for per-model dispatch via existing REM PCSubType wiring: looks for gea-shopfloor-keyence-\manifest.json on share). if not "%KEYENCEMODEL%"=="" ( echo %KEYENCEMODEL%> W:\Enrollment\keyence-model.txt echo %KEYENCEMODEL%> W:\Enrollment\pc-subtype.txt ) REM CMM bay ID + resolved config. CMMID comes from the bay picker (e.g. CMM4). REM Written to machine-number.txt (same field collections/waxtrace use) so REM TargetMachineNumbers on the SFLD share manifest gates per-bay entries. REM resolve-cmm-bay-config.ps1 reads the CSV and writes version.txt + doda.txt REM to W:\Enrollment\cmm\ for 09-Setup-CMM.ps1 to consume. if "%CMMID%"=="" goto cmm_id_done echo %CMMID%> W:\Enrollment\machine-number.txt mkdir W:\Enrollment\cmm 2>NUL if exist "Y:\installers-post\cmm\resolve-cmm-bay-config.ps1" ( powershell.exe -NoProfile -ExecutionPolicy Bypass -File "Y:\installers-post\cmm\resolve-cmm-bay-config.ps1" -ConfigPath "Y:\installers-post\cmm\cmm-bay-config.csv" -CmmId "%CMMID%" -OutDir "W:\Enrollment\cmm" ) REM Read doda flag to set pc-subtype.txt for GE-Enforce manifest gating. REM goto-flow avoids CMD variable scoping issues inside parens blocks. if not exist W:\Enrollment\cmm\doda.txt goto cmm_id_done set /p CMMDODA= W:\Enrollment\pc-subtype.txt :cmm_id_done robocopy "Y:\shopfloor-setup" "W:\Enrollment" "Run-ShopfloorSetup.ps1" /R:1 /W:1 /NFL /NDL /NJH /NJS REM Post-boot bulk re-fetch. WinPE staging below is best-effort (it can fail if REM the Y: mount went idle-dead during the WIM apply); Fetch-StagingPayload.ps1 REM re-pulls the shopfloor-setup tree + preinstall bundle at first logon on a REM FRESH mount. The unattend FirstLogonCommands runs it before the PowerShell 7 REM MSI + Run-ShopfloorSetup. Stage the script + its source coords here. robocopy "Y:\shopfloor-setup" "W:\Enrollment" "Fetch-StagingPayload.ps1" /R:1 /W:1 /NFL /NDL /NJH /NJS REM Stage the staging self-heal directly too, so the unattend Order 5 heal step REM runs even if Fetch-StagingPayload itself did not land. Small, reliable copy. robocopy "Y:\shopfloor-setup" "W:\Enrollment" "Verify-And-Heal-Staging.ps1" /R:1 /W:1 /NFL /NDL /NJH /NJS > W:\Enrollment\fetch-source.txt ( echo \\172.16.9.1\enrollment echo pxe-upload echo pxe ) REM --- Always copy Shopfloor baseline scripts --- mkdir W:\Enrollment\shopfloor-setup 2>NUL robocopy "Y:\shopfloor-setup" "W:\Enrollment\shopfloor-setup" "backup_lockdown.bat" /R:1 /W:1 /NFL /NDL /NJH /NJS if exist "Y:\shopfloor-setup\Shopfloor" ( mkdir W:\Enrollment\shopfloor-setup\Shopfloor 2>NUL robocopy "Y:\shopfloor-setup\Shopfloor" "W:\Enrollment\shopfloor-setup\Shopfloor" /E /MT:16 /R:1 /W:1 /NFL /NDL /LOG+:"%STAGELOG%" if errorlevel 8 echo WARNING: shopfloor-setup\Shopfloor robocopy exit %ERRORLEVEL% echo Copied Shopfloor baseline setup files. echo [%TIME%] Copied Shopfloor baseline >> "%STAGELOG%" ) 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 robocopy "Y:\shopfloor-setup\common" "W:\Enrollment\shopfloor-setup\common" /E /MT:16 /R:1 /W:1 /NFL /NDL /LOG+:"%STAGELOG%" if errorlevel 8 echo WARNING: shopfloor-setup\common robocopy exit %ERRORLEVEL% echo Copied common setup files. echo [%TIME%] Copied common >> "%STAGELOG%" ) REM --- Copy _ntlars-backups (147 per-bay .reg files restored by gea-shopfloor-{collections,nocollections}\03-RestoreEDncConfig.ps1) --- REM Same root level as common/, referenced by 03-RestoreEDncConfig.ps1 via Join-Path $PSScriptRoot '..\_ntlars-backups'. if exist "Y:\shopfloor-setup\_ntlars-backups" ( mkdir W:\Enrollment\shopfloor-setup\_ntlars-backups 2>NUL robocopy "Y:\shopfloor-setup\_ntlars-backups" "W:\Enrollment\shopfloor-setup\_ntlars-backups" /E /MT:16 /R:1 /W:1 /NFL /NDL /LOG+:"%STAGELOG%" if errorlevel 8 echo WARNING: _ntlars-backups robocopy exit %ERRORLEVEL% echo Copied _ntlars-backups. echo [%TIME%] Copied _ntlars-backups >> "%STAGELOG%" ) REM --- Copy type-specific scripts on top of baseline --- if exist "Y:\shopfloor-setup\%PCTYPE%" ( mkdir "W:\Enrollment\shopfloor-setup\%PCTYPE%" 2>NUL robocopy "Y:\shopfloor-setup\%PCTYPE%" "W:\Enrollment\shopfloor-setup\%PCTYPE%" /E /MT:16 /R:1 /W:1 /NFL /NDL /LOG+:"%STAGELOG%" if errorlevel 8 echo WARNING: shopfloor-setup\%PCTYPE% robocopy exit %ERRORLEVEL% echo Copied %PCTYPE% setup files. echo [%TIME%] Copied %PCTYPE% type-specific >> "%STAGELOG%" ) else ( echo WARNING: No setup files found for PC type %PCTYPE%. echo [%TIME%] WARNING: No setup files for %PCTYPE% >> "%STAGELOG%" ) 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 robocopy "Y:\pre-install" "W:\PreInstall" "preinstall.json" /R:1 /W:1 /NFL /NDL /NJH /NJS if exist "Y:\pre-install\installers" ( robocopy "Y:\pre-install\installers" "W:\PreInstall\installers" /E /MT:16 /R:1 /W:1 /NFL /NDL /LOG+:"%STAGELOG%" if errorlevel 8 echo WARNING: pre-install\installers robocopy exit %ERRORLEVEL% echo Staged preinstall bundle to W:\PreInstall. echo [%TIME%] Staged preinstall bundle >> "%STAGELOG%" ) else ( echo WARNING: Y:\pre-install\installers not found - preinstall.json staged without installers. ) if exist "Y:\pre-install\udc-backups" ( robocopy "Y:\pre-install\udc-backups" "W:\PreInstall\udc-backups" /E /MT:16 /R:1 /W:1 /NFL /NDL /LOG+:"%STAGELOG%" if errorlevel 8 echo WARNING: pre-install\udc-backups robocopy exit %ERRORLEVEL% echo Staged UDC settings backups to W:\PreInstall\udc-backups. echo [%TIME%] Staged UDC backups >> "%STAGELOG%" ) ) 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%"=="gea-shopfloor-cmm" goto skip_cmm_stage if exist "Y:\installers-post\cmm\cmm-manifest.json" ( mkdir W:\CMM-Install 2>NUL REM /XD the backups tree: it holds EVERY bay's settings backup (some 240 MB REM each). Copying all of it to every imaged CMM would waste GBs. The bulk REM copy excludes it; the selected bay's backup is staged separately below. robocopy "Y:\installers-post\cmm" "W:\CMM-Install" /E /XD "Y:\installers-post\cmm\backups" /MT:16 /R:1 /W:1 /NFL /NDL /LOG+:"%STAGELOG%" if errorlevel 8 echo WARNING: cmm robocopy exit %ERRORLEVEL% echo Staged CMM bootstrap to W:\CMM-Install. echo [%TIME%] Staged CMM bootstrap >> "%STAGELOG%" ) else ( echo WARNING: Y:\cmm-installers not found - CMM PC cannot install Hexagon apps at imaging time. ) REM Stage ONLY the selected bay's settings backup. 09-Setup-CMM's Restore-CMM REM reads W:\CMM-Install\backups\%CMMID%\ to restore PC-DMIS + goCMM settings. if not defined CMMID goto skip_cmm_stage if exist "Y:\installers-post\cmm\backups\%CMMID%" ( robocopy "Y:\installers-post\cmm\backups\%CMMID%" "W:\CMM-Install\backups\%CMMID%" /E /MT:16 /R:1 /W:1 /NFL /NDL /LOG+:"%STAGELOG%" echo Staged %CMMID% settings backup for restore. echo [%TIME%] Staged %CMMID% backup >> "%STAGELOG%" ) :skip_cmm_stage REM --- Stage Keyence per-model bootstrap bundle (Keyence PCs only) --- REM Copies only the selected model's MSI + Data cabs from the PXE enrollment REM share to the target disk. installers-post/keyence// contains: REM manifest.json REM installers/{MSI, Data1.cab, [Data11.cab for vr3000], 1033.mst} REM drivers/ (vr6000 only - older external .inf; vr3000/vr5000 drivers REM are embedded in their MSIs) REM 09-Setup-Keyence.ps1 reads C:\Enrollment\keyence-model.txt to know which. if /i not "%PCTYPE%"=="gea-shopfloor-keyence" goto skip_keyence_stage if "%KEYENCEMODEL%"=="" goto skip_keyence_stage if exist "Y:\installers-post\keyence\%KEYENCEMODEL%\manifest.json" ( mkdir W:\KeyenceInstall 2>NUL mkdir W:\KeyenceInstall\%KEYENCEMODEL% 2>NUL robocopy "Y:\installers-post\keyence\%KEYENCEMODEL%" "W:\KeyenceInstall\%KEYENCEMODEL%" /E /MT:16 /R:1 /W:1 /NFL /NDL /LOG+:"%STAGELOG%" if errorlevel 8 echo WARNING: keyence\%KEYENCEMODEL% robocopy exit %ERRORLEVEL% echo Staged Keyence %KEYENCEMODEL% bootstrap to W:\KeyenceInstall\%KEYENCEMODEL%\. echo [%TIME%] Staged Keyence %KEYENCEMODEL% >> "%STAGELOG%" ) else ( echo WARNING: Y:\installers-post\keyence\%KEYENCEMODEL% not found - Keyence %KEYENCEMODEL% cannot install at imaging time. ) :skip_keyence_stage REM --- Stage WaxTrace bootstrap bundle (wax/trace gea-shopfloor-waxtrace only) --- REM Three-step process: REM 1. robocopy installers-post\waxtrace -> W:\WaxTrace-Install (everything REM EXCEPT the formtracepak\ subdir, via /XD - that subdir carries all REM 7 vendor ISOs and we only need one of them) REM 2. resolve-bay-config.ps1: reads bay-config.csv + asset_tag, writes REM W:\Enrollment\waxtrace\{version,model,userid}.txt for 09-Setup to read REM 3. robocopy ONLY the bay's matching FORMTRACEPAK-V.iso from REM Y:\installers-post\waxtrace\formtracepak\ onto the target disk REM (so 09-Setup-WaxAndTrace.ps1 mounts the right version per bay) if /i not "%PCTYPE%"=="gea-shopfloor-waxtrace" goto skip_waxtrace_stage if not exist "Y:\installers-post\waxtrace\waxtrace-manifest.json" goto skip_waxtrace_missing mkdir W:\WaxTrace-Install 2>NUL REM robocopy /XD excludes the formtracepak\ dir up front so we don't waste REM disk + time copying 12+ GB of vendor ISOs only to delete them. The REM matched FTPak ISO gets cherry-picked below into the same target dir. REM /NFL/NDL keep the listing manageable; output left visible (no >NUL) so REM any failure is debuggable from the install log. robocopy exit codes REM 0-7 are "OK" (per Microsoft); 8+ is real failure. robocopy "Y:\installers-post\waxtrace" "W:\WaxTrace-Install" /E /XD formtracepak /MT:16 /R:1 /W:1 /NFL /NDL if errorlevel 8 echo WARNING: robocopy exit %ERRORLEVEL% - some files may not have copied. mkdir W:\WaxTrace-Install\formtracepak 2>NUL echo Staged WaxTrace bootstrap minus formtracepak\ to W:\WaxTrace-Install. REM Resolve bay-config: writes W:\Enrollment\waxtrace\{version,model,userid}.txt mkdir W:\Enrollment\waxtrace 2>NUL if not "%MACHINENUM%"=="" ( powershell.exe -NoProfile -ExecutionPolicy Bypass -File "Y:\installers-post\waxtrace\resolve-bay-config.ps1" -Asset "%MACHINENUM%" -OutDir "W:\Enrollment\waxtrace" ) else ( echo WARNING: no MACHINENUM set - skipping bay-config resolve. 09-Setup-WaxAndTrace will abort cleanly with no version. ) REM Read the resolved version + robocopy ONLY that FTPak ISO (avoids dumping REM 12 GB of ISOs on the bay disk; only the matched ~2 GB ISO lands locally). set WTVER= if exist W:\Enrollment\waxtrace\version.txt set /p WTVER=.zip REM as part of the robocopy bundle above (backups\ is not in the /XD list). REM 09-Setup-WaxAndTrace.ps1 Step 3b reads C:\WaxTrace-Install\backups\ REM .zip post-vendor-MSI and runs Install-FormtracepakSettings.ps1 REM -RestoreData -RestoreConfig. Total ~17 MB on disk for the whole set, no REM cherry-pick needed. if not "%MACHINENUM%"=="" ( if exist "W:\WaxTrace-Install\backups\%MACHINENUM%.zip" ( echo Backup ZIP %MACHINENUM%.zip is in the bundle - 09-Setup Step 3b will restore. ) else ( echo INFO: No backup ZIP for %MACHINENUM% in W:\WaxTrace-Install\backups - 09-Setup will skip the restore step. ) ) goto skip_waxtrace_stage :skip_waxtrace_missing echo WARNING: Y:\installers-post\waxtrace not found - WaxTrace PC cannot install FormTracePak at imaging time. :skip_waxtrace_stage :pctype_done if defined STAGELOG echo [%TIME%] WinPE staging complete >> "%STAGELOG%" REM --- BIOS update sub-stage push (fires AFTER W: copies complete) --- REM check-bios.cmd drops X:\bios-fired.flag iff it actually flashed or REM staged a firmware update. Reading the flag file is more reliable than REM scanning BIOS_STATUS for substrings (caret escaping inside quoted SET REM is subtle in WinPE cmd.exe). Push must happen before Y: cleanup since REM the push script lives on the share. if exist X:\bios-fired.flag ( if exist "Y:\scripts\winpe-status-push.ps1" ( powershell -NoProfile -ExecutionPolicy Bypass -File "Y:\scripts\winpe-status-push.ps1" -CurrentStage "WinPE: BIOS firmware update" ) ) :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