Generic build for other GE sites: no WJ data, one shopfloor type, Windows USB builder

Everything West Jefferson specific moved out to a separate repo
(pxe-site-wj): NTLARS/UDC/heat-treat backups keyed by WJ machine numbers,
CMM and Wax/Trace bay lists, WJ OpenText profiles, site-config.json, the
WJ preinstall list, and the WJ shopfloor PC types (Collections,
NoCollections, Common, Keyence, CMM, Genspect, HeatTreat, Wax/Trace,
Display, PartMarker) with GE-Enforce, machine numbers and the desktop
layout. The part-marker bench tools moved to their own repo. Dead
scripts removed: build-proxmox-iso, deploy-bios, sync_hardware_models,
mirror-from-gold, pull-bios, startnet-template.cmd.

Shopfloor is one generic type, gea-shopfloor-standard, with today's
timing:
- PPKG at first logon (unattend Order 10, unchanged).
- Install-AppList.ps1 runs C:\PreInstall\preinstall.json during setup.
- A new SYSTEM task, GE Shopfloor Post-PPKG, runs postppkg.json once
  after the post-PPKG reboot. It also clears AutoLogonCount after the
  ShopFloor handover (the Users-level monitor can be denied that HKLM
  write) and removes the Intune Sync task when done.
- Both lists ship empty. A site adds entries and installers.
- WinPE choice 3 goes straight to the PPKG menu. Staging, fetch and heal
  carry only the generic payload. The webapp's shopfloor sub-menu editor
  is gone, and the imaging tiles name the new stages.
- The playbook deploys the empty lists only if missing. It now deploys
  the PowerShell 7 MSI the shopfloor unattend installs, which it never
  did before.

Blancco site settings move into the webapp (Updates > Blancco releases):
business location, licensing Wi-Fi SSID and password. They are rendered
into the served preferences.xml and applied to every staged release, and
are seeded from site-vars (site_name, blancco_wifi_ssid,
blancco_wifi_password) only while none exist. The repo XML carries no
site values; the plaintext Wi-Fi password is gone from it.

New site_name and site_timezone settings: report and evidence-pack site
name, server clock and webapp time zone. No more West Jefferson defaults
in webapp/config.py or the dashboard title. Sync-BPRT.ps1 gets the
server address filled in at download instead of WJ's GE address.

USB on Windows:
- scripts/Build-PxeUsb.ps1 runs the same checks as build-usb.sh. It
  writes one FAT32 CIDATA partition (ISO files plus patched grub.cfg plus
  payload) with diskpart and reads every file back by SHA-256.
- Tested with Windows PowerShell 5.1 in the win11 VM, and the layout
  installs and first-boots in the pxetest VM.
- scripts/stage-usb-share.sh stages the build folder on a share.
- site-content/ is optional for both builders.

KB docs/kb/How_To_Deploy_PXE_Server_New_Site.html: new-site deployment,
Windows only, with a site-vars.yml guide.

Checks: webapp tests pass (5 suites); the unattend lint and playbook
syntax checks pass; every .ps1 parses; there are no WJ hosts, IPs, names
or PC types in playbook/, webapp/, scripts/ or autoinstall/.
This commit is contained in:
cproudlock
2026-10-16 20:37:22 -04:00
parent b11e678297
commit 04db6d6605
710 changed files with 3113 additions and 82414 deletions

View File

@@ -48,20 +48,17 @@ echo Please select an option:
echo.
echo 1. GEA Standard
echo 2. GEA Engineer
echo 3. GEA Shopfloor (sub-menu)
echo 3. GEA Shopfloor
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.
REM --- Choice 3 = GEA Shopfloor: one generic type, gea-shopfloor-standard, then
REM the GCCH enrollment (PPKG) menu.
set PPKG=
set PCCONFIG=
if "%choice%"=="3" goto gea_shopfloor_submenu
if "%choice%"=="6" goto enroll_menu
if "%choice%"=="7" goto enroll_menu
if "%choice%"=="3" goto gea_shopfloor_type
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
@@ -113,133 +110,10 @@ 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
:gea_shopfloor_type
REM One generic shopfloor type: an (empty) app list during setup, the PPKG, an
REM (empty) post-PPKG app list, then the ShopFloor lockdown handover.
set PCTYPE=gea-shopfloor-standard
goto enroll_menu
:enroll_menu
@@ -319,60 +193,9 @@ if not "%TARGET_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.
REM Skip the re-map when Y: is already mounted (System error 85 otherwise).
set NEED_ENROLL=0
if not "%PPKG%"=="" set NEED_ENROLL=1
if not "%PCTYPE%"=="" set NEED_ENROLL=1
@@ -416,33 +239,6 @@ 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
@@ -550,7 +346,7 @@ 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%"
echo PCTYPE=%PCTYPE% PPKG=%PPKG% 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
@@ -569,21 +365,6 @@ if not "%PCCONFIG%"=="" (
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
@@ -615,36 +396,6 @@ echo Manual fallback created at %OSDRIVE%\enroll.cmd
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
@@ -662,7 +413,6 @@ 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%"
@@ -678,52 +428,12 @@ if exist "Y:\shopfloor-setup\Shopfloor" (
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) ---
REM --- Stage the site app lists + installers (pre-install = during setup,
REM postppkg = after the post-PPKG reboot; both empty in the generic build) ---
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
robocopy "Y:\pre-install" "%OSDRIVE%\PreInstall" "preinstall.json" "postppkg.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 (
@@ -735,148 +445,10 @@ if exist "Y:\pre-install\preinstall.json" (
) 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%"
@@ -891,23 +463,23 @@ 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 not exist "%OSDRIVE%\Enrollment\shopfloor-setup\Shopfloor\lib\Monitor-IntuneProgress.ps1" set STAGEBAD=%STAGEBAD% shopfloor-setup\Shopfloor
if not exist "%OSDRIVE%\PreInstall\preinstall.json" set STAGEBAD=%STAGEBAD% PreInstall\preinstall.json
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
robocopy "Y:\shopfloor-setup\Shopfloor" "%OSDRIVE%\Enrollment\shopfloor-setup\Shopfloor" /E /MT:16 /R:2 /W:2 /NFL /NDL /NJH /NJS
robocopy "Y:\pre-install" "%OSDRIVE%\PreInstall" "preinstall.json" "postppkg.json" /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 not exist "%OSDRIVE%\Enrollment\shopfloor-setup\Shopfloor\lib\Monitor-IntuneProgress.ps1" set STAGEBAD=%STAGEBAD% shopfloor-setup\Shopfloor
if not exist "%OSDRIVE%\PreInstall\preinstall.json" set STAGEBAD=%STAGEBAD% PreInstall\preinstall.json
if "%STAGEBAD%"=="" (
echo Staging verify: retry fixed it.
echo [%TIME%] VERIFY: retry succeeded >> "%STAGELOG%"
@@ -991,10 +563,6 @@ REM without cross-referencing the webapp.
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%