Identify a marker by its device, without moving what NTLARS reports
A part marker has no machine number of its own - the device is what a backup belongs to, and C:\Enrollment\asset-id.txt is what names it. Reading that file inside the shared machine-number lookup looked like the tidy place for it and was wrong: marker bays run eDNC too, so Backup-NtlarsSettings.ps1 reaches the same lookup, and it would have started posting a machine's DNC settings under the marker's asset number where today it exits quietly. The marker script asks for the fallback explicitly instead, which is what -MachineNumberFallback is for. Also from review: Returning a byte array bare lets the pipeline enumerate it, so an EMPTY file came back as $null, ComputeHash threw, and with ErrorActionPreference=Continue the manifest entry silently kept the previous file's hash - a corrupted manifest stored as a good revision. Empty parameter files are plausible. Reading registry values directly under StrictMode throws when one is absent, so the "no Port Id" guard was unreachable and a partially configured marker bay reported itself as having no marker at all, permanently and quietly. Values are now read through a presence check with the fleet's own defaults. The outside-window quiet state embedded the hour, so the say-once module said it hourly. Command replies now have their checksum verified like data blocks do, since a corrupted listing entry would otherwise be trusted and a file requested under a name the controller does not have. A controller that genuinely holds nothing is no longer reported as a failed capture. A snapshot that could not be written to the share now counts as a missed backup like the rest, and the header no longer claims orphaned snapshots get tidied - they are kept on purpose, because a timed-out post may still have been recorded.
This commit is contained in:
@@ -26,12 +26,18 @@
|
||||
# changed would look exactly like one whose backup died six months ago. So an
|
||||
# unchanged controller still posts, gets action=noop, and stays green.
|
||||
#
|
||||
# ORDER OF OPERATIONS - write to the share BEFORE posting, then clean up on a
|
||||
# no-op. A failed post then leaves a real directory the next run tidies, rather
|
||||
# ORDER OF OPERATIONS - write to the share BEFORE posting, then delete again on
|
||||
# a no-op. That way a failed post leaves a real snapshot on the share rather
|
||||
# than a database row pointing at a directory that was never created. Deleting
|
||||
# after a no-op is safe precisely because a no-op proves identical content
|
||||
# already exists in the previous snapshot.
|
||||
#
|
||||
# A snapshot whose POST failed is deliberately KEPT, and nothing tidies it
|
||||
# later. It cannot safely be deleted here: a client-side timeout does not mean
|
||||
# the server rejected it, so the revision may exist and point at this very
|
||||
# directory. An orphan directory costs a few hundred kilobytes; deleting a
|
||||
# snapshot ShopDB has recorded costs the backup itself.
|
||||
#
|
||||
# PORT CONTENTION IS THE MAIN HAZARD. MarkTelesis holds the serial port whenever
|
||||
# the marker is in service, and so does a tech running Backup470 by hand. This
|
||||
# never takes the port from either - it checks, skips the cycle, and says so
|
||||
@@ -206,7 +212,11 @@ if (-not $Force) {
|
||||
'WARNING: no successful capture in {0:N1} days ({1}). Every shift change has been busy - check whether the marker application is holding the port permanently.' -f
|
||||
$daysold, $(if (Test-Path $markerfile) { 'last attempt ' + $since.LastWriteTime.ToString('yyyy-MM-dd HH:mm') } else { 'never captured on this PC' }))
|
||||
} else {
|
||||
Write-ShopdbQuietState -Kind $KIND -State ('outside-window-{0}' -f $now.Hour) -Message (
|
||||
# State is the CONDITION, not the clock. Embedding the hour made
|
||||
# it "new" every hour, so the say-once module wrote the same line
|
||||
# ~20 times a day per bay - a small rerun of the 3,234-line log it
|
||||
# was built to stop.
|
||||
Write-ShopdbQuietState -Kind $KIND -State 'outside-window' -Message (
|
||||
'Outside the capture window ({0}). The marker port is shared with eDNC, so the daily capture waits for a shift change. Use -Force to override.' -f
|
||||
(($WindowHours | ForEach-Object { '{0:00}:00' -f $_ }) -join ', '))
|
||||
}
|
||||
@@ -239,8 +249,17 @@ try {
|
||||
exit 0
|
||||
}
|
||||
|
||||
# -MachineNumberFallback, not a shared default: a marker bay legitimately has
|
||||
# no machine number - the DEVICE is what the backup belongs to, and
|
||||
# asset-id.txt is what names it. Putting this in the shared lookup would change
|
||||
# what the NTLARS backup reports on these same bays, which run eDNC too.
|
||||
#
|
||||
# Safe on the wire: the part-marker kind resolves the reporting PC to its own
|
||||
# marker by hostname first, and falls back to matching this value against
|
||||
# assets.assetnumber - which is exactly what asset-id.txt holds.
|
||||
$ctx = Initialize-ShopdbBackup -Kind $KIND -Force:$Force `
|
||||
-BaseUrl $(if ($BaseUrl) { $BaseUrl } else { '' })
|
||||
-BaseUrl $(if ($BaseUrl) { $BaseUrl } else { '' }) `
|
||||
-MachineNumberFallback { Get-ShopdbAssetId }
|
||||
if (-not $ctx.Proceed) { exit 0 }
|
||||
|
||||
# --- Capture everything off the controller ----------------------------------
|
||||
@@ -307,7 +326,12 @@ try {
|
||||
if ($port -and $port.IsOpen) { $port.Close() }
|
||||
}
|
||||
|
||||
if ($null -eq $files -or $files.Count -eq 0) {
|
||||
# $null means the capture broke partway. An EMPTY hashtable means the capture
|
||||
# worked and the controller genuinely holds nothing - a factory-reset or
|
||||
# just-replaced unit. Treating those the same made a wiped controller log a
|
||||
# capture failure every window for ever, and escalate to the loud warning, when
|
||||
# in fact the backup was working perfectly and reporting the truth.
|
||||
if ($null -eq $files) {
|
||||
# A failed capture is a missed backup too, and it is the more worrying kind:
|
||||
# port contention resolves itself, a controller that will not answer does
|
||||
# not. Counted with its own reason so the two are distinguishable in the
|
||||
@@ -361,6 +385,10 @@ try {
|
||||
} | ConvertTo-Json -Depth 4 |
|
||||
Set-Content -LiteralPath (Join-Path $snapshotdir 'manifest.json') -Encoding UTF8
|
||||
} catch {
|
||||
# Counted like the others: a snapshot captured but not stored is just as
|
||||
# missed as one never captured, and share credentials failing on a bay is
|
||||
# exactly the kind of quiet breakage this count exists to surface.
|
||||
Add-ShopdbBackupSkip -Kind $KIND -Reason 'could not write to the share'
|
||||
Write-ShopdbBackupLog -Kind $KIND -Message "Could not write $snapshotdir : $_"
|
||||
exit 0
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user