Files
pxe-server/playbook/shopfloor-setup/CMM/01-Setup-CMM.ps1
cproudlock b236b18fbc CMM: share-based installer framework with SFLD credential lookup
Refactored CMM/01-Setup-CMM.ps1 from local-file installer to network-
share-based pattern. CMM apps live on a file share instead of being
pre-staged locally or pulled from Azure Blob.

Framework:
  1. Reads share path from site-config.json CMM profile (cmmSharePath),
     falls back to West Jefferson default
  2. Scans HKLM:\SOFTWARE\GE\SFLD\Credentials\* for a credential entry
     whose TargetHost matches the share's server name
  3. Mounts the share as S: using net use with the stored creds
  4. (Placeholder) Install apps from the share
  5. Disconnects the share

The Get-SFLDCredential helper function is generic and will be reused by
Genspect/Keyence scripts when their share-based installs are built. It
matches credentials by TargetHost field, supporting exact match and
domain-suffix matching.

App install blocks are commented out as placeholders — uncomment when
PC-DMIS, CLM License, and other Hexagon app details are finalized.

Added cmmSharePath to site-config.json CMM profile.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 11:24:22 -04:00

174 lines
6.9 KiB
PowerShell

# 01-Setup-CMM.ps1 - CMM-specific setup (runs after Shopfloor baseline)
#
# Installs Hexagon CMM applications from a network share using credentials
# stored in the SFLD registry by SetupCredentials.ps1 (PPKG phase).
#
# Unlike Standard PC apps (which are pre-staged locally via preinstall.json
# or pulled from Azure Blob via DSC), CMM apps live on a file share and
# are installed directly from there. The share credentials come from the
# PPKG's YAML config and are already in the registry by the time this
# script runs.
#
# The share path and app list are read from site-config.json's CMM profile
# when available, with hardcoded West Jefferson defaults as fallback.
#
# PLACEHOLDER: specific app installers (PC-DMIS, CLM License, etc.) are
# not yet finalized. The framework below handles credential lookup, share
# mounting, and has slots for each install step.
Write-Host "=== CMM Setup ==="
# --- Load site config + PC profile ---
. "$PSScriptRoot\..\Shopfloor\lib\Get-PCProfile.ps1"
# --- Configuration ---
# Share path for Hexagon CMM installers. Read from profile config,
# fall back to the known West Jefferson path.
$defaultSharePath = '\\tsgwp00525.wjs.geaerospace.net\shared\dt\shopfloor\cmm\hexagon\machineapps'
$sharePath = $defaultSharePath
if ($pcProfile -and $pcProfile.cmmSharePath) {
$sharePath = $pcProfile.cmmSharePath
} elseif ($siteConfig -and $siteConfig.pcProfiles -and $siteConfig.pcProfiles.CMM -and $siteConfig.pcProfiles.CMM.cmmSharePath) {
$sharePath = $siteConfig.pcProfiles.CMM.cmmSharePath
}
Write-Host " Share: $sharePath"
# ============================================================================
# Credential lookup - reads from HKLM:\SOFTWARE\GE\SFLD\Credentials\*
# Written by SetupCredentials.ps1 during the PPKG phase. We scan all
# credential entries and find one whose TargetHost matches the share's
# server name.
# ============================================================================
function Get-SFLDCredential {
param([string]$ServerName)
$basePath = 'HKLM:\SOFTWARE\GE\SFLD\Credentials'
if (-not (Test-Path $basePath)) {
Write-Warning "SFLD credential registry not found at $basePath"
return $null
}
$entries = Get-ChildItem -Path $basePath -ErrorAction SilentlyContinue
foreach ($entry in $entries) {
$props = Get-ItemProperty -Path $entry.PSPath -ErrorAction SilentlyContinue
if (-not $props) { continue }
$targetHost = $props.TargetHost
if (-not $targetHost) { continue }
# Match by hostname (with or without domain suffix)
if ($targetHost -eq $ServerName -or
$targetHost -like "$ServerName.*" -or
$ServerName -like "$targetHost.*") {
return @{
Username = $props.Username
Password = $props.Password
TargetHost = $targetHost
KeyName = $entry.PSChildName
}
}
}
Write-Warning "No SFLD credential found for server '$ServerName'"
return $null
}
# ============================================================================
# Mount the share
# ============================================================================
# Extract server name from UNC path: \\server\share\... -> server
$serverName = ($sharePath -replace '^\\\\', '') -split '\\' | Select-Object -First 1
$cred = Get-SFLDCredential -ServerName $serverName
$driveLetter = 'S:'
if ($cred) {
Write-Host " Credential: $($cred.KeyName) (user: $($cred.Username))"
} else {
Write-Host " No credential found for $serverName - attempting guest/current-user access"
}
# Disconnect any stale mapping
net use $driveLetter /delete /y 2>$null | Out-Null
$mountOk = $false
if ($cred -and $cred.Username -and $cred.Password) {
$result = & net use $driveLetter $sharePath /user:$($cred.Username) $($cred.Password) /persistent:no 2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host " Mounted $sharePath as $driveLetter"
$mountOk = $true
} else {
Write-Warning " net use failed (exit $LASTEXITCODE): $result"
}
} else {
# Try without explicit credentials (rely on CredMan or current user)
$result = & net use $driveLetter $sharePath /persistent:no 2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host " Mounted $sharePath as $driveLetter (no explicit creds)"
$mountOk = $true
} else {
Write-Warning " net use failed (exit $LASTEXITCODE): $result"
}
}
if (-not $mountOk) {
Write-Warning "Cannot access $sharePath - skipping CMM app installs."
Write-Host "=== CMM Setup Complete (share unavailable) ==="
exit 0
}
# ============================================================================
# Install apps from the share
#
# PLACEHOLDER: uncomment and adjust when app details are finalized.
# Each block follows the pattern:
# 1. Find installer on the share
# 2. Run it with silent args
# 3. Check exit code
# 4. Log result
# ============================================================================
$installRoot = $driveLetter
# --- Example: CLM Tools (license manager, install first) ---
# $clm = Get-ChildItem -Path $installRoot -Filter "CLM_*.exe" -ErrorAction SilentlyContinue | Select-Object -First 1
# if ($clm) {
# Write-Host "Installing CLM Tools: $($clm.Name)..."
# $p = Start-Process -FilePath $clm.FullName -ArgumentList "-q -norestart" -Wait -PassThru
# Write-Host " CLM Tools exit code: $($p.ExitCode)"
# } else {
# Write-Warning "CLM Tools installer not found (expected CLM_*.exe)"
# }
# --- Example: PC-DMIS 2016 ---
# $pcdmis16 = Get-ChildItem -Path $installRoot -Filter "Pcdmis2016*x64.exe" -ErrorAction SilentlyContinue | Select-Object -First 1
# if ($pcdmis16) {
# Write-Host "Installing PC-DMIS 2016: $($pcdmis16.Name)..."
# $p = Start-Process -FilePath $pcdmis16.FullName -ArgumentList "-q INSTALLPDFCONVERTER=0 INSTALLOFFLINEHELP=0 HEIP=0 -norestart" -Wait -PassThru
# Write-Host " PC-DMIS 2016 exit code: $($p.ExitCode)"
# } else {
# Write-Warning "PC-DMIS 2016 installer not found"
# }
# --- Example: PC-DMIS 2019 R2 ---
# $pcdmis19 = Get-ChildItem -Path $installRoot -Filter "Pcdmis2019*x64.exe" -ErrorAction SilentlyContinue | Select-Object -First 1
# if ($pcdmis19) {
# Write-Host "Installing PC-DMIS 2019 R2: $($pcdmis19.Name)..."
# $p = Start-Process -FilePath $pcdmis19.FullName -ArgumentList "-q INSTALLPDFCONVERTER=0 INSTALLOFFLINEHELP=0 HEIP=0 -norestart" -Wait -PassThru
# Write-Host " PC-DMIS 2019 exit code: $($p.ExitCode)"
# } else {
# Write-Warning "PC-DMIS 2019 installer not found"
# }
Write-Host " (no apps configured yet - uncomment install blocks when ready)"
# ============================================================================
# Cleanup
# ============================================================================
Write-Host "Disconnecting $driveLetter..."
net use $driveLetter /delete /y 2>$null | Out-Null
Write-Host "=== CMM Setup Complete ==="