startnet: stage against PESetup's own W:, and stop reporting failed copies as successes

Brings the repo back in line with what is actually running in boot.wim, validated
end to end on bay 579C144 today.

WHAT THIS FILE NOW DOES DIFFERENTLY

Applied-volume detection. The volume finder and the diskpart letter reassignment
are gone. PESetup hardcodes W: in nine places and creates it during its own disk
preparation, so there is nothing to search for, and searching actively broke
staging: a scan run before PESetup finished disking returned the PREVIOUS
install, startnet relabelled that partition W:, and PESetup's own DISKPART then
erased it mid-copy. Timestamps from that failure are in the comment so nobody
rebuilds the finder from the same premise. The wait is back on
W:\Windows\System32\config\system, which only exists once the WIM apply has
written it.

Copy reporting. Eight sites echoed "Copied ..." unconditionally, so a run where
every robocopy exited 16 and moved zero bytes still printed six success lines.
They now branch on errorlevel 8 and say FAILED, including in the staging log.
%ERRORLEVEL% is no longer printed inside parenthesised blocks - it expands at
parse time there and showed a stale value. The WaxTrace test moved above its
mkdir, which sets its own errorlevel.

Per-PCTYPE media. Maps Z: to _media\<PCTYPE> and probes
Z:\Deploy\Control\HardwareDriver.json before trusting it, falling back to the
shared media with a warning.

findstr -> find. findstr.exe is not in this WinPE image. It failed with errorlevel
9009, which "if errorlevel 1" read as true, so an SFLD package took the non-SFLD
branch and never got its BPRT-tagged name.

VERIFIED ON A REAL BAY, from C:\Enrollment\winpe-staging.log:

    PPKG=GCCH_Prod_SFLD_NoOffice_US_Exp_20260831_v4.16.ppkg
    Copied PPKG GCCH_Prod_SFLD_v4.16.ppkg as GCCH_Prod_SFLD_NoOffice_US_Exp_...
    Shopfloor 44 files / common 17 / _ntlars 147 / display 1 / preinstall 85
    FAILED: 0 across every copy
This commit is contained in:
cproudlock
2026-08-06 12:25:18 -04:00
parent 385acfefa7
commit 2b6189f739

View File

