- CMM imaging pipeline: WinPE-staged bootstrap + on-logon enforcer against tsgwp00525 share, manifest-driven installer runner shared via Install-FromManifest.ps1. Installs PC-DMIS 2016/2019 R2, CLM 1.8, goCMM; enables .NET 3.5 prereq; registers GE CMM Enforce logon task for ongoing version enforcement. - Shopfloor serial drivers: StarTech PCIe serial + Prolific PL2303 USB-to-serial via Install-Drivers.cmd wrapper calling pnputil /add-driver /subdirs /install. Scoped to Standard PCs. - OpenText extended to CMM/Keyence/Genspect/WaxAndTrace via preinstall.json PCTypes; Defect Tracker added to CMM profile desktopApps + taskbarPins. - Configure-PC startup-item toggle now persists across the logon sweep via C:\\ProgramData\\GE\\Shopfloor\\startup-overrides.json; 06-OrganizeDesktop Phase 3 respects suppressed items. - Get-ProfileValue helper added to Shopfloor/lib/Get-PCProfile.ps1; distinguishes explicit empty array from missing key (fixes Lab getting Plant Apps in startup because empty array was falsy). - 06-OrganizeDesktop gains transcript logging at C:\\Logs\\SFLD\\ 06-OrganizeDesktop.log and now deletes the stale Shopfloor Intune Sync task when C:\\Enrollment\\sync-complete.txt is present (task was registered with Limited principal and couldn't self-unregister). - startnet.cmd CMM xcopy block (gated on pc-type=CMM) stages the bundle to W:\\CMM-Install during WinPE. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
210 lines
6.9 KiB
Bash
Executable File
210 lines
6.9 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"
|
|
"dependencies/drivers"
|
|
)
|
|
|
|
# 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"
|