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>
132 lines
4.0 KiB
Bash
Executable File
132 lines
4.0 KiB
Bash
Executable File
#!/bin/bash
|
|
# sync-cmm.sh - Push CMM bootstrap bundle to the PXE server enrollment share.
|
|
#
|
|
# Copies the Hexagon installers + cmm-manifest.json from the local workstation
|
|
# to /srv/samba/enrollment/cmm-installers on the PXE server. That directory
|
|
# becomes visible as \\10.9.100.1\enrollment\cmm-installers so startnet.cmd
|
|
# can xcopy it onto the target disk during WinPE phase.
|
|
#
|
|
# Run this on the workstation (not on the PXE server) any time:
|
|
# - You update cmm-manifest.json in playbook/shopfloor-setup/CMM/
|
|
# - You drop new/updated installers into /home/camp/pxe-images/cmm/hexagon/
|
|
#
|
|
# Same pattern as sync-preinstall.sh. The remote tree is updated in place and
|
|
# the next imaged CMM PC picks up the new files automatically.
|
|
#
|
|
# Usage:
|
|
# ./playbook/sync-cmm.sh
|
|
#
|
|
# Requires: sshpass (apt install sshpass), scp, ssh
|
|
|
|
set -euo pipefail
|
|
|
|
# --- Config ---
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
|
|
PXE_HOST="${PXE_HOST:-10.9.100.1}"
|
|
PXE_USER="${PXE_USER:-pxe}"
|
|
PXE_PASS="${PXE_PASS:-pxe}"
|
|
|
|
MANIFEST_SRC="$PROJECT_ROOT/playbook/shopfloor-setup/CMM/cmm-manifest.json"
|
|
INSTALLERS_SRC="${CMM_INSTALLERS_DIR:-/home/camp/pxe-images/cmm/hexagon}"
|
|
|
|
REMOTE_DIR="/srv/samba/enrollment/cmm-installers"
|
|
REMOTE_TEMP="/tmp/cmm-stage"
|
|
|
|
# --- Helpers ---
|
|
ssh_run() {
|
|
sshpass -p "$PXE_PASS" ssh -o StrictHostKeyChecking=no -o LogLevel=ERROR "$PXE_USER@$PXE_HOST" "$@"
|
|
}
|
|
|
|
scp_to() {
|
|
sshpass -p "$PXE_PASS" scp -o StrictHostKeyChecking=no -o LogLevel=ERROR "$1" "$PXE_USER@$PXE_HOST:'$2'"
|
|
}
|
|
|
|
# --- Validate sources ---
|
|
echo "Validating source files..."
|
|
|
|
if [ ! -f "$MANIFEST_SRC" ]; then
|
|
echo "ERROR: cmm-manifest.json not found at $MANIFEST_SRC" >&2
|
|
exit 1
|
|
fi
|
|
printf " OK %10d cmm-manifest.json\n" "$(stat -c %s "$MANIFEST_SRC")"
|
|
|
|
if [ ! -d "$INSTALLERS_SRC" ]; then
|
|
echo "ERROR: installers dir not found: $INSTALLERS_SRC" >&2
|
|
echo " Set CMM_INSTALLERS_DIR env var to override the default" >&2
|
|
exit 1
|
|
fi
|
|
|
|
installers=()
|
|
while IFS= read -r f; do
|
|
installers+=("$f")
|
|
done < <(find "$INSTALLERS_SRC" -maxdepth 1 -type f \( -name '*.exe' -o -name '*.msi' \) | sort)
|
|
|
|
if [ "${#installers[@]}" -eq 0 ]; then
|
|
echo "ERROR: no .exe or .msi files under $INSTALLERS_SRC" >&2
|
|
exit 1
|
|
fi
|
|
|
|
total_bytes=0
|
|
for f in "${installers[@]}"; do
|
|
size=$(stat -c %s "$f")
|
|
total_bytes=$((total_bytes + size))
|
|
printf " OK %10d %s\n" "$size" "$(basename "$f")"
|
|
done
|
|
printf " Total payload: %d bytes (%.1f GB)\n" "$total_bytes" "$(echo "scale=2; $total_bytes/1073741824" | bc)"
|
|
|
|
# --- Verify PXE server reachable ---
|
|
echo "Pinging PXE server $PXE_HOST..."
|
|
if ! ping -c 1 -W 2 "$PXE_HOST" >/dev/null 2>&1; then
|
|
echo "ERROR: PXE server $PXE_HOST not reachable" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# --- Stage files to /tmp on PXE, then sudo install to enrollment share ---
|
|
echo "Staging files to $PXE_HOST:$REMOTE_TEMP..."
|
|
ssh_run "rm -rf $REMOTE_TEMP && mkdir -p $REMOTE_TEMP/files"
|
|
|
|
echo " -> cmm-manifest.json"
|
|
scp_to "$MANIFEST_SRC" "$REMOTE_TEMP/files/cmm-manifest.json"
|
|
|
|
for f in "${installers[@]}"; do
|
|
base="$(basename "$f")"
|
|
echo " -> $base"
|
|
scp_to "$f" "$REMOTE_TEMP/files/$base"
|
|
done
|
|
|
|
# --- Build remote install script (runs under sudo on PXE) ---
|
|
LOCAL_TEMP_SCRIPT="$(mktemp /tmp/sync-cmm-remote.XXXXXX.sh)"
|
|
trap 'rm -f "${LOCAL_TEMP_SCRIPT:-}"' EXIT
|
|
|
|
cat > "$LOCAL_TEMP_SCRIPT" <<REMOTE_SCRIPT
|
|
#!/bin/bash
|
|
set -e
|
|
mkdir -p "$REMOTE_DIR"
|
|
|
|
# Fresh deploy: remove stale files (old installer versions) so a shrinking
|
|
# manifest doesn't leave orphan binaries on the share.
|
|
find "$REMOTE_DIR" -maxdepth 1 -type f -delete
|
|
|
|
cp "$REMOTE_TEMP/files/"* "$REMOTE_DIR/"
|
|
|
|
chown -R root:root "$REMOTE_DIR"
|
|
find "$REMOTE_DIR" -type f -exec chmod 0644 {} +
|
|
find "$REMOTE_DIR" -type d -exec chmod 0755 {} +
|
|
|
|
rm -rf "$REMOTE_TEMP"
|
|
|
|
echo
|
|
echo "Final state of $REMOTE_DIR:"
|
|
ls -la "$REMOTE_DIR"
|
|
REMOTE_SCRIPT
|
|
|
|
scp_to "$LOCAL_TEMP_SCRIPT" "$REMOTE_TEMP/_install.sh"
|
|
|
|
echo "Installing files to $REMOTE_DIR (sudo)..."
|
|
ssh_run "echo '$PXE_PASS' | sudo -S bash $REMOTE_TEMP/_install.sh"
|
|
|
|
echo
|
|
echo "Done. CMM bootstrap synced to $PXE_HOST:$REMOTE_DIR"
|