@@ -149,8 +149,8 @@ if "%CMMID%"=="" (
goto enroll_menu
)
echo CMM bay: %CMMID%
REM Resolve bay config (writes version.txt + doda.txt to W:\Enrollment\cmm\
REM after W: appears). Resolution deferred to after imaging starts - store
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
@@ -195,6 +195,7 @@ 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: \\172.16.9.1\enrollment /user:pxe-upload pxe /persistent:no >nul 2>&1
set SOURCE_PPKG=
set TARGET_PPKG=
set PPKG_VER=
set PPKG_EXP=
if exist "Y:\ppkg.conf" (
@@ -202,6 +203,7 @@ if exist "Y:\ppkg.conf" (
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
@@ -219,7 +221,32 @@ 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 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
@@ -368,26 +395,75 @@ 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: ...
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
if %OSWAIT% GEQ 120 goto os_not_found
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
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=W:\Enrollment\winpe-staging.log
set STAGELOG=%OSDRIVE%\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%"
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%"
@@ -395,7 +471,7 @@ if exist "Y:\config\site-config.json" (
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
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.
@@ -403,106 +479,126 @@ if errorlevel 8 (
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%"
if not "%SOURCE_PPKG%"=="%PPKG%" ren "%OSDRIVE%\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
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 ---
> W:\enroll.cmd (
> %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:\run-enrollment.ps1"
echo powershell.exe -ExecutionPolicy Bypass -File "C:\Enrollment\run-enrollment.ps1"
)
echo Manual fallback created at W:\enroll.cmd
echo Manual fallback created at %OSDRIVE%\enroll.cmd
:copy_pctype
REM --- Copy shopfloor PC type setup scripts ---
if "%PCTYPE%"=="" goto cleanup_enroll
echo %PCTYPE%> W:\Enrollment\pc-type.txt
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%> W:\Enrollment\display-type.txt
if not "%MACHINENUM%"=="" echo %MACHINENUM%> W:\Enrollment\machine-number.txt
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%> W:\Enrollment\keyence-model.txt
echo %KEYENCEMODEL%> W:\Enrollment\pc-subtype.txt
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 W:\Enrollment\cmm\ for 09-Setup-CMM.ps1 to consume.
REM to %OSDRIVE%\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
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 "W:\Enrollment\cmm"
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 W:\Enrollment\cmm\doda.txt goto cmm_id_done
set /p CMMDODA=<W:\Enrollment\cmm\doda.txt
if /i "%CMMDODA%"=="yes" echo doda> W:\Enrollment\pc-subtype.txt
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" "W:\Enrollment" "Run-ShopfloorSetup.ps1" /R:1 /W:1 /NFL /NDL /NJH /NJS
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" "W:\Enrollment" "Fetch-StagingPayload.ps1" /R:1 /W:1 /NFL /NDL /NJH /NJS
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" "W:\Enrollment" "Verify-And-Heal-Staging.ps1" /R:1 /W:1 /NFL /NDL /NJH /NJS
> W:\Enrollment\fetch-source.txt (
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 \\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
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 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%"
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 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%"
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 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%"
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 "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%"
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%"
@@ -510,21 +606,27 @@ if exist "Y:\shopfloor-setup\%PCTYPE%" (
REM --- Stage preinstall bundle (apps installed locally to save Azure bandwidth) ---
if exist "Y:\pre-install\preinstall.json" (
mkdir W:\PreInstall 2>NUL
mkdir W:\PreInstall\installers 2>NUL
robocopy "Y:\pre-install" "W:\PreInstall" "preinstall.json" /R:1 /W:1 /NFL /NDL /NJH /NJS
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" "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.
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" "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.
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 (
@@ -540,24 +642,32 @@ 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
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" "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.
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 W:\CMM-Install\backups\%CMMID%\ to restore PC-DMIS + goCMM settings.
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%" "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%"
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
@@ -572,11 +682,14 @@ 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%\.
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.
@@ -585,44 +698,46 @@ if exist "Y:\installers-post\keyence\%KEYENCEMODEL%\manifest.json" (
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 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 W:\Enrollment\waxtrace\{version,model,userid}.txt for 09-Setup to read
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 W:\WaxTrace-Install 2>NUL
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" "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
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 "W:\Enrollment\waxtrace"
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 W:\Enrollment\waxtrace\version.txt set /p WTVER=<W:\Enrollment\waxtrace\version.txt
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" "W:\WaxTrace-Install\formtracepak" "FORMTRACEPAK-V%WTVER%.iso" /J /R:1 /W:1 /NFL /NDL
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.
@@ -630,17 +745,17 @@ if not "%WTVER%"=="" (
) else (
echo WARNING: bay-config did not resolve a FTPak version for %MACHINENUM%.
)
REM Per-asset backup ZIPs land at W:\WaxTrace-Install\backups\<asset>.zip
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 "W:\WaxTrace-Install\backups\%MACHINENUM%.zip" (
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 W:\WaxTrace-Install\backups - 09-Setup will skip the restore step.
echo INFO: No backup ZIP for %MACHINENUM% in %OSDRIVE%\WaxTrace-Install\backups - 09-Setup will skip the restore step.
)
)
goto skip_waxtrace_stage
@@ -650,7 +765,7 @@ echo WARNING: Y:\installers-post\waxtrace not found - WaxTrace PC cannot install
:pctype_done
if defined STAGELOG echo [%TIME%] WinPE staging complete >> "%STAGELOG%"
REM --- BIOS update sub-stage push (fires AFTER W: copies complete) ---
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