From 2b6189f739c86ed0536a10f110681e9626a8c461 Mon Sep 17 00:00:00 2001 From: cproudlock Date: Thu, 6 Aug 2026 12:25:18 -0400 Subject: [PATCH] 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\ 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 --- playbook/startnet.cmd | 301 +++++++++++++++++++++++++++++------------- 1 file changed, 208 insertions(+), 93 deletions(-) diff --git a/playbook/startnet.cmd b/playbook/startnet.cmd index b134482..5be5e20 100644 --- a/playbook/startnet.cmd +++ b/playbook/startnet.cmd @@ -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___Exp__.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-\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\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.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=.zip +REM Per-asset backup ZIPs land at %OSDRIVE%\WaxTrace-Install\backups\.zip REM as part of the robocopy bundle above (backups\ is not in the /XD list). REM 09-Setup-WaxAndTrace.ps1 Step 3b reads C:\WaxTrace-Install\backups\ REM .zip post-vendor-MSI and runs Install-FormtracepakSettings.ps1 REM -RestoreData -RestoreConfig. Total ~17 MB on disk for the whole set, no REM cherry-pick needed. if not "%MACHINENUM%"=="" ( - if exist "W:\WaxTrace-Install\backups\%MACHINENUM%.zip" ( + 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