Files
pxe-server/playbook/shopfloor-setup/gea-shopfloor-collections/Debug-ShopDBReporting.ps1
cproudlock e97e5bd049 shopfloor: CMM PC-DMIS version gate, ShopDB reporter fixes, staging self-heal
- lib Install-FromManifest 2.5->2.6: add _CmmVersion per-entry filter (reads
  C:\Enrollment\cmm\version.txt). Lifted the version gate out of 09-Setup-CMM
  into the shared lib so imaging and GE-Enforce apply it identically and cannot
  drift (root cause of PC-DMIS 2016 installing on every CMM).
- Install-goCMMSettings: canonicalize the part-group share host to the FQDN in
  both the registry and ApplicationSettings.xml. Handles bare \\tsgwp00525\ and
  the legacy rd.ds.ge.com domain; idempotent. VM-tested.
- Report-AssetToShopDB: resolve the machine number eDNC registry first, then fall
  back to C:\Enrollment\machine-number.txt (matches the lib resolution order) so
  a freshly imaged PC still reports its number for the PC-machine relationship.
- Add Update-CMMEnforcer.ps1/.bat: update one CMM's local lib to the gated
  version and self-heal its PC-DMIS version.
- Add Debug-ShopDBReporting.ps1/.bat: one-shot reporter triage (preconditions,
  client log, live test POST, verdict).
- Add Verify-And-Heal-Staging.ps1/.bat: post-boot check that every imaging
  payload arrived and re-pull anything missing from the share, including the CMM
  bundle and the selected bay's backup (the payload that times out in WinPE).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 09:14:54 -04:00

200 lines
9.3 KiB
PowerShell

