diff --git a/playbook/shopfloor-setup/CMM/lib/Install-FromManifest.ps1 b/playbook/shopfloor-setup/CMM/lib/Install-FromManifest.ps1 index b0c5280..86b3f07 100644 --- a/playbook/shopfloor-setup/CMM/lib/Install-FromManifest.ps1 +++ b/playbook/shopfloor-setup/CMM/lib/Install-FromManifest.ps1 @@ -123,6 +123,20 @@ function Test-AppInstalled { "File" { return Test-Path $App.DetectionPath } + "Hash" { + # Compare SHA256 of the on-disk file against the manifest's + # expected value. Used for content-versioned files that do not + # expose a DisplayVersion (secrets like eMxInfo.txt). Bumping + # DetectionValue in the manifest and replacing the file on the + # share is the entire update workflow. + if (-not (Test-Path $App.DetectionPath)) { return $false } + if (-not $App.DetectionValue) { + Write-InstallLog " Hash detection requires DetectionValue - treating as not installed" "WARN" + return $false + } + $actual = (Get-FileHash -Path $App.DetectionPath -Algorithm SHA256 -ErrorAction Stop).Hash + return ($actual -ieq $App.DetectionValue) + } default { Write-InstallLog " Unknown detection method: $($App.DetectionMethod)" "WARN" return $false diff --git a/playbook/shopfloor-setup/Standard/Install-eMxInfo.cmd.template b/playbook/shopfloor-setup/Standard/Install-eMxInfo.cmd.template new file mode 100644 index 0000000..bb44220 --- /dev/null +++ b/playbook/shopfloor-setup/Standard/Install-eMxInfo.cmd.template @@ -0,0 +1,19 @@ +@echo off +REM Install-eMxInfo.cmd - copy the site-specific eMxInfo.txt into both +REM Program Files eDNC paths. Run by Install-FromManifest.ps1 (Type=CMD) +REM when Hash detection on C:\Program Files\eDNC\eMxInfo.txt fails. + +set "SRC=%~dp0eMxInfo.txt" +if not exist "%SRC%" ( + echo Install-eMxInfo: source file not found at %SRC% + exit /b 1 +) + +if not exist "C:\Program Files\eDNC\" mkdir "C:\Program Files\eDNC\" 2>/dev/null +if not exist "C:\Program Files (x86)\eDNC\" mkdir "C:\Program Files (x86)\eDNC\" 2>/dev/null + +copy /Y "%SRC%" "C:\Program Files\eDNC\eMxInfo.txt" >/dev/null || exit /b 2 +copy /Y "%SRC%" "C:\Program Files (x86)\eDNC\eMxInfo.txt" >/dev/null || exit /b 3 + +echo Install-eMxInfo: deployed eMxInfo.txt to both eDNC paths +exit /b 0 diff --git a/playbook/shopfloor-setup/Standard/lib/Install-FromManifest.ps1 b/playbook/shopfloor-setup/Standard/lib/Install-FromManifest.ps1 index 256c530..5a3e8dd 100644 --- a/playbook/shopfloor-setup/Standard/lib/Install-FromManifest.ps1 +++ b/playbook/shopfloor-setup/Standard/lib/Install-FromManifest.ps1 @@ -111,6 +111,20 @@ function Test-AppInstalled { "File" { return Test-Path $App.DetectionPath } + "Hash" { + # Compare SHA256 of the on-disk file against the manifest's + # expected value. Used for content-versioned files that do not + # expose a DisplayVersion (secrets like eMxInfo.txt). Bumping + # DetectionValue in the manifest and replacing the file on the + # share is the entire update workflow. + if (-not (Test-Path $App.DetectionPath)) { return $false } + if (-not $App.DetectionValue) { + Write-InstallLog " Hash detection requires DetectionValue - treating as not installed" "WARN" + return $false + } + $actual = (Get-FileHash -Path $App.DetectionPath -Algorithm SHA256 -ErrorAction Stop).Hash + return ($actual -ieq $App.DetectionValue) + } default { Write-InstallLog " Unknown detection method: $($App.DetectionMethod)" "WARN" return $false diff --git a/playbook/shopfloor-setup/Standard/machineapps-manifest.template.json b/playbook/shopfloor-setup/Standard/machineapps-manifest.template.json index 178b28a..c7cdfe3 100644 --- a/playbook/shopfloor-setup/Standard/machineapps-manifest.template.json +++ b/playbook/shopfloor-setup/Standard/machineapps-manifest.template.json @@ -14,23 +14,22 @@ "DetectionValue": "REPLACE_WITH_PINNED_UDC_VERSION" }, { - "_comment": "eDNC 6.4.3. SITESELECTED is the property that encodes the site (was a recurring bug in early shopfloor-setup scripts that omitted it). Adjust to your site's value if not West Jefferson.", - "Name": "eDNC", + "_comment": "eDNC 6.4.3. Ships with NTLARS bundled (NTLARS.exe lands at C:\\Program Files (x86)\\Dnc\\Common\\ as part of the same install), so no separate NTLARS entry is needed. SITESELECTED encodes the site (was a recurring bug in early shopfloor-setup scripts that omitted it). Adjust to your site's value if not West Jefferson. Detection uses File on the NTLARS binary: catches the case where eDNC is installed but the sub-components we actually care about are missing. DisplayVersion detection via Registry would be tighter but the x86 uninstall key path for eDNC varies across 6.x releases.", + "Name": "eDNC (bundles NTLARS)", "Installer": "eDNC-6.4.3.msi", "Type": "MSI", "InstallArgs": "/qn /norestart ALLUSERS=1 REBOOT=ReallySuppress SITESELECTED=\"West Jefferson\"", - "DetectionMethod": "Registry", - "DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\GE Aircraft Engines\\DNC\\General", - "DetectionName": "MachineNo" - }, - { - "_comment": "NTLARS. Replace installer filename + args once we know what the vendor ships. Registry detection path guessed from the Defect_Tracker pattern; verify with a real install before relying on it.", - "Name": "NTLARS", - "Installer": "NTLARS_Setup.exe", - "Type": "EXE", - "InstallArgs": "/S", "DetectionMethod": "File", "DetectionPath": "C:\\Program Files (x86)\\Dnc\\Common\\NTLARS.exe" + }, + { + "_comment": "Custom eMxInfo.txt (site-specific eDNC config). No vendor installer - the secret file lives on the SFLD share alongside the eDNC MSI. Install-eMxInfo.cmd copies it to both 32-bit and 64-bit eDNC Program Files paths. Hash detection catches both 'file missing' and 'file is a stale version'. Yearly rotation procedure: drop the new eMxInfo.txt on the share, recompute its SHA256 (PowerShell: (Get-FileHash .\\eMxInfo.txt -Algorithm SHA256).Hash), paste the new hash into DetectionValue here, save. Every Machine PC catches up on the next user logon. Content-sensitive: eMxInfo.txt must NEVER be committed to git (already in .gitignore).", + "Name": "eMxInfo.txt", + "Installer": "Install-eMxInfo.cmd", + "Type": "CMD", + "DetectionMethod": "Hash", + "DetectionPath": "C:\\Program Files\\eDNC\\eMxInfo.txt", + "DetectionValue": "87733201CB11E7343BD432F1E303FBF41DB58EBAAEFF37BD4C3C9B267B145A20" } ] } diff --git a/playbook/shopfloor-setup/common/lib/Install-FromManifest.ps1 b/playbook/shopfloor-setup/common/lib/Install-FromManifest.ps1 index 256c530..5a3e8dd 100644 --- a/playbook/shopfloor-setup/common/lib/Install-FromManifest.ps1 +++ b/playbook/shopfloor-setup/common/lib/Install-FromManifest.ps1 @@ -111,6 +111,20 @@ function Test-AppInstalled { "File" { return Test-Path $App.DetectionPath } + "Hash" { + # Compare SHA256 of the on-disk file against the manifest's + # expected value. Used for content-versioned files that do not + # expose a DisplayVersion (secrets like eMxInfo.txt). Bumping + # DetectionValue in the manifest and replacing the file on the + # share is the entire update workflow. + if (-not (Test-Path $App.DetectionPath)) { return $false } + if (-not $App.DetectionValue) { + Write-InstallLog " Hash detection requires DetectionValue - treating as not installed" "WARN" + return $false + } + $actual = (Get-FileHash -Path $App.DetectionPath -Algorithm SHA256 -ErrorAction Stop).Hash + return ($actual -ieq $App.DetectionValue) + } default { Write-InstallLog " Unknown detection method: $($App.DetectionMethod)" "WARN" return $false