diff --git a/.gitignore b/.gitignore index eb188d4..468d803 100644 --- a/.gitignore +++ b/.gitignore @@ -101,6 +101,12 @@ playbook/shopfloor-setup/Shopfloor/PrinterInstallerMap.exe # /home/camp/pxe-images/keyence/Logs/Keyence/install.log for the signature). # Canonical source on the GE-Enforce SFLD share: # tsgwp00525\sfld$\v2\shared\dt\shopfloor\gea-shopfloor-keyence\apps\Data1.cab -# Stage to playbook/shopfloor-setup/gea-shopfloor-keyence/installers/Data1.cab # before building the USB image. -playbook/shopfloor-setup/gea-shopfloor-keyence/installers/Data1.cab +playbook/shopfloor-setup/gea-shopfloor-waxtrace/captured-binary/ + +# Keyence per-model installer payloads - too big for git, staged via sync-keyence.sh +playbook/shopfloor-setup/gea-shopfloor-keyence/vr3000/installers/Data*.cab +playbook/shopfloor-setup/gea-shopfloor-keyence/vr3000/installers/*.msi +playbook/shopfloor-setup/gea-shopfloor-keyence/vr5000/installers/Data*.cab +playbook/shopfloor-setup/gea-shopfloor-keyence/vr5000/installers/*.msi +playbook/shopfloor-setup/gea-shopfloor-keyence/vr6000/installers/Data1.cab diff --git a/playbook/select-waxtrace-asset.ps1 b/playbook/select-waxtrace-asset.ps1 new file mode 100644 index 0000000..47b4b5c --- /dev/null +++ b/playbook/select-waxtrace-asset.ps1 @@ -0,0 +1,100 @@ +# select-waxtrace-asset.ps1 - Arrow-key bay picker for wax/trace imaging. +# +# Reads the calibration INDEX.csv on the PXE share to build the menu of known +# bays. Operator picks with Up/Down arrows + Enter. Always appends an +# "Other (new bay)" option at the end for bays that don't have a cal ISO yet - +# selecting it falls back to a free-text prompt. +# +# Writes the chosen asset tag to $OutFile (one line, no trailing newline). +# startnet.cmd reads that file back into the MACHINENUM batch var. +# +# Runs in WinPE PowerShell. Win10/11 WinPE ships powershell.exe with +# System.Console.ReadKey support. Tested 2026-05-18. +# +# Exit codes: +# 0 = asset tag written to $OutFile +# 1 = user cancelled (Esc) - $OutFile not written +# 2 = INDEX.csv unreadable AND no fallback entered + +param( + [string]$IndexPath = 'Y:\installers-post\waxtrace\calibrations\INDEX.csv', + [Parameter(Mandatory=$true)][string]$OutFile +) + +$ErrorActionPreference = 'Continue' + +function Read-BayList { + param([string]$Path) + if (-not (Test-Path -LiteralPath $Path)) { return @() } + try { + return Import-Csv -LiteralPath $Path | Select-Object -Property asset_tag, unit_serial, probe_part + } catch { + return @() + } +} + +function Show-Menu { + param( + [object[]]$Items, + [int]$Selected, + [string]$Title + ) + Clear-Host + Write-Host "" + Write-Host " ========================================" + Write-Host " $Title" + Write-Host " ========================================" + Write-Host "" + Write-Host " Up / Down arrows = navigate, Enter = select, Esc = cancel" + Write-Host "" + for ($i = 0; $i -lt $Items.Count; $i++) { + $item = $Items[$i] + $line = if ($item -is [string]) { $item } else { "{0,-10} serial={1,-12} probe={2}" -f $item.asset_tag, $item.unit_serial, $item.probe_part } + if ($i -eq $Selected) { + Write-Host (" > " + $line) -ForegroundColor Black -BackgroundColor White + } else { + Write-Host (" " + $line) + } + } + Write-Host "" +} + +$bays = @(Read-BayList -Path $IndexPath) +$menuItems = @() +foreach ($b in $bays) { $menuItems += $b } +$menuItems += '** Other (new bay - enter asset tag manually) **' + +$sel = 0 +while ($true) { + Show-Menu -Items $menuItems -Selected $sel -Title "Wax/Trace Asset Tag" + $key = [System.Console]::ReadKey($true) + switch ($key.Key) { + 'UpArrow' { if ($sel -gt 0) { $sel-- } } + 'DownArrow' { if ($sel -lt ($menuItems.Count - 1)) { $sel++ } } + 'Enter' { + if ($sel -eq ($menuItems.Count - 1)) { + # Manual entry + Write-Host "" + $manual = Read-Host " Enter asset tag (e.g. WJRP9999) or blank to abort" + if ($manual) { + $manual = $manual.Trim().ToUpper() + Set-Content -LiteralPath $OutFile -Value $manual -NoNewline -Encoding ascii + Write-Host "" + Write-Host " Saved asset tag: $manual" + Start-Sleep -Seconds 1 + exit 0 + } else { + exit 1 + } + } else { + $pick = $bays[$sel].asset_tag + Set-Content -LiteralPath $OutFile -Value $pick -NoNewline -Encoding ascii + Write-Host "" + Write-Host " Selected: $pick" + Start-Sleep -Seconds 1 + exit 0 + } + } + 'Escape' { exit 1 } + } +} diff --git a/playbook/shopfloor-setup/gea-shopfloor-keyence/09-Setup-Keyence.ps1 b/playbook/shopfloor-setup/gea-shopfloor-keyence/09-Setup-Keyence.ps1 index 541c8d5..8bf93c6 100644 --- a/playbook/shopfloor-setup/gea-shopfloor-keyence/09-Setup-Keyence.ps1 +++ b/playbook/shopfloor-setup/gea-shopfloor-keyence/09-Setup-Keyence.ps1 @@ -1,15 +1,18 @@ # 09-Setup-Keyence.ps1 - Keyence type setup (runs during shopfloor-setup phase). # -# Performs the imaging-time install of Keyence VR-6000 Series Software MSI + -# KEYENCE VR Series USB driver from the staged bundle. Ongoing enforcement -# is handled by GE-Enforce (registered separately in Run-ShopfloorSetup.ps1) -# reading keyence/manifest.json from the tsgwp00525 share. +# Performs the imaging-time install of one of three Keyence model variants: +# VR-3000 G2 / VR-5000 / VR-6000 +# based on C:\Enrollment\keyence-model.txt (vr3000 / vr5000 / vr6000), set +# during the WinPE menu. Per-model manifest + installers live at +# /manifest.json + /installers/. Ongoing enforcement is handled +# by GE-Enforce reading keyence/manifest.json from the tsgwp00525 share. # # Layout at $PSScriptRoot (xcopied by startnet.cmd only for PCTYPE=Keyence): -# keyence-manifest.json # 09-Setup-Keyence.ps1 (this file) -# installers\VR-6000 Series Software.msi -# drivers\keyence_vr_series.inf (+ cat + amd64\{Wdf,WinUsb}CoInstaller*.dll) +# vr3000\manifest.json + installers\VR-3000 G2 Series Software.msi + Data*.cab +# vr5000\manifest.json + installers\VR-5000 Series Software.msi + Data1.cab +# vr6000\manifest.json + installers\VR-6000 Series Software.msi + Data1.cab +# + drivers\keyence_vr_series.inf (legacy - only VR-6000) # # Library lookup: the imaging-time install uses the common Install-FromManifest # library at ..\common\lib\Install-FromManifest.ps1 (relative to $PSScriptRoot). @@ -19,8 +22,26 @@ $ErrorActionPreference = 'Continue' -$manifestPath = Join-Path $PSScriptRoot 'keyence-manifest.json' -$libSource = Join-Path $PSScriptRoot '..\common\lib\Install-FromManifest.ps1' +$libSource = Join-Path $PSScriptRoot '..\common\lib\Install-FromManifest.ps1' + +# Resolve which Keyence model variant to install. WinPE writes the choice +# (vr3000 / vr5000 / vr6000) into C:\Enrollment\keyence-model.txt during +# the imaging menu. If the file is missing, default to vr6000 since that +# was the original single-model setup before this refactor. +$modelFile = 'C:\Enrollment\keyence-model.txt' +if (Test-Path -LiteralPath $modelFile) { + $model = (Get-Content -LiteralPath $modelFile -First 1 -ErrorAction SilentlyContinue).Trim().ToLower() +} +if (-not $model) { $model = 'vr6000' } + +# Manifest comes via shopfloor-setup tree xcopy (small file, git-tracked). +# Installer payload (MSI + Data*.cab) comes via installers-post stage at +# C:\KeyenceInstall\\ - placed there by startnet.cmd's keyence-stage +# block. So manifest paths reference installers\... which resolve relative +# to InstallerRoot=C:\KeyenceInstall\. +$modelRoot = Join-Path $PSScriptRoot $model +$manifestPath = Join-Path $modelRoot 'manifest.json' +$stagingRoot = "C:\KeyenceInstall\$model" $logDir = 'C:\Logs\Keyence' $installLog = Join-Path $logDir 'install.log' @@ -80,8 +101,11 @@ foreach ($file in @('pc-type.txt','pc-subtype.txt','machine-number.txt')) { # If either step fails, log + continue - the MSI is still expected to install # successfully; the only fallout is the GUI prompt the operator would have # had to click through anyway. -$driverInf = Join-Path $PSScriptRoot 'drivers\keyence_vr_series.inf' -$driverCat = Join-Path $PSScriptRoot 'drivers\KEYENCE_VR_SERIES.cat' +# Drivers come via the staging dir now. Only VR-6000 ships an external .inf; +# VR-3000 + VR-5000 embed drivers inside the MSI so the pre-stage step is a +# no-op for those models (no file found, log + continue). +$driverInf = Join-Path $stagingRoot 'drivers\keyence_vr_series.inf' +$driverCat = Join-Path $stagingRoot 'drivers\KEYENCE_VR_SERIES.cat' if (Test-Path -LiteralPath $driverInf) { Write-KeyenceLog "Pre-staging USB driver via pnputil (suppresses dpinst GUI inside MSI)" @@ -124,8 +148,8 @@ if (-not (Test-Path $manifestPath)) { } elseif (-not (Test-Path $libSource)) { Write-KeyenceLog "Install-FromManifest.ps1 not found at $libSource" "ERROR" } else { - Write-KeyenceLog "Running Install-FromManifest (InstallerRoot=$PSScriptRoot)" - & $libSource -ManifestPath $manifestPath -InstallerRoot $PSScriptRoot -LogFile $installLog + Write-KeyenceLog "Running Install-FromManifest (InstallerRoot=$stagingRoot)" + & $libSource -ManifestPath $manifestPath -InstallerRoot $stagingRoot -LogFile $installLog $rc = $LASTEXITCODE Write-KeyenceLog "Install-FromManifest returned $rc" } @@ -138,11 +162,15 @@ if (-not (Test-Path $manifestPath)) { # the application is not installed correctly. Install from the following # folder: C:\Program Files\Keyence\VR-6000\Common\DirectX End-User Runtimes\ # DXSETUP.exe". Run it silently here; /silent suppresses all UI + reboot. -$dxSetup = 'C:\Program Files\KEYENCE\VR-6000\Common\DirectX End-User Runtimes\DXSETUP.exe' -$dxSetupAlt = 'C:\Program Files (x86)\KEYENCE\VR-6000\Common\DirectX End-User Runtimes\DXSETUP.exe' -if (Test-Path -LiteralPath $dxSetup) { $dxPath = $dxSetup } -elseif (Test-Path -LiteralPath $dxSetupAlt) { $dxPath = $dxSetupAlt } -else { $dxPath = $null } +# Probe both VR-3000 G2, VR-5000, VR-6000 install paths under both Program Files +# roots. Whichever model's MSI installed will have its DXSETUP at one of these. +$dxCandidates = @() +foreach ($pf in @('C:\Program Files\KEYENCE','C:\Program Files (x86)\KEYENCE')) { + foreach ($prod in @('VR-3000 G2','VR-5000','VR-6000')) { + $dxCandidates += (Join-Path $pf "$prod\Common\DirectX End-User Runtimes\DXSETUP.exe") + } +} +$dxPath = $dxCandidates | Where-Object { Test-Path -LiteralPath $_ } | Select-Object -First 1 if ($dxPath) { Write-KeyenceLog "Running DirectX End-User Runtimes: $dxPath /silent" diff --git a/playbook/shopfloor-setup/gea-shopfloor-keyence/vr3000/installers/1033.mst b/playbook/shopfloor-setup/gea-shopfloor-keyence/vr3000/installers/1033.mst new file mode 100644 index 0000000..c75d1e1 Binary files /dev/null and b/playbook/shopfloor-setup/gea-shopfloor-keyence/vr3000/installers/1033.mst differ diff --git a/playbook/shopfloor-setup/gea-shopfloor-keyence/vr3000/manifest.json b/playbook/shopfloor-setup/gea-shopfloor-keyence/vr3000/manifest.json new file mode 100644 index 0000000..3bb278b --- /dev/null +++ b/playbook/shopfloor-setup/gea-shopfloor-keyence/vr3000/manifest.json @@ -0,0 +1,17 @@ +{ + "Version": "1.0", + "_comment": "Keyence VR-3000 G2 imaging-time manifest. Consumed by 09-Setup-Keyence.ps1 when keyence-model.txt = vr3000. USB drivers are embedded in the MSI (newer InstallShield deploys them via custom action) - no separate .inf needed. The MSI references Data1.cab (2.0 GB) + Data11.cab (388 MB) in the same Installer\\ dir; those cabs are gitignored (see .gitignore). Stage them from /home/camp/pxe-images/iso/keyence/Keyence-VR-3000-G2-v2.5.0.iso (Installer/Data*.cab) into installers/ before sync-keyence.sh. Verified silent install via msiexec on Win11 2026-05-18 with /qn /norestart ALLUSERS=1 REBOOT=ReallySuppress TRANSFORMS=1033.mst (English transform).", + "Applications": [ + { + "_comment": "VR-3000 G2 Series Software. v2.5.0 Sept 2017. ProductCode {9CC9A062-2A93-4D3B-AECA-F70C691A46F2}. The bundled InstallShield setup.exe wrapper is 227 MB and bundles its own VC++/DotNet prereqs; we skip it and call the MSI directly via msiexec since modern Win11 ships compatible runtimes.", + "Name": "VR-3000 G2 Series Software", + "Installer": "installers\\VR-3000 G2 Series Software.msi", + "Type": "MSI", + "InstallArgs": "/qn /norestart ALLUSERS=1 REBOOT=ReallySuppress TRANSFORMS=installers\\1033.mst", + "DetectionMethod": "Registry", + "DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{9CC9A062-2A93-4D3B-AECA-F70C691A46F2}", + "DetectionName": "DisplayVersion", + "DetectionValue": "2.5.0" + } + ] +} diff --git a/playbook/shopfloor-setup/gea-shopfloor-keyence/vr5000/installers/1033.mst b/playbook/shopfloor-setup/gea-shopfloor-keyence/vr5000/installers/1033.mst new file mode 100644 index 0000000..ab5f983 Binary files /dev/null and b/playbook/shopfloor-setup/gea-shopfloor-keyence/vr5000/installers/1033.mst differ diff --git a/playbook/shopfloor-setup/gea-shopfloor-keyence/vr5000/manifest.json b/playbook/shopfloor-setup/gea-shopfloor-keyence/vr5000/manifest.json new file mode 100644 index 0000000..109d7bb --- /dev/null +++ b/playbook/shopfloor-setup/gea-shopfloor-keyence/vr5000/manifest.json @@ -0,0 +1,17 @@ +{ + "Version": "1.0", + "_comment": "Keyence VR-5000 imaging-time manifest. Consumed by 09-Setup-Keyence.ps1 when keyence-model.txt = vr5000. USB drivers embedded in MSI (newer InstallShield). MSI references Data1.cab (702 MB) in installers/ - gitignored, stage from /home/camp/pxe-images/iso/keyence/Keyence-VR-5000-v3.3.1.iso. Verified silent install via msiexec on Win11 2026-05-18.", + "Applications": [ + { + "_comment": "VR-5000 Series Software v3.3.1 Nov 2018. ProductCode {AF7E8B93-DBEB-4DB1-91CB-4DA592D8E222}. Same bypass-bootstrapper pattern: call MSI directly skipping the InstallShield setup.exe (203 MB - prereq bundle we don't need).", + "Name": "VR-5000 Series Software", + "Installer": "installers\\VR-5000 Series Software.msi", + "Type": "MSI", + "InstallArgs": "/qn /norestart ALLUSERS=1 REBOOT=ReallySuppress TRANSFORMS=installers\\1033.mst", + "DetectionMethod": "Registry", + "DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{AF7E8B93-DBEB-4DB1-91CB-4DA592D8E222}", + "DetectionName": "DisplayVersion", + "DetectionValue": "3.3.1" + } + ] +} diff --git a/playbook/shopfloor-setup/gea-shopfloor-keyence/drivers/KEYENCE_VR_SERIES.cat b/playbook/shopfloor-setup/gea-shopfloor-keyence/vr6000/drivers/KEYENCE_VR_SERIES.cat similarity index 100% rename from playbook/shopfloor-setup/gea-shopfloor-keyence/drivers/KEYENCE_VR_SERIES.cat rename to playbook/shopfloor-setup/gea-shopfloor-keyence/vr6000/drivers/KEYENCE_VR_SERIES.cat diff --git a/playbook/shopfloor-setup/gea-shopfloor-keyence/drivers/amd64/WdfCoInstaller01009.dll b/playbook/shopfloor-setup/gea-shopfloor-keyence/vr6000/drivers/amd64/WdfCoInstaller01009.dll similarity index 100% rename from playbook/shopfloor-setup/gea-shopfloor-keyence/drivers/amd64/WdfCoInstaller01009.dll rename to playbook/shopfloor-setup/gea-shopfloor-keyence/vr6000/drivers/amd64/WdfCoInstaller01009.dll diff --git a/playbook/shopfloor-setup/gea-shopfloor-keyence/drivers/amd64/WinUsbCoinstaller2.dll b/playbook/shopfloor-setup/gea-shopfloor-keyence/vr6000/drivers/amd64/WinUsbCoinstaller2.dll similarity index 100% rename from playbook/shopfloor-setup/gea-shopfloor-keyence/drivers/amd64/WinUsbCoinstaller2.dll rename to playbook/shopfloor-setup/gea-shopfloor-keyence/vr6000/drivers/amd64/WinUsbCoinstaller2.dll diff --git a/playbook/shopfloor-setup/gea-shopfloor-keyence/drivers/keyence_vr_series.inf b/playbook/shopfloor-setup/gea-shopfloor-keyence/vr6000/drivers/keyence_vr_series.inf similarity index 100% rename from playbook/shopfloor-setup/gea-shopfloor-keyence/drivers/keyence_vr_series.inf rename to playbook/shopfloor-setup/gea-shopfloor-keyence/vr6000/drivers/keyence_vr_series.inf diff --git a/playbook/shopfloor-setup/gea-shopfloor-keyence/installers/VR-6000 Series Software.msi b/playbook/shopfloor-setup/gea-shopfloor-keyence/vr6000/installers/VR-6000 Series Software.msi similarity index 100% rename from playbook/shopfloor-setup/gea-shopfloor-keyence/installers/VR-6000 Series Software.msi rename to playbook/shopfloor-setup/gea-shopfloor-keyence/vr6000/installers/VR-6000 Series Software.msi diff --git a/playbook/shopfloor-setup/gea-shopfloor-keyence/keyence-manifest.json b/playbook/shopfloor-setup/gea-shopfloor-keyence/vr6000/manifest.json similarity index 100% rename from playbook/shopfloor-setup/gea-shopfloor-keyence/keyence-manifest.json rename to playbook/shopfloor-setup/gea-shopfloor-keyence/vr6000/manifest.json diff --git a/playbook/shopfloor-setup/gea-shopfloor-waxtrace/09-Setup-WaxAndTrace.ps1 b/playbook/shopfloor-setup/gea-shopfloor-waxtrace/09-Setup-WaxAndTrace.ps1 index 85daa86..8509cee 100644 --- a/playbook/shopfloor-setup/gea-shopfloor-waxtrace/09-Setup-WaxAndTrace.ps1 +++ b/playbook/shopfloor-setup/gea-shopfloor-waxtrace/09-Setup-WaxAndTrace.ps1 @@ -1,22 +1,217 @@ -# 09-Setup-WaxAndTrace.ps1 - Wax and Trace pc-type setup +# 09-Setup-WaxAndTrace.ps1 - Wax and Trace pc-type setup (Mitutoyo FormTracePak v6.0) # -# Currently OpenText-only (same as common). Wax-and-Trace-specific software -# will be added here when the application catalog is finalized. +# Imaging-time install. Mitutoyo's CD-ROM-bound VB6 wrapper (Setup.exe + +# appSetup.exe) is unreliable on Win11 and requires interactive clicks +# through model + cal + HASP dialogs. We bypass it entirely: prereqs install +# via manifest, FormTracePak itself is xcopy + reg-import from a master capture. +# +# Master capture was taken 2026-05-18 on a Win11 VM with both CV-3000/4000 +# series + SV-C3000/4000 series installed via Mount-DiskImage approach (see +# project-waxtrace-image.md). Covers all WJ wax/trace bays since both series +# end up sharing the same Program Files dir + reg. +# +# Layout at C:\WaxTrace-Install\ (xcopied by startnet.cmd): +# waxtrace-manifest.json +# 09-Setup-WaxAndTrace.ps1 (this file) +# prereqs\vcredist_x86.exe (VC++ 2008 x86) +# prereqs\vcredist_x64.exe (VC++ 2008 x64) +# prereqs\vc_redist.x86.exe (VC++ 2017 x86) +# prereqs\vc_redist.x64.exe (VC++ 2017 x64) +# prereqs\HASPUserSetup.exe (Sentinel Runtime / HASP dongle driver) +# captured\pf-x86-MitutoyoApp.zip (~108 MB compressed -> 675 MB) +# captured\c-MitutoyoApp.zip (data dir skeleton, mostly empty) +# captured\reg\hklm-wow-mitutoyo.reg.gz (gzipped, ~218 KB -> 5.4 MB) +# captured\arp-entries.json (informational - what to expect) +# calibrations\CAL-WJRP_serial-_probe-.iso (per-machine) +# +# Per-machine calibration is applied separately (mount cal ISO + run its +# Setup.exe), keyed by C:\Enrollment\machine-number.txt. +# +# Log: C:\Logs\WaxTrace\09-Setup-WaxAndTrace.log +# C:\Logs\WaxTrace\install.log (written by Install-FromManifest) -$lib = Join-Path $PSScriptRoot '..\Shopfloor\lib\Set-OpenTextAutoStart.ps1' +$ErrorActionPreference = 'Continue' -Write-Host '=== Wax and Trace Setup ===' +# Mirror the CMM pattern (09-Setup-CMM.ps1): the script itself lives in the +# shopfloor-setup tree (xcopied during WinPE), but the bulky bootstrap bundle +# (prereqs + captured master + cal ISOs) lives at C:\WaxTrace-Install\, put +# there by startnet.cmd from Y:\installers-post\waxtrace\ at imaging time. +$stagingRoot = 'C:\WaxTrace-Install' +$manifestPath = Join-Path $stagingRoot 'waxtrace-manifest.json' +$libSource = Join-Path $PSScriptRoot '..\common\lib\Install-FromManifest.ps1' + +$logDir = 'C:\Logs\WaxTrace' +$installLog = Join-Path $logDir 'install.log' +$transcriptLog = Join-Path $logDir '09-Setup-WaxAndTrace.log' + +if (-not (Test-Path $logDir)) { + New-Item -Path $logDir -ItemType Directory -Force | Out-Null +} + +try { Start-Transcript -Path $transcriptLog -Append -Force | Out-Null } catch {} + +function Write-WTLog { + param([string]$Message, [string]$Level = 'INFO') + $stamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" + Write-Host "[$stamp] [$Level] $Message" +} + +Write-WTLog "================================================================" +Write-WTLog "=== WaxTrace Setup (imaging-time) session start (PID $PID) ===" +Write-WTLog "Running as: $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name)" +Write-WTLog "Script root: $PSScriptRoot" +Write-WTLog "================================================================" + +# Status push - best-effort. $pxeStatusLib = Join-Path $PSScriptRoot '..\Shopfloor\lib\Send-PxeStatus.ps1' if (Test-Path $pxeStatusLib) { try { . $pxeStatusLib; Send-PxeStatus -Stage '09-Setup-WaxAndTrace: starting' -StageIndex 3 -StageTotal 8 } catch { } } -if (Test-Path -LiteralPath $lib) { - & $lib + +foreach ($file in @('pc-type.txt','machine-number.txt')) { + $path = "C:\Enrollment\$file" + if (Test-Path -LiteralPath $path) { + $content = (Get-Content -LiteralPath $path -First 1 -ErrorAction SilentlyContinue).Trim() + Write-WTLog " $file = $content" + } else { + Write-WTLog " $file = (not present)" + } +} + +# ============================================================================ +# Step 1: Prereqs via manifest (VC++ 2008 + 2017, HASP/Sentinel) +# ============================================================================ +if (-not (Test-Path $manifestPath)) { + Write-WTLog "waxtrace-manifest.json not found at $manifestPath" 'ERROR' +} elseif (-not (Test-Path $libSource)) { + Write-WTLog "Install-FromManifest.ps1 not found at $libSource" 'ERROR' } else { - Write-Warning "Set-OpenTextAutoStart.ps1 not found at $lib - OpenText auto-start NOT configured" + Write-WTLog "Running Install-FromManifest (InstallerRoot=$PSScriptRoot)" + & $libSource -ManifestPath $manifestPath -InstallerRoot $stagingRoot -LogFile $installLog + $rc = $LASTEXITCODE + Write-WTLog "Install-FromManifest returned $rc" } -# TODO: Wax and Trace-specific apps go here. + +# ============================================================================ +# Step 2: Replay FormTracePak install from master capture +# ============================================================================ +# Detection: skip if Formtracepak already present (re-run safe). +$ftpakExe = 'C:\Program Files (x86)\MitutoyoApp\Formtracepak\Formtracepak.exe' +if (Test-Path -LiteralPath $ftpakExe) { + Write-WTLog "Formtracepak.exe already present - skipping replay" +} else { + $pfZip = Join-Path $stagingRoot 'captured\pf-x86-MitutoyoApp.zip' + $maZip = Join-Path $stagingRoot 'captured\c-MitutoyoApp.zip' + $regGz = Join-Path $stagingRoot 'captured\reg\hklm-wow-mitutoyo.reg.gz' + + if (-not (Test-Path $pfZip)) { + Write-WTLog "Master capture pf-x86-MitutoyoApp.zip not found at $pfZip" 'ERROR' + } else { + $pfDest = 'C:\Program Files (x86)\MitutoyoApp' + Write-WTLog "Extracting $pfZip -> $pfDest" + try { + if (-not (Test-Path $pfDest)) { New-Item -Path $pfDest -ItemType Directory -Force | Out-Null } + Expand-Archive -Path $pfZip -DestinationPath $pfDest -Force + $count = (Get-ChildItem $pfDest -Recurse -File -ErrorAction SilentlyContinue).Count + Write-WTLog " extracted $count files" + } catch { + Write-WTLog " Expand-Archive failed: $_" 'ERROR' + } + } + + if (Test-Path $maZip) { + $maDest = 'C:\MitutoyoApp' + Write-WTLog "Extracting $maZip -> $maDest" + try { + if (-not (Test-Path $maDest)) { New-Item -Path $maDest -ItemType Directory -Force | Out-Null } + Expand-Archive -Path $maZip -DestinationPath $maDest -Force + } catch { + Write-WTLog " Expand-Archive failed: $_" 'WARN' + } + } + + if (Test-Path $regGz) { + $regOut = Join-Path $env:TEMP 'hklm-wow-mitutoyo.reg' + Write-WTLog "Decompressing $regGz -> $regOut" + try { + $inGz = [IO.File]::OpenRead($regGz) + $gz = New-Object IO.Compression.GZipStream($inGz, [IO.Compression.CompressionMode]::Decompress) + $out = [IO.File]::Create($regOut) + $gz.CopyTo($out) + $out.Close(); $gz.Close(); $inGz.Close() + Write-WTLog "Importing reg file via reg.exe /s" + & reg.exe import $regOut 2>&1 | ForEach-Object { Write-WTLog " reg: $_" } + Write-WTLog " reg import exit $LASTEXITCODE" + Remove-Item $regOut -Force -ErrorAction SilentlyContinue + } catch { + Write-WTLog " reg import failed: $_" 'ERROR' + } + } +} + +# ============================================================================ +# Step 3: Per-machine calibration ISO (mount + apply via cal Setup.exe) +# ============================================================================ +# Cal ISOs are keyed by asset_tag. Read machine-number.txt to pick the right +# ISO. Each cal ISO is ~1.7MB and contains a tiny Mitutoyo wrapper Setup.exe +# plus data/*.txt compensation tables for the bay's specific probe + serial. +$mnPath = 'C:\Enrollment\machine-number.txt' +$asset = $null +if (Test-Path -LiteralPath $mnPath) { + $asset = (Get-Content -LiteralPath $mnPath -First 1 -ErrorAction SilentlyContinue).Trim() +} +if (-not $asset) { + Write-WTLog "machine-number.txt missing or empty - skipping calibration apply" 'WARN' +} else { + $calDir = Join-Path $stagingRoot 'calibrations' + $candidate = Get-ChildItem $calDir -Filter "CAL-${asset}_*.iso" -ErrorAction SilentlyContinue | Select-Object -First 1 + if (-not $candidate) { + Write-WTLog "No cal ISO matched CAL-${asset}_*.iso in $calDir - skipping" 'WARN' + } else { + Write-WTLog "Mounting cal ISO: $($candidate.FullName)" + try { + $img = Mount-DiskImage -ImagePath $candidate.FullName -PassThru -ErrorAction Stop + Start-Sleep -Seconds 2 + $calDrive = ($img | Get-Volume).DriveLetter + Write-WTLog " mounted at ${calDrive}:" + $calSetup = "${calDrive}:\Setup.exe" + if (Test-Path -LiteralPath $calSetup) { + Write-WTLog " running cal Setup.exe (may prompt - VB6 wrapper, same vintage as main installer)" + # Cal ISO Setup.exe is tiny (135KB) - if it prompts, user has to click through. + # Acceptable today; future: dark-deploy the data/*.txt files directly into + # the FormTracePak data dir + skip Setup.exe. + $p = Start-Process -FilePath $calSetup -WorkingDirectory "${calDrive}:\" -Wait -PassThru + Write-WTLog " cal Setup.exe exit $($p.ExitCode)" + } else { + Write-WTLog " cal Setup.exe not found on ISO at $calSetup" 'WARN' + } + Dismount-DiskImage -ImagePath $candidate.FullName -ErrorAction SilentlyContinue | Out-Null + Write-WTLog " cal ISO dismounted" + } catch { + Write-WTLog " Mount-DiskImage failed: $_" 'ERROR' + } + } +} + +# ============================================================================ +# Step 4: OpenText auto-start at login (HostExplorer "WJ Shopfloor" session) +# ============================================================================ +$autoStartLib = Join-Path $PSScriptRoot '..\Shopfloor\lib\Set-OpenTextAutoStart.ps1' +if (Test-Path -LiteralPath $autoStartLib) { + Write-WTLog "Calling $autoStartLib" + & $autoStartLib +} else { + Write-WTLog "Set-OpenTextAutoStart.ps1 not found at $autoStartLib - OpenText auto-start NOT configured" 'WARN' +} + if (Get-Command Send-PxeStatus -ErrorAction SilentlyContinue) { - Send-PxeStatus -Stage '09-Setup-WaxAndTrace: complete' -StageIndex 4 -StageTotal 8 + $finalStatus = if ($rc -eq 0) { 'in_progress' } else { 'failed' } + $finalErr = if ($rc -ne 0) { "Install-FromManifest exit $rc" } else { '' } + Send-PxeStatus -Stage '09-Setup-WaxAndTrace: complete' -StageIndex 4 -StageTotal 8 -Status $finalStatus -Error_ $finalErr } -Write-Host '=== Wax and Trace Setup Complete ===' + +Write-WTLog "================================================================" +Write-WTLog "=== WaxTrace Setup session end ===" +Write-WTLog "================================================================" + +try { Stop-Transcript | Out-Null } catch {} diff --git a/playbook/shopfloor-setup/gea-shopfloor-waxtrace/captured/arp-entries.json b/playbook/shopfloor-setup/gea-shopfloor-waxtrace/captured/arp-entries.json new file mode 100644 index 0000000..af00f09 --- /dev/null +++ b/playbook/shopfloor-setup/gea-shopfloor-waxtrace/captured/arp-entries.json @@ -0,0 +1,98 @@ +[ + { + "DisplayName": "Formtracepak", + "DisplayVersion": null, + "Publisher": "Mitutoyo Corporation", + "PSPath": "Microsoft.PowerShell.Core\\Registry::HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Formtracepak" + }, + { + "DisplayName": "Microsoft Visual C++ 2017 x86 Additional Runtime - 14.15.26706", + "DisplayVersion": "14.15.26706", + "Publisher": "Microsoft Corporation", + "PSPath": "Microsoft.PowerShell.Core\\Registry::HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{2757496A-3E74-320A-B007-36120A9F126D}" + }, + { + "DisplayName": "Microsoft Visual C++ 2017 x86 Minimum Runtime - 14.15.26706", + "DisplayVersion": "14.15.26706", + "Publisher": "Microsoft Corporation", + "PSPath": "Microsoft.PowerShell.Core\\Registry::HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{39E15475-23F2-345D-8977-B5DC47A94E26}" + }, + { + "DisplayName": "Microsoft Visual C++ 2017 Redistributable (x86) - 14.15.26706", + "DisplayVersion": "14.15.26706.0", + "Publisher": "Microsoft Corporation", + "PSPath": "Microsoft.PowerShell.Core\\Registry::HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{7e9fae12-5bbf-47fb-b944-09c49e75c061}" + }, + { + "DisplayName": "Microsoft Visual C++ 2017 Redistributable (x64) - 14.15.26706", + "DisplayVersion": "14.15.26706.0", + "Publisher": "Microsoft Corporation", + "PSPath": "Microsoft.PowerShell.Core\\Registry::HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{95ac1cfa-f4fb-4d1b-8912-7f9d5fbb140d}" + }, + { + "DisplayName": "Microsoft Visual C++ 2008 Redistributable - x86 9.0.30729.17", + "DisplayVersion": "9.0.30729", + "Publisher": "Microsoft Corporation", + "PSPath": "Microsoft.PowerShell.Core\\Registry::HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{9A25302D-30C0-39D9-BD6F-21E6EC160475}" + }, + { + "DisplayName": "Sentinel Runtime", + "DisplayVersion": "7.92.28470.60000", + "Publisher": "Gemalto", + "PSPath": "Microsoft.PowerShell.Core\\Registry::HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{C8903CCB-67B6-4801-AA7B-B4E54E2B8406}" + }, + { + "DisplayName": "Windows Driver Package - Mitutoyo Corporation (WinUSB) USB (01/26/2014 1.0.0.0)", + "DisplayVersion": "01/26/2014 1.0.0.0", + "Publisher": "Mitutoyo Corporation", + "PSPath": "Microsoft.PowerShell.Core\\Registry::HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\0C2BF85342810B30769EBCA6B95E4E4BE156E077" + }, + { + "DisplayName": "Windows Driver Package - Mitutoyo Corporation (WinUSB) USB (03/26/2012 6.1.7600.16385)", + "DisplayVersion": "03/26/2012 6.1.7600.16385", + "Publisher": "Mitutoyo Corporation", + "PSPath": "Microsoft.PowerShell.Core\\Registry::HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\0D65E8F8146B3CCE8C4649A829EDCAFD02F3E6CF" + }, + { + "DisplayName": "Windows Driver Package - Mitutoyo Corporation (WinUSB) USB (01/01/2016 1.0.0.0)", + "DisplayVersion": "01/01/2016 1.0.0.0", + "Publisher": "Mitutoyo Corporation", + "PSPath": "Microsoft.PowerShell.Core\\Registry::HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\17940B80DB5791E80624748EB1CFB7CF28FA0BAE" + }, + { + "DisplayName": "Windows Driver Package - Mitutoyo Corporation (WinUSB) USB (01/26/2014 1.0.0.0)", + "DisplayVersion": "01/26/2014 1.0.0.0", + "Publisher": "Mitutoyo Corporation", + "PSPath": "Microsoft.PowerShell.Core\\Registry::HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\2B01E4170B345A54C5865F65CEA1BAFA50BB9C2C" + }, + { + "DisplayName": "Windows Driver Package - Mitutoyo Corporation (WinUSB) USB (01/26/2014 1.0.0.0)", + "DisplayVersion": "01/26/2014 1.0.0.0", + "Publisher": "Mitutoyo Corporation", + "PSPath": "Microsoft.PowerShell.Core\\Registry::HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\CB4E6EDB5EA0AB4F2E28F4C0CA4E0B09C7AE1F54" + }, + { + "DisplayName": "Windows Driver Package - Mitutoyo Corporation (WinUSB) USB (01/26/2014 1.0.0.0)", + "DisplayVersion": "01/26/2014 1.0.0.0", + "Publisher": "Mitutoyo Corporation", + "PSPath": "Microsoft.PowerShell.Core\\Registry::HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\F3159CAB242459F45CAF22F84A47213A0101C6CE" + }, + { + "DisplayName": "Microsoft Visual C++ 2008 Redistributable - x64 9.0.21022", + "DisplayVersion": "9.0.21022", + "Publisher": "Microsoft Corporation", + "PSPath": "Microsoft.PowerShell.Core\\Registry::HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{350AA351-21FA-3270-8B7A-835434E766AD}" + }, + { + "DisplayName": "Microsoft Visual C++ 2017 x64 Minimum Runtime - 14.15.26706", + "DisplayVersion": "14.15.26706", + "Publisher": "Microsoft Corporation", + "PSPath": "Microsoft.PowerShell.Core\\Registry::HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{C77195A4-CEB8-38EE-BDD6-C46CB459EF6E}" + }, + { + "DisplayName": "Microsoft Visual C++ 2017 x64 Additional Runtime - 14.15.26706", + "DisplayVersion": "14.15.26706", + "Publisher": "Microsoft Corporation", + "PSPath": "Microsoft.PowerShell.Core\\Registry::HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{F106B700-BFF8-3065-B305-14D36AD40539}" + } +] diff --git a/playbook/shopfloor-setup/gea-shopfloor-waxtrace/captured/arp-entries.xml b/playbook/shopfloor-setup/gea-shopfloor-waxtrace/captured/arp-entries.xml new file mode 100644 index 0000000..a5c7c95 Binary files /dev/null and b/playbook/shopfloor-setup/gea-shopfloor-waxtrace/captured/arp-entries.xml differ diff --git a/playbook/shopfloor-setup/gea-shopfloor-waxtrace/captured/capture.log b/playbook/shopfloor-setup/gea-shopfloor-waxtrace/captured/capture.log new file mode 100644 index 0000000..154d48a Binary files /dev/null and b/playbook/shopfloor-setup/gea-shopfloor-waxtrace/captured/capture.log differ diff --git a/playbook/shopfloor-setup/gea-shopfloor-waxtrace/captured/manifest.json b/playbook/shopfloor-setup/gea-shopfloor-waxtrace/captured/manifest.json new file mode 100644 index 0000000..c163d81 --- /dev/null +++ b/playbook/shopfloor-setup/gea-shopfloor-waxtrace/captured/manifest.json @@ -0,0 +1,9 @@ +{ + "Label": "combined", + "CapturedAt": "2026-05-18T05:20:48", + "PfX86Mb": 107.9, + "DataMb": 0, + "ArpCount": 16, + "SysFilesAdded": 0, + "HklmWowMitutoyoExists": true +} diff --git a/playbook/shopfloor-setup/gea-shopfloor-waxtrace/captured/pnputil-drivers.txt b/playbook/shopfloor-setup/gea-shopfloor-waxtrace/captured/pnputil-drivers.txt new file mode 100644 index 0000000..75f3119 --- /dev/null +++ b/playbook/shopfloor-setup/gea-shopfloor-waxtrace/captured/pnputil-drivers.txt @@ -0,0 +1,237 @@ +Microsoft PnP Utility + +Published Name: oem2.inf +Original Name: balloon.inf +Provider Name: Red Hat, Inc. +Class Name: System +Class GUID: {4d36e97d-e325-11ce-bfc1-08002be10318} +Driver Version: 07/09/2025 100.101.104.28500 +Signer Name: Microsoft Windows Hardware Compatibility Publisher +Attributes: Universal + Attested +WHCP Version: Unknown + +Published Name: oem3.inf +Original Name: fwcfg.inf +Provider Name: Red Hat, Inc. +Class Name: System +Class GUID: {4d36e97d-e325-11ce-bfc1-08002be10318} +Driver Version: 07/09/2025 100.101.104.28500 +Signer Name: Microsoft Windows Hardware Compatibility Publisher +Attributes: Universal + Attested +WHCP Version: Unknown + +Published Name: oem5.inf +Original Name: pvpanic.inf +Provider Name: Red Hat, Inc. +Class Name: System +Class GUID: {4d36e97d-e325-11ce-bfc1-08002be10318} +Driver Version: 07/09/2025 100.101.104.28500 +Signer Name: Microsoft Windows Hardware Compatibility Publisher +Attributes: Universal + Attested +WHCP Version: Unknown + +Published Name: oem7.inf +Original Name: viofs.inf +Provider Name: Red Hat, Inc. +Class Name: System +Class GUID: {4d36e97d-e325-11ce-bfc1-08002be10318} +Driver Version: 07/09/2025 100.101.104.28500 +Signer Name: Microsoft Windows Hardware Compatibility Publisher +Attributes: Universal + Attested +WHCP Version: Unknown + +Published Name: oem9.inf +Original Name: vioinput.inf +Provider Name: Red Hat, Inc. +Class Name: HIDClass +Class GUID: {745a17a0-74d3-11d0-b6fe-00a0c90f57da} +Driver Version: 07/09/2025 100.101.104.28500 +Signer Name: Microsoft Windows Hardware Compatibility Publisher +Attributes: Universal + Attested +WHCP Version: Unknown + +Published Name: oem11.inf +Original Name: viorng.inf +Provider Name: Red Hat, Inc. +Class Name: System +Class GUID: {4d36e97d-e325-11ce-bfc1-08002be10318} +Driver Version: 07/09/2025 100.101.104.28500 +Signer Name: Microsoft Windows Hardware Compatibility Publisher +Attributes: Universal + Attested +WHCP Version: Unknown + +Published Name: oem12.inf +Original Name: vioscsi.inf +Provider Name: Red Hat, Inc. +Class Name: SCSIAdapter +Class GUID: {4d36e97b-e325-11ce-bfc1-08002be10318} +Driver Version: 07/09/2025 100.101.104.28500 +Signer Name: Microsoft Windows Hardware Compatibility Publisher +Attributes: Universal + Attested +WHCP Version: Unknown + +Published Name: oem13.inf +Original Name: vioser.inf +Provider Name: Red Hat, Inc. +Class Name: System +Class GUID: {4d36e97d-e325-11ce-bfc1-08002be10318} +Driver Version: 07/09/2025 100.101.104.28500 +Signer Name: Microsoft Windows Hardware Compatibility Publisher +Attributes: Universal + Attested +WHCP Version: Unknown + +Published Name: oem14.inf +Original Name: viostor.inf +Provider Name: Red Hat, Inc. +Class Name: SCSIAdapter +Class GUID: {4d36e97b-e325-11ce-bfc1-08002be10318} +Driver Version: 07/09/2025 100.101.104.28500 +Signer Name: Microsoft Windows Hardware Compatibility Publisher +Attributes: Universal + Attested +WHCP Version: Unknown + +Published Name: oem8.inf +Original Name: cnc_comm.inf +Provider Name: Mitutoyo Corporation +Class Name: USB +Class GUID: {1c01d8a8-e874-42e2-8da3-25f5f61527d1} +Driver Version: 01/26/2014 1.0.0.0 +Signer Name: MITUTOYO CORPORATION +Attributes: Legacy +WHCP Version: Unknown + +Published Name: oem17.inf +Original Name: cps-476.inf +Provider Name: Mitutoyo Corporation +Class Name: USB +Class GUID: {a2e18d78-b77a-45af-bca9-2d7d3f27cf74} +Driver Version: 03/26/2012 6.1.7600.16385 +Signer Name: Mitutoyo Corporation +Attributes: Legacy +WHCP Version: Unknown + +Published Name: oem18.inf +Original Name: cs3200_comm.inf +Provider Name: Mitutoyo Corporation +Class Name: USB +Class GUID: {1c01d8a8-e874-42e2-8da3-25f5f61527d1} +Driver Version: 01/01/2016 1.0.0.0 +Signer Name: MITUTOYO CORPORATION +Attributes: Legacy +WHCP Version: Unknown + +Published Name: oem19.inf +Original Name: cv_1000_or_cv_2000.inf +Provider Name: Mitutoyo Corporation +Class Name: USB +Class GUID: {1c01d8a8-e874-42e2-8da3-25f5f61527d1} +Driver Version: 01/26/2014 1.0.0.0 +Signer Name: MITUTOYO CORPORATION +Attributes: Legacy +WHCP Version: Unknown + +Published Name: oem20.inf +Original Name: cv_2100.inf +Provider Name: Mitutoyo Corporation +Class Name: USB +Class GUID: {1c01d8a8-e874-42e2-8da3-25f5f61527d1} +Driver Version: 01/26/2014 1.0.0.0 +Signer Name: MITUTOYO CORPORATION +Attributes: Legacy +WHCP Version: Unknown + +Published Name: oem16.inf +Original Name: keyence_vr_series.inf +Provider Name: KEYENCE +Class Name: KeyenceUSB +Class GUID: {ee304f37-f588-45fc-91fe-b76873981ad1} +Driver Version: 03/26/2020 1.0.0.0 +Signer Name: Microsoft Windows Hardware Compatibility Publisher +Attributes: Declarative + Attested +WHCP Version: Unknown + +Published Name: oem4.inf +Original Name: netkvm.inf +Provider Name: Red Hat, Inc. +Class Name: Net +Class GUID: {4d36e972-e325-11ce-bfc1-08002be10318} +Driver Version: 07/09/2025 100.101.104.28500 +Signer Name: Microsoft Windows Hardware Compatibility Publisher +Attributes: Universal + Attested +WHCP Version: Unknown + +Published Name: oem0.inf +Original Name: prnms009.inf +Provider Name: Microsoft +Class Name: Printer +Class GUID: {4d36e979-e325-11ce-bfc1-08002be10318} +Class Version: 4.0 +Driver Version: 06/21/2006 10.0.26100.4484 +Signer Name: Microsoft Windows +Attributes: Legacy +WHCP Version: Unknown + +Published Name: oem6.inf +Original Name: qemupciserial.inf +Provider Name: QEMU +Class Name: MultiFunction +Class GUID: {4d36e971-e325-11ce-bfc1-08002be10318} +Driver Version: 05/21/2022 100.90.104.22100 +Signer Name: Microsoft Windows Hardware Compatibility Publisher +Attributes: Declarative + Attested +WHCP Version: Unknown + +Published Name: oem15.inf +Original Name: qxldod.inf +Provider Name: Red Hat, Inc. +Class Name: Display +Class GUID: {4d36e968-e325-11ce-bfc1-08002be10318} +Driver Version: 11/20/2020 10.0.0.21000 +Signer Name: Microsoft Windows Hardware Compatibility Publisher +Attributes: Universal +WHCP Version: Unknown + +Published Name: oem21.inf +Original Name: sj_comm.inf +Provider Name: Mitutoyo Corporation +Class Name: USB +Class GUID: {1c01d8a8-e874-42e2-8da3-25f5f61527d1} +Driver Version: 01/26/2014 1.0.0.0 +Signer Name: MITUTOYO CORPORATION +Attributes: Legacy +WHCP Version: Unknown + +Published Name: oem10.inf +Original Name: viomem.inf +Provider Name: Red Hat, Inc. +Class Name: MTD +Class GUID: {4d36e970-e325-11ce-bfc1-08002be10318} +Driver Version: 07/09/2025 100.101.104.28500 +Signer Name: Microsoft Windows Hardware Compatibility Publisher +Attributes: Universal + Attested +WHCP Version: Unknown + +Published Name: oem1.inf +Original Name: voiceclarityep_audio_component.inf +Provider Name: Microsoft Corporation +Class Name: AudioProcessingObject +Class GUID: {5989fce8-9cd0-467d-8a6a-5419e31529d4} +Driver Version: 03/31/2026 10.0.26100.6710 +Signer Name: Microsoft Windows Hardware Compatibility Publisher +Attributes: Universal +WHCP Version: Unknown + + diff --git a/playbook/shopfloor-setup/gea-shopfloor-waxtrace/captured/reg/hklm-wow-mitutoyo.reg.gz b/playbook/shopfloor-setup/gea-shopfloor-waxtrace/captured/reg/hklm-wow-mitutoyo.reg.gz new file mode 100644 index 0000000..76e76f4 Binary files /dev/null and b/playbook/shopfloor-setup/gea-shopfloor-waxtrace/captured/reg/hklm-wow-mitutoyo.reg.gz differ diff --git a/playbook/shopfloor-setup/gea-shopfloor-waxtrace/captured/sys-files-added.csv b/playbook/shopfloor-setup/gea-shopfloor-waxtrace/captured/sys-files-added.csv new file mode 100644 index 0000000..e69de29 diff --git a/playbook/shopfloor-setup/gea-shopfloor-waxtrace/waxtrace-manifest.json b/playbook/shopfloor-setup/gea-shopfloor-waxtrace/waxtrace-manifest.json new file mode 100644 index 0000000..81794fa --- /dev/null +++ b/playbook/shopfloor-setup/gea-shopfloor-waxtrace/waxtrace-manifest.json @@ -0,0 +1,61 @@ +{ + "Version": "2.0", + "_comment": "Wax/Trace (Mitutoyo FormTracePak v6.0) imaging-time prereq manifest. Consumed by 09-Setup-WaxAndTrace.ps1 reading from C:\\WaxTrace-Install\\. Covers BOTH CV-3000/4000 and SV-C3000/4000 series bays since the master install merges them. Does NOT run Mitutoyo's appSetup.exe / Setup.exe wrappers - those are CD-ROM-bound + dongle-gated + unreliable on Win11. The actual FormTracePak install replay (Program Files xcopy + HKLM reg import) is handled by 09-Setup-WaxAndTrace.ps1 directly, after this manifest installs the prereqs.", + "Applications": [ + { + "_comment": "Visual C++ 2008 x86 redist. Mitutoyo's vcredist_x86.exe (2008 SP1 vintage) at Lang\\English\\ on the FormTracePak ISO. /q is the 2005-era silent flag still supported by 2008 redist EXEs.", + "Name": "Microsoft Visual C++ 2008 Redistributable - x86", + "Installer": "prereqs\\vcredist_x86.exe", + "Type": "EXE", + "InstallArgs": "/q", + "DetectionMethod": "Registry", + "DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{9BE518E6-ECC6-35A9-88E4-87755C07200F}", + "DetectionName": "DisplayVersion", + "DetectionValue": "9.0.30729" + }, + { + "_comment": "Visual C++ 2008 x64 redist.", + "Name": "Microsoft Visual C++ 2008 Redistributable - x64", + "Installer": "prereqs\\vcredist_x64.exe", + "Type": "EXE", + "InstallArgs": "/q", + "DetectionMethod": "Registry", + "DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{8220EEFE-38CD-377E-8595-13398D740ACE}", + "DetectionName": "DisplayVersion", + "DetectionValue": "9.0.21022" + }, + { + "_comment": "Visual C++ 2017 x86 redist (14.15.26706 = VS2017 Update 7 era). Mitutoyo's vc_redist.x86.exe at Lang\\English\\ on the FormTracePak ISO. Uses VS2015+ universal redist installer flag set.", + "Name": "Microsoft Visual C++ 2017 Redistributable (x86)", + "Installer": "prereqs\\vc_redist.x86.exe", + "Type": "EXE", + "InstallArgs": "/quiet /norestart", + "DetectionMethod": "Registry", + "DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\VisualStudio\\14.0\\VC\\Runtimes\\x86", + "DetectionName": "Version", + "DetectionValue": "v14.15.26706" + }, + { + "_comment": "Visual C++ 2017 x64 redist.", + "Name": "Microsoft Visual C++ 2017 Redistributable (x64)", + "Installer": "prereqs\\vc_redist.x64.exe", + "Type": "EXE", + "InstallArgs": "/quiet /norestart", + "DetectionMethod": "Registry", + "DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\VisualStudio\\14.0\\VC\\Runtimes\\x64", + "DetectionName": "Version", + "DetectionValue": "v14.15.26706" + }, + { + "_comment": "Sentinel Runtime / HASP USB dongle driver from Gemalto (now Thales). Vintage 2019 InstallShield wrapper, classic InstallShield silent install via /s + nested /v args. FormTracePak licensing is dongle-bound; the runtime + drivers must be present before Formtracepak.exe will run. Tech inserts physical HASP USB dongle on the bay post-imaging to license.", + "Name": "Sentinel Runtime (HASP)", + "Installer": "prereqs\\HASPUserSetup.exe", + "Type": "EXE", + "InstallArgs": "/s /v/qn /v/norestart", + "DetectionMethod": "Registry", + "DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{C8903CCB-67B6-4801-AA7B-B4E54E2B8406}", + "DetectionName": "DisplayVersion", + "DetectionValue": "7.92.28470.60000" + } + ] +} diff --git a/playbook/startnet.cmd b/playbook/startnet.cmd index fe93267..88f46d4 100644 --- a/playbook/startnet.cmd +++ b/playbook/startnet.cmd @@ -66,7 +66,7 @@ echo. echo 1. Machine with Collections (eDNC + UDC + Plant Apps) echo 2. Machine without Collections (eDNC + Plant Apps, no UDC) echo 3. Common (Timeclock, Lab; WJ Shopfloor only) -echo 4. Keyence (VR-6000 microscope/profilometer) +echo 4. Keyence (VR-3000 / VR-5000 / VR-6000 microscope) echo 5. CMM (Hexagon PC-DMIS + Protect Viewer) echo 6. Genspect echo 7. Heattreat (placeholder) @@ -86,6 +86,27 @@ if "%ges_choice%"=="8" set PCTYPE=gea-shopfloor-waxtrace if "%ges_choice%"=="9" set PCTYPE=gea-shopfloor-display if "%PCTYPE%"=="" goto gea_shopfloor_submenu if "%PCTYPE%"=="gea-shopfloor-display" goto display_submenu +if "%PCTYPE%"=="gea-shopfloor-keyence" goto keyence_submenu +goto enroll_menu + +:keyence_submenu +cls +echo. +echo ======================================== +echo Keyence Model +echo ======================================== +echo. +echo 1. VR-3000 G2 (older microscope/profilometer line) +echo 2. VR-5000 (mid-range) +echo 3. VR-6000 (current line) +echo. +set KEYENCEMODEL= +set /p kmod_choice=Enter your choice (1-3): +if "%kmod_choice%"=="1" set KEYENCEMODEL=vr3000 +if "%kmod_choice%"=="2" set KEYENCEMODEL=vr5000 +if "%kmod_choice%"=="3" set KEYENCEMODEL=vr6000 +if "%KEYENCEMODEL%"=="" goto keyence_submenu +echo Keyence model: %KEYENCEMODEL% goto enroll_menu :display_submenu @@ -150,16 +171,32 @@ REM vs Dashboard to choose installer + Get-PCProfile builds Display-{type} REM profile key. set PCSUBTYPE= -REM --- Machine number (collections + nocollections only; other variants don't use one) --- +REM --- Machine number / asset tag (only PC types that key per-machine config) --- +REM collections + nocollections = 4-digit machine number for shopfloor identification. +REM waxtrace = asset tag like WJRP2335 used to match per-machine cal ISO during +REM 09-Setup-WaxAndTrace.ps1. Cal ISO files are named +REM CAL-{asset_tag}_serial-*_probe-*.iso. set MACHINENUM=9999 if /i "%PCTYPE%"=="gea-shopfloor-collections" goto prompt_machinenum if /i "%PCTYPE%"=="gea-shopfloor-nocollections" goto prompt_machinenum +if /i "%PCTYPE%"=="gea-shopfloor-waxtrace" goto prompt_waxtrace_asset goto skip_machinenum :prompt_machinenum echo. set /p MACHINENUM=Enter machine number (digits, or Enter for 9999): if "%MACHINENUM%"=="" set MACHINENUM=9999 echo Machine number: %MACHINENUM% +goto skip_machinenum +:prompt_waxtrace_asset +echo. +echo Wax/Trace bays use the asset tag (e.g. WJRP2335) to pick the right +echo calibration ISO during shopfloor setup. +set /p MACHINENUM=Enter asset tag (e.g. WJRP2335): +if "%MACHINENUM%"=="" ( + echo WARNING: no asset tag entered - calibration apply will be skipped. + set MACHINENUM= +) +echo Asset tag: %MACHINENUM% :skip_machinenum REM --- Map enrollment share early (kept open for copy after imaging) --- @@ -311,6 +348,13 @@ REM Install-KioskApp.cmd reads it to pick Lobby vs Dashboard installer REM and Get-PCProfile.ps1 reads it to build the Display-{type} profile key. if not "%DISPLAYTYPE%"=="" echo %DISPLAYTYPE%> W:\Enrollment\display-type.txt if not "%MACHINENUM%"=="" echo %MACHINENUM%> W:\Enrollment\machine-number.txt +REM Keyence model goes to BOTH keyence-model.txt (read by 09-Setup-Keyence) AND +REM pc-subtype.txt (read by GE-Enforce for per-model dispatch via existing +REM PCSubType wiring: looks for gea-shopfloor-keyence-\manifest.json on share). +if not "%KEYENCEMODEL%"=="" ( + echo %KEYENCEMODEL%> W:\Enrollment\keyence-model.txt + echo %KEYENCEMODEL%> W:\Enrollment\pc-subtype.txt +) copy /Y "Y:\shopfloor-setup\Run-ShopfloorSetup.ps1" "W:\Enrollment\Run-ShopfloorSetup.ps1" REM --- Always copy Shopfloor baseline scripts --- mkdir W:\Enrollment\shopfloor-setup 2>NUL @@ -377,6 +421,41 @@ if exist "Y:\installers-post\cmm\cmm-manifest.json" ( echo WARNING: Y:\cmm-installers not found - CMM PC cannot install Hexagon apps at imaging time. ) :skip_cmm_stage + +REM --- Stage Keyence per-model bootstrap bundle (Keyence PCs only) --- +REM Copies only the selected model's MSI + Data cabs from the PXE enrollment +REM share to the target disk. installers-post/keyence// contains: +REM manifest.json +REM installers/{MSI, Data1.cab, [Data11.cab for vr3000], 1033.mst} +REM drivers/ (vr6000 only - older external .inf; vr3000/vr5000 drivers +REM are embedded in their MSIs) +REM 09-Setup-Keyence.ps1 reads C:\Enrollment\keyence-model.txt to know which. +if /i not "%PCTYPE%"=="gea-shopfloor-keyence" goto skip_keyence_stage +if "%KEYENCEMODEL%"=="" goto skip_keyence_stage +if exist "Y:\installers-post\keyence\%KEYENCEMODEL%\manifest.json" ( + mkdir W:\KeyenceInstall 2>NUL + mkdir W:\KeyenceInstall\%KEYENCEMODEL% 2>NUL + xcopy /E /Y /I "Y:\installers-post\keyence\%KEYENCEMODEL%" "W:\KeyenceInstall\%KEYENCEMODEL%\" + echo Staged Keyence %KEYENCEMODEL% bootstrap to W:\KeyenceInstall\%KEYENCEMODEL%\. +) else ( + echo WARNING: Y:\installers-post\keyence\%KEYENCEMODEL% not found - Keyence %KEYENCEMODEL% cannot install at imaging time. +) +:skip_keyence_stage + +REM --- Stage WaxTrace bootstrap bundle (wax/trace gea-shopfloor-waxtrace only) --- +REM Copies the FormTracePak master capture (~110 MB compressed) + HASP + +REM VC++ redists + per-machine cal ISOs from the enrollment share onto the +REM target disk so 09-Setup-WaxAndTrace.ps1 can install FormTracePak via +REM xcopy + reg-import (bypassing Mitutoyo's CD-ROM-bound VB6 wrapper). +if /i not "%PCTYPE%"=="gea-shopfloor-waxtrace" goto skip_waxtrace_stage +if exist "Y:\installers-post\waxtrace\waxtrace-manifest.json" ( + mkdir W:\WaxTrace-Install 2>NUL + xcopy /E /Y /I "Y:\installers-post\waxtrace" "W:\WaxTrace-Install\" + echo Staged WaxTrace bootstrap to W:\WaxTrace-Install. +) else ( + echo WARNING: Y:\installers-post\waxtrace not found - WaxTrace PC cannot install FormTracePak at imaging time. +) +:skip_waxtrace_stage :pctype_done REM --- BIOS update sub-stage push (fires AFTER W: copies complete) --- diff --git a/playbook/sync-keyence.sh b/playbook/sync-keyence.sh new file mode 100755 index 0000000..3dda97d --- /dev/null +++ b/playbook/sync-keyence.sh @@ -0,0 +1,86 @@ +#!/bin/bash +# sync-keyence.sh - Push Keyence per-model bootstrap bundles to the PXE share. +# +# Mirrors sync-waxtrace.sh / sync-cmm.sh pattern. For each Keyence model +# (vr3000, vr5000, vr6000) ships the manifest + installer payload (MSI + cabs +# + drivers) from the local workstation to +# /srv/samba/enrollment/installers-post/keyence// on the PXE server. +# +# This becomes visible as \\172.16.9.1\enrollment\installers-post\keyence\ +# so startnet.cmd can selectively xcopy the chosen model bundle onto the +# target disk during WinPE phase (W:\KeyenceInstall, becomes C:\KeyenceInstall +# post-reboot). +# +# Run on the workstation any time: +# - A per-model manifest changes +# - Big installer payloads (Data1.cab, etc) change +# +# Big payloads (Data1.cab, Data11.cab, MSIs) live in the repo under +# playbook/shopfloor-setup/gea-shopfloor-keyence//installers/ but +# are gitignored. Stage them locally from the ripped ISOs in +# /home/camp/pxe-images/iso/keyence/ before running this script. +# +# Requires: sshpass, scp, ssh + +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}" + +KEYENCE_DIR="$PROJECT_ROOT/playbook/shopfloor-setup/gea-shopfloor-keyence" +REMOTE_DIR="/srv/samba/enrollment/installers-post/keyence" +REMOTE_TEMP="/tmp/keyence-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 +for f in 09-Setup-Keyence.ps1 vr3000/manifest.json vr5000/manifest.json vr6000/manifest.json; do + test -f "$KEYENCE_DIR/$f" || { echo "Missing $KEYENCE_DIR/$f"; exit 1; } +done + +echo "==> Staging tree locally" +STAGE="$(mktemp -d -p /tmp keyence-stage.XXXXXX)" +trap "rm -rf $STAGE" EXIT + +for model in vr3000 vr5000 vr6000; do + mkdir -p "$STAGE/$model/installers" + cp "$KEYENCE_DIR/$model/manifest.json" "$STAGE/$model/" + if [ -d "$KEYENCE_DIR/$model/installers" ]; then + cp -a "$KEYENCE_DIR/$model/installers/." "$STAGE/$model/installers/" 2>/dev/null || true + fi + if [ -d "$KEYENCE_DIR/$model/drivers" ]; then + mkdir -p "$STAGE/$model/drivers" + cp -a "$KEYENCE_DIR/$model/drivers/." "$STAGE/$model/drivers/" + fi + sz=$(du -sh "$STAGE/$model" | cut -f1) + echo " $model: $sz" +done + +echo "==> Local stage size: $(du -sh $STAGE | cut -f1)" + +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 Keyence PC picks up the new bundles." diff --git a/playbook/sync-waxtrace.sh b/playbook/sync-waxtrace.sh new file mode 100755 index 0000000..f8426eb --- /dev/null +++ b/playbook/sync-waxtrace.sh @@ -0,0 +1,95 @@ +#!/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 +# - The captured master is rebuilt (captured-binary/ + captured/) +# - A new cal ISO is added under /home/camp/pxe-images/iso/mitutoyo-cal/ +# - Prereqs are updated +# +# 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" || { echo "Missing $WAXTRACE_DIR/captured-binary (run capture-ftpak.ps1 first)"; exit 1; } +test -f "$WAXTRACE_DIR/captured-binary/pf-x86-MitutoyoApp.zip" || { echo "Missing master capture zip"; exit 1; } +test -d "$WAXTRACE_DIR/captured-binary/prereqs" || { echo "Missing prereqs dir"; exit 1; } + +echo "==> Staging tree locally" +STAGE="$(mktemp -d -p /tmp waxtrace-stage.XXXXXX)" +trap "rm -rf $STAGE" EXIT + +mkdir -p "$STAGE/captured/reg" "$STAGE/prereqs" "$STAGE/calibrations" +cp "$WAXTRACE_DIR/waxtrace-manifest.json" "$STAGE/" +cp "$WAXTRACE_DIR/09-Setup-WaxAndTrace.ps1" "$STAGE/" +cp -r "$WAXTRACE_DIR/captured/." "$STAGE/captured/" +cp "$WAXTRACE_DIR/captured-binary/pf-x86-MitutoyoApp.zip" "$STAGE/captured/" +cp "$WAXTRACE_DIR/captured-binary/hklm-wow-mitutoyo.reg" "$STAGE/captured/reg/" 2>/dev/null || true +cp "$WAXTRACE_DIR/captured-binary/c-MitutoyoApp.zip" "$STAGE/captured/" 2>/dev/null || true +cp "$WAXTRACE_DIR/captured-binary/prereqs/"*.exe "$STAGE/prereqs/" + +# 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 + +echo "==> Local stage size: $(du -sh $STAGE | cut -f1)" +ls "$STAGE/" +ls "$STAGE/captured/" +ls "$STAGE/prereqs/" +ls "$STAGE/calibrations/" 2>/dev/null || echo "(no cal ISOs)" + +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."