OpenText HostExplorer ShopFloor was previously delivered as an Intune Win32 LOB app that ran the inner OpenTextHostExplorer15x64.msi directly, which (a) skipped the [Files] section of the WJDT-built Inno Setup wrapper that deploys profile/keymap/menu/macro files, and (b) deployed desktop shortcuts pointing at C:\\GE Aerospace\\Hummingbird\\ - a path HostExplorer doesn't search, so the profile would open from the desktop shortcut but the keymaps and macros never got picked up. This commit moves the install to the PXE PreInstall pipeline so it gets baked into every Standard PC during imaging instead of being pulled per-device by Intune. The DSC side ships separately as Setup-OpenText.ps1 + Install-OpenText.ps1 wrapper in the pxe-images/main/ tree (uploaded to Azure Blob). preinstall.json: new entry for OpenText pointing at opentext\\Setup-OpenText.cmd, a tiny launcher in the bundled subtree that hands off to Setup-OpenText.ps1 (the runner only handles MSI/EXE types). No DetectionMethod fields - Setup-OpenText.ps1 reads version from version.txt next to itself and short-circuits via its own HKLM\\SOFTWARE\\GE\\OpenText\\Installed marker check, so the version constant lives in exactly one place (version.txt). Trade-off: ~1s PowerShell launch on every up-to-date runner pass instead of a zero-cost registry compare, in exchange for never having to bump the version in multiple places. sync-preinstall.sh: added dependencies/opentext to TREE_SUBDIRS so the whole bundle (base MSI + cab + SP1 patch + ShopFloor transform + profile/accessories/keymap/menu/W10shortcuts content + Setup-OpenText script and cmd wrapper + version.txt) rides through the existing tar pipe. Also added OpenText.exe to the legacy-cleanup rm list since the old flat machineapps/OpenText.exe path is now obsolete. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
209 lines
6.8 KiB
Bash
Executable File
209 lines
6.8 KiB
Bash
Executable File
#!/bin/bash
|
|
# sync-preinstall.sh - Push preinstall.json + installer binaries to the live PXE server.
|
|
#
|
|
# Run this on the workstation (not on the PXE server) any time:
|
|
# - You update preinstall.json in playbook/preinstall/
|
|
# - You update installer binaries in /home/camp/pxe-images/main/
|
|
#
|
|
# The PXE server's /srv/samba/enrollment/preinstall/ tree is updated in place. The
|
|
# next imaged PC picks up the new files via startnet.cmd's xcopy during WinPE phase.
|
|
#
|
|
# Usage:
|
|
# ./playbook/sync-preinstall.sh
|
|
#
|
|
# Requires: sshpass (apt install sshpass), scp, ssh, tar
|
|
|
|
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}"
|
|
|
|
PREINSTALL_JSON="$PROJECT_ROOT/playbook/preinstall/preinstall.json"
|
|
PXE_IMAGES_DIR="${PXE_IMAGES_DIR:-/home/camp/pxe-images/main}"
|
|
|
|
REMOTE_DIR="/srv/samba/enrollment/preinstall"
|
|
REMOTE_INSTALLERS="$REMOTE_DIR/installers"
|
|
REMOTE_TEMP="/tmp/preinstall-stage"
|
|
|
|
# Subtrees copied recursively into installers/, preserving directory structure.
|
|
#
|
|
# vcredist/ holds per-version MSI+CAB pairs (one subdir per version) extracted from
|
|
# the Microsoft bootstrappers. The bootstrappers ignore /norestart and trigger
|
|
# immediate Windows reboots; the extracted MSIs honor REBOOT=ReallySuppress and do
|
|
# not. Each MSI's CAB filename ('vc_red.cab' for 2008/2010, 'cab1.cab' for the rest)
|
|
# is hardcoded in the MSI's Media table - do not rename.
|
|
#
|
|
# opentext/ holds the OpenText HostExplorer 15 SP1 install bundle (base MSI + cab,
|
|
# ShopFloor.mst transform, SP1 .msp patch, plus the Profile/Accessories/HostExplorer/
|
|
# W10shortcuts content trees and Setup-OpenText.ps1/.cmd). Setup-OpenText.ps1 runs
|
|
# msiexec, applies SP1, then deploys profile content into ProgramData\Shared,
|
|
# Default User, and every existing user profile. The .cmd wrapper exists so the
|
|
# preinstall.json runner (which only knows MSI/EXE types) can launch it.
|
|
TREE_SUBDIRS=(
|
|
"dependencies/vcredist"
|
|
"dependencies/opentext"
|
|
)
|
|
|
|
# Individual files copied flat (basename only) into installers/.
|
|
FLAT_INSTALLERS=(
|
|
"machineapps/UDC_Setup.exe"
|
|
"globalassets/oracleclient/Oracle 10.2.0.3.msi"
|
|
)
|
|
|
|
# --- 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 "$PREINSTALL_JSON" ]; then
|
|
echo "ERROR: preinstall.json not found at $PREINSTALL_JSON" >&2
|
|
exit 1
|
|
fi
|
|
|
|
missing=0
|
|
|
|
for tree in "${TREE_SUBDIRS[@]}"; do
|
|
src="$PXE_IMAGES_DIR/$tree"
|
|
if [ ! -d "$src" ]; then
|
|
echo " MISSING: $src (directory)" >&2
|
|
missing=$((missing + 1))
|
|
else
|
|
size=$(du -sb "$src" | cut -f1)
|
|
printf " OK %10d %s/ (tree)\n" "$size" "$tree"
|
|
fi
|
|
done
|
|
|
|
for rel in "${FLAT_INSTALLERS[@]}"; do
|
|
src="$PXE_IMAGES_DIR/$rel"
|
|
if [ ! -f "$src" ]; then
|
|
echo " MISSING: $src" >&2
|
|
missing=$((missing + 1))
|
|
else
|
|
printf " OK %10d %s\n" "$(stat -c %s "$src")" "$rel"
|
|
fi
|
|
done
|
|
|
|
if [ "$missing" -gt 0 ]; then
|
|
echo "ERROR: $missing source(s) missing in $PXE_IMAGES_DIR" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# --- 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
|
|
|
|
# --- Build local tarball of all TREE_SUBDIRS ---
|
|
LOCAL_TARBALL="$(mktemp /tmp/preinstall-trees.XXXXXX.tar)"
|
|
trap 'rm -f "$LOCAL_TARBALL" "${LOCAL_TEMP_SCRIPT:-}"' EXIT
|
|
|
|
echo "Building local tarball of subtrees..."
|
|
tar_args=()
|
|
for tree in "${TREE_SUBDIRS[@]}"; do
|
|
parent_dir="$PXE_IMAGES_DIR/$(dirname "$tree")"
|
|
leaf="$(basename "$tree")"
|
|
tar_args+=( -C "$parent_dir" "$leaf" )
|
|
done
|
|
tar cf "$LOCAL_TARBALL" "${tar_args[@]}"
|
|
echo " -> $(stat -c %s "$LOCAL_TARBALL") bytes"
|
|
|
|
# --- Stage to /tmp on PXE, then sudo install ---
|
|
echo "Staging files to $PXE_HOST:$REMOTE_TEMP..."
|
|
ssh_run "rm -rf $REMOTE_TEMP && mkdir -p $REMOTE_TEMP/flat"
|
|
|
|
# preinstall.json
|
|
echo " -> preinstall.json"
|
|
scp_to "$PREINSTALL_JSON" "$REMOTE_TEMP/preinstall.json"
|
|
|
|
# tarball of subtrees
|
|
echo " -> trees.tar"
|
|
scp_to "$LOCAL_TARBALL" "$REMOTE_TEMP/trees.tar"
|
|
|
|
# flat installers (preserve filenames including spaces, all into flat/)
|
|
for rel in "${FLAT_INSTALLERS[@]}"; do
|
|
src="$PXE_IMAGES_DIR/$rel"
|
|
base="$(basename "$rel")"
|
|
echo " -> $base"
|
|
scp_to "$src" "$REMOTE_TEMP/flat/$base"
|
|
done
|
|
|
|
# --- Build remote install script (runs under sudo on PXE) ---
|
|
LOCAL_TEMP_SCRIPT="$(mktemp /tmp/sync-preinstall-remote.XXXXXX.sh)"
|
|
|
|
cat > "$LOCAL_TEMP_SCRIPT" <<REMOTE_SCRIPT
|
|
#!/bin/bash
|
|
set -e
|
|
mkdir -p "$REMOTE_INSTALLERS"
|
|
|
|
# preinstall.json -> /srv/samba/enrollment/preinstall/preinstall.json
|
|
cp "$REMOTE_TEMP/preinstall.json" "$REMOTE_DIR/preinstall.json"
|
|
chmod 0644 "$REMOTE_DIR/preinstall.json"
|
|
chown root:root "$REMOTE_DIR/preinstall.json"
|
|
|
|
# Remove legacy flat VC++ files (replaced by vcredist/ subdir tree). These were the
|
|
# pre-Burn-extraction layout where 2008's MSI/CAB sat at the root and 2010/2012/2013/
|
|
# 2015 used bootstrappers directly. All four now live under vcredist/<version>/.
|
|
rm -f "$REMOTE_INSTALLERS/vc_red.msi" \
|
|
"$REMOTE_INSTALLERS/vc_red.cab" \
|
|
"$REMOTE_INSTALLERS/vcredist2008_x86.exe" \
|
|
"$REMOTE_INSTALLERS/vcredist2010_x86.exe" \
|
|
"$REMOTE_INSTALLERS/vcredist2012_x86.exe" \
|
|
"$REMOTE_INSTALLERS/vcredist2013_x86.exe" \
|
|
"$REMOTE_INSTALLERS/vcredist2015_2017_2019_2022_x86.exe"
|
|
|
|
# Remove legacy flat OpenText.exe (Inno wrapper, replaced by dependencies/opentext/
|
|
# subtree + Setup-OpenText.ps1).
|
|
rm -f "$REMOTE_INSTALLERS/OpenText.exe"
|
|
|
|
# Extract tree tarball into installers/ (preserves subdirs)
|
|
tar xf "$REMOTE_TEMP/trees.tar" -C "$REMOTE_INSTALLERS/"
|
|
|
|
# Flat installers -> installers/
|
|
shopt -s dotglob nullglob
|
|
for f in "$REMOTE_TEMP/flat/"*; do
|
|
base="\$(basename "\$f")"
|
|
cp "\$f" "$REMOTE_INSTALLERS/\$base"
|
|
done
|
|
|
|
# Normalize ownership and perms (files 0644, dirs 0755, all root:root)
|
|
chown -R root:root "$REMOTE_INSTALLERS"
|
|
find "$REMOTE_INSTALLERS" -type f -exec chmod 0644 {} +
|
|
find "$REMOTE_INSTALLERS" -type d -exec chmod 0755 {} +
|
|
|
|
rm -rf "$REMOTE_TEMP"
|
|
|
|
echo
|
|
echo "Final state of $REMOTE_DIR:"
|
|
ls -la "$REMOTE_DIR"
|
|
echo
|
|
echo "Final state of $REMOTE_INSTALLERS:"
|
|
ls -la "$REMOTE_INSTALLERS"
|
|
echo
|
|
echo "vcredist tree:"
|
|
find "$REMOTE_INSTALLERS/vcredist" -type f -printf '%10s %p\n' 2>/dev/null | sort -k2
|
|
REMOTE_SCRIPT
|
|
|
|
# Stage the install script alongside the data files
|
|
scp_to "$LOCAL_TEMP_SCRIPT" "$REMOTE_TEMP/_install.sh"
|
|
|
|
# Execute remotely with sudo
|
|
echo "Installing files to $REMOTE_DIR (sudo)..."
|
|
ssh_run "echo '$PXE_PASS' | sudo -S bash $REMOTE_TEMP/_install.sh"
|
|
|
|
echo
|
|
echo "Done. Preinstall bundle synced to $PXE_HOST:$REMOTE_DIR"
|