Files
pxe-server/playbook/shopfloor-setup/Shopfloor/lib/Update-MachineNumber.ps1
cproudlock 0d9c4fdac4 Rename every copy of an MTConnect device name, not just the agent's
Set-MachineNumber rewrote one Devices.xml per variant and restarted the agent.
That is right for Okuma and eDNC, which keep the device name in that one file -
checked across 7 Okuma and 15 eDNC bay captures. Fanuc and Makino keep it in
several, and editing only the agent's copy leaves the adapter streaming under
the old identity.

It has already happened. Seven of thirty-four captured Fanuc bays have the
agent on the right machine number and the adapter still on the bay it was
imaged from: 4007 on a 7801 Toshulin, 3031 on a 7804, 2005 against 2006 on a
dual-spindle pair. Both captured Makino bays have Devices.xml on the machine
number and the other three files still on MAKINO-1.

Update-MTConnectVariantName renames across a declared set of files with the
owning services stopped first. Makino needs that ordering more than most: the
vendor's guide says the Adapter Manager rewrites the COMPLETE configuration
from memory as it stops, so an edit made while it runs is discarded, and that
the name must be identical in every file or the agent may not start.

It collects every name in play before rewriting rather than discovering one.
A bay half-renamed by the old code carries two at once, and converging on the
one that happened to be found leaves the other behind - which is the state this
is meant to end, not reproduce. Nothing is written if a service will not stop,
and whatever was stopped is started again.

Tested on Windows 11 against copies of the real captures: the 7801 bay (adapter
4007) converges to 7801 in two files and leaves the correct agent alone; the
7502 Makino bay converges all four; second runs report no changes. Service
ordering verified by process id, using stand-in services - sc.exe fakes named
after the real ones are not real services, so the service list is a parameter
defaulting to the production names.

Does not fix the bays already in this state; they need a run each.
2026-08-11 14:28:03 -04:00

532 lines
27 KiB
PowerShell

