#!/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 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" # Files to push (source paths under PXE_IMAGES_DIR). # vc_red.msi + vc_red.cab are extracted from vcredist2008_x86.exe and used directly # (instead of the bootstrapper) because the 2008 bootstrapper ignores /norestart and # triggers an immediate reboot. The MSI honors REBOOT=ReallySuppress, the bootstrapper # does not. The .cab MUST be named "vc_red.cab" exactly because that name is hardcoded # in the MSI's Media table. INSTALLERS=( "dependencies/vc_red.msi" "dependencies/vc_red.cab" "dependencies/vcredist2010_x86.exe" "dependencies/vcredist2012_x86.exe" "dependencies/vcredist2013_x86.exe" "dependencies/vcredist2015_2017_2019_2022_x86.exe" "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() { # Remote path is double-escaped: outer ssh layer + inner shell layer. # Wrap in single-quotes inside the destination so spaces in filenames survive. 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 rel in "${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 installer file(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 # --- Stage to /tmp on PXE, then sudo install --- echo "Staging files to $PXE_HOST:$REMOTE_TEMP..." ssh_run "mkdir -p $REMOTE_TEMP && rm -f $REMOTE_TEMP/*" # preinstall.json echo " -> preinstall.json" scp_to "$PREINSTALL_JSON" "$REMOTE_TEMP/preinstall.json" # installers (preserve filenames including spaces) for rel in "${INSTALLERS[@]}"; do src="$PXE_IMAGES_DIR/$rel" base="$(basename "$rel")" echo " -> $base" scp_to "$src" "$REMOTE_TEMP/$base" done # --- Build remote install script (runs under sudo on PXE) --- LOCAL_TEMP_SCRIPT="$(mktemp /tmp/sync-preinstall-remote.XXXXXX.sh)" trap 'rm -f "$LOCAL_TEMP_SCRIPT"' EXIT cat > "$LOCAL_TEMP_SCRIPT" < /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" # All other files -> installers/ shopt -s dotglob nullglob for f in "$REMOTE_TEMP"/*; do base="\$(basename "\$f")" if [ "\$base" != "preinstall.json" ] && [ "\$base" != "_install.sh" ]; then cp "\$f" "$REMOTE_INSTALLERS/\$base" chmod 0644 "$REMOTE_INSTALLERS/\$base" chown root:root "$REMOTE_INSTALLERS/\$base" fi done 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" 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"