master
barrett-land Publish 0.0.42 7b8ee75 2mo ago
# Install-AdomBridge.ps1 — hand-install the AdomBridge extension.
#
# Altium ships no silent extension-install CLI (AltiumInstaller.exe has no /silent-style switch,
# and no .rcs registers an install process), but the Extensions folder and ExtensionsRegistry.xml
# both carry an inherited "Everyone: Modify" ACE, so writing the files directly IS the supported
# shape. This is what a working third-party extension's Deploy.ps1 does too.
#
# Does NOT restart Altium — killing a live Altium risks unsaved schematics. Restart is the
# caller's decision, made explicitly.
#
#   powershell -ExecutionPolicy Bypass -File Install-AdomBridge.ps1 -Source <dir> [-Remove]

[CmdletBinding()]
param(
    [string] $Source = "$PSScriptRoot\AdomBridge",
    [switch] $Remove
)
$ErrorActionPreference = 'Stop'

$adRoot = Get-ChildItem 'C:\ProgramData\Altium' -Directory |
          Where-Object { $_.Name -like 'Altium Designer*' } | Select-Object -First 1
if (-not $adRoot) { throw 'No "Altium Designer {GUID}" folder under C:\ProgramData\Altium' }

$extRoot = Join-Path $adRoot.FullName 'Extensions'
$target  = Join-Path $extRoot 'AdomBridge'
$reg     = Join-Path $extRoot 'ExtensionsRegistry.xml'
$guid    = 'CDFE1901-218C-5A6A-BEF9-E5BE7083B9FC'

Write-Output "extensions root : $extRoot"
Write-Output "registry        : $reg"

# --- always back the registry up before touching it -------------------------------------
$backup = "$reg.bak-" + (Get-Date -Format 'yyyyMMdd-HHmmss')
Copy-Item -LiteralPath $reg -Destination $backup -Force
Write-Output "registry backup : $backup"

$xml = [xml](Get-Content -LiteralPath $reg -Raw)
$existing = $xml.SelectNodes('//Item') | Where-Object { $_.GetAttribute('HRID') -eq 'AdomBridge' }
foreach ($n in $existing) { [void]$n.ParentNode.RemoveChild($n) }   # idempotent re-install

if ($Remove) {
    $xml.Save($reg)
    if (Test-Path $target) { Remove-Item -LiteralPath $target -Recurse -Force }
    Write-Output 'REMOVED (restart Altium to unload)'
    exit 0
}

# --- files ------------------------------------------------------------------------------
if (Test-Path $target) { Remove-Item -LiteralPath $target -Recurse -Force }
Copy-Item -LiteralPath $Source -Destination $target -Recurse -Force
Write-Output "installed files : $target"
Get-ChildItem $target -Recurse -File | ForEach-Object { Write-Output ('   ' + $_.FullName.Substring($target.Length + 1)) }

# --- registry node ----------------------------------------------------------------------
# Field set mirrors the shipped entries; anything Altium fills in itself is left empty.
$item = $xml.CreateElement('Item')
$item.SetAttribute('HRID', 'AdomBridge')
$item.SetAttribute('Guid', $guid)
function Add-Child([string]$name, [string]$text) {
    $e = $xml.CreateElement($name); $e.InnerText = $text; [void]$item.AppendChild($e)
}
Add-Child 'Path'             $target
Add-Child 'Status'           '0'
Add-Child 'VaultGuid'        ''
Add-Child 'CreatedBy'        'Adom Inc.'
Add-Child 'CategoryGuid'     ''
Add-Child 'CategoryName'     ''
Add-Child 'ReadMe'           ''
Add-Child 'Help'             ''
Add-Child 'Requirements'     ''
Add-Child 'Title'            'Adom Bridge'
Add-Child 'ShortDescription' 'Parameterized in-process automation for container-driven Altium.'
Add-Child 'LongDescription'  'Registers processes that accept arguments, so a container can drive Altium without the wizard-and-click surface Altium exposes externally.'
Add-Child 'SmallImage'       ''
Add-Child 'LargeImage'       ''
Add-Child 'Version'          '0.1.0.0'
Add-Child 'VersionGuid'      ([guid]::NewGuid().ToString().ToUpper())
$oleNow = [string]([datetime]::Now.ToOADate())
Add-Child 'ReleasedDate'     $oleNow
Add-Child 'ReleaseNotes'     ''
Add-Child 'DateInstalled'    $oleNow

# Shipped entries all carry this block; absent it, the client may treat the entry as malformed.
$pv = $xml.CreateElement('PlatformVersions')
foreach ($pair in @(@('DXP','1.0.16.43'), @('EDP','10.0.16.43'), @('MaxDXP','0.0.0.0'), @('MaxEDP','0.0.0.0'))) {
    $e = $xml.CreateElement($pair[0]); $e.SetAttribute('BuildNumber', $pair[1]); [void]$pv.AppendChild($e)
}
[void]$item.AppendChild($pv)
[void]$xml.DocumentElement.AppendChild($item)

# AltiumInstaller carries a "…it is opened by some process" string, so tolerate a transient lock.
for ($i = 0; $i -lt 5; $i++) {
    try { $xml.Save($reg); break }
    catch { if ($i -eq 4) { throw }; Start-Sleep -Seconds 2 }
}

$check = [xml](Get-Content -LiteralPath $reg -Raw)
$n = ($check.SelectNodes('//Item') | Where-Object { $_.GetAttribute('HRID') -eq 'AdomBridge' }).Count
Write-Output "registry items  : $(($check.SelectNodes('//Item')).Count) total, AdomBridge nodes = $n"
Write-Output 'INSTALLED — Altium must be restarted before the server is loaded.'