# Update-MachineNumber.ps1 - Shared helper for reading and updating the
# machine number in UDC and eDNC. Dot-source from any script that needs
# machine-number operations:
#
# . "$PSScriptRoot\lib\Update-MachineNumber.ps1" (from Shopfloor\ scripts)
# . "$PSScriptRoot\..\Shopfloor\lib\Update-MachineNumber.ps1" (from Standard\ scripts)
# . "$PSScriptRoot\Update-MachineNumber.ps1" (from lib\ scripts)
#
# Exported functions:
# Get-CurrentMachineNumber - returns @{ Udc = $string_or_null; Ednc = $string_or_null }
# Update-MachineNumber - updates both, returns @{ UdcUpdated = $bool; EdncUpdated = $bool; Errors = @() }
#
# Both handle missing files/keys gracefully (app not installed = skip, not error).
$script:UdcSettingsPath = 'C:\ProgramData\UDC\udc_settings.json'
$script:UdcExePath = 'C:\Program Files\UDC\UDC.exe'
$script:EdncRegPath = 'HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines\DNC\General'
function Get-CurrentMachineNumber {
<#
.SYNOPSIS
Reads the current machine number from UDC settings JSON and eDNC registry.
.OUTPUTS
Hashtable with keys Udc ($string or $null) and Ednc ($string or $null).
#>
$result = @{ Udc = $null; Ednc = $null }
if (Test-Path $script:UdcSettingsPath) {
try {
$json = Get-Content $script:UdcSettingsPath -Raw | ConvertFrom-Json
$result.Udc = $json.GeneralSettings.MachineNumber
} catch {}
}
if (Test-Path $script:EdncRegPath) {
try {
$result.Ednc = (Get-ItemProperty -Path $script:EdncRegPath -Name MachineNo -ErrorAction Stop).MachineNo
} catch {}
}
return $result
}
function Update-MTConnectVariantName {
<#
.SYNOPSIS
Renames an MTConnect device across every file of a variant that carries it.
.DESCRIPTION
Makino and Fanuc do not fit the one-file-one-service shape the other
variants do.
Per the vendor's "Installation Configuration and Trouble Shooting" guide,
the device name lives in several files that must be identical or the agent
may not start, and the Adapter Manager service rewrites the COMPLETE
configuration when it stops - so an edit made while it runs is thrown away.
Makino, from a real bay capture:
Agent\Devices.xml <Device name="7502" uuid="7502" id="MC41">
Agent\Devices.EDM.xml <Device name="MAKINO-1" uuid="MAKINO-1" id="EDM41">
Data\AdapterDataFile.xml <Name>MAKINO-1</Name>
Agent\Agent.cfg Adapters { MAKINO-1 { Host=localhost ... } }
Fanuc, likewise:
Agent\devices.xml <Device id="3101" name="3101" uuid="3101">
Adapter\devices.xml the adapter's own generated copy
Adapter\adapter.xml <DeviceName>/<DeviceID>/<DeviceUUID>3101
Editing only the agent's copy leaves the adapter streaming under the old
identity. Seven of thirty-four captured Fanuc bays are in that state -
agent on the right machine number, adapter still on the bay it was
imaged from (4007 on a 7801 Toshulin, 3031 on a 7804).
The vendor's own path is ConfigurationManager.exe, a GUI tool, which a
remote renumber cannot drive. This does what it does, in the required
order: stop the manager and the agent, rewrite, start again.
Anything that cannot be renamed is reported rather than half-applied -
a bay whose files disagree is worse than one still on its old name.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory)][string]$NewNumber,
[Parameter(Mandatory)][hashtable[]]$Targets,
# Overridable so the rename can be exercised against a captured bay.
[Parameter(Mandatory)][string]$Root,
# Whatever owns the files goes down first - for Makino the Adapter
# Manager rewrites its configuration from memory as it stops, and for
# Fanuc the adapter holds its own copy. Overridable only so a test can
# drive the stop/start ordering with real services.
[string[]]$Services = @()
)
$out = @{ Updated = @(); Errors = @() }
$present = @($Targets |
ForEach-Object { @{ Path = (Join-Path $Root $_.Path); Kind = $_.Kind } } |
Where-Object { Test-Path -LiteralPath $_.Path })
if (-not $present) { return $out }
# Collect EVERY name in play, not just one. A bay half-renamed by the old
# code carries two at once - Devices.xml already on the machine number while
# the adapter files still say MAKINO-n - and replacing only the name we
# happened to discover leaves the other behind, which is the very state this
# is meant to end. Gather them all, then converge every file on the target.
$names = New-Object System.Collections.Generic.HashSet[string]
foreach ($t in $present) {
$raw = Get-Content -LiteralPath $t.Path -Raw -ErrorAction SilentlyContinue
if (-not $raw) { continue }
switch ($t.Kind) {
'attr' { if ($raw -match '<Device[^>]+name="([^"]+)"') { [void]$names.Add($matches[1]) } }
'name' { if ($raw -match '<Name>\s*([^<]+?)\s*</Name>') { [void]$names.Add($matches[1]) } }
'cfg' {
# The adapter block's key is the bare line inside Adapters { }.
if ($raw -match '(?ms)Adapters\s*\{\s*\r?\n\s*([^\s{]+)') { [void]$names.Add($matches[1]) }
}
}
}
[void]$names.Remove($NewNumber)
if ($names.Count -eq 0) { return $out } # every file already on the target
# Agent is stopped too, so it re-reads Agent.cfg on the way back up.
$stopped = @()
foreach ($name in $Services) {
$svc = Get-Service -Name $name -ErrorAction SilentlyContinue
if (-not $svc) { continue }
if ($svc.Status -ne 'Stopped') {
try {
Stop-Service -Name $name -Force -ErrorAction Stop
$stopped += $name
} catch {
$out.Errors += "MTConnect: could not stop '$name' ($_); nothing was changed"
foreach ($back in $stopped) {
try { Start-Service -Name $back -ErrorAction Stop } catch {}
}
return $out
}
}
}
foreach ($t in $present) {
try {
$content = Get-Content -LiteralPath $t.Path -Raw -ErrorAction Stop
$updated = $content
$from = @()
foreach ($old in $names) {
$escaped = [regex]::Escape($old)
switch ($t.Kind) {
'attr' { $next = $updated -replace ('"' + $escaped + '"'), ('"' + $NewNumber + '"') }
'name' { $next = $updated -replace ('<Name>\s*' + $escaped + '\s*</Name>'), ("<Name>$NewNumber</Name>") }
# The adapter block is keyed by a bare name on its own line.
'cfg' { $next = $updated -replace ('(?m)^(\s*)' + $escaped + '(\s*)$'), ("`${1}$NewNumber`${2}") }
# <DeviceName>/<DeviceID>/<DeviceUUID> in the Fanuc adapter config
'elem' { $next = $updated -replace ('(<Device(?:Name|ID|UUID)>)\s*' + $escaped + '\s*(</Device(?:Name|ID|UUID)>)'), ("`${1}$NewNumber`${2}") }
}
if ($next -ne $updated) { $from += $old; $updated = $next }
}
if ($updated -eq $content) { continue } # this file was already done
Set-Content -LiteralPath $t.Path -Value $updated -NoNewline -ErrorAction Stop
$out.Updated += "$($t.Path) ($($from -join ', ') -> $NewNumber)"
} catch {
$out.Errors += "MTConnect: rewrite failed for $($t.Path): $_"
}
}
foreach ($name in $stopped) {
try { Start-Service -Name $name -ErrorAction Stop }
catch { $out.Errors += "MTConnect: restart of '$name' failed: $_" }
}
return $out
}
function Update-MachineNumber {
<#
.SYNOPSIS
Updates UDC + eDNC machine number in one step. Stops UDC before writing,
relaunches after.
.PARAMETER NewNumber
The new machine number (digits only - caller validates).
.PARAMETER Site
Site name passed to UDC.exe -site argument. Defaults to 'West Jefferson'.
.OUTPUTS
Hashtable: @{ UdcUpdated = $bool; EdncUpdated = $bool; Errors = @() }
#>
param(
[Parameter(Mandatory)]
[string]$NewNumber,
[string]$Site = 'West Jefferson'
)
$out = @{ UdcUpdated = $false; EdncUpdated = $false; Errors = @(); RegImported = $null; OldUdc = $null; OldEdnc = $null }
# If the machine number is changing (placeholder->real OR real->real
# reassignment after a duplicate-image), pull per-machine state for the
# new number from the SFLD share: NTLARS .reg, UDC settings, UDC live
# data. The live-data restore is idempotent via one-shot migrated/
# consumption, so it stays safe on reassign too.
$current = Get-CurrentMachineNumber
$out.OldUdc = $current.Udc
$out.OldEdnc = $current.Ednc
$isChanging = ($current.Udc -ne $NewNumber) -or ($current.Ednc -ne $NewNumber)
if ($isChanging -and $NewNumber -ne '9999') {
$sharePath = $null
$siteCfgPath = 'C:\Enrollment\site-config.json'
if (Test-Path $siteCfgPath) {
try {
$cfg = Get-Content $siteCfgPath -Raw | ConvertFrom-Json
# Alias-aware lookup: prefer new key, fall back to legacy.
# PowerShell 5.1 has no null-coalesce operator.
$sharePath = $cfg.pcProfiles.'gea-shopfloor-collections'.ntlarsBackupSharePath
if (-not $sharePath) { $sharePath = $cfg.pcProfiles.'Standard-Machine'.ntlarsBackupSharePath }
} catch {}
}
if ($sharePath) {
try {
. (Join-Path $PSScriptRoot 'Restore-EDncReg.ps1')
$mounted = Mount-SFLDShare -SharePath $sharePath -DriveLetter 'V:'
if ($mounted) {
try {
$out.RegImported = Import-EDncRegBackup -SourceRoot 'V:\' -MachineNumber $NewNumber
} finally {
& net use V: /delete /y 2>$null | Out-Null
}
} else {
Write-Host " Update-MachineNumber: SFLD share unreachable - skipping restore."
}
} catch {
$out.Errors += "ntlars restore failed: $_"
}
}
# --- UDC settings JSON restore: pull udc_settings_<NewNumber>.json
# from the SFLD UDC settings_backups share. At imaging time
# 00-PreInstall-MachineApps.ps1 pulls this from the local
# C:\Enrollment mirror, but a 9999-placeholder PC has no real
# pre-stage. Once the tech sets the real number we have SFLD
# creds, so go direct to the canonical share. ---
$udcSettingsSharePath = $null
if ($cfg) {
try {
$udcSettingsSharePath = $cfg.pcProfiles.'gea-shopfloor-collections'.udcSettingsSharePath
if (-not $udcSettingsSharePath) { $udcSettingsSharePath = $cfg.pcProfiles.'Standard-Machine'.udcSettingsSharePath }
} catch {}
}
if ($udcSettingsSharePath) {
try {
$mountedUdcSet = Mount-SFLDShare -SharePath $udcSettingsSharePath -DriveLetter 'X:'
if ($mountedUdcSet) {
try {
$srcSettings = Join-Path 'X:\' "udc_settings_$NewNumber.json"
if (Test-Path -LiteralPath $srcSettings) {
Get-Process UDC -ErrorAction SilentlyContinue | ForEach-Object {
try { $_.Kill(); $_.WaitForExit(5000) | Out-Null } catch {}
}
Start-Sleep -Milliseconds 500
$localUdcDir = 'C:\ProgramData\UDC'
if (-not (Test-Path $localUdcDir)) { New-Item -ItemType Directory -Path $localUdcDir -Force | Out-Null }
Copy-Item -LiteralPath $srcSettings -Destination $script:UdcSettingsPath -Force -ErrorAction Stop
$out.UdcSettingsRestored = $true
Write-Host " Update-MachineNumber: UDC settings restored from $srcSettings"
} else {
Write-Host " Update-MachineNumber: no udc_settings_$NewNumber.json on settings_backups share"
}
} finally {
& net use X: /delete /y 2>$null | Out-Null
}
} else {
Write-Host " Update-MachineNumber: UDC settings_backups share unreachable - skipping settings restore."
}
} catch {
$out.Errors += "UDC settings restore failed: $_"
}
}
# --- UDC data restore: pull CurrentData.json + ArchivedData/ from
# the per-bay backup at <udcBackupSharePath>\<NewNumber>\.
# One-shot: after successful restore, the live backup at the root
# is moved into <NewNumber>\migrated\<timestamp>\ so it can't be
# replayed on subsequent reboots or reused for a future PC at the
# same bay. The 'isPlaceholder' guard above ensures this whole
# block only ever fires once per PC's lifetime (placeholder->real
# transition). ---
$udcSharePath = $null
if ($cfg) {
try {
$udcSharePath = $cfg.pcProfiles.'gea-shopfloor-collections'.udcBackupSharePath
if (-not $udcSharePath) { $udcSharePath = $cfg.pcProfiles.'Standard-Machine'.udcBackupSharePath }
} catch {}
}
if ($udcSharePath) {
try {
# N:, never W:. GE-Enforce owns W: for its whole cycle, and this
# runs as SYSTEM in the same drive namespace - taking W: here kills
# the share out from under an in-flight enforce cycle.
$mountedUdc = Mount-SFLDShare -SharePath $udcSharePath -DriveLetter 'N:'
if ($mountedUdc) {
try {
$bayDir = Join-Path 'N:\' $NewNumber
$srcCur = Join-Path $bayDir 'CurrentData.json'
$srcArc = Join-Path $bayDir 'ArchivedData'
if (Test-Path -LiteralPath $srcCur) {
Write-Host " Update-MachineNumber: UDC backup found at $bayDir - restoring."
# Stop UDC pre-emptively so CurrentData.json isn't locked
Get-Process UDC -ErrorAction SilentlyContinue | ForEach-Object {
try { $_.Kill(); $_.WaitForExit(5000) | Out-Null } catch {}
}
Start-Sleep -Milliseconds 500
$localUdcDir = 'C:\ProgramData\UDC'
if (-not (Test-Path $localUdcDir)) { New-Item -ItemType Directory -Path $localUdcDir -Force | Out-Null }
$localArc = Join-Path $localUdcDir 'ArchivedData'
# Copy
Copy-Item -LiteralPath $srcCur -Destination (Join-Path $localUdcDir 'CurrentData.json') -Force -ErrorAction Stop
if (Test-Path -LiteralPath $srcArc) {
if (Test-Path -LiteralPath $localArc) { Remove-Item -LiteralPath $localArc -Recurse -Force -ErrorAction SilentlyContinue }
Copy-Item -LiteralPath $srcArc -Destination $localArc -Recurse -Force -ErrorAction Stop
}
# Move live backup -> migrated/<timestamp>/ (one-shot consumption)
$stamp = (Get-Date -Format 'yyyy-MM-ddTHH-mm-ssZ')
$migDir = Join-Path $bayDir 'migrated'
$migStamp = Join-Path $migDir $stamp
if (-not (Test-Path -LiteralPath $migDir)) { New-Item -ItemType Directory -Path $migDir -Force | Out-Null }
if (-not (Test-Path -LiteralPath $migStamp)) { New-Item -ItemType Directory -Path $migStamp -Force | Out-Null }
Move-Item -LiteralPath $srcCur -Destination (Join-Path $migStamp 'CurrentData.json') -Force -ErrorAction Stop
if (Test-Path -LiteralPath $srcArc) {
Move-Item -LiteralPath $srcArc -Destination (Join-Path $migStamp 'ArchivedData') -Force -ErrorAction Stop
}
$bakManifest = Join-Path $bayDir 'backup.manifest.json'
if (Test-Path -LiteralPath $bakManifest) {
Move-Item -LiteralPath $bakManifest -Destination (Join-Path $migStamp 'backup.manifest.json') -Force -ErrorAction SilentlyContinue
}
# Audit manifest in migrated/<stamp>/
$localArcInfo = if (Test-Path $localArc) { Get-ChildItem $localArc -Recurse -File -ErrorAction SilentlyContinue } else { @() }
$restoreManifest = [ordered]@{
RestoredAt = (Get-Date -Format 'o')
DestinationHostname = $env:COMPUTERNAME
DestinationUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
MachineNumber = $NewNumber
CurrentDataBytes = (Get-Item (Join-Path $localUdcDir 'CurrentData.json')).Length
ArchivedDataFiles = $localArcInfo.Count
ArchivedDataBytes = ($localArcInfo | Measure-Object Length -Sum).Sum
RestoredVia = 'Update-MachineNumber.ps1'
}
$restoreManifest | ConvertTo-Json | Set-Content -Path (Join-Path $migStamp 'restore.manifest.json') -Encoding UTF8
$out.UdcRestored = $true
Write-Host " Update-MachineNumber: UDC restore OK (consumed -> migrated\$stamp\)"
} else {
Write-Host " Update-MachineNumber: no UDC backup at $bayDir (fresh PC, no prior data)"
}
} finally {
& net use N: /delete /y 2>$null | Out-Null
}
} else {
Write-Host " Update-MachineNumber: UDC backup share unreachable - skipping UDC restore."
}
} catch {
$out.Errors += "UDC restore failed: $_"
}
}
}
# --- Stop UDC before editing its JSON (avoid stale shutdown write) ---
Get-Process UDC -ErrorAction SilentlyContinue | ForEach-Object {
try { $_.Kill(); $_.WaitForExit(5000) | Out-Null } catch {}
}
Start-Sleep -Seconds 1
# --- Update UDC settings JSON ---
# -ErrorAction Stop on the WRITE so PermissionDenied / IO errors become
# terminating and actually hit the catch block. Without this, the cmdlet
# writes a non-terminating error (visible in transcript) but flow
# continues + $out.UdcUpdated is set to $true, leading the dialog to
# report "UDC updated" when the file write actually failed.
if (Test-Path $script:UdcSettingsPath) {
try {
$json = Get-Content $script:UdcSettingsPath -Raw -ErrorAction Stop | ConvertFrom-Json
$json.GeneralSettings.MachineNumber = $NewNumber
$json | ConvertTo-Json -Depth 99 | Set-Content -Path $script:UdcSettingsPath -Encoding UTF8 -ErrorAction Stop
$out.UdcUpdated = $true
} catch {
$out.Errors += "UDC update failed: $_"
}
}
# --- Update eDNC registry ---
# Same -ErrorAction Stop reasoning as above. Set-ItemProperty's
# PermissionDenied is non-terminating by default; without -ErrorAction
# Stop, the catch block never fires and $out.EdncUpdated=$true gets set
# despite the write failing. This is the bug that made the 13:35:39
# tech run on FGY07FZ3 report "eDNC updated to 3005 / All updates
# succeeded" while the actual reg value stayed at 9999.
if (Test-Path $script:EdncRegPath) {
try {
Set-ItemProperty -Path $script:EdncRegPath -Name MachineNo -Value $NewNumber -Type String -Force -ErrorAction Stop
$out.EdncUpdated = $true
} catch {
$out.Errors += "eDNC update failed: $_"
}
}
# --- Relaunch UDC with new args ---
if ((Test-Path $script:UdcExePath) -and $out.UdcUpdated) {
try {
# UDC.exe arg signature: quoted site name (with space), then
# dash-prefixed machine number. Example: UDC.exe "West Jefferson" -7605
Start-Process -FilePath $script:UdcExePath -ArgumentList @("`"$Site`"", "-$NewNumber")
} catch {
$out.Errors += "UDC relaunch failed: $_"
}
}
# --- Update MTConnect Devices.xml (per-variant) + restart agent services ---
# MTConnect deploys via the GE-Enforce manifest engine + the
# Install_MTConnect_ExisDir_BatConvert.ps1 wrapper. Devices.xml on disk
# has the machine number embedded in the <Device name= uuid= id=> attrs.
# When the tech changes 9999 -> real number, those attrs need to follow,
# OR MTConnect data will keep reporting under the old/wrong identity.
#
# We do an inline substitution rather than re-running the full wrapper
# because the tech may not have credential delegation to the SFLD share
# from their interactive session.
$out.MTConnectUpdated = @()
# Drive this off "is the service installed?" rather than file existence:
# Fanuc and Okuma both deploy to C:\MTConnect\Agent\, distinguishable only
# by the registered service name (NTFS is case-insensitive so the two
# devices.xml / Devices.xml entries collapse to the same file). Without
# this filter, the Okuma branch on an Okuma PC sees the file already
# rewritten by the (no-op) Fanuc branch and skips the service restart.
# Okuma and eDNC keep the name in one file only - verified across 7 Okuma
# and 15 eDNC bay captures - so the simple edit is right for them. Fanuc and
# Makino are handled below instead.
$mtcVariants = @(
@{ Service='MTConnect Agent Okuma'; Path='C:\MTConnect\Agent\Devices.xml' },
@{ Service='MTConnect eDNC Agent'; Path='C:\MTConnect_eDNC\Agent\Devices.xml' }
)
foreach ($v in $mtcVariants) {
$svc = Get-Service -Name $v.Service -ErrorAction SilentlyContinue
if (-not $svc) { continue }
if (-not (Test-Path -LiteralPath $v.Path)) { continue }
try {
$content = Get-Content -LiteralPath $v.Path -Raw -ErrorAction Stop
# Find the Device root's name= attr to discover the OLD identifier
if ($content -notmatch '<Device[^>]+name="([^"]+)"') { continue }
$oldName = $matches[1]
# Most variants encode machine number as the trailing digit run:
# Fanuc/Makino: name="9999" -> trailing 9999
# OKUMA: name="loc9999" -> trailing 9999, prefix 'loc'
# eDNC: name="eDNC_OKUMA9999" -> trailing 9999, prefix 'eDNC_OKUMA'
if ($oldName -notmatch '^(.*?)(\d+)$') { continue }
$prefix = $matches[1]
$oldDigits = $matches[2]
if ($oldDigits -eq $NewNumber) { continue } # already correct
$oldFull = "$prefix$oldDigits"
$newFull = "$prefix$NewNumber"
$oldEsc = [regex]::Escape($oldFull)
# Quoted attr value: name="X" / uuid="X" / id="X"
$content = $content -replace ('"' + $oldEsc + '"'), ('"' + $newFull + '"')
# OKUMA-style with serial after dot: uuid="locX.<serial>"
$content = $content -replace ('"' + $oldEsc + '\.'), ('"' + $newFull + '.')
Set-Content -LiteralPath $v.Path -Value $content -NoNewline -ErrorAction Stop
$out.MTConnectUpdated += "$($v.Path) ($oldFull -> $newFull)"
try { Restart-Service -Name $v.Service -Force -ErrorAction Stop }
catch { $out.Errors += "Restart $($v.Service) failed: $_" }
} catch {
$out.Errors += "MTConnect Devices.xml update failed for $($v.Path): $_"
}
}
# --- Multi-file variants: rename every copy, services stopped first ---
# Fanuc and Makino each keep the device name in more than one file, and the
# agent's copy alone is not enough - the adapter goes on streaming under the
# old identity, which is how seven captured Fanuc bays ended up with the
# agent on the right machine number and the adapter on the bay it was
# imaged from.
$multiFileVariants = @(
@{
Probe = 'MTConnect Agent Fanuc'
Root = 'C:\MTConnect'
Services = @('MTConnect Adapter Fanuc', 'MTConnect Agent Fanuc')
Targets = @(
@{ Path = 'Agent\devices.xml'; Kind = 'attr' },
@{ Path = 'Adapter\devices.xml'; Kind = 'attr' },
@{ Path = 'Adapter\adapter.xml'; Kind = 'elem' }
)
},
@{
Probe = 'Makino MTConnect Agent'
Root = 'C:\Makino-MTConnect'
Services = @('Makino Adapter Manager', 'Makino MTConnect Agent')
Targets = @(
@{ Path = 'Agent\Devices.xml'; Kind = 'attr' },
@{ Path = 'Agent\Devices.EDM.xml'; Kind = 'attr' },
@{ Path = 'Data\AdapterDataFile.xml'; Kind = 'name' },
@{ Path = 'Agent\Agent.cfg'; Kind = 'cfg' }
)
}
)
foreach ($variant in $multiFileVariants) {
if (-not (Get-Service -Name $variant.Probe -ErrorAction SilentlyContinue)) { continue }
$renamed = Update-MTConnectVariantName -NewNumber $NewNumber `
-Root $variant.Root -Targets $variant.Targets -Services $variant.Services
$out.MTConnectUpdated += $renamed.Updated
$out.Errors += $renamed.Errors
}
# Keep C:\Enrollment\machine-number.txt in sync. Post-imaging GE-Enforce
# prefers eDNC reg, but imaging-time scripts (Install-FromManifest
# TargetMachineNumbers filter, 01-eDNC.ps1, 03-RestoreEDncConfig.ps1)
# still read this file. Avoid drift on reassign.
try {
$mnFile = 'C:\Enrollment\machine-number.txt'
$mnDir = Split-Path -Parent $mnFile
if (-not (Test-Path $mnDir)) { New-Item -ItemType Directory -Path $mnDir -Force | Out-Null }
Set-Content -Path $mnFile -Value $NewNumber -Encoding UTF8 -NoNewline
$out.MachineNumberTxtUpdated = $true
} catch {
$out.Errors += "machine-number.txt update failed: $_"
}
return $out
}