Files
pxe-server/playbook/sync-waxtrace.sh
cproudlock de7d41f5e5 Wax/Trace: defer HKEY_USERS per-user prefs restore to first ShopFloor logon via SYSTEM scheduled task
Bay's ShopFloor user account exists but has never logged in at imaging
time, so its NTUSER.DAT doesn't exist yet and we can't reg-load its
hive to remap source SID -> ShopFloor SID. The in-line restore at
09-Setup Step 3b handles HKLM (controller config, device-map) + files,
but per-user prefs (LouteditS Layout, Page margins, Recent Files, ~2700
rows in a typical WJF capture) get skipped.

Fix: register a SYSTEM-context scheduled task at imaging time that
fires AtLogOn UserId=ShopFloor. When ShopFloor first logs in, Windows
loads their NTUSER.DAT automatically; task fires (running as SYSTEM
so lockdown policies on ShopFloor's user-context don't block HKLM
writes via the same Install script); SID-remap path finds the live
hive and writes prefs into HKEY_USERS\<ShopFloor-sid>. Task writes a
flag file + unregisters itself after one successful run.

Pieces:
- Install-FormtracepakSettings.ps1: new -HKEYUsersOnly switch that
  skips the HKLM .reg files + HKLM CSV rows (already restored at
  imaging time). Fallback user chain ShopFloor->SupportUser->$USERNAME.
- Schedule-WaxTracePerUserRestore.ps1: registers the task, writes
  C:\WaxTrace-Install\Run-WaxTracePerUserRestore.ps1 task action which
  invokes Install with -HKEYUsersOnly and self-cleans on success.
- 09-Setup-WaxAndTrace.ps1 Step 3b: in-line restore now uses
  -RestoreRegistry -RestoreData -RestoreConfig (HKLM + files now);
  calls Schedule-WaxTracePerUserRestore.ps1 to queue HKEY_USERS for
  first ShopFloor logon.
- sync-waxtrace.sh: pushes Schedule-WaxTracePerUserRestore.ps1 to
  PXE share alongside Install-FormtracepakSettings.ps1.

Smoke tested on win11 VM partially: task registration works, manual
trigger fires + self-unregisters cleanly, flag file lands. Real per-
user SID-remap happens at first ShopFloor logon (can't simulate from
qga without an interactive ShopFloor session).
2026-05-24 16:19:45 -04:00

162 lines
6.8 KiB
Bash
Executable File

