CMM: patched-MSI install chain for PC-DMIS 2016 + 2019 R2

PC-DMIS refuses to install without a valid license in /qn mode; its
BA / MSI custom actions ProcessLicensingFromBundle (which spins for
~13 minutes trying to activate against licensing.wilcoxassoc.com)
and IsLicenseDateValid (which errors 1603 when no license file is
present) are the gate. Bypassed by dark-extracting the chained MSIs
from each Burn bundle and pre-patching both custom actions'
InstallExecuteSequence.Condition columns to '0' via Windows
Installer COM SQL UPDATE. The patched MSIs install cleanly with no
license, PCDLRN.exe loads at runtime, hits its own runtime license
check, and shows the normal "no license" dialog. Tech activates via
clmadmin.exe post-imaging and PC-DMIS launches normally.

- playbook/preinstall/preinstall.json: adds VC++ 2010 x64 and VC++
  2012 x64 redistributable entries scoped to all PC types. PC-DMIS
  links msvcr100.dll / mfc100u.dll (VS 2010) and msvcr110.dll /
  mfc110u.dll (VS 2012); without these the exe gets DLL_NOT_FOUND
  (0xC0000135) at launch. Win11 ships VC++ 2022 (covers 2015+) but
  not 2010/2012, so we ship these from the dark-extracted bundle
  payloads. Small (~13 MB combined), inert on PCs that don't need
  them, so the filter is "*".
- playbook/shopfloor-setup/CMM/cmm-manifest.json: version 2.0.
  Drops the bundle EXEs, installs patched MSIs directly with
  properly quoted INSTALLFOLDER / APPLICATIONFOLDER paths (the
  earlier "hangs" were caused by Start-Process splitting unquoted
  paths on spaces, not actual msiexec hangs). Skips the chained
  CLM Tools 1.5/1.7 MSIs - CLM 1.8.73 standalone provides the same
  interfaces and PC-DMIS MSIs have no LaunchCondition requiring
  Tools 1.5 / 1.7 specifically. Keeps Protect Viewer from the 2019
  R2 bundle as a separate entry. CLM 1.8 and goCMM bundles run
  unpatched (no install-time license check).
- playbook/sync-cmm.sh: now also includes *.msi files in the
  upload set, not just *.exe.

Known caveats: patched MSIs have HashMismatch signatures (expected
- Windows Installer accepts them in /qn mode on locally-cached
  machines). Every Hexagon bundle version bump requires re-dark-
extracting and re-patching. Unsupported by Hexagon; do not call
them for install-related issues without reverting to the original
bundles first.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-04-11 16:52:54 -04:00
parent c595d3b9cb
commit b88e4d3272
3 changed files with 49 additions and 18 deletions

View File

