From a7cb7164d955b2efcfa872b308e8a028919f8d20 Mon Sep 17 00:00:00 2001 From: cproudlock Date: Thu, 6 Aug 2026 16:58:53 -0400 Subject: [PATCH] Kiosks stop installing shopfloor apps, and empty config stops meaning everything PREINSTALL SCOPE Sixteen entries carried PCTypes ['*'], so a Display kiosk installed Adobe Acrobat, OpenText HostExplorer, WJF Defect Tracker, the shopfloor serial drivers and twelve legacy VC++ redistributables. Those are now scoped to the nine machine-tool types. A Display now installs 3 of 21 entries: PowerShell 7.5.4 SFLD-ApplyDSCConfig runs pwsh.exe 7 VC++ Redistributable 2015-2022 x64 modern x64 runtime Edge/WebView2/PS7 lean on Display Kiosk App already Display-scoped Kept as wildcards deliberately - removing the x64 runtime risks breaking the kiosk itself, and PS7 is a hard dependency of the DSC task. Everything else a kiosk has no use for. Edited as targeted text replacement, 16 line pairs, so the file's formatting and its long _comment blocks are untouched. THE LAST OF THE EMPTY-MEANS-DEFAULT BUGS Configure-PC.ps1 and 07-TaskbarLayout.ps1 had the same test as the two fixed earlier: $null -ne $cfg -AND .Count -gt 0, so an explicitly empty list fell through to a hardcoded shopfloor default. Configure-PC is the one that actually bit - it runs in the finalization phase and put these in the all-users Startup folder on 579C144, timestamped mid-image: Defect Tracker.lnk 16:46:03 Plant Apps.lnk 16:46:03 Plant Apps launching msedge --new-window on a kiosk. eDNC was in the same hardcoded list and only escaped because its Test-Path guard found no DncMain.exe. 08-EdgeDefaultBrowser.ps1 had it too, with a Plant Apps + WJ Shopfloor + Dashboard tab fallback. Harmless today because the Display profiles configure a real tab, but one edit away from biting. Get-ProfileValue returns $null only when a key is absent from BOTH the profile and site-config, so $null is the only honest "not configured" signal and an empty array means what it says. VERIFIED against the post-fix capture: the S: mapper Run key and the machine number prompt task are both gone, and 'ShopDB Kiosk Bootstrap' registered correctly with boot and time triggers. Also: the collector's StartupApproved decoder now handles 0x04/0x05, which that same capture surfaced as unknown. Still baked into the WIM and unaffected by any of this: WJ Shopfloor.lnk, dated April, sitting in the all-users Startup folder. --- playbook/preinstall/preinstall.json | 32 +++++++++---------- .../Shopfloor/07-TaskbarLayout.ps1 | 10 +++++- .../Shopfloor/08-EdgeDefaultBrowser.ps1 | 8 ++++- .../Shopfloor/Configure-PC.ps1 | 16 +++++++++- 4 files changed, 47 insertions(+), 19 deletions(-) diff --git a/playbook/preinstall/preinstall.json b/playbook/preinstall/preinstall.json index e4cf823..af6dde0 100644 --- a/playbook/preinstall/preinstall.json +++ b/playbook/preinstall/preinstall.json @@ -34,7 +34,7 @@ "InstallArgs": "/qn /norestart REBOOT=ReallySuppress NOVSUI=1 USING_EXUIH_SILENT=1", "DetectionMethod": "Registry", "DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{9BE518E6-ECC6-35A9-88E4-87755C07200F}", - "PCTypes": ["*"] + "PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"] }, { "_comment": "VC++ 2010 x86 - same fix as 2008. Bootstrapper ignores /norestart; extracted MSI with REBOOT=ReallySuppress does not.", @@ -44,7 +44,7 @@ "InstallArgs": "/qn /norestart REBOOT=ReallySuppress NOVSUI=1 USING_EXUIH_SILENT=1", "DetectionMethod": "Registry", "DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{F0C3E5D1-1ADE-321E-8167-68EF0DE699A5}", - "PCTypes": ["*"] + "PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"] }, { "_comment": "VC++ 2012 x86 Minimum Runtime - extracted from vcredist2012_x86.exe Burn bundle. Same REBOOT=ReallySuppress fix.", @@ -54,7 +54,7 @@ "InstallArgs": "/qn /norestart REBOOT=ReallySuppress NOVSUI=1 USING_EXUIH_SILENT=1", "DetectionMethod": "Registry", "DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{BD95A8CD-1D9F-35AD-981A-3E7925026EBB}", - "PCTypes": ["*"] + "PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"] }, { "Name": "VC++ Redistributable 2012 x86 (Additional)", @@ -63,7 +63,7 @@ "InstallArgs": "/qn /norestart REBOOT=ReallySuppress NOVSUI=1 USING_EXUIH_SILENT=1", "DetectionMethod": "Registry", "DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{B175520C-86A2-35A7-8619-86DC379688B9}", - "PCTypes": ["*"] + "PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"] }, { "_comment": "VC++ 2013 x86 Minimum Runtime - extracted from vcredist2013_x86.exe Burn bundle.", @@ -73,7 +73,7 @@ "InstallArgs": "/qn /norestart REBOOT=ReallySuppress NOVSUI=1 USING_EXUIH_SILENT=1", "DetectionMethod": "Registry", "DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{13A4EE12-23EA-3371-91EE-EFB36DDFFF3E}", - "PCTypes": ["*"] + "PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"] }, { "Name": "VC++ Redistributable 2013 x86 (Additional)", @@ -82,7 +82,7 @@ "InstallArgs": "/qn /norestart REBOOT=ReallySuppress NOVSUI=1 USING_EXUIH_SILENT=1", "DetectionMethod": "Registry", "DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{F8CFEB22-A2E7-3971-9EDA-4B11EDEFC185}", - "PCTypes": ["*"] + "PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"] }, { "_comment": "VC++ 2013 x64 Minimum Runtime - required by Keyence VR-6000 Series Software. Extracted from the Keyence installer's Windows Installer cache. Same REBOOT=ReallySuppress pattern as the x86 variants.", @@ -92,7 +92,7 @@ "InstallArgs": "/qn /norestart REBOOT=ReallySuppress NOVSUI=1 USING_EXUIH_SILENT=1", "DetectionMethod": "Registry", "DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{A749D8E6-B613-3BE3-8F5F-045C84EBA29B}", - "PCTypes": ["*"] + "PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"] }, { "_comment": "VC++ 2013 x64 Additional Runtime - required by Keyence VR-6000 Series Software. Pairs with the Minimum Runtime above.", @@ -102,7 +102,7 @@ "InstallArgs": "/qn /norestart REBOOT=ReallySuppress NOVSUI=1 USING_EXUIH_SILENT=1", "DetectionMethod": "Registry", "DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{929FBD26-9020-399B-9A7A-751D61F0B942}", - "PCTypes": ["*"] + "PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"] }, { "_comment": "VC++ 2010 x64 - required by PC-DMIS 2016/2019 R2 on CMM PCs. PCDLRN.exe links against msvcr100.dll and the VS 2010 MFC DLLs which are only provided by this redistributable. Extracted from the PC-DMIS 2016 bundle's attached container (a1 payload). Silent install: /q /norestart. Detection: Uninstall key under the native x64 hive with fixed product GUID.", @@ -114,7 +114,7 @@ "DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{1D8E6291-B0D5-35EC-8441-6616F567A0F7}", "DetectionName": "DisplayVersion", "DetectionValue": "10.0.40219", - "PCTypes": ["*"] + "PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"] }, { "_comment": "VC++ 2012 x64 - required by PC-DMIS 2016/2019 R2. Same rationale as 2010 x64; PC-DMIS links against msvcr110.dll / MFC110. Extracted from the PC-DMIS 2016 bundle's attached container (a2 payload). Detection on the Minimum Runtime GUID (the main redist wrapper installs both Minimum and Additional sub-packages).", @@ -126,7 +126,7 @@ "DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{5AF4E09F-5C9B-3AAF-B731-544D3DC821DD}", "DetectionName": "DisplayVersion", "DetectionValue": "11.0.51106", - "PCTypes": ["*"] + "PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"] }, { "_comment": "VC++ 2015-2022 x86 - extracted from vcredist2015_2017_2019_2022_x86.exe Burn bundle. The bundle contains 2022 14.44.35211 plus 8 chained KB updates for older 2015/2017/2019 releases. We install only the 2022 Min+Add MSIs - the CRT v140 ABI is shared across 2015/2017/2019/2022, so the latest pair covers all four versions on Windows 10/11.", @@ -136,7 +136,7 @@ "InstallArgs": "/qn /norestart REBOOT=ReallySuppress NOVSUI=1 USING_EXUIH_SILENT=1", "DetectionMethod": "Registry", "DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{922480B5-CAEB-4B1B-AAA4-9716EFDCE26B}", - "PCTypes": ["*"] + "PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"] }, { "Name": "VC++ Redistributable 2022 x86 (Additional)", @@ -145,7 +145,7 @@ "InstallArgs": "/qn /norestart REBOOT=ReallySuppress NOVSUI=1 USING_EXUIH_SILENT=1", "DetectionMethod": "Registry", "DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{C18FB403-1E88-43C8-AD8A-CED50F23DE8B}", - "PCTypes": ["*"] + "PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"] }, { "_comment": "VC++ 2015-2022 x64 - required by PC-DMIS 2026 (PCDLRN.exe links vcruntime140_1.dll, added in VC++ 2019 / v14.20). The x64 redist line above previously stopped at 2013, so 64-bit PC-DMIS 2026 was missing its runtime and PCDLRN.exe failed to start with 'vcruntime140_1.dll was not found'. The patched PC-DMIS MSI bypasses Hexagon's Burn bundle, which is what would otherwise have pulled this in. Full vc_redist.x64.exe (14.44.35211, 2015-2022 shared CRT). Modern bootstrapper honors /norestart. Detect on the DLL itself so it is version-independent.", @@ -165,7 +165,7 @@ "InstallArgs": "", "DetectionMethod": "File", "DetectionPath": "C:\\Program Files (x86)\\Adobe\\Acrobat Reader DC\\Reader\\AcroRd32.exe", - "PCTypes": ["*"] + "PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"] }, { "_comment": "OpenText HostExplorer 15 SP1 ShopFloor - replaced the WJDT-built OpenText.exe Inno wrapper with our own Setup-OpenText.ps1 that does the same install steps (msiexec base + ShopFloor.mst transform + SP1 .msp patch) PLUS fans the per-user profile/keymap/menu/macro content out to Default User and every existing user profile. The Inno wrapper deployed per-user content to {userappdata} which resolves to whichever user is running the installer (SYSTEM under DSC, single user under PreInstall) so Azure-AD users never saw the profiles. Setup-OpenText.cmd is a tiny launcher that hands off to Setup-OpenText.ps1 because the runner only handles MSI/EXE types. All bundled files live in vcredist-style subtree at dependencies/opentext/ and get xcopied through WinPE staging. NO DetectionMethod here on purpose - Setup-OpenText.ps1 owns its own version check by reading version.txt next to itself and comparing to HKLM:\\SOFTWARE\\GE\\OpenText\\Installed; the runner always invokes the wrapper (cost: ~1s of PowerShell launch when up-to-date) so the version constant lives in exactly one place: dependencies/opentext/version.txt.", @@ -174,7 +174,7 @@ "Type": "EXE", "InstallArgs": "", "LogFile": "C:\\Logs\\PreInstall\\Setup-OpenText.log", - "PCTypes": ["*"] + "PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"] }, { "_comment": "UDC_Setup.exe spawns a hidden WPF window (UDC.exe) after install and never exits, so the runner needs KillAfterDetection: true to terminate UDC_Setup.exe + UDC.exe once the registry detection passes. This is an OPT-IN flag - normal installers should NOT set it because killing msiexec mid-install leaves msiserver holding the install mutex and the next msiexec call returns 1618 (Oracle hit this exact bug).", @@ -206,7 +206,7 @@ "InstallArgs": "/qn /norestart ALLUSERS=1 REBOOT=ReallySuppress TARGETDIR=\"C:\\Program Files (x86)\\WJF_Defect_Tracker\"", "DetectionMethod": "File", "DetectionPath": "C:\\Program Files (x86)\\WJF_Defect_Tracker\\Defect_Tracker.exe", - "PCTypes": ["*"] + "PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"] }, { "_comment": "Shopfloor Standard serial-port drivers: StarTech PCIe serial adapter (MosChip-based) + Prolific PL2303 USB-to-serial. Install-Drivers.cmd runs pnputil /add-driver with /subdirs /install so every bundled INF under drivers/ lands in the Windows driver store and auto-binds to matching hardware present now or plugged in later. Installed on every PC type (PCTypes ['*']) because serial hardware turns up across bays; a serial driver on a PC without the hardware is harmless - it just sits in the driver store until matching hardware is plugged in.", @@ -217,7 +217,7 @@ "LogFile": "C:\\Logs\\PreInstall\\Install-Drivers.log", "DetectionMethod": "File", "DetectionPath": "C:\\ProgramData\\PXEDrivers\\drivers-installed.marker", - "PCTypes": ["*"] + "PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"] } ] } diff --git a/playbook/shopfloor-setup/Shopfloor/07-TaskbarLayout.ps1 b/playbook/shopfloor-setup/Shopfloor/07-TaskbarLayout.ps1 index cb1ca56..e0d9d9f 100644 --- a/playbook/shopfloor-setup/Shopfloor/07-TaskbarLayout.ps1 +++ b/playbook/shopfloor-setup/Shopfloor/07-TaskbarLayout.ps1 @@ -47,7 +47,15 @@ $layoutXmlPath = Join-Path $defaultUserShell 'LayoutModification.xml' # ============================================================================ $cfgPins = Get-ProfileValue 'taskbarPins' -if ($null -ne $cfgPins -and $cfgPins.Count -gt 0) { +# An EMPTY configured list means "no pins" and must be honoured. Get-ProfileValue +# returns $null only when the key is absent from BOTH the profile and +# site-config, so $null is the real "not configured" signal. Requiring +# .Count -gt 0 as well makes "taskbarPins": [] fall through to the hardcoded +# shopfloor list - configuring "none" producing "everything", the same bug that +# put Plant Apps and Defect Tracker in a Display kiosk's Startup folder +# (Configure-PC.ps1) and machine-tool shortcuts on its desktop +# (06-OrganizeDesktop.ps1). +if ($null -ne $cfgPins) { $pinSpec = @($cfgPins | ForEach-Object { @{ Name = $_.name diff --git a/playbook/shopfloor-setup/Shopfloor/08-EdgeDefaultBrowser.ps1 b/playbook/shopfloor-setup/Shopfloor/08-EdgeDefaultBrowser.ps1 index 3e04fee..0a7b5da 100644 --- a/playbook/shopfloor-setup/Shopfloor/08-EdgeDefaultBrowser.ps1 +++ b/playbook/shopfloor-setup/Shopfloor/08-EdgeDefaultBrowser.ps1 @@ -203,7 +203,13 @@ $cfgTabs = Get-ProfileValue 'edgeStartupTabs' $startupTabs = @() -if ($null -ne $cfgTabs -and $cfgTabs.Count -gt 0) { +# Empty configured list = "no startup tabs", and must be honoured. $null (key +# absent from both profile and site-config) is the only "not configured" signal. +# Requiring .Count -gt 0 would make "edgeStartupTabs": [] fall through to the +# Plant Apps + WJ Shopfloor + Dashboard fallback below - the same +# configuring-none-gives-everything bug fixed in Configure-PC.ps1, +# 06-OrganizeDesktop.ps1 and 07-TaskbarLayout.ps1. +if ($null -ne $cfgTabs) { foreach ($tab in $cfgTabs) { $fallback = if ($tab.fallbackUrlKey -and $siteConfig.urls) { $siteConfig.urls.$($tab.fallbackUrlKey) } else { '' } $url = Resolve-StartupUrl -BaseName $tab.baseName -Fallback $fallback diff --git a/playbook/shopfloor-setup/Shopfloor/Configure-PC.ps1 b/playbook/shopfloor-setup/Shopfloor/Configure-PC.ps1 index 3091ff1..cef8782 100644 --- a/playbook/shopfloor-setup/Shopfloor/Configure-PC.ps1 +++ b/playbook/shopfloor-setup/Shopfloor/Configure-PC.ps1 @@ -143,7 +143,21 @@ $edgePath = @( $cfgItems = Get-ProfileValue 'startupItems' -if ($null -ne $cfgItems -and $cfgItems.Count -gt 0) { +# An EMPTY configured list means "no startup items" and must be honoured. +# Get-ProfileValue returns $null only when the key is absent from BOTH the +# profile and site-config, so $null is the real "not configured" signal. +# +# The old test also required .Count -gt 0, so "startupItems": [] fell through to +# the hardcoded list below and a Display kiosk was given UDC, eDNC, Defect +# Tracker, WJ Shopfloor and Plant Apps startup shortcuts - Plant Apps launching +# Edge in a new window on a kiosk. Confirmed on 579C144 2026-08-06: +# +# C:\ProgramData\...\StartUp\Defect Tracker.lnk 16:46:03 +# C:\ProgramData\...\StartUp\Plant Apps.lnk 16:46:03 +# +# Configuring "none" produced "everything". Same bug as desktopApps in +# 06-OrganizeDesktop.ps1 and taskbarPins in 07-TaskbarLayout.ps1. +if ($null -ne $cfgItems) { $items = @() $num = 0 foreach ($si in $cfgItems) {