<#
Debug-ShopDBReporting.ps1
One-shot diagnosis of why a shopfloor PC is not updating its ShopDB entry through
api.asp (action=updateCompleteAsset). Runs the whole triage and prints a verdict:
1. Preconditions - hostname, BIOS serial (api.asp requires it), eDNC MachineNo
(the PC->machine relationship needs it).
2. Client log - the latest C:\Logs\Shopfloor\report-asset-*.log POST/RESPONSE.
3. Live test POST - calls api.asp updateCompleteAsset and parses the JSON.
4. Verdict - likely cause + fix.
NOTE: the live POST WRITES to ShopDB (it is the real reporter action - an idempotent
upsert of this PC's row, same as the scheduled reporter does). Use -NoPost to skip
it and only inspect the local log + registry.
Run as administrator on the problem PC.
Params:
-ApiUrl override the api.asp endpoint
-MachineNo override the machine number sent (default: read from eDNC registry)
-NoPost do not send the live test POST
#>
param(
[string]$ApiUrl = 'https://tsgwp00525.wjs.geaerospace.net/shopdb/api.asp',
[string]$MachineNo,
[int]$TimeoutSec = 30,
[switch]$NoPost
)
$ErrorActionPreference = 'Continue'
function Section($t){ Write-Host ''; Write-Host ("==== {0} ====" -f $t) -ForegroundColor Cyan }
function KV($k,$v){ Write-Host (" {0,-20}: {1}" -f $k, $v) }
Write-Host '########################################################'
Write-Host '# ShopDB Reporting Debug'
Write-Host ("# {0}" -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'))
Write-Host '########################################################'
# ---------------------------------------------------------------------------
# 1. Preconditions
# ---------------------------------------------------------------------------
Section '1. Preconditions'
$hostname = $env:COMPUTERNAME
$serial = ''
try { $serial = (Get-CimInstance Win32_BIOS -ErrorAction Stop).SerialNumber } catch {
try { $serial = (Get-WmiObject Win32_BIOS -ErrorAction Stop).SerialNumber } catch {}
}
$serial = ("" + $serial).Trim()
# Resolve machine number the same way the reporter / GE-Enforce lib do:
# eDNC registry (WOW6432Node then native) first, then C:\Enrollment\machine-number.txt.
$regMachineNo = ''
foreach ($rp in @('HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines\DNC\General',
'HKLM:\SOFTWARE\GE Aircraft Engines\DNC\General')) {
if ($regMachineNo) { break }
if (Test-Path $rp) {
try { $regMachineNo = ("" + (Get-ItemProperty -Path $rp -Name MachineNo -ErrorAction Stop).MachineNo).Trim() } catch {}
}
}
$txtMachineNo = ''
$mnFile = 'C:\Enrollment\machine-number.txt'
if (Test-Path -LiteralPath $mnFile) {
try { $txtMachineNo = ("" + (Get-Content -LiteralPath $mnFile -First 1 -ErrorAction Stop)).Trim() } catch {}
}
$machineNoSource = ''
if (-not $MachineNo) {
if ($regMachineNo) { $MachineNo = $regMachineNo; $machineNoSource = 'eDNC registry' }
elseif ($txtMachineNo) { $MachineNo = $txtMachineNo; $machineNoSource = 'machine-number.txt (fallback)' }
} else { $machineNoSource = 'override param' }
$corpIp = ''
try {
$corpIp = (Get-NetIPAddress -AddressFamily IPv4 -ErrorAction Stop |
Where-Object { $_.IPAddress -notmatch '^(127\.|169\.254\.)' } |
Select-Object -First 1).IPAddress
} catch {}
KV 'Hostname' $hostname
KV 'BIOS serial' ($(if ($serial) { $serial } else { '(MISSING - api.asp will reject)' }))
KV 'eDNC MachineNo (reg)' ($(if ($regMachineNo) { $regMachineNo } else { '(none)' }))
KV 'machine-number.txt' ($(if ($txtMachineNo) { $txtMachineNo } else { '(none)' }))
KV 'MachineNo to send' ($(if ($MachineNo) { "$MachineNo [from $machineNoSource]" } else { '(none - relationship will be skipped)' }))
KV 'Corp IPv4' ($(if ($corpIp) { $corpIp } else { '(none found)' }))
KV 'API endpoint' $ApiUrl
# ---------------------------------------------------------------------------
# 2. Latest client reporter log
# ---------------------------------------------------------------------------
Section '2. Latest client reporter log'
$logDir = 'C:\Logs\Shopfloor'
$log = $null
if (Test-Path $logDir) {
$log = Get-ChildItem -Path $logDir -Filter 'report-asset-*.log' -ErrorAction SilentlyContinue |
Sort-Object LastWriteTime | Select-Object -Last 1
}
if ($log) {
KV 'Log file' $log.FullName
KV 'Last written' $log.LastWriteTime
Write-Host ' --- last POST / RESPONSE / ERROR lines ---'
Get-Content $log.FullName -ErrorAction SilentlyContinue |
Select-String -Pattern 'POST |RESPONSE |ERROR ' |
Select-Object -Last 6 | ForEach-Object { Write-Host (" " + $_.Line) }
} else {
Write-Host ' No report-asset-*.log found. The reporter may never have run on this PC.'
Write-Host ' -> check the scheduled task / GE-Enforce entry that invokes Report-AssetToShopDB.ps1'
}
# ---------------------------------------------------------------------------
# 3. Live test POST
# ---------------------------------------------------------------------------
Section '3. Live test POST to api.asp'
$resp = $null; $postErr = $null; $rawText = $null
if ($NoPost) {
Write-Host ' -NoPost set: skipping the live POST.'
} elseif (-not $serial) {
Write-Host ' SKIPPED: no BIOS serial, api.asp requires serialNumber. Fix the hardware/WMI read first.'
} else {
# Accept the internal IIS certificate for this run (PS 5.1-safe).
try {
if (-not ([System.Management.Automation.PSTypeName]'TrustAllCerts').Type) {
Add-Type @"
using System.Net; using System.Security.Cryptography.X509Certificates;
public class TrustAllCerts : ICertificatePolicy {
public bool CheckValidationResult(ServicePoint sp, X509Certificate c, WebRequest r, int p) { return true; }
}
"@
}
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCerts
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
} catch {}
$body = @{
action = 'updateCompleteAsset'
hostname = $hostname
serialNumber = $serial
pcType = 'Shopfloor'
}
if ($MachineNo) { $body['machineNo'] = $MachineNo }
Write-Host (" POST host={0} serial={1} machineNo={2}" -f $hostname, $serial, $(if ($MachineNo) { $MachineNo } else { '(none)' }))
try {
$resp = Invoke-RestMethod -Uri $ApiUrl -Method Post -Body $body -TimeoutSec $TimeoutSec -ErrorAction Stop
Write-Host ' --- response JSON ---'
Write-Host (" " + ($resp | ConvertTo-Json -Compress -Depth 5))
} catch {
$postErr = $_.Exception.Message
Write-Host (" POST FAILED: {0}" -f $postErr) -ForegroundColor Red
try { $rawText = $_.Exception.Response } catch {}
}
}
# ---------------------------------------------------------------------------
# 4. Verdict
# ---------------------------------------------------------------------------
Section '4. VERDICT'
function Truthy($v){ return ($v -eq $true -or "$v" -eq 'True' -or "$v" -eq '1') }
if ($NoPost) {
Write-Host ' (live POST skipped) Inspect section 1-2 above.'
if (-not $MachineNo) { Write-Host ' NOTE: no machine number (eDNC registry and machine-number.txt both empty) -> no relationship until set.' -ForegroundColor Yellow }
}
elseif ($postErr) {
Write-Host ' CANNOT REACH api.asp - network, TLS, DNS, or IIS error.' -ForegroundColor Red
Write-Host (" Detail: {0}" -f $postErr)
Write-Host ' -> ping/curl the host, confirm IIS is up, check the cert and the /shopdb/ path.'
}
elseif (-not $serial) {
Write-Host ' BIOS SERIAL MISSING - api.asp rejects the POST (serialNumber required).' -ForegroundColor Red
Write-Host ' -> fix WMI/Win32_BIOS on this PC; it is a hardware/OS read issue, not ShopDB.'
}
elseif (-not (Truthy $resp.success)) {
Write-Host ' SERVER RETURNED success=false - it aborted at a DB step.' -ForegroundColor Red
Write-Host (" Breadcrumb/message: {0}" -f $resp.message)
Write-Host ' -> the LAST "N-OK," token in that message is where it stopped. Match N to api.asp.'
}
elseif (-not (Truthy $resp.relationshipCreated)) {
if (-not $MachineNo) {
Write-Host ' ASSET OK, but NO RELATIONSHIP because this PC has no machine number.' -ForegroundColor Yellow
Write-Host (" machineid={0}. Neither the eDNC registry nor C:\Enrollment\machine-number.txt" -f $resp.machineid)
Write-Host ' has a value, so api.asp skips the relationship by design.'
Write-Host ' -> set the bay machine number (Set-MachineNumber writes the eDNC registry), then'
Write-Host ' re-run. CMM/keyence/wax-trace bays have no DNC number and register asset-only.'
} else {
Write-Host ' ASSET OK, but RELATIONSHIP NOT CREATED even though MachineNo was sent.' -ForegroundColor Red
Write-Host (" machineid={0}, machineNo={1}." -f $resp.machineid, $MachineNo)
Write-Host ' -> this is the server-side silent abort (LogToFile Err-leak). Deploy the api.asp fix'
Write-Host ' (commit a4051e3) to prod IIS, then re-run. Also confirm the IIS logs dir is'
Write-Host ' writable by the app-pool identity (that is the trigger).'
}
}
else {
Write-Host ' HEALTHY.' -ForegroundColor Green
Write-Host (" Asset updated (machineid={0}) and PC->machine relationship created." -f $resp.machineid)
Write-Host ' If ShopDB still looks wrong, the issue is data/display, not the reporter path.'
}
Write-Host ''
Write-Host 'Done.'