geenforce: shadow runs inside the enforce cycle, not on its own clock
Test bays reported 0 installed / 0 skipped / 0 failed and nothing was being processed. The share is a TRANSIENT mount: GE-Enforce.ps1 maps it for the length of its cycle and unmounts at the end - mounted 12:10:02, unmounted 12:10:27 on FB9TP7V3. The shadow task ran on its own 15-minute schedule, so it woke with the drive gone, handed the engine a path that no longer resolved, and the summary zero-filled. A silent nothing, indistinguishable from a healthy no-op, which is why it read as "not processing" rather than as a failure. Register-ShopdbShadow.ps1 is replaced by Invoke-ShopdbShadow.ps1, which runs AS a manifest entry and invokes the runner directly. The share is mounted because the enforce cycle is what called us; there is one cadence instead of two; and there is no task to register, drift, or heal. It also unregisters the superseded task, so bays that already carry it clean themselves up rather than keeping a run that cannot see the share and overwrites the real result with 0/0/0. The runner gains the Test-Path guard that should have been there: an unreachable -ShareManifestPath now logs, writes an event, and reports a real failure naming the reason, instead of running the engine against nothing. That silent zero is what made this expensive to find. Verified on the win11 VM with a substituted drive removed between runs - the same call gives real counts while mapped and the guard when not. The earlier task self-heal is moot now; it was a fix at the wrong layer, and testing against a local path is what hid a mount I had already noted was dynamic.
This commit is contained in:
@@ -131,6 +131,29 @@ try {
|
||||
if ($ShadowMode -and $ShareManifestPath) {
|
||||
# Shadow: install from the share exactly as today (no payload resolve,
|
||||
# no common merge - the share already carries its own common scope).
|
||||
#
|
||||
# GUARDED, because the share is a TRANSIENT mount. GE-Enforce.ps1 maps it
|
||||
# for the length of its cycle and unmounts at the end, so a caller that
|
||||
# runs on its own schedule finds the drive gone. Handing the engine a
|
||||
# path on a dead drive returned nothing usable and the summary zero-filled
|
||||
# to 0 installed / 0 skipped / 0 failed - a silent nothing that reads
|
||||
# exactly like a healthy no-op. Shadow must run INSIDE the enforce cycle;
|
||||
# this makes the alternative loud instead of invisible.
|
||||
if (-not (Test-Path -LiteralPath $ShareManifestPath)) {
|
||||
$reason = "share manifest not reachable at $ShareManifestPath " +
|
||||
'(is the share still mounted? shadow must run inside the ' +
|
||||
'enforce cycle)'
|
||||
Write-Log $reason 'WARN'
|
||||
Write-ShopdbEventLog -Message ("GE-Enforce shadow could not reach the share manifest for scope '$Scope': $reason") -EntryType 'Error' -EventId 1002
|
||||
try {
|
||||
$failReport = New-ShopdbReport -Scope $Scope -AppliedVersion 0 -Summary @{
|
||||
Installed = 0; Skipped = 0; Failed = 1; Filtered = 0; EnforcerVersion = '2.6'
|
||||
Results = @(@{ Name = '(share-manifest)'; Action = 'failed'; Message = $reason })
|
||||
}
|
||||
Send-ShopdbReport -Config $config -Report $failReport | Out-Null
|
||||
} catch {}
|
||||
exit 0
|
||||
}
|
||||
$manifestToRun = $ShareManifestPath
|
||||
} else {
|
||||
# Optional common-scope inheritance (OFF by default; displays are
|
||||
|
||||
Reference in New Issue
Block a user