#!/bin/bash
# sync-waxtrace.sh - Push Wax/Trace (Mitutoyo FormTracePak) bootstrap bundle
# to the PXE server enrollment share.
#
# Copies waxtrace-manifest.json + 09-Setup-WaxAndTrace.ps1 (from the
# gea-shopfloor-waxtrace/ tree) plus the big binary payload (captured master
# zip + reg + HASP + VC++ redists + per-machine cal ISOs) from the local
# workstation to /srv/samba/enrollment/installers-post/waxtrace on the PXE
# server. That directory becomes visible as
# \\172.16.9.1\enrollment\installers-post\waxtrace so startnet.cmd can xcopy
# it onto the target disk during WinPE phase (W:\WaxTrace-Install, becomes
# C:\WaxTrace-Install post-reboot).
#
# Run this on the workstation any time:
# - waxtrace-manifest.json changes
# - 09-Setup-WaxAndTrace.ps1 changes
# - A new cal ISO is added under /home/camp/pxe-images/iso/mitutoyo-cal/
# - Prereqs (VC++, HASP) are updated
# - FormTracePak vendor ISO is bumped (default v6.213, override with $FTPAK_ISO)
#
# Usage:
# ./playbook/sync-waxtrace.sh
#
# Requires: sshpass, scp, ssh, gzip (already in captured/reg/).
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
PXE_HOST="${PXE_HOST:-172.16.9.1}"
PXE_USER="${PXE_USER:-pxe}"
PXE_PASS="${PXE_PASS:-pxe}"
WAXTRACE_DIR="$PROJECT_ROOT/playbook/shopfloor-setup/gea-shopfloor-waxtrace"
CAL_ISO_DIR="${MITUTOYO_CAL_DIR:-/home/camp/pxe-images/iso/mitutoyo-cal}"
REMOTE_DIR="/srv/samba/enrollment/installers-post/waxtrace"
REMOTE_TEMP="/tmp/waxtrace-stage-$$"
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 "$@"
}
# Sanity check
test -f "$WAXTRACE_DIR/waxtrace-manifest.json" || { echo "Missing $WAXTRACE_DIR/waxtrace-manifest.json"; exit 1; }
test -f "$WAXTRACE_DIR/09-Setup-WaxAndTrace.ps1" || { echo "Missing 09-Setup-WaxAndTrace.ps1"; exit 1; }
test -d "$WAXTRACE_DIR/captured-binary/prereqs" || { echo "Missing $WAXTRACE_DIR/captured-binary/prereqs (VC++/HASP installers)"; exit 1; }
echo "==> Staging tree locally"
STAGE="$(mktemp -d -p /tmp waxtrace-stage.XXXXXX)"
trap "rm -rf $STAGE" EXIT
mkdir -p "$STAGE/prereqs" "$STAGE/calibrations" "$STAGE/formtracepak"
cp "$WAXTRACE_DIR/waxtrace-manifest.json" "$STAGE/"
cp "$WAXTRACE_DIR/09-Setup-WaxAndTrace.ps1" "$STAGE/"
# Arrow-key picker invoked from startnet.cmd. Reads INDEX.csv to build the
# menu, falls back to free-text prompt if it errors. Lives next to the
# calibrations dir since it depends on INDEX.csv being adjacent.
if [ -f "$WAXTRACE_DIR/select-waxtrace-asset.ps1" ]; then
cp "$WAXTRACE_DIR/select-waxtrace-asset.ps1" "$STAGE/"
fi
# Bay-config CSV + resolver. startnet.cmd invokes resolve-bay-config.ps1 in
# WinPE to pick the right FTPak version per bay. resolver reads bay-config.csv
# from this share (or W:\WaxTrace-Install\) and writes
# W:\Enrollment\waxtrace\{version,model,userid}.txt.
if [ -f "$WAXTRACE_DIR/bay-config.csv" ]; then
cp "$WAXTRACE_DIR/bay-config.csv" "$STAGE/"
fi
if [ -f "$WAXTRACE_DIR/resolve-bay-config.ps1" ]; then
cp "$WAXTRACE_DIR/resolve-bay-config.ps1" "$STAGE/"
fi
# Install-FormtracepakSettings.ps1 - called from 09-Setup-WaxAndTrace.ps1
# Step 3b to restore captured layouts / prefs / data from the per-asset
# backup ZIP. Path on the bay post-startnet-xcopy:
# C:\WaxTrace-Install\Install-FormtracepakSettings.ps1.
if [ -f "$WAXTRACE_DIR/scripts/Install-FormtracepakSettings.ps1" ]; then
cp "$WAXTRACE_DIR/scripts/Install-FormtracepakSettings.ps1" "$STAGE/"
fi
# Schedule-WaxTracePerUserRestore.ps1 - registers a SYSTEM scheduled task
# that fires on first ShopFloor logon to restore HKEY_USERS per-user prefs
# (deferred from imaging time because ShopFloor's hive isn't loaded yet).
# Path on the bay post-startnet-robocopy:
# C:\WaxTrace-Install\Schedule-WaxTracePerUserRestore.ps1.
if [ -f "$WAXTRACE_DIR/scripts/Schedule-WaxTracePerUserRestore.ps1" ]; then
cp "$WAXTRACE_DIR/scripts/Schedule-WaxTracePerUserRestore.ps1" "$STAGE/"
fi
cp "$WAXTRACE_DIR/captured-binary/prereqs/"*.exe "$STAGE/prereqs/"
# FormTracePak vendor installer ISOs - all available versions get pushed.
# startnet.cmd cherry-picks the matching FORMTRACEPAK-V<ver>.iso based on
# bay-config.csv lookup, xcopies just that one to the local disk (~2 GB).
# Total on PXE share: ~12 GB; per-bay xcopy: ~2 GB.
FTPAK_ISO_DIR="${FTPAK_ISO_DIR:-/home/camp/pxe-images/iso}"
FTPAK_COUNT=0
for iso in "$FTPAK_ISO_DIR"/FORMTRACEPAK-V*.iso; do
[ -f "$iso" ] || continue
cp "$iso" "$STAGE/formtracepak/"
FTPAK_COUNT=$((FTPAK_COUNT+1))
done
if [ "$FTPAK_COUNT" -eq 0 ]; then
echo "WARNING: no FORMTRACEPAK-V*.iso in $FTPAK_ISO_DIR - bays cannot install at imaging time."
else
echo "Staged $FTPAK_COUNT FormTracePak version ISO(s) from $FTPAK_ISO_DIR"
fi
# Cal ISOs - one per wax/trace bay
if [ -d "$CAL_ISO_DIR" ]; then
cp "$CAL_ISO_DIR"/CAL-*.iso "$STAGE/calibrations/" 2>/dev/null || true
cp "$CAL_ISO_DIR/INDEX.csv" "$STAGE/calibrations/" 2>/dev/null || true
fi
# Per-asset FormTracePak backup ZIPs. The tech captures these on the live
# bays via Backup-FormtracepakSettings.bat (lands at
# S:\DT\Shopfloor\backup\waxandtrace\<asset>\formtracepak_backup_*.zip on
# tsgwp00525), then mirrors them down to /home/camp/pxe-images/wt/<asset>/
# on this Linux host. Pick the newest ZIP per asset and stage as
# <asset>.zip so startnet.cmd can cherry-pick a known filename per bay.
BACKUP_SRC_DIR="${WAXTRACE_BACKUP_DIR:-/home/camp/pxe-images/wt}"
mkdir -p "$STAGE/backups"
BACKUP_COUNT=0
if [ -d "$BACKUP_SRC_DIR" ]; then
for asset_dir in "$BACKUP_SRC_DIR"/WJ*/; do
[ -d "$asset_dir" ] || continue
asset=$(basename "$asset_dir")
newest=$(ls -1t "$asset_dir"/formtracepak_backup_*.zip 2>/dev/null | head -1)
if [ -n "$newest" ] && [ -s "$newest" ]; then
cp "$newest" "$STAGE/backups/${asset}.zip"
BACKUP_COUNT=$((BACKUP_COUNT+1))
fi
done
fi
echo "Staged $BACKUP_COUNT per-asset backup ZIP(s) from $BACKUP_SRC_DIR"
echo "==> Local stage size: $(du -sh $STAGE | cut -f1)"
ls "$STAGE/"
ls "$STAGE/prereqs/"
ls "$STAGE/formtracepak/" 2>/dev/null || echo "(no FormTracePak ISO)"
ls "$STAGE/calibrations/" 2>/dev/null || echo "(no cal ISOs)"
ls "$STAGE/backups/" 2>/dev/null || echo "(no per-asset backup ZIPs)"
echo "==> Pushing to $PXE_USER@$PXE_HOST:$REMOTE_TEMP"
ssh_run "rm -rf '$REMOTE_TEMP' && mkdir -p '$REMOTE_TEMP'"
scp_to -r "$STAGE/." "$PXE_USER@$PXE_HOST:$REMOTE_TEMP/"
echo "==> Atomic move into $REMOTE_DIR"
ssh_run "echo $PXE_PASS | sudo -S bash -c '
mkdir -p $(dirname $REMOTE_DIR)
if [ -d $REMOTE_DIR ]; then
mv $REMOTE_DIR ${REMOTE_DIR}.pre-\$(date +%Y%m%d-%H%M%S)
fi
mv $REMOTE_TEMP $REMOTE_DIR
chown -R pxe:pxe $REMOTE_DIR
ls -la $REMOTE_DIR
'"
echo "==> Done. Next imaged Wax/Trace PC picks up the new bundle."