@@ -71,6 +71,30 @@
"DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{F8CFEB22-A2E7-3971-9EDA-4B11EDEFC185}", "DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{F8CFEB22-A2E7-3971-9EDA-4B11EDEFC185}",
"PCTypes": ["*"] "PCTypes": ["*"]
}, },
{
"_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.",
"Name": "VC++ Redistributable 2010 x64",
"Installer": "vcredist/2010-x64/vcredist_x64.exe",
"Type": "EXE",
"InstallArgs": "/q /norestart",
"DetectionMethod": "Registry",
"DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{1D8E6291-B0D5-35EC-8441-6616F567A0F7}",
"DetectionName": "DisplayVersion",
"DetectionValue": "10.0.40219",
"PCTypes": ["*"]
},
{
"_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).",
"Name": "VC++ Redistributable 2012 x64",
"Installer": "vcredist/2012-x64/vcredist_x64.exe",
"Type": "EXE",
"InstallArgs": "/q /norestart",
"DetectionMethod": "Registry",
"DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{5AF4E09F-5C9B-3AAF-B731-544D3DC821DD}",
"DetectionName": "DisplayVersion",
"DetectionValue": "11.0.51106",
"PCTypes": ["*"]
},
{ {
"_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.", "_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.",
"Name": "VC++ Redistributable 2022 x86 (Minimum)", "Name": "VC++ Redistributable 2022 x86 (Minimum)",

View File

@@ -1,33 +1,40 @@
{ {
"Version": "1.0", "Version": "2.0",
"_comment": "CMM machine-app manifest. Consumed by both 01-Setup-CMM.ps1 (at imaging time, reading from C:\\CMM-Install\\) and CMM-Enforce.ps1 (on logon, reading from the tsgwp00525 share). Detection uses the WiX Burn bundle Registration GUIDs pulled from each installer's .wixburn PE section + embedded BurnManifest.xml; bumping DetectionValue (and uploading a matching installer) is how IT ships version updates post-imaging. Install order matters: PC-DMIS 2016 first (it chains an older CLM Tools MSI), then PC-DMIS 2019 R2 (chains CLM 1.7), then standalone CLM 1.8.73 (final CLM Admin upgrade), then goCMM. CLM is left unlicensed - a tech activates via clmadmin.exe post-imaging.", "_comment": "CMM machine-app manifest. Consumed by both 01-Setup-CMM.ps1 (at imaging time, reading from C:\\CMM-Install\\) and CMM-Enforce.ps1 (on logon, reading from the tsgwp00525 share). Option 3 (patched-MSI) install strategy: we bypass Hexagon's Burn bundle entirely for PC-DMIS 2016 and 2019 R2. The main PC-DMIS MSIs have been patched via COM SQL UPDATE (msibuild-style) to force the Condition column to '0' for two custom actions: ProcessLicensingFromBundle (which would otherwise spin for ~13 minutes trying to activate against licensing.wilcoxassoc.com with empty credentials) and IsLicenseDateValid (which would fail the install with 'no valid license'). With both CAs disabled, the MSI installs cleanly with no license present; PCDLRN.exe installs and loads at runtime and the tech activates a real license via clmadmin.exe after imaging. VS 2010/2012 x64 runtime prereqs are handled by the shared preinstall.json VC++ x64 entries (which run before this manifest). CLM Tools 1.5/1.7 chained MSIs from the original bundles are intentionally SKIPPED; CLM 1.8.73 standalone provides the admin + runtime interfaces. Protect Viewer is kept because it's useful alongside PC-DMIS 2019 R2.",
"Applications": [ "Applications": [
{ {
"_comment": "PC-DMIS 2016 - WiX Burn bundle. INSTALLPDFCONVERTER=0 skips Nitro PDF (saves ~100MB, avoids third-party registration). HEIP=0 disables Hexagon telemetry/error reporting. 2016 does not expose INSTALLOFFLINEHELP (added in 2019). Chained MSIs: CLM Tools + PC-DMIS. Chained EXEs: Win Installer 4.5, VS 2010 x64, VS 2012 x64, .NET 4.6.1, PDF Converter.", "_comment": "PC-DMIS 2016 main MSI (PATCHED). ProcessLicensingFromBundle + IsLicenseDateValid custom actions have been pre-disabled by SQL UPDATE of InstallExecuteSequence.Condition to '0'. Install args: INSTALLFOLDER/APPLICATIONFOLDER paths have embedded double quotes to survive the runner's command-line concatenation when the path contains spaces. USINGWPFINSTALLER=1 mirrors the Burn bundle default and ensures HandleLicenseChoice CA (seq 783) stays skipped. HEIP=0 disables Hexagon telemetry. INSTALLPDFCONVERTER=0 skips the Nitro PDF converter. The patched MSI has a HashMismatch signature, which is expected and accepted by Windows Installer in /qn mode.",
"Name": "PC-DMIS 2016", "Name": "PC-DMIS 2016",
"Installer": "Pcdmis2016.0_Release_11.0.1179.0_x64.exe", "Installer": "pcdmis2016-main-patched.msi",
"Type": "EXE", "Type": "MSI",
"InstallArgs": "/quiet /norestart /log \"C:\\Logs\\CMM\\Pcdmis2016.log\" INSTALLPDFCONVERTER=0 HEIP=0", "InstallArgs": "/qn /norestart ALLUSERS=1 MSIFASTINSTALL=7 INSTALLFOLDER=\"C:\\Program Files\\Hexagon\\PC-DMIS 2016.0 64-bit\" APPLICATIONFOLDER=\"C:\\Program Files\\Hexagon\\PC-DMIS 2016.0 64-bit\" USINGWPFINSTALLER=1 HEIP=0 INSTALLPDFCONVERTER=0 REBOOT=ReallySuppress LICENSETYPE=LMSEntitlement",
"LogFile": "C:\\Logs\\CMM\\Pcdmis2016.log",
"DetectionMethod": "Registry", "DetectionMethod": "Registry",
"DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{b3f85c1a-ba25-43d7-a295-7f2775d83526}", "DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{5389B196-81F0-44A9-A073-4C1D72041F09}",
"DetectionName": "DisplayVersion", "DetectionName": "DisplayVersion",
"DetectionValue": "11.0.1179.0" "DetectionValue": "11.0.1179.0"
}, },
{ {
"_comment": "PC-DMIS 2019 R2 - WiX Burn bundle. INSTALLOFFLINEHELP=0 skips the ~1-2GB offline help content. INSTALLUNIVERSALUPDATER=0 disables Hexagon's auto-updater (keeps the version frozen until IT bumps it here). INSTALLPDFCONVERTER=0 + HEIP=0 same as 2016. Chained MSIs: CLM Tools 1.7, Protect Viewer, PC-DMIS. Chained EXEs: Win Installer 4.5, VS 2012 x64, VS 2015 x64, .NET 4.6.1, PDF Converter, Universal Updater.", "_comment": "PC-DMIS 2019 R2 main MSI (PATCHED). Same patch strategy as 2016. Adds INSTALLOFFLINEHELP=0 (saves ~1.5 GB) and INSTALLUNIVERSALUPDATER=0 (disables Hexagon's auto-updater which we do not want on air-gapped shopfloor machines). Protect Viewer is a separate MSI installed next.",
"Name": "PC-DMIS 2019 R2", "Name": "PC-DMIS 2019 R2",
"Installer": "Pcdmis2019_R2_14.2.728.0_x64.exe", "Installer": "pcdmis2019-main-patched.msi",
"Type": "EXE", "Type": "MSI",
"InstallArgs": "/quiet /norestart /log \"C:\\Logs\\CMM\\Pcdmis2019.log\" INSTALLPDFCONVERTER=0 INSTALLOFFLINEHELP=0 INSTALLUNIVERSALUPDATER=0 HEIP=0", "InstallArgs": "/qn /norestart ALLUSERS=1 MSIFASTINSTALL=7 INSTALLFOLDER=\"C:\\Program Files\\Hexagon\\PC-DMIS 2019 R2 64-bit\" APPLICATIONFOLDER=\"C:\\Program Files\\Hexagon\\PC-DMIS 2019 R2 64-bit\" USINGWPFINSTALLER=1 HEIP=0 INSTALLPDFCONVERTER=0 INSTALLOFFLINEHELP=0 INSTALLUNIVERSALUPDATER=0 REBOOT=ReallySuppress LICENSETYPE=LMSEntitlement",
"LogFile": "C:\\Logs\\CMM\\Pcdmis2019.log",
"DetectionMethod": "Registry", "DetectionMethod": "Registry",
"DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{4c816d47-9e18-420a-a7d5-0b38ecdabf50}", "DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{49DBE7F9-228A-4E66-8BB5-DB5A446DCAE7}",
"DetectionName": "DisplayVersion", "DetectionName": "DisplayVersion",
"DetectionValue": "14.2.728.0" "DetectionValue": "14.2.728.0"
}, },
{ {
"_comment": "CLM Admin 1.8.73 standalone - upgrades the CLM Tools chained from the PC-DMIS bundles to the latest admin tool. Installs after both PC-DMIS versions so its upgrade path is clean. Chained EXE: VS 2015 x64 redist. No license activation at install time - a tech activates via clmadmin.exe (or the CLM Admin desktop shortcut) post-imaging against licensing.wilcoxassoc.com.", "_comment": "Protect Viewer - companion tool bundled with PC-DMIS 2019 R2. Separate MSI with no license check of its own. Dark-extracted from the 2019 R2 Burn bundle and shipped as-is.",
"Name": "Protect Viewer",
"Installer": "ProtectViewer.msi",
"Type": "MSI",
"InstallArgs": "/qn /norestart ALLUSERS=1 MSIFASTINSTALL=7 REBOOT=ReallySuppress",
"DetectionMethod": "Registry",
"DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{7DE6B8AF-F580-4CDE-845F-FBE46C1FCF69}"
},
{
"_comment": "CLM 1.8.73 standalone bundle - provides clmadmin.exe and the runtime licensing libraries that both PC-DMIS 2016 and 2019 R2 use. Unlike the PC-DMIS bundles, CLM's WiX Burn bundle has no install-time license check (it IS the license tool), so we run it via its original EXE with no patches. The tech uses clmadmin.exe to activate a real license post-imaging, which unlocks both PC-DMIS versions.",
"Name": "CLM 1.8.73", "Name": "CLM 1.8.73",
"Installer": "CLM_1.8.73.0_x64.exe", "Installer": "CLM_1.8.73.0_x64.exe",
"Type": "EXE", "Type": "EXE",
@@ -39,7 +46,7 @@
"DetectionValue": "1.8.73.0" "DetectionValue": "1.8.73.0"
}, },
{ {
"_comment": "goCMM 1.1.6718 - Hexagon's CMM job launcher utility. Chained EXEs: .NET 4.5.1 (NDP451), VC++ x86 redist. Independent of CLM/PC-DMIS, install order doesn't matter but we install it last.", "_comment": "goCMM 1.1.6718 - Hexagon's CMM job launcher utility. No license check. Unpatched bundle EXE runs as-is.",
"Name": "goCMM", "Name": "goCMM",
"Installer": "goCMM_1.1.6718.31289.exe", "Installer": "goCMM_1.1.6718.31289.exe",
"Type": "EXE", "Type": "EXE",

View File

@@ -61,10 +61,10 @@ fi
installers=() installers=()
while IFS= read -r f; do while IFS= read -r f; do
installers+=("$f") installers+=("$f")
done < <(find "$INSTALLERS_SRC" -maxdepth 1 -type f -name '*.exe' | sort) done < <(find "$INSTALLERS_SRC" -maxdepth 1 -type f \( -name '*.exe' -o -name '*.msi' \) | sort)
if [ "${#installers[@]}" -eq 0 ]; then if [ "${#installers[@]}" -eq 0 ]; then
echo "ERROR: no .exe files under $INSTALLERS_SRC" >&2 echo "ERROR: no .exe or .msi files under $INSTALLERS_SRC" >&2
exit 1 exit 1
fi fi