collections: add eDNC detection diagnostic scripts
This commit is contained in:
@@ -0,0 +1,35 @@
|
|||||||
|
@echo off
|
||||||
|
REM ==========================================================================
|
||||||
|
REM Diagnose-eDNCDetection.bat - diagnose the eDNC 6.4.5 enforce loop (MSI
|
||||||
|
REM 1603 "same or newer already installed" every 5 minutes).
|
||||||
|
REM
|
||||||
|
REM Usage (run on the problem PC):
|
||||||
|
REM Diagnose-eDNCDetection.bat auto-find manifest (W: or UNC)
|
||||||
|
REM Diagnose-eDNCDetection.bat /manifest <path> explicit manifest.json path
|
||||||
|
REM
|
||||||
|
REM Read-only: no installs, no share writes.
|
||||||
|
REM ==========================================================================
|
||||||
|
setlocal EnableDelayedExpansion
|
||||||
|
|
||||||
|
REM --- self-elevate ---
|
||||||
|
net session >nul 2>&1
|
||||||
|
if %errorlevel% neq 0 (
|
||||||
|
echo Requesting administrator elevation...
|
||||||
|
powershell -NoProfile -Command "Start-Process -Verb RunAs -FilePath '%~f0' -ArgumentList '%*'"
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
|
||||||
|
set "PS=%~dp0Diagnose-eDNCDetection.ps1"
|
||||||
|
set "ARGS="
|
||||||
|
|
||||||
|
:parse
|
||||||
|
if "%~1"=="" goto run
|
||||||
|
if /I "%~1"=="/manifest" set "ARGS=!ARGS! -ManifestPath '%~2'" & shift & shift & goto parse
|
||||||
|
shift
|
||||||
|
goto parse
|
||||||
|
|
||||||
|
:run
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%PS%" !ARGS!
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
|
endlocal
|
||||||
@@ -0,0 +1,232 @@
|
|||||||
|
<#
|
||||||
|
Diagnose-eDNCDetection.ps1
|
||||||
|
|
||||||
|
One-shot diagnosis of the eDNC 6.4.5 enforce loop: GE-Enforce re-runs
|
||||||
|
eDNC_6-4-5.msi every 5 minutes, the MSI aborts 1603 with "The same or newer
|
||||||
|
version of this software is already installed", and InUseCheck kills DncMain
|
||||||
|
in the process. Root cause is the manifest entry's Detection* fields not
|
||||||
|
matching what is actually installed.
|
||||||
|
|
||||||
|
Runs the whole triage and prints a verdict:
|
||||||
|
|
||||||
|
1. Installed state - DncMain.exe / NTLARS.exe file versions, x86+x64
|
||||||
|
uninstall registry entries for eDNC (DisplayVersion,
|
||||||
|
ProductCode).
|
||||||
|
2. Manifest entry - the live "eDNC (bundles NTLARS)" entry from the SFLD
|
||||||
|
share manifest (uses W: if enforce has it mounted,
|
||||||
|
else direct UNC, else -ManifestPath).
|
||||||
|
3. Comparison - replays Install-FromManifest's Test-AppInstalled
|
||||||
|
logic against the entry and says WHY it misses.
|
||||||
|
4. Verdict - suggested corrected manifest JSON.
|
||||||
|
|
||||||
|
Read-only: no installs, no share writes. Run as administrator on the
|
||||||
|
problem PC (registry + share read).
|
||||||
|
|
||||||
|
Params:
|
||||||
|
-ManifestPath explicit path to the collections manifest.json (skips
|
||||||
|
W:/UNC auto-discovery)
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[string]$ManifestPath
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = 'Continue'
|
||||||
|
function Section($t){ Write-Host ''; Write-Host ("==== {0} ====" -f $t) -ForegroundColor Cyan }
|
||||||
|
function KV($k,$v){ Write-Host (" {0,-24}: {1}" -f $k, $v) }
|
||||||
|
|
||||||
|
Write-Host '########################################################'
|
||||||
|
Write-Host '# eDNC Detection Loop Diagnosis'
|
||||||
|
Write-Host ("# {0} host {1}" -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), [System.Environment]::MachineName)
|
||||||
|
Write-Host '########################################################'
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# 1. Installed state
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
Section '1. Installed eDNC state on this PC'
|
||||||
|
|
||||||
|
$dncMain = 'C:\Program Files (x86)\Dnc\bin\DncMain.exe'
|
||||||
|
$ntlars = 'C:\Program Files (x86)\Dnc\Common\NTLARS.exe'
|
||||||
|
$dncMainVer = ''
|
||||||
|
$ntlarsVer = ''
|
||||||
|
|
||||||
|
if (Test-Path $dncMain) {
|
||||||
|
$dncMainVer = (Get-Item $dncMain).VersionInfo.FileVersion
|
||||||
|
KV 'DncMain.exe' ("present, FileVersion {0}" -f $dncMainVer)
|
||||||
|
} else {
|
||||||
|
KV 'DncMain.exe' 'MISSING'
|
||||||
|
}
|
||||||
|
if (Test-Path $ntlars) {
|
||||||
|
$ntlarsVer = (Get-Item $ntlars).VersionInfo.FileVersion
|
||||||
|
KV 'NTLARS.exe' ("present, FileVersion {0}" -f $ntlarsVer)
|
||||||
|
} else {
|
||||||
|
KV 'NTLARS.exe' 'MISSING'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Uninstall entries - both registry views. Win32_Product deliberately avoided
|
||||||
|
# (it triggers MSI self-repair on enumeration).
|
||||||
|
$uninstallRoots = @(
|
||||||
|
'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*',
|
||||||
|
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*'
|
||||||
|
)
|
||||||
|
$edncProducts = @()
|
||||||
|
foreach ($root in $uninstallRoots) {
|
||||||
|
$edncProducts += Get-ItemProperty -Path $root -ErrorAction SilentlyContinue |
|
||||||
|
Where-Object { $_.DisplayName -like '*eDNC*' -or $_.DisplayName -like '*DNC*Client*' }
|
||||||
|
}
|
||||||
|
if ($edncProducts) {
|
||||||
|
foreach ($p in $edncProducts) {
|
||||||
|
Write-Host ''
|
||||||
|
KV 'DisplayName' $p.DisplayName
|
||||||
|
KV 'DisplayVersion' $p.DisplayVersion
|
||||||
|
KV 'ProductCode' $p.PSChildName
|
||||||
|
KV 'InstallDate' $p.InstallDate
|
||||||
|
KV 'RegistryView' ($(if ($p.PSPath -like '*WOW6432Node*') { 'x86 (WOW6432Node)' } else { 'x64' }))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Host ' No eDNC uninstall entry found in either registry view.' -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# 2. Manifest entry from the share
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
Section '2. Manifest entry (share)'
|
||||||
|
|
||||||
|
$candidates = @()
|
||||||
|
if ($ManifestPath) { $candidates += $ManifestPath }
|
||||||
|
$candidates += 'W:\gea-shopfloor-collections\manifest.json'
|
||||||
|
$candidates += '\\tsgwp00525.wjs.geaerospace.net\shared\dt\shopfloor\gea-shopfloor-collections\manifest.json'
|
||||||
|
|
||||||
|
$manifestFile = $null
|
||||||
|
foreach ($c in $candidates) {
|
||||||
|
if (Test-Path $c) { $manifestFile = $c; break }
|
||||||
|
}
|
||||||
|
|
||||||
|
$entry = $null
|
||||||
|
if ($manifestFile) {
|
||||||
|
KV 'Manifest' $manifestFile
|
||||||
|
try {
|
||||||
|
$manifest = Get-Content -LiteralPath $manifestFile -Raw | ConvertFrom-Json
|
||||||
|
$entry = $manifest.Applications | Where-Object { $_.Name -like 'eDNC*' } | Select-Object -First 1
|
||||||
|
} catch {
|
||||||
|
Write-Host (" Failed to parse manifest: {0}" -f $_) -ForegroundColor Red
|
||||||
|
}
|
||||||
|
if ($entry) {
|
||||||
|
KV 'Name' $entry.Name
|
||||||
|
KV 'Installer' $entry.Installer
|
||||||
|
KV 'Type' $entry.Type
|
||||||
|
KV 'InstallArgs' $entry.InstallArgs
|
||||||
|
KV 'DetectionMethod' $entry.DetectionMethod
|
||||||
|
KV 'DetectionPath' $entry.DetectionPath
|
||||||
|
KV 'DetectionName' $entry.DetectionName
|
||||||
|
KV 'DetectionValue' $entry.DetectionValue
|
||||||
|
} else {
|
||||||
|
Write-Host ' No eDNC* entry found in manifest Applications.' -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Host ' Manifest not reachable (no W: mount, UNC denied).' -ForegroundColor Yellow
|
||||||
|
Write-Host ' Re-run with -ManifestPath, or run while GE-Enforce has W: mounted.'
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# 3. Replay Test-AppInstalled against the entry
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
Section '3. Detection replay'
|
||||||
|
|
||||||
|
$detected = $null
|
||||||
|
$missReason = ''
|
||||||
|
if ($entry) {
|
||||||
|
switch ($entry.DetectionMethod) {
|
||||||
|
'File' {
|
||||||
|
$detected = Test-Path $entry.DetectionPath
|
||||||
|
if (-not $detected) { $missReason = "DetectionPath does not exist: $($entry.DetectionPath)" }
|
||||||
|
}
|
||||||
|
'FileVersion' {
|
||||||
|
if (-not (Test-Path $entry.DetectionPath)) {
|
||||||
|
$detected = $false
|
||||||
|
$missReason = "DetectionPath does not exist: $($entry.DetectionPath)"
|
||||||
|
} elseif (-not $entry.DetectionValue) {
|
||||||
|
$detected = $false
|
||||||
|
$missReason = 'FileVersion detection with no DetectionValue always misses'
|
||||||
|
} else {
|
||||||
|
$actual = (Get-Item $entry.DetectionPath -ErrorAction SilentlyContinue).VersionInfo.FileVersion
|
||||||
|
$detected = ($actual -eq $entry.DetectionValue)
|
||||||
|
if (-not $detected) {
|
||||||
|
$missReason = "exact-match compare failed: actual '$actual' vs DetectionValue '$($entry.DetectionValue)'"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'Registry' {
|
||||||
|
if (-not (Test-Path $entry.DetectionPath)) {
|
||||||
|
$detected = $false
|
||||||
|
$missReason = "registry key does not exist: $($entry.DetectionPath) (eDNC uninstall key path varies across 6.x releases)"
|
||||||
|
} elseif ($entry.DetectionName) {
|
||||||
|
$v = Get-ItemProperty -Path $entry.DetectionPath -Name $entry.DetectionName -ErrorAction SilentlyContinue
|
||||||
|
if (-not $v) {
|
||||||
|
$detected = $false
|
||||||
|
$missReason = "value '$($entry.DetectionName)' missing under $($entry.DetectionPath)"
|
||||||
|
} elseif ($entry.DetectionValue) {
|
||||||
|
$actual = $v.$($entry.DetectionName)
|
||||||
|
$detected = ("$actual" -eq "$($entry.DetectionValue)")
|
||||||
|
if (-not $detected) {
|
||||||
|
$missReason = "exact-match compare failed: actual '$actual' vs DetectionValue '$($entry.DetectionValue)'"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$detected = $true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$detected = $true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default {
|
||||||
|
$missReason = "detection method '$($entry.DetectionMethod)' not replayed by this script"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($null -ne $detected) {
|
||||||
|
KV 'Test-AppInstalled' ($(if ($detected) { 'TRUE (would skip install)' } else { 'FALSE (re-runs MSI every cycle)' }))
|
||||||
|
if ($missReason) { KV 'Miss reason' $missReason }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Host ' Skipped - no manifest entry available to replay.'
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# 4. Verdict
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
Section '4. Verdict'
|
||||||
|
|
||||||
|
$edncInstalled = ($edncProducts.Count -gt 0) -or (Test-Path $dncMain)
|
||||||
|
|
||||||
|
if (-not $edncInstalled) {
|
||||||
|
Write-Host ' eDNC does NOT appear installed. The 1603 "same or newer" abort'
|
||||||
|
Write-Host ' then points at a stale MSI registration; check the upgrade-code'
|
||||||
|
Write-Host ' products under HKLM:\SOFTWARE\Classes\Installer\UpgradeCodes.'
|
||||||
|
} elseif ($detected -eq $true) {
|
||||||
|
Write-Host ' Detection passes now. If enforce still loops, the manifest on the'
|
||||||
|
Write-Host ' share differs from the one inspected here - confirm the path.'
|
||||||
|
} else {
|
||||||
|
Write-Host ' eDNC IS installed but the manifest entry does not detect it, so'
|
||||||
|
Write-Host ' GE-Enforce re-runs the MSI every cycle and the MSI aborts 1603'
|
||||||
|
Write-Host ' ("same or newer already installed"). Fix the manifest entry on'
|
||||||
|
Write-Host ' the share. Suggested replacement (File detection on NTLARS.exe,'
|
||||||
|
Write-Host ' same approach as the working 6.4.3 machineapps entry):'
|
||||||
|
Write-Host ''
|
||||||
|
$suggested = [ordered]@{
|
||||||
|
Name = 'eDNC (bundles NTLARS)'
|
||||||
|
Installer = 'apps\eDNC_6-4-5.msi'
|
||||||
|
Type = 'MSI'
|
||||||
|
InstallArgs = '/qn /norestart ALLUSERS=1 REBOOT=ReallySuppress SITESELECTED="West Jefferson"'
|
||||||
|
DetectionMethod = 'File'
|
||||||
|
DetectionPath = 'C:\Program Files (x86)\Dnc\Common\NTLARS.exe'
|
||||||
|
} | ConvertTo-Json
|
||||||
|
Write-Host $suggested
|
||||||
|
Write-Host ''
|
||||||
|
if ($edncProducts) {
|
||||||
|
$dv = ($edncProducts | Select-Object -First 1).DisplayVersion
|
||||||
|
Write-Host (" Alternative: keep Registry detection but set DetectionValue to the")
|
||||||
|
Write-Host (" actual installed DisplayVersion: '{0}'" -f $dv)
|
||||||
|
}
|
||||||
|
Write-Host ' Until the manifest is fixed, every enforce cycle also risks killing'
|
||||||
|
Write-Host ' a live DncMain session (InUseCheck force-kill before the doomed MSI).'
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ''
|
||||||
Reference in New Issue
Block a user