The PXE server address appeared 14 times and the share credentials 13, so moving the server or rotating the account meant editing every net use in the file and rebuilding boot.wim - with no way to tell from a diff whether one had been missed. Now set once at the top as PXESERVER / SHAREUSER / SHAREPASS. Exactly one literal address remains, the definition on line 6. Prose in REM comments is left alone so the paths stay readable. This also reaches the post-boot self-heal for free. startnet already writes C:\Enrollment\fetch-source.txt, and both Fetch-StagingPayload.ps1 and Verify-And-Heal-Staging.ps1 read it (line1=UNC, line2=user, line3=pass) with their own hardcoded values only as a fallback. Confirmed on 579C144: [13:30:35] [INFO] fetch-source.txt: UNC=\172.16.9.1\enrollment user=pxe-upload [13:30:36] [INFO] Mounting \172.16.9.1\enrollment as Z: (attempt 1/5)... so the seeded file wins and the heal follows PXESERVER automatically. My earlier claim that the heal scripts were hardcoded was wrong - they were already config-driven and startnet was already seeding them. The hardcoding was all in startnet itself. Verified: set on line 13, first use on line 20; parens balance; every goto resolves; 1005 CRLF lines with no bare LF; the deployed copy contains exactly one literal address. boot.wim md5 7a9b832b.
1006 lines
48 KiB
Batchfile
1006 lines
48 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 --- Site values -----------------------------------------------------
|
|
REM The PXE server address and share credentials appeared 14 and 13 times
|
|
REM respectively, so moving this server or rotating the account meant editing
|
|
REM every net use in the file and rebuilding boot.wim. Set them once here.
|
|
REM These are also written to C:\Enrollment\fetch-source.txt, which
|
|
REM Fetch-StagingPayload.ps1 and Verify-And-Heal-Staging.ps1 read at first
|
|
REM logon - so the post-boot self-heal follows this value automatically.
|
|
set PXESERVER=172.16.9.1
|
|
set SHAREUSER=pxe-upload
|
|
set SHAREPASS=pxe
|
|
|
|
REM --- Wait for network (DHCP may take a moment after wpeinit) ---
|
|
echo Waiting for network...
|
|
:wait_net
|
|
ping -n 2 %PXESERVER% >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: \\%PXESERVER%\winpeapps_bios /user:%SHAREUSER% %SHAREPASS% /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=
|
|
set PCCONFIG=
|
|
if "%choice%"=="3" goto gea_shopfloor_submenu
|
|
if "%choice%"=="6" goto enroll_menu
|
|
if "%choice%"=="7" goto enroll_menu
|
|
REM Standard and engineer enrol through the vendor orchestrator, which asks for
|
|
REM tenant + PC purpose with a GUI at first logon. Ask here instead, while the
|
|
REM tech who knows what the machine is for is standing at it, and pre-seed the
|
|
REM answer so the dialog never appears. See :gea_purpose_submenu.
|
|
if "%choice%"=="1" goto gea_purpose_submenu
|
|
if "%choice%"=="2" goto gea_purpose_submenu
|
|
goto enroll_staged
|
|
|
|
:gea_purpose_submenu
|
|
cls
|
|
echo.
|
|
echo ========================================
|
|
echo PC Purpose - Entra enrollment
|
|
echo ========================================
|
|
echo.
|
|
echo 1. Single-User PC (one assigned person)
|
|
echo 2. Shared PC (multiple users)
|
|
echo 3. Loaner PC (temporary assignment)
|
|
echo.
|
|
echo 4. Ask at first logon (show the vendor dialog instead)
|
|
echo.
|
|
set PCPURPOSE=
|
|
set /p purp_choice=Enter your choice (1-4):
|
|
if "%purp_choice%"=="1" set PCPURPOSE=PERS
|
|
if "%purp_choice%"=="2" set PCPURPOSE=SH
|
|
if "%purp_choice%"=="3" set PCPURPOSE=LOAN
|
|
if "%purp_choice%"=="4" goto enroll_staged
|
|
if "%PCPURPOSE%"=="" goto gea_purpose_submenu
|
|
|
|
:gea_tenant_submenu
|
|
cls
|
|
echo.
|
|
echo ========================================
|
|
echo Entra Tenant
|
|
echo ========================================
|
|
echo.
|
|
echo 1. GCC High (GCCH - US)
|
|
echo 2. Rest of World (RoW)
|
|
echo.
|
|
REM The tenant is not cosmetic: Insert-BPRTToPPKG.ps1 matches the bulk token by
|
|
REM Tenant AND Purpose, so this picks which token gets injected.
|
|
set PCTENANT=
|
|
set /p ten_choice=Enter your choice (1-2):
|
|
if "%ten_choice%"=="1" set PCTENANT=GCCH
|
|
if "%ten_choice%"=="2" set PCTENANT=RoW
|
|
if "%PCTENANT%"=="" goto gea_tenant_submenu
|
|
set PCCONFIG=%PCTENANT%_%PCPURPOSE%
|
|
echo.
|
|
echo PC config: %PCCONFIG%
|
|
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: \\%PXESERVER%\enrollment /user:%SHAREUSER% %SHAREPASS% /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=<X:\pctype.txt
|
|
if not "%PCTYPE%"=="" goto gea_shopfloor_have_type
|
|
|
|
:gea_shopfloor_submenu_fallback
|
|
cls
|
|
echo.
|
|
echo ========================================
|
|
echo GEA Shopfloor PC Sub-Type
|
|
echo ========================================
|
|
echo.
|
|
echo 1. Machine with Collections (eDNC + UDC + Plant Apps)
|
|
echo 2. Machine without Collections (eDNC + Plant Apps, no UDC)
|
|
echo 3. Common (Timeclock, Lab; WJ Shopfloor only)
|
|
echo 4. Keyence (VR-3000 / VR-5000 / VR-6000 microscope)
|
|
echo 5. CMM (Hexagon PC-DMIS + Protect Viewer)
|
|
echo 6. Genspect
|
|
echo 7. Heattreat (eDNC + HeatTreat app)
|
|
echo 8. Wax and Trace
|
|
echo 9. Display (kiosk dashboard)
|
|
echo 10. Part Marker (eDNC + Telesis Mark)
|
|
echo.
|
|
set /p ges_choice=Enter your choice (1-10):
|
|
if "%ges_choice%"=="1" set PCTYPE=gea-shopfloor-collections
|
|
if "%ges_choice%"=="2" set PCTYPE=gea-shopfloor-nocollections
|
|
if "%ges_choice%"=="3" set PCTYPE=gea-shopfloor-common
|
|
if "%ges_choice%"=="4" set PCTYPE=gea-shopfloor-keyence
|
|
if "%ges_choice%"=="5" set PCTYPE=gea-shopfloor-cmm
|
|
if "%ges_choice%"=="6" set PCTYPE=gea-shopfloor-genspect
|
|
if "%ges_choice%"=="7" set PCTYPE=gea-shopfloor-heattreat
|
|
if "%ges_choice%"=="8" set PCTYPE=gea-shopfloor-waxtrace
|
|
if "%ges_choice%"=="9" set PCTYPE=gea-shopfloor-display
|
|
if "%ges_choice%"=="10" set PCTYPE=gea-shopfloor-partmarker
|
|
if "%PCTYPE%"=="" goto gea_shopfloor_submenu_fallback
|
|
|
|
:gea_shopfloor_have_type
|
|
if "%PCTYPE%"=="gea-shopfloor-display" goto display_submenu
|
|
if "%PCTYPE%"=="gea-shopfloor-keyence" goto keyence_submenu
|
|
if "%PCTYPE%"=="gea-shopfloor-cmm" goto cmm_submenu
|
|
goto enroll_menu
|
|
|
|
:keyence_submenu
|
|
cls
|
|
echo.
|
|
echo ========================================
|
|
echo Keyence Model
|
|
echo ========================================
|
|
echo.
|
|
echo 1. VR-3000 G2 (older microscope/profilometer line)
|
|
echo 2. VR-5000 (mid-range)
|
|
echo 3. VR-6000 (current line)
|
|
echo.
|
|
set KEYENCEMODEL=
|
|
set /p kmod_choice=Enter your choice (1-3):
|
|
if "%kmod_choice%"=="1" set KEYENCEMODEL=vr3000
|
|
if "%kmod_choice%"=="2" set KEYENCEMODEL=vr5000
|
|
if "%kmod_choice%"=="3" set KEYENCEMODEL=vr6000
|
|
if "%KEYENCEMODEL%"=="" goto keyence_submenu
|
|
echo Keyence model: %KEYENCEMODEL%
|
|
goto enroll_menu
|
|
|
|
:cmm_submenu
|
|
cls
|
|
echo.
|
|
echo ========================================
|
|
echo CMM Bay Selection
|
|
echo ========================================
|
|
echo.
|
|
echo Loading CMM bay list from PXE share...
|
|
REM Mount enrollment share early so the picker can read the CSV.
|
|
net use Y: \\%PXESERVER%\enrollment /user:%SHAREUSER% %SHAREPASS% /persistent:no >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=<X:\cmm-bay.txt
|
|
if not "%CMMID%"=="" goto cmm_have_bay
|
|
echo.
|
|
echo Picker unavailable or cancelled. Falling back to manual entry.
|
|
set /p CMMID=Enter CMM ID (e.g. CMM1):
|
|
:cmm_have_bay
|
|
if "%CMMID%"=="" (
|
|
echo WARNING: no CMM ID entered. Defaulting to standard variant.
|
|
goto enroll_menu
|
|
)
|
|
echo CMM bay: %CMMID%
|
|
REM Resolve bay config (writes version.txt + doda.txt to %OSDRIVE%\Enrollment\cmm\
|
|
REM after %OSDRIVE% appears). Resolution deferred to after imaging starts - store
|
|
REM the CMMID for now and resolve in the post-imaging copy block below.
|
|
goto enroll_menu
|
|
|
|
:display_submenu
|
|
cls
|
|
echo.
|
|
echo ========================================
|
|
echo Display Kiosk Sub-Type
|
|
echo ========================================
|
|
echo.
|
|
echo 1. Dashboard (shop floor metrics dashboard)
|
|
echo 2. Lobby Display (lobby information screen)
|
|
echo 3. 3D Parts Kiosk (printed-parts kiosk)
|
|
echo.
|
|
REM These values are KEYS into the GE-Enforce display scope
|
|
REM (shopdb-flask plugins/geenforce/seed_display_scope.py):
|
|
REM Dashboard -> /shopdb/shopfloor, Lobby -> /shopdb/tv,
|
|
REM 3DPrintRoom -> /shopdb/parts-kiosk
|
|
REM They are written to C:\Enrollment\display-type.txt and the dispatcher reads
|
|
REM that as its fallback when the server has no IP-based role for the device, so
|
|
REM the spelling must match the map exactly. 3DPrintRoom was in the map but had
|
|
REM no menu entry, so a parts kiosk could only be set by hand after imaging.
|
|
set DISPLAYTYPE=
|
|
set /p disp_choice=Enter your choice (1-3):
|
|
if "%disp_choice%"=="1" set DISPLAYTYPE=Dashboard
|
|
if "%disp_choice%"=="2" set DISPLAYTYPE=Lobby
|
|
if "%disp_choice%"=="3" set DISPLAYTYPE=3DPrintRoom
|
|
if "%DISPLAYTYPE%"=="" goto display_submenu
|
|
goto enroll_menu
|
|
|
|
: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 The ACTIVE ppkg is read from \\172.16.9.1\enrollment\ppkg.conf, which the
|
|
REM PXE webapp writes on upload - so a new ppkg goes live with no startnet edit.
|
|
REM The baked-in values below are only a fallback if ppkg.conf is missing.
|
|
net use Y: \\%PXESERVER%\enrollment /user:%SHAREUSER% %SHAREPASS% /persistent:no >nul 2>&1
|
|
set SOURCE_PPKG=
|
|
set TARGET_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 /i "%%A"=="TARGET_PPKG" set "TARGET_PPKG=%%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=
|
|
REM Target filename for the staged package.
|
|
REM
|
|
REM The SFLD-era scheme encoded an Office variant in the name
|
|
REM (GCCH_Prod_SFLD_<Office>_<Region>_Exp_<date>_<ver>.ppkg) because one source
|
|
REM package was renamed per Office choice. MCL packages do not work that way -
|
|
REM Office is installed by Install-Office.ps1 inside the package - and renaming
|
|
REM an MCL package into the SFLD scheme just produces a misleading filename.
|
|
REM
|
|
REM So: honour TARGET_PPKG from ppkg.conf when present, otherwise keep the
|
|
REM source filename unchanged. The SFLD construction remains only as a fallback
|
|
REM for a legacy SFLD source package.
|
|
if not "%TARGET_PPKG%"=="" (
|
|
set PPKG=%TARGET_PPKG%
|
|
) else (
|
|
REM find, NOT findstr: findstr.exe is not in this WinPE image (find.exe is,
|
|
REM and startnet already uses it for the PESetup wait). findstr fails with
|
|
REM "not recognized", leaves errorlevel 9009, and "if errorlevel 1" then
|
|
REM takes the NON-SFLD branch for an SFLD package - so the staged ppkg keeps
|
|
REM its source name and never gets the BPRT-tagged one.
|
|
echo %SOURCE_PPKG% | find /I "_SFLD_" >NUL
|
|
if errorlevel 1 (
|
|
set PPKG=%SOURCE_PPKG%
|
|
) else (
|
|
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: \\%PXESERVER%\enrollment /user:%SHAREUSER% %SHAREPASS% /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:\waxtrace-asset.txt
|
|
if not "%MACHINENUM%"=="" goto waxtrace_have_asset
|
|
echo.
|
|
echo Picker unavailable or cancelled. Falling back to free-text prompt.
|
|
echo Wax/Trace bays use the asset tag, e.g. WJRP2335 or WJF00159, to pick
|
|
echo the right calibration ISO during shopfloor setup.
|
|
set /p MACHINENUM=Enter asset tag:
|
|
:waxtrace_have_asset
|
|
if "%MACHINENUM%"=="" echo WARNING: no asset tag entered - calibration apply will be skipped.
|
|
echo Asset tag: %MACHINENUM%
|
|
:skip_machinenum
|
|
|
|
REM --- Map enrollment share early (kept open for copy after imaging) ---
|
|
REM Y: may already be mapped from :prompt_waxtrace_asset (picker block).
|
|
REM net use of an already-mapped letter throws "System error 85: The local
|
|
REM device name is already in use" which is harmless but noisy on screen.
|
|
REM Skip the re-map when Y: is already mounted.
|
|
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
|
|
if exist Y:\ goto enroll_already_mapped
|
|
net use Y: \\%PXESERVER%\enrollment /user:%SHAREUSER% %SHAREPASS% /persistent:no
|
|
:enroll_already_mapped
|
|
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
|
|
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: \\%PXESERVER%\winpeapps\gea-standard /user:%SHAREUSER% %SHAREPASS% /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: \\%PXESERVER%\winpeapps\gea-engineer /user:%SHAREUSER% %SHAREPASS% /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 <media>\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\<PCTYPE> 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: \\%PXESERVER%\winpeapps\_media\%PCTYPE% /user:%SHAREUSER% %SHAREPASS% /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: \\%PXESERVER%\winpeapps\gea-shopfloor /user:%SHAREUSER% %SHAREPASS% /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"
|
|
)
|
|
|
|
REM --- Pre-imaging checks ---------------------------------------------------
|
|
REM Checks the things PESetup fails on, before it fails on them: secure boot
|
|
REM (hard failure at GatherData), disk >= 120 GB, a driver pack matching THIS
|
|
REM model, and media age. The driver check is the one that earns its keep - a
|
|
REM miss is only a WARNING to PESetup, so the bay images with no NIC and the
|
|
REM symptom shows up much later as a DNS failure during enrollment.
|
|
REM Advisory: it reports and pauses on a blocker, it does not abort. The tech
|
|
REM decides. Lives on the share so it can be fixed without a boot.wim rebuild.
|
|
if exist "Y:\scripts\preflight.ps1" (
|
|
powershell -NoProfile -ExecutionPolicy Bypass -File "Y:\scripts\preflight.ps1" -MediaDrive Z:
|
|
if errorlevel 1 (
|
|
echo Press any key to image anyway, or power off the bay to stop.
|
|
pause >NUL
|
|
)
|
|
)
|
|
|
|
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 ---
|
|
REM PCCONFIG is here so standard/engineer builds still reach the volume wait:
|
|
REM they select no ppkg and no PCTYPE, but they do need pc-config.txt written.
|
|
if "%PPKG%"=="" if "%PCTYPE%"=="" if "%PCCONFIG%"=="" goto wait_finish
|
|
REM --- Wait for the volume PESetup applies Windows to -----------------------
|
|
REM PESetup hardcodes W: in nine places - every copy destination, both DISM
|
|
REM offline sessions, bcdboot and reagentc - and CREATES it during its own disk
|
|
REM preparation. See docs/PESETUP-INTERNALS.md. There is nothing to search for.
|
|
REM
|
|
REM Do NOT try to locate the volume earlier by scanning for a Windows install.
|
|
REM Proven on 579C144, 2026-08-06, PESetup 4.0.0.20:
|
|
REM 11:30:07 PESetup logs the OLD install still mounted at C:
|
|
REM 11:30:18 operator presses Next
|
|
REM 11:30:20 PESetup runs DISKPART /S X:\diskpartEFI0.txt - the wipe
|
|
REM 11:30:24 a volume scan had returned that C:, startnet assigned it W: and
|
|
REM staged into the partition PESetup was mid-way through erasing.
|
|
REM Every robocopy died, "The system cannot find the path
|
|
REM specified", and NOTHING was staged.
|
|
REM 11:30:30 PESetup creates its own W: and starts copying to it
|
|
REM The SYSTEM hive is the signal that distinguishes the applied image from the
|
|
REM one being wiped: it exists only once the WIM apply has written it. Do not
|
|
REM weaken this test to "the volume exists" or "Windows is present".
|
|
set OSDRIVE=
|
|
echo Waiting for the applied Windows volume at W: ...
|
|
set OSWAIT=0
|
|
:wait_enroll
|
|
if exist W:\Windows\System32\config\system (
|
|
set OSDRIVE=W:
|
|
goto found_os
|
|
)
|
|
set /a OSWAIT+=1
|
|
REM 270 polls at ~10s = 45 minutes. Was 120 (20 min), which is fine on NVMe but
|
|
REM tight on slow media - a WIM apply can run 25+ minutes there, and the failure
|
|
REM mode is the scary os_not_found banner plus nothing staged. Waiting longer
|
|
REM costs nothing: the loop exits the moment the SYSTEM hive appears.
|
|
if %OSWAIT% GEQ 270 goto os_not_found
|
|
ping -n 11 127.0.0.1 >NUL
|
|
goto wait_enroll
|
|
|
|
:os_not_found
|
|
echo.
|
|
echo ******************************************************************
|
|
echo ERROR: no applied Windows volume found.
|
|
echo NOTHING was staged: pc-type.txt, the enrollment package and
|
|
echo shopfloor-setup are all missing. Imaging will finish but the
|
|
echo post-install setup will NOT run. Tell the PXE admin.
|
|
echo ******************************************************************
|
|
echo.
|
|
goto cleanup_enroll
|
|
|
|
:found_os
|
|
echo Found Windows at %OSDRIVE%
|
|
|
|
REM No drive-letter reassignment here. PESetup owns W: and runs its own DISKPART
|
|
REM against the same disk; a second diskpart racing it destroys the volume that
|
|
REM staging is writing to. The unattend's hardcoded W:\Drivers path is PESetup's
|
|
REM own destination (CopyDrivers unzips there), so it lines up by construction.
|
|
mkdir %OSDRIVE%\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=%OSDRIVE%\Enrollment\winpe-staging.log
|
|
echo [%DATE% %TIME%] WinPE staging started >> "%STAGELOG%"
|
|
echo PCTYPE=%PCTYPE% PPKG=%PPKG% MACHINENUM=%MACHINENUM% CMMID=%CMMID% PCCONFIG=%PCCONFIG% >> "%STAGELOG%"
|
|
|
|
REM --- Pre-seed the tenant + PC purpose for the enrollment orchestrator -----
|
|
REM Start-BulkEnrollOrchestrator.ps1 asks for this with a GUI at first logon
|
|
REM (Select-PCConfig.ps1) and uses the answer twice: to pick which MCL package
|
|
REM to apply, and to select which bulk token Insert-BPRTToPPKG.ps1 injects -
|
|
REM it matches on Tenant AND Purpose. Writing the answer here lets the shim
|
|
REM return it non-interactively, so an unattended build never stops on a dialog.
|
|
REM Format is exactly what the vendor dialog returns: {Tenant}_{Purpose},
|
|
REM e.g. GCCH_PERS, GCCH_SH, RoW_LOAN.
|
|
REM Only the CHOICE is pre-seeded. Token injection still happens at first logon
|
|
REM because it fetches an encrypted token table from mcl.dwcdn.geaerospace.com,
|
|
REM which is unreachable from this isolated imaging LAN.
|
|
if not "%PCCONFIG%"=="" (
|
|
echo %PCCONFIG%> %OSDRIVE%\Enrollment\pc-config.txt
|
|
echo Pre-seeded PC config %PCCONFIG% for the enrollment orchestrator.
|
|
echo [%TIME%] Wrote pc-config.txt=%PCCONFIG% >> "%STAGELOG%"
|
|
)
|
|
|
|
REM --- Copy site config (drives site-specific values in all setup scripts) ---
|
|
if exist "Y:\config\site-config.json" (
|
|
robocopy "Y:\config" "%OSDRIVE%\Enrollment" "site-config.json" /R:1 /W:1 /NFL /NDL /NJH /NJS
|
|
if errorlevel 8 (
|
|
echo WARNING: site-config.json robocopy FAILED - not staged.
|
|
echo [%TIME%] FAILED: site-config.json robocopy >> "%STAGELOG%"
|
|
) else (
|
|
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" "%OSDRIVE%\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 "%OSDRIVE%\Enrollment\%SOURCE_PPKG%" "%PPKG%"
|
|
echo [%TIME%] Copied PPKG %SOURCE_PPKG% as %PPKG% >> "%STAGELOG%"
|
|
robocopy "Y:\scripts" "%OSDRIVE%\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 ---
|
|
> %OSDRIVE%\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:\Enrollment\run-enrollment.ps1"
|
|
)
|
|
echo Manual fallback created at %OSDRIVE%\enroll.cmd
|
|
|
|
:copy_pctype
|
|
REM --- Copy shopfloor PC type setup scripts ---
|
|
if "%PCTYPE%"=="" goto cleanup_enroll
|
|
echo %PCTYPE%> %OSDRIVE%\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%> %OSDRIVE%\Enrollment\display-type.txt
|
|
if not "%MACHINENUM%"=="" echo %MACHINENUM%> %OSDRIVE%\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-<model>\manifest.json on share).
|
|
if not "%KEYENCEMODEL%"=="" (
|
|
echo %KEYENCEMODEL%> %OSDRIVE%\Enrollment\keyence-model.txt
|
|
echo %KEYENCEMODEL%> %OSDRIVE%\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 %OSDRIVE%\Enrollment\cmm\ for 09-Setup-CMM.ps1 to consume.
|
|
if "%CMMID%"=="" goto cmm_id_done
|
|
echo %CMMID%> %OSDRIVE%\Enrollment\machine-number.txt
|
|
mkdir %OSDRIVE%\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 "%OSDRIVE%\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 %OSDRIVE%\Enrollment\cmm\doda.txt goto cmm_id_done
|
|
set /p CMMDODA=<%OSDRIVE%\Enrollment\cmm\doda.txt
|
|
if /i "%CMMDODA%"=="yes" echo doda> %OSDRIVE%\Enrollment\pc-subtype.txt
|
|
:cmm_id_done
|
|
robocopy "Y:\shopfloor-setup" "%OSDRIVE%\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" "%OSDRIVE%\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" "%OSDRIVE%\Enrollment" "Verify-And-Heal-Staging.ps1" /R:1 /W:1 /NFL /NDL /NJH /NJS
|
|
> %OSDRIVE%\Enrollment\fetch-source.txt (
|
|
echo \\%PXESERVER%\enrollment
|
|
echo %SHAREUSER%
|
|
echo %SHAREPASS%
|
|
)
|
|
REM --- Always copy Shopfloor baseline scripts ---
|
|
mkdir %OSDRIVE%\Enrollment\shopfloor-setup 2>NUL
|
|
robocopy "Y:\shopfloor-setup" "%OSDRIVE%\Enrollment\shopfloor-setup" "backup_lockdown.bat" /R:1 /W:1 /NFL /NDL /NJH /NJS
|
|
if exist "Y:\shopfloor-setup\Shopfloor" (
|
|
mkdir %OSDRIVE%\Enrollment\shopfloor-setup\Shopfloor 2>NUL
|
|
robocopy "Y:\shopfloor-setup\Shopfloor" "%OSDRIVE%\Enrollment\shopfloor-setup\Shopfloor" /E /MT:16 /R:1 /W:1 /NFL /NDL /LOG+:"%STAGELOG%"
|
|
REM Report what actually happened. These echoes used to run unconditionally
|
|
REM and printed "Copied ..." for six copies that moved zero bytes.
|
|
REM %ERRORLEVEL% is not printed: inside a parenthesised block it expands at
|
|
REM PARSE time, so it shows a stale value from before the robocopy ran.
|
|
if errorlevel 8 (
|
|
echo WARNING: shopfloor-setup\Shopfloor robocopy FAILED - nothing copied.
|
|
echo [%TIME%] FAILED: Shopfloor baseline robocopy >> "%STAGELOG%"
|
|
) else (
|
|
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 %OSDRIVE%\Enrollment\shopfloor-setup\common 2>NUL
|
|
robocopy "Y:\shopfloor-setup\common" "%OSDRIVE%\Enrollment\shopfloor-setup\common" /E /MT:16 /R:1 /W:1 /NFL /NDL /LOG+:"%STAGELOG%"
|
|
if errorlevel 8 (
|
|
echo WARNING: shopfloor-setup\common robocopy FAILED - nothing copied.
|
|
echo [%TIME%] FAILED: common robocopy >> "%STAGELOG%"
|
|
) else (
|
|
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 %OSDRIVE%\Enrollment\shopfloor-setup\_ntlars-backups 2>NUL
|
|
robocopy "Y:\shopfloor-setup\_ntlars-backups" "%OSDRIVE%\Enrollment\shopfloor-setup\_ntlars-backups" /E /MT:16 /R:1 /W:1 /NFL /NDL /LOG+:"%STAGELOG%"
|
|
if errorlevel 8 (
|
|
echo WARNING: _ntlars-backups robocopy FAILED - nothing copied.
|
|
echo [%TIME%] FAILED: _ntlars-backups robocopy >> "%STAGELOG%"
|
|
) else (
|
|
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 "%OSDRIVE%\Enrollment\shopfloor-setup\%PCTYPE%" 2>NUL
|
|
robocopy "Y:\shopfloor-setup\%PCTYPE%" "%OSDRIVE%\Enrollment\shopfloor-setup\%PCTYPE%" /E /MT:16 /R:1 /W:1 /NFL /NDL /LOG+:"%STAGELOG%"
|
|
if errorlevel 8 (
|
|
echo WARNING: shopfloor-setup\%PCTYPE% robocopy FAILED - nothing copied.
|
|
echo [%TIME%] FAILED: %PCTYPE% type-specific robocopy >> "%STAGELOG%"
|
|
) else (
|
|
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 %OSDRIVE%\PreInstall 2>NUL
|
|
mkdir %OSDRIVE%\PreInstall\installers 2>NUL
|
|
robocopy "Y:\pre-install" "%OSDRIVE%\PreInstall" "preinstall.json" /R:1 /W:1 /NFL /NDL /NJH /NJS
|
|
if exist "Y:\pre-install\installers" (
|
|
robocopy "Y:\pre-install\installers" "%OSDRIVE%\PreInstall\installers" /E /MT:16 /R:1 /W:1 /NFL /NDL /LOG+:"%STAGELOG%"
|
|
if errorlevel 8 (
|
|
echo WARNING: pre-install\installers robocopy FAILED - nothing staged.
|
|
) else (
|
|
echo Staged preinstall bundle to %OSDRIVE%\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" "%OSDRIVE%\PreInstall\udc-backups" /E /MT:16 /R:1 /W:1 /NFL /NDL /LOG+:"%STAGELOG%"
|
|
if errorlevel 8 (
|
|
echo WARNING: pre-install\udc-backups robocopy FAILED - nothing staged.
|
|
) else (
|
|
echo Staged UDC settings backups to %OSDRIVE%\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 %OSDRIVE%\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" "%OSDRIVE%\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 FAILED - CMM bootstrap NOT staged.
|
|
) else (
|
|
echo Staged CMM bootstrap to %OSDRIVE%\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 %OSDRIVE%\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%" "%OSDRIVE%\CMM-Install\backups\%CMMID%" /E /MT:16 /R:1 /W:1 /NFL /NDL /LOG+:"%STAGELOG%"
|
|
if errorlevel 8 (
|
|
echo WARNING: %CMMID% backup robocopy FAILED - settings will NOT restore.
|
|
echo [%TIME%] FAILED: %CMMID% backup robocopy >> "%STAGELOG%"
|
|
) else (
|
|
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/<model>/ 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 %OSDRIVE%\KeyenceInstall 2>NUL
|
|
mkdir %OSDRIVE%\KeyenceInstall\%KEYENCEMODEL% 2>NUL
|
|
robocopy "Y:\installers-post\keyence\%KEYENCEMODEL%" "%OSDRIVE%\KeyenceInstall\%KEYENCEMODEL%" /E /MT:16 /R:1 /W:1 /NFL /NDL /LOG+:"%STAGELOG%"
|
|
if errorlevel 8 (
|
|
echo WARNING: keyence\%KEYENCEMODEL% robocopy FAILED - nothing staged.
|
|
) else (
|
|
echo Staged Keyence %KEYENCEMODEL% bootstrap to %OSDRIVE%\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 -> %OSDRIVE%\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 %OSDRIVE%\Enrollment\waxtrace\{version,model,userid}.txt for 09-Setup to read
|
|
REM 3. robocopy ONLY the bay's matching FORMTRACEPAK-V<ver>.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 %OSDRIVE%\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" "%OSDRIVE%\WaxTrace-Install" /E /XD formtracepak /MT:16 /R:1 /W:1 /NFL /NDL
|
|
REM Both tests read the robocopy result, so they must sit before any command
|
|
REM that sets its own errorlevel - mkdir does, which is why it moved below.
|
|
if errorlevel 8 echo WARNING: WaxTrace bootstrap robocopy FAILED - nothing staged.
|
|
if not errorlevel 8 echo Staged WaxTrace bootstrap minus formtracepak\ to %OSDRIVE%\WaxTrace-Install.
|
|
mkdir %OSDRIVE%\WaxTrace-Install\formtracepak 2>NUL
|
|
REM Resolve bay-config: writes %OSDRIVE%\Enrollment\waxtrace\{version,model,userid}.txt
|
|
mkdir %OSDRIVE%\Enrollment\waxtrace 2>NUL
|
|
if not "%MACHINENUM%"=="" (
|
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "Y:\installers-post\waxtrace\resolve-bay-config.ps1" -Asset "%MACHINENUM%" -OutDir "%OSDRIVE%\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 %OSDRIVE%\Enrollment\waxtrace\version.txt set /p WTVER=<%OSDRIVE%\Enrollment\waxtrace\version.txt
|
|
if not "%WTVER%"=="" (
|
|
if exist "Y:\installers-post\waxtrace\formtracepak\FORMTRACEPAK-V%WTVER%.iso" (
|
|
REM robocopy /J = unbuffered I/O, meaningfully faster than xcopy on
|
|
REM 2 GB FTPak ISOs over SMB. Single-file syntax: source dir, dest
|
|
REM dir, file pattern.
|
|
robocopy "Y:\installers-post\waxtrace\formtracepak" "%OSDRIVE%\WaxTrace-Install\formtracepak" "FORMTRACEPAK-V%WTVER%.iso" /J /R:1 /W:1 /NFL /NDL
|
|
echo Staged FormTracePak V%WTVER%.iso for %MACHINENUM%.
|
|
) else (
|
|
echo WARNING: No FORMTRACEPAK-V%WTVER%.iso on share for %MACHINENUM% - 09-Setup-WaxAndTrace will abort cleanly with the version-mismatch error.
|
|
)
|
|
) else (
|
|
echo WARNING: bay-config did not resolve a FTPak version for %MACHINENUM%.
|
|
)
|
|
REM Per-asset backup ZIPs land at %OSDRIVE%\WaxTrace-Install\backups\<asset>.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 <asset>.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 "%OSDRIVE%\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 %OSDRIVE%\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 --- Verify what we just staged ------------------------------------------
|
|
REM Check the payload BEFORE anything depends on it, while a tech is still
|
|
REM standing at the machine. A short copy found here costs 30 seconds; the same
|
|
REM copy found at first logon costs 20 minutes, and found never costs a rebuild.
|
|
REM Four Display bays sat at "imaging stage 2, green" for weeks because nothing
|
|
REM checked. Retry once for the small trees; the ppkg is 8 GB so report it
|
|
REM rather than blindly re-pulling it.
|
|
if "%PCTYPE%"=="" goto verify_done
|
|
set STAGEBAD=
|
|
if not exist "%OSDRIVE%\Enrollment\pc-type.txt" set STAGEBAD=%STAGEBAD% pc-type.txt
|
|
if not exist "%OSDRIVE%\Enrollment\Run-ShopfloorSetup.ps1" set STAGEBAD=%STAGEBAD% Run-ShopfloorSetup.ps1
|
|
if not exist "%OSDRIVE%\Enrollment\shopfloor-setup\common" set STAGEBAD=%STAGEBAD% shopfloor-setup\common
|
|
if not exist "%OSDRIVE%\Enrollment\shopfloor-setup\%PCTYPE%" set STAGEBAD=%STAGEBAD% shopfloor-setup\%PCTYPE%
|
|
if "%STAGEBAD%"=="" goto verify_ppkg
|
|
|
|
echo.
|
|
echo Staging verify: missing%STAGEBAD% - retrying once...
|
|
echo [%TIME%] VERIFY: missing%STAGEBAD% - retry >> "%STAGELOG%"
|
|
robocopy "Y:\shopfloor-setup" "%OSDRIVE%\Enrollment" "Run-ShopfloorSetup.ps1" /R:2 /W:2 /NFL /NDL /NJH /NJS
|
|
robocopy "Y:\shopfloor-setup\common" "%OSDRIVE%\Enrollment\shopfloor-setup\common" /E /MT:16 /R:2 /W:2 /NFL /NDL /NJH /NJS
|
|
robocopy "Y:\shopfloor-setup\%PCTYPE%" "%OSDRIVE%\Enrollment\shopfloor-setup\%PCTYPE%" /E /MT:16 /R:2 /W:2 /NFL /NDL /NJH /NJS
|
|
if not exist "%OSDRIVE%\Enrollment\pc-type.txt" echo %PCTYPE%> %OSDRIVE%\Enrollment\pc-type.txt
|
|
|
|
set STAGEBAD=
|
|
if not exist "%OSDRIVE%\Enrollment\pc-type.txt" set STAGEBAD=%STAGEBAD% pc-type.txt
|
|
if not exist "%OSDRIVE%\Enrollment\Run-ShopfloorSetup.ps1" set STAGEBAD=%STAGEBAD% Run-ShopfloorSetup.ps1
|
|
if not exist "%OSDRIVE%\Enrollment\shopfloor-setup\common" set STAGEBAD=%STAGEBAD% shopfloor-setup\common
|
|
if not exist "%OSDRIVE%\Enrollment\shopfloor-setup\%PCTYPE%" set STAGEBAD=%STAGEBAD% shopfloor-setup\%PCTYPE%
|
|
if "%STAGEBAD%"=="" (
|
|
echo Staging verify: retry fixed it.
|
|
echo [%TIME%] VERIFY: retry succeeded >> "%STAGELOG%"
|
|
goto verify_ppkg
|
|
)
|
|
echo.
|
|
echo ******************************************************************
|
|
echo STAGING INCOMPLETE after retry:%STAGEBAD%
|
|
echo This bay will image but the post-install setup will NOT run
|
|
echo properly. Fix the share and re-image. Tell the PXE admin.
|
|
echo ******************************************************************
|
|
echo.
|
|
echo [%TIME%] VERIFY FAILED after retry:%STAGEBAD% >> "%STAGELOG%"
|
|
|
|
:verify_ppkg
|
|
REM The enrollment package is the expensive one - 8 GB. Report, do not re-pull.
|
|
if "%PPKG%"=="" goto verify_done
|
|
if exist "%OSDRIVE%\Enrollment\%PPKG%" (
|
|
echo Staging verify: enrollment package present.
|
|
echo [%TIME%] VERIFY: %PPKG% present >> "%STAGELOG%"
|
|
) else (
|
|
echo.
|
|
echo WARNING: enrollment package %PPKG% is MISSING from %OSDRIVE%\Enrollment.
|
|
echo Enrollment will not run. Re-image this bay.
|
|
echo.
|
|
echo [%TIME%] VERIFY FAILED: %PPKG% missing >> "%STAGELOG%"
|
|
)
|
|
:verify_done
|
|
|
|
REM --- BIOS update sub-stage push (fires AFTER %OSDRIVE% 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
|
|
|
|
REM --- Harvest the imaging logs to the share --------------------------------
|
|
REM Every diagnosis of a failed build so far has meant walking to the bay and
|
|
REM copying files off by hand. PESetup preserves its log and the generated
|
|
REM unattend, DISM writes its apply logs, and our staging log sits on the target
|
|
REM - all of it is thrown away at reboot unless collected now. Runs after
|
|
REM PESetup exits so the logs are final, which means re-mapping Y: (cleanup
|
|
REM already dropped it).
|
|
REM Best-effort throughout: a bay must never fail to reboot because a log copy
|
|
REM did not work.
|
|
set SERIAL=
|
|
for /f "skip=1 tokens=*" %%S in ('wmic bios get serialnumber 2^>NUL') do if not defined SERIAL set SERIAL=%%S
|
|
for /f "tokens=*" %%a in ("%SERIAL%") do set SERIAL=%%a
|
|
if "%SERIAL%"=="" set SERIAL=unknown-serial
|
|
|
|
net use Y: \\%PXESERVER%\enrollment /user:%SHAREUSER% %SHAREPASS% /persistent:no >NUL 2>&1
|
|
if not exist "Y:\" goto harvest_done
|
|
set LOGDEST=Y:\imaging-logs\%SERIAL%
|
|
mkdir "Y:\imaging-logs" 2>NUL
|
|
mkdir "%LOGDEST%" 2>NUL
|
|
echo Collecting imaging logs to %LOGDEST% ...
|
|
|
|
REM WinPE side: DISM apply logs, the unattend PESetup generated, BIOS flash log.
|
|
robocopy X:\ "%LOGDEST%" "*.log" "Unattend.xml" /R:1 /W:1 /NFL /NDL /NJH /NJS >NUL 2>&1
|
|
REM Target side: PESetup's own log lands in Panther, and our staging log.
|
|
if defined OSDRIVE (
|
|
robocopy "%OSDRIVE%\Windows\Panther" "%LOGDEST%" "PESetup*.log" /R:1 /W:1 /NFL /NDL /NJH /NJS >NUL 2>&1
|
|
robocopy "%OSDRIVE%\Enrollment" "%LOGDEST%" "winpe-staging.log" /R:1 /W:1 /NFL /NDL /NJH /NJS >NUL 2>&1
|
|
)
|
|
REM A breadcrumb of what this build actually was, so the logs are readable
|
|
REM without cross-referencing the webapp.
|
|
> "%LOGDEST%\build-context.txt" (
|
|
echo Serial=%SERIAL%
|
|
echo PCTYPE=%PCTYPE%
|
|
echo PPKG=%PPKG%
|
|
echo MACHINENUM=%MACHINENUM%
|
|
echo CMMID=%CMMID%
|
|
echo KEYENCEMODEL=%KEYENCEMODEL%
|
|
echo DISPLAYTYPE=%DISPLAYTYPE%
|
|
echo OSDRIVE=%OSDRIVE%
|
|
echo Media=%MEDIAPATH%
|
|
echo Date=%DATE% %TIME%
|
|
)
|
|
echo Imaging logs collected.
|
|
net use Y: /delete /y >NUL 2>&1
|
|
:harvest_done
|
|
|
|
echo.
|
|
echo Imaging complete. Rebooting in 15 seconds...
|
|
echo Press Ctrl+C to cancel.
|
|
ping -n 16 127.0.0.1 >NUL
|
|
wpeutil reboot
|