Recognition edit hid the time fields (grouped with Recertification), so start/end could not be adjusted even though the backend honors them. Show the time fields for every type except Recertification (due-date driven); Recognition end still auto-fills to the next 8 AM reset when blank. Also GE-Enforce B2 client (HTTPS payload consume): ShopdbEnforceClient.psm1 gains Get-ShopdbPayload (fetch by sha256, verify, cache) + Resolve-ShopdbPayloads (rewrite http/inline entries to local staged files so the engine installs from local, no SMB); Invoke-ShopdbEnforce resolves payloads before running the engine; importer parses PayloadSource/PayloadSha256/PayloadRef. VM-verified: a SYSTEM Windows client fetched a payload over HTTP by hash, hash matched.
115 lines
4.9 KiB
PowerShell
115 lines
4.9 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Reference orchestrator: source a GE-Enforce manifest from shopdb, run the
|
|
UNCHANGED engine against it, and report the result back to shopdb.
|
|
|
|
This is a thin wrapper around Install-FromManifest.ps1 (the engine). It is a
|
|
reference a site adapts into its GE-Enforce.ps1 flow; it is not the live
|
|
dispatcher. The engine, detection, self-heal, and SMB payload resolution are
|
|
untouched - only the source of the manifest JSON moves from a share file to
|
|
shopdb, plus a result report.
|
|
|
|
.PARAMETER Scope
|
|
The imaging pc-type / scope name (e.g. gea-shopfloor-cmm), same value the
|
|
dispatcher already resolves from C:\Enrollment\pc-type.txt.
|
|
|
|
.PARAMETER EnginePath
|
|
Path to Install-FromManifest.ps1 (the engine lib, >= 2.6).
|
|
|
|
.PARAMETER ShareManifestPath
|
|
The current on-share manifest for this scope. In shadow mode the engine runs
|
|
against THIS (unchanged behavior) and shopdb is only compared + reported. Once
|
|
cut over, omit it and the engine runs against the shopdb-sourced manifest.
|
|
|
|
.PARAMETER ShadowMode
|
|
Fetch + compare + report, but install from the share (no behavior change).
|
|
|
|
.NOTES
|
|
Fail-safe: any error exits 0 so a bad web app never blocks or breaks a PC.
|
|
Config comes from HKLM:\SOFTWARE\GE\ShopDB (BaseUrl, ApiToken) - see the psm1.
|
|
#>
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory)] [string]$Scope,
|
|
[Parameter(Mandatory)] [string]$EnginePath,
|
|
[string]$ShareManifestPath,
|
|
[switch]$ShadowMode,
|
|
[string]$BaseUrl,
|
|
[string]$ApiToken,
|
|
[string]$LogFile = "C:\Logs\Shopfloor\shopdb-enforce-$(Get-Date -Format yyyyMMdd).log"
|
|
)
|
|
|
|
function Write-Log {
|
|
param([string]$Message, [string]$Level = 'INFO')
|
|
$line = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [$Level] $Message"
|
|
try { Add-Content -LiteralPath $LogFile -Value $line -ErrorAction SilentlyContinue } catch {}
|
|
Write-Host $line
|
|
}
|
|
|
|
try {
|
|
Import-Module (Join-Path $PSScriptRoot 'ShopdbEnforceClient.psm1') -Force
|
|
|
|
$config = Get-ShopdbConfig -BaseUrl $BaseUrl -ApiToken $ApiToken
|
|
if (-not $config) {
|
|
Write-Log 'No shopdb BaseUrl/ApiToken configured yet - retry next cycle.' 'WARN'
|
|
exit 0
|
|
}
|
|
|
|
$sync = Sync-ShopdbManifest -Scope $Scope -Config $config
|
|
if (-not $sync.Path) {
|
|
Write-Log "No manifest available for $Scope (shopdb unreachable, no cache)." 'WARN'
|
|
exit 0
|
|
}
|
|
Write-Log "Manifest for $Scope from $($sync.Source) (v$($sync.Version))."
|
|
|
|
# Shadow mode: compare shopdb vs the share, but install from the share.
|
|
if ($ShadowMode -and $ShareManifestPath -and (Test-Path $ShareManifestPath)) {
|
|
$diff = Compare-ShopdbShadow -ShopdbManifestPath $sync.Path -ShareManifestPath $ShareManifestPath
|
|
if ($diff.Same) {
|
|
Write-Log 'Shadow: shopdb manifest matches the share.'
|
|
} else {
|
|
Write-Log ("Shadow DIFF: shopdb-only=[{0}] share-only=[{1}] orderDiff={2}" -f `
|
|
($diff.ShopdbOnly -join ','), ($diff.ShareOnly -join ','), $diff.OrderDiff) 'WARN'
|
|
}
|
|
}
|
|
|
|
# Which manifest the engine actually runs against.
|
|
if ($ShadowMode -and $ShareManifestPath) {
|
|
# Shadow: install from the share exactly as today (no payload resolve).
|
|
$manifestToRun = $ShareManifestPath
|
|
} else {
|
|
# Cutover: stage any http/inline payloads to local files and rewrite the
|
|
# manifest to point at them, so the UNCHANGED engine installs from local
|
|
# (no SMB needed for share-less PCs).
|
|
$manifestToRun = Resolve-ShopdbPayloads -ManifestPath $sync.Path -Config $config
|
|
if ($manifestToRun -ne $sync.Path) {
|
|
Write-Log "Resolved http/inline payloads to local files: $manifestToRun"
|
|
}
|
|
}
|
|
|
|
# --- INTEGRATION POINT ---------------------------------------------------
|
|
# Run the engine. Install-FromManifest.ps1 is expected to return (or you
|
|
# adapt it to return) a summary carrying Installed/Skipped/Failed/Filtered
|
|
# and a Results list of @{Name;Action;SelfHealed;ExitCode;Message}. Wire this
|
|
# to your engine's actual return/parse; the shape below is the contract.
|
|
Write-Log "Running engine against $manifestToRun"
|
|
$summary = & $EnginePath -ManifestPath $manifestToRun -PCType $Scope
|
|
if (-not $summary) {
|
|
$summary = @{ Installed = 0; Skipped = 0; Failed = 0; Filtered = 0; Results = @() }
|
|
}
|
|
if (-not $summary.EnforcerVersion) { $summary.EnforcerVersion = '2.6' }
|
|
|
|
# Report the result (best-effort).
|
|
$appliedVersion = 0
|
|
if ($sync.Version) { [int]::TryParse($sync.Version, [ref]$appliedVersion) | Out-Null }
|
|
$report = New-ShopdbReport -Scope $Scope -AppliedVersion $appliedVersion -Summary $summary
|
|
if (Send-ShopdbReport -Config $config -Report $report) {
|
|
Write-Log "Reported: installed=$($summary.Installed) skipped=$($summary.Skipped) failed=$($summary.Failed)."
|
|
} else {
|
|
Write-Log 'Report POST failed (non-fatal).' 'WARN'
|
|
}
|
|
} catch {
|
|
Write-Log "Unhandled error (non-fatal): $($_.Exception.Message)" 'ERROR'
|
|
}
|
|
exit 0
|