<# Convert-goCMMSettings.ps1 Convert a legacy goCMM 1.1 ApplicationSettings.xml (C:\geaofi\) to the goCMM 2.12.3 goCMMSettings.xml schema. The two are different SettingsModel schemas (different filename too). This is a TEMPLATE-based converter: new-only fields get defaults, the per-bay values are carried over from the old XML (+ optional overrides). Decisions baked in (2026-06-19): access-control left blank, operator key normalized to "Operator", cal intervals/restart use template defaults (old values NOT carried), Slack/Andon /Quindos/Emx dropped. Program paths default to the goCMM 2.12 convention (C:\geaofi\goCMM PC-DMIS Programs\) - override with -ResetProgram / -ProbeCalibrationProgram if the .PRG files live elsewhere. Those .PRG files MUST exist at the path written here. Usage: .\Convert-goCMMSettings.ps1 -OldXml C:\geaofi\ApplicationSettings.xml ` -OutFile C:\geaofi\goCMMSettings.xml -PcdmisVersion 2016 -CmmId CMM10 #> param( [Parameter(Mandatory=$true)][string]$OldXml, [Parameter(Mandatory=$true)][string]$OutFile, [string]$PcdmisVersion, # 2016 | 2019 | 2026 (or full "PC-DMIS ... 64-bit") [string]$CmmId, # e.g. CMM10 - used for the cal-program name default [string]$PartGroup, # optional override (friendly S:\ or UNC); else from old XML [string]$ResetProgram, # optional override [string]$ProbeCalibrationProgram # optional override ) $ErrorActionPreference = 'Stop' if (-not (Test-Path -LiteralPath $OldXml)) { throw "Old XML not found: $OldXml" } [xml]$old = Get-Content -LiteralPath $OldXml -Raw # --- part-group share canonicalization (FQDN + \SHARED, matches goCMM 2.12) --- function Canon([string]$pg) { if (-not $pg) { return $pg } $pg = $pg -replace '(?i)^S:\\', '\\tsgwp00525.wjs.geaerospace.net\SHARED\' $pg = [regex]::Replace($pg, '(?i)\\\\tsgwp00525(?:\.[A-Za-z0-9.\-]+)?\\shared(?=\\|$)', '\\tsgwp00525.wjs.geaerospace.net\SHARED') return $pg } # --- resolve per-bay values (override -> old XML -> default) --- # NOTE: read attributes with GetAttribute() - .Name collides with XmlElement.Name. $pg = $PartGroup if (-not $pg) { $pgNode = $old.SettingsModel.PartGroups.PartGroup if ($pgNode) { $pg = $pgNode.GetAttribute('FullName'); if (-not $pg) { $pg = $pgNode.FullName } } } $pg = Canon $pg # NB: PowerShell vars are case-insensitive - do NOT name this $cmmid (collides with the $CmmId param). $machineCmmId = $old.SettingsModel.MachineDefinition.CMMID if (-not $machineCmmId -and $CmmId) { $machineCmmId = "WJRP/$CmmId" } # SelectedVersionString from -PcdmisVersion $verMap = @{ '2016' = 'PC-DMIS 2016.0 64-bit'; '2019' = 'PC-DMIS 2019 R2 64-bit'; '2026' = 'PC-DMIS 2026.1 64-bit' } $selVer = '' if ($PcdmisVersion) { $selVer = if ($verMap.ContainsKey($PcdmisVersion)) { $verMap[$PcdmisVersion] } else { $PcdmisVersion } } # bool carryovers (old flat flags -> new IsEnabled) function OldBool($node, $default='false') { $v = $node; if ($null -eq $v -or $v -eq '') { $default } else { ([string]$v).ToLower() } } $pcdmisEnabled = OldBool $old.SettingsModel.UsingPcDmis 'true' $modusEnabled = OldBool $old.SettingsModel.UsingModus 'false' $winState = if ($old.SettingsModel.DefaultWindowState) { $old.SettingsModel.DefaultWindowState } else { 'Maximized' } $allowSel = OldBool $old.SettingsModel.AllowOperationProgramSelection 'true' $visExec = OldBool $old.SettingsModel.PcDmisSettings.VisibleDuringExecution 'true' $cmmMode = if ($old.SettingsModel.PcDmisSettings.CMMMode) { $old.SettingsModel.PcDmisSettings.CMMMode } else { 'Online' } $sizeTol = if ($old.SettingsModel.MachineDefinition.ProbeCalSizeTol) { $old.SettingsModel.MachineDefinition.ProbeCalSizeTol } else { '0.0005' } $formTol = if ($old.SettingsModel.MachineDefinition.ProbeCalFormTol) { $old.SettingsModel.MachineDefinition.ProbeCalFormTol } else { '0.0005' } $hasRotary = OldBool $old.SettingsModel.MachineDefinition.MachineHasRotaryTable 'false' # program paths (override -> goCMM 2.12 convention default) $progDir = 'C:\geaofi\goCMM PC-DMIS Programs' if (-not $ResetProgram) { $ResetProgram = "$progDir\MachineResetProgram.prg" } if (-not $ProbeCalibrationProgram) { $calName = if ($CmmId) { "${CmmId}_Cal_All_Probes_rev2.PRG" } else { 'Cal_All_Probes_rev2.PRG' } $ProbeCalibrationProgram = "$progDir\$calName" } # --- operator inputs (old KeyLabel + NonTBIInputs -> new OperatorInput; OPER -> Operator) --- $inputs = @() $kl = $old.SettingsModel.OperatorInputs.KeyLabel if ($kl) { $inputs += [pscustomobject]@{ Key = $kl.GetAttribute('Name'); Display = $kl.GetAttribute('Display') } } foreach ($oi in $old.SettingsModel.OperatorInputs.NonTBIInputs.OperatorInput) { if ($oi -is [System.Xml.XmlElement]) { $inputs += [pscustomobject]@{ Key = $oi.GetAttribute('Name'); Display = $oi.GetAttribute('Display') } } } if (-not $inputs) { $inputs = @([pscustomobject]@{Key='SERNO';Display='Serial Number'}, [pscustomobject]@{Key='Operator';Display='Operator'}) } $opXml = ($inputs | ForEach-Object { $k = if ($_.Key -ieq 'OPER') { 'Operator' } else { $_.Key } # decision #4 $d = if ($_.Key -ieq 'OPER') { 'Operator' } else { $_.Display } " `n $k`n $d`n `n " }) -join "`n" function X([string]$s){ [System.Security.SecurityElement]::Escape($s) } $xml = @" true PCDMIS $(X $pg) $opXml false $(X $winState) $allowSel $pcdmisEnabled $visExec $(X $ResetProgram) false false $(X $ProbeCalibrationProgram) false false 1000 true ProgramCount false $(X $selVer) 5 5 0 false false $modusEnabled true false false -Organiser $(X $machineCmmId) false $sizeTol $formTol 72 0 24 0 $hasRotary false $(X $cmmMode) "@ $dir = Split-Path -Parent $OutFile if ($dir -and -not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null } # validate well-formed before writing [void][xml]$xml Set-Content -LiteralPath $OutFile -Value $xml -Encoding UTF8 Write-Host "Wrote $OutFile" Write-Host " PartGroup = $pg" Write-Host " CMMID = $machineCmmId" Write-Host " SelectedVersion = $selVer" Write-Host " ResetProgram = $ResetProgram" Write-Host " ProbeCalProgram = $ProbeCalibrationProgram" Write-Host "NOTE: confirm those .PRG files exist at the paths above (-ResetProgram / -ProbeCalibrationProgram to override)."