265 lines
9.5 KiB
PowerShell
265 lines
9.5 KiB
PowerShell
#requires -Version 5.1
|
|
<#
|
|
.SYNOPSIS
|
|
Seed HKLM:\SOFTWARE\GE\ShopDB\DeviceId from whatever identity a bay already
|
|
carries, so device identity can move off C:\Enrollment and into the
|
|
registry.
|
|
|
|
.DESCRIPTION
|
|
Phase 3 of docs/proposals/device-identity.md. The registry is the
|
|
destination because it survives the profile cleanup and disk hygiene that
|
|
eats C:\Enrollment, is readable as SYSTEM with no file ACL to get wrong, and
|
|
is already where the collector looks for BaseUrl and ApiToken.
|
|
|
|
This script does the one-time backfill: it reads the identity a bay holds
|
|
today and writes it to DeviceId. It is idempotent and safe to run every
|
|
GE-Enforce cycle.
|
|
|
|
THE SOURCE DEPENDS ON THE PC TYPE, AND THAT IS THE WHOLE POINT.
|
|
|
|
DeviceId names the DEVICE hanging off this PC. A machine number is a
|
|
different fact - "which bay is this" rather than "which device is this" -
|
|
and the two coincide for exactly one family:
|
|
|
|
CMM bays the machine number IS the instrument id (CMM4), which is
|
|
why cmmid.txt has always doubled as identity. Copying it
|
|
is correct.
|
|
|
|
part markers the machine number is the OPERATION (0613), and several
|
|
markers serve one operation. Copying it would name the
|
|
operation as the device. The collector refuses that
|
|
("asset X is not a Part Marker; not linked") because a
|
|
machine filed under a device label reads as a marker
|
|
everywhere downstream. So machine number is NEVER a
|
|
source here.
|
|
|
|
Keyence, no per-bay id exists at all. asset-id.txt is the only
|
|
Genspect, identity these have ever had.
|
|
wax-trace
|
|
|
|
everything not a device bay. DeviceId is not consumed for these
|
|
else pc-types, so writing one is a landmine for the day that
|
|
pc-type gains a device spec. Writes nothing.
|
|
|
|
9999 is the unassigned placeholder and is skipped everywhere, matching
|
|
Report-AssetToShopDB.ps1 and the server.
|
|
|
|
.PARAMETER Force
|
|
Overwrite a DeviceId that is already set to a DIFFERENT value.
|
|
|
|
Off by default on purpose. asset-id.txt is written ONCE at imaging and
|
|
nothing updates it when a device is swapped, so a stale file overwriting a
|
|
corrected registry value would re-introduce the exact defect this move is
|
|
meant to fix. A disagreement is reported and left alone for a human.
|
|
|
|
.PARAMETER PCType
|
|
Override the pc-type instead of reading C:\Enrollment\pc-type.txt. For
|
|
testing and for a bay whose file is missing.
|
|
|
|
.PARAMETER DeviceId
|
|
Write this value directly, skipping resolution. Still honours -Force and
|
|
the 9999 rule.
|
|
|
|
.PARAMETER LogPath
|
|
Append a transcript here as well as writing to the pipeline.
|
|
|
|
.EXAMPLE
|
|
.\Set-ShopDBDeviceId.ps1 -WhatIf
|
|
Show what would be written on this bay without touching the registry.
|
|
|
|
.EXAMPLE
|
|
.\Set-ShopDBDeviceId.ps1
|
|
Seed DeviceId. Safe to run repeatedly and from a GE-Enforce PS1 entry.
|
|
|
|
.NOTES
|
|
Exit codes:
|
|
0 wrote a value, it was already correct, or this is not a device bay
|
|
1 an error stopped the write
|
|
2 an existing DeviceId disagrees with the resolved value; needs a human
|
|
or -Force
|
|
#>
|
|
[CmdletBinding(SupportsShouldProcess = $true)]
|
|
param(
|
|
[switch]$Force,
|
|
[string]$PCType,
|
|
[string]$DeviceId,
|
|
[string]$LogPath
|
|
)
|
|
|
|
Set-StrictMode -Version Latest
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
$RegPath = 'HKLM:\SOFTWARE\GE\ShopDB'
|
|
$RegValueName = 'DeviceId'
|
|
$Placeholder = '9999'
|
|
|
|
function Log {
|
|
param([string]$Message)
|
|
$line = "{0} [Set-ShopDBDeviceId] {1}" -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $Message
|
|
Write-Output $line
|
|
if ($LogPath) {
|
|
try { Add-Content -LiteralPath $LogPath -Value $line -ErrorAction Stop } catch { }
|
|
}
|
|
}
|
|
|
|
function Read-FirstLine {
|
|
# One line, trimmed, empty when absent or unreadable. A bay missing a file
|
|
# is the normal case, not an error.
|
|
param([string]$Path)
|
|
if (-not (Test-Path -LiteralPath $Path)) { return '' }
|
|
try {
|
|
$v = [string](Get-Content -LiteralPath $Path -First 1 -ErrorAction Stop)
|
|
return $v.Trim()
|
|
} catch {
|
|
Log "WARN could not read ${Path}: $($_.Exception.Message)"
|
|
return ''
|
|
}
|
|
}
|
|
|
|
function Get-MachineNoFromRegistry {
|
|
# eDNC/NTLARS, WOW6432Node first, matching Report-AssetToShopDB.ps1.
|
|
foreach ($rp in @(
|
|
'HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines\DNC\General',
|
|
'HKLM:\SOFTWARE\GE Aircraft Engines\DNC\General'
|
|
)) {
|
|
try {
|
|
if (Test-Path $rp) {
|
|
$v = [string](Get-ItemProperty -Path $rp -Name MachineNo -ErrorAction Stop).MachineNo
|
|
if ($v) {
|
|
$v = $v.Trim()
|
|
if ($v -and $v -ne $Placeholder) { return $v }
|
|
}
|
|
}
|
|
} catch {
|
|
Log "WARN could not read MachineNo from ${rp}: $($_.Exception.Message)"
|
|
}
|
|
}
|
|
return ''
|
|
}
|
|
|
|
# Which pc-types drive a device, and whether the machine number is a legitimate
|
|
# identity for that device. Mirrors SUBORDINATE_DEVICE_MAP in
|
|
# plugins/computers/pctypemap.py. A site that added its own device pc-type
|
|
# through a subordinatedevice_<pctype> setting adds it here too.
|
|
$DeviceFamilies = @{
|
|
'gea-shopfloor-cmm' = @{ Label = 'CMM'; MachineNoIsDevice = $true }
|
|
'gea-shopfloor-keyence' = @{ Label = 'Vision System'; MachineNoIsDevice = $false }
|
|
'gea-shopfloor-genspect' = @{ Label = 'Genspect'; MachineNoIsDevice = $false }
|
|
'gea-shopfloor-waxtrace' = @{ Label = 'Form Tracer'; MachineNoIsDevice = $false }
|
|
'gea-shopfloor-partmarker'= @{ Label = 'Part Marker'; MachineNoIsDevice = $false }
|
|
}
|
|
|
|
# --- 1. what kind of bay is this -------------------------------------------
|
|
|
|
if (-not $PCType) { $PCType = Read-FirstLine 'C:\Enrollment\pc-type.txt' }
|
|
|
|
if (-not $PCType) {
|
|
Log 'no pc-type on this PC (C:\Enrollment\pc-type.txt missing or empty); nothing to do'
|
|
exit 0
|
|
}
|
|
|
|
if (-not $DeviceFamilies.ContainsKey($PCType)) {
|
|
Log "pc-type '$PCType' does not drive a device; DeviceId not written"
|
|
exit 0
|
|
}
|
|
|
|
$family = $DeviceFamilies[$PCType]
|
|
Log "pc-type '$PCType' drives a $($family.Label)"
|
|
|
|
# --- 2. resolve the identity ------------------------------------------------
|
|
|
|
$resolved = ''
|
|
$source = ''
|
|
|
|
if ($DeviceId) {
|
|
$resolved = $DeviceId.Trim()
|
|
$source = '-DeviceId parameter'
|
|
} else {
|
|
# Most stable identity first, and the machine number only where it really
|
|
# names the device.
|
|
if ($family.MachineNoIsDevice) {
|
|
$v = Read-FirstLine 'C:\Enrollment\cmm\cmmid.txt'
|
|
if ($v -and $v -ne $Placeholder) { $resolved = $v; $source = 'C:\Enrollment\cmm\cmmid.txt' }
|
|
|
|
if (-not $resolved) {
|
|
$v = Get-MachineNoFromRegistry
|
|
if ($v) { $resolved = $v; $source = 'eDNC MachineNo registry' }
|
|
}
|
|
}
|
|
|
|
if (-not $resolved) {
|
|
$v = Read-FirstLine 'C:\Enrollment\asset-id.txt'
|
|
if ($v -and $v -ne $Placeholder) { $resolved = $v; $source = 'C:\Enrollment\asset-id.txt' }
|
|
}
|
|
|
|
if (-not $resolved) {
|
|
# The 0.12.0 name, before the file was generalised.
|
|
$v = Read-FirstLine 'C:\Enrollment\measuringtool-id.txt'
|
|
if ($v -and $v -ne $Placeholder) { $resolved = $v; $source = 'C:\Enrollment\measuringtool-id.txt' }
|
|
}
|
|
}
|
|
|
|
if (-not $resolved) {
|
|
# Nothing to copy. Silence is the right answer: the collector still adopts
|
|
# or mints as it does today, and inventing a value here would name a device
|
|
# that nobody can account for.
|
|
Log "no identity found for this $($family.Label) bay; DeviceId not written"
|
|
exit 0
|
|
}
|
|
|
|
if ($resolved -eq $Placeholder) {
|
|
Log "resolved value is the $Placeholder placeholder; DeviceId not written"
|
|
exit 0
|
|
}
|
|
|
|
Log "resolved DeviceId '$resolved' from $source"
|
|
|
|
# --- 3. write it ------------------------------------------------------------
|
|
|
|
$existing = ''
|
|
try {
|
|
if (Test-Path $RegPath) {
|
|
$prop = Get-ItemProperty -Path $RegPath -Name $RegValueName -ErrorAction SilentlyContinue
|
|
if ($prop) { $existing = [string]$prop.$RegValueName; $existing = $existing.Trim() }
|
|
}
|
|
} catch {
|
|
Log "WARN could not read existing ${RegValueName}: $($_.Exception.Message)"
|
|
}
|
|
|
|
if ($existing -eq $resolved) {
|
|
Log "DeviceId already '$resolved'; nothing to do"
|
|
exit 0
|
|
}
|
|
|
|
if ($existing -and -not $Force) {
|
|
# The registry value wins by default. C:\Enrollment is written once at
|
|
# imaging and never updated on a device swap, so the file is the more
|
|
# likely one to be wrong.
|
|
Log "REFUSING to overwrite: DeviceId is '$existing', $source says '$resolved'"
|
|
Log 'Re-run with -Force if the file is right, or fix the file if the registry is.'
|
|
exit 2
|
|
}
|
|
|
|
try {
|
|
if (-not (Test-Path $RegPath)) {
|
|
if ($PSCmdlet.ShouldProcess($RegPath, 'Create registry key')) {
|
|
New-Item -Path $RegPath -Force | Out-Null
|
|
Log "created $RegPath"
|
|
}
|
|
}
|
|
$action = if ($existing) { "Set $RegValueName '$existing' -> '$resolved'" }
|
|
else { "Set $RegValueName '$resolved'" }
|
|
if ($PSCmdlet.ShouldProcess($RegPath, $action)) {
|
|
New-ItemProperty -Path $RegPath -Name $RegValueName -Value $resolved `
|
|
-PropertyType String -Force | Out-Null
|
|
Log "wrote $RegPath\$RegValueName = '$resolved'"
|
|
} else {
|
|
Log "WHATIF would write $RegPath\$RegValueName = '$resolved'"
|
|
}
|
|
} catch {
|
|
Log "ERROR could not write ${RegValueName}: $($_.Exception.Message)"
|
|
exit 1
|
|
}
|
|
|
|
exit 0
|