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>
This commit is contained in:
cproudlock
2026-04-10 11:24:22 -04:00
parent ed803539e0
commit b236b18fbc
2 changed files with 174 additions and 45 deletions

View File

@@ -1,45 +1,173 @@
# 01-Setup-CMM.ps1 CMM-specific setup (runs after Shopfloor baseline) # 01-Setup-CMM.ps1 - CMM-specific setup (runs after Shopfloor baseline)
# Installs Hexagon CLM Tools, PC-DMIS 2016, and PC-DMIS 2019 R2 #
# Installs Hexagon CMM applications from a network share using credentials
Write-Host "=== CMM Setup ===" # stored in the SFLD registry by SetupCredentials.ps1 (PPKG phase).
#
$hexDir = "C:\Enrollment\shopfloor-setup\CMM\hexagon" # 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
if (-not (Test-Path $hexDir)) { # are installed directly from there. The share credentials come from the
Write-Warning "Hexagon folder not found at $hexDir — skipping CMM installs." # PPKG's YAML config and are already in the registry by the time this
exit 0 # script runs.
} #
# The share path and app list are read from site-config.json's CMM profile
# --- Find installers --- # when available, with hardcoded West Jefferson defaults as fallback.
$clm = Get-ChildItem -Path $hexDir -Filter "CLM_*.exe" | Select-Object -First 1 #
$pcdmis16 = Get-ChildItem -Path $hexDir -Filter "Pcdmis2016*x64.exe" | Select-Object -First 1 # PLACEHOLDER: specific app installers (PC-DMIS, CLM License, etc.) are
$pcdmis19 = Get-ChildItem -Path $hexDir -Filter "Pcdmis2019*x64.exe" | Select-Object -First 1 # not yet finalized. The framework below handles credential lookup, share
# mounting, and has slots for each install step.
# --- 1. Install CLM Tools (license manager — must be first) ---
if ($clm) { Write-Host "=== CMM Setup ==="
Write-Host "Installing CLM Tools: $($clm.Name)..."
$p = Start-Process -FilePath $clm.FullName -ArgumentList "-q -norestart" -Wait -PassThru # --- Load site config + PC profile ---
Write-Host " CLM Tools exit code: $($p.ExitCode)" . "$PSScriptRoot\..\Shopfloor\lib\Get-PCProfile.ps1"
} else {
Write-Warning "CLM Tools installer not found in $hexDir (expected CLM_*.exe)" # --- Configuration ---
} # Share path for Hexagon CMM installers. Read from profile config,
# fall back to the known West Jefferson path.
# --- 2. Install PC-DMIS 2016 --- $defaultSharePath = '\\tsgwp00525.wjs.geaerospace.net\shared\dt\shopfloor\cmm\hexagon\machineapps'
if ($pcdmis16) {
Write-Host "Installing PC-DMIS 2016: $($pcdmis16.Name)..." $sharePath = $defaultSharePath
$p = Start-Process -FilePath $pcdmis16.FullName -ArgumentList "-q INSTALLPDFCONVERTER=0 INSTALLOFFLINEHELP=0 HEIP=0 -norestart" -Wait -PassThru if ($pcProfile -and $pcProfile.cmmSharePath) {
Write-Host " PC-DMIS 2016 exit code: $($p.ExitCode)" $sharePath = $pcProfile.cmmSharePath
} else { } elseif ($siteConfig -and $siteConfig.pcProfiles -and $siteConfig.pcProfiles.CMM -and $siteConfig.pcProfiles.CMM.cmmSharePath) {
Write-Warning "PC-DMIS 2016 installer not found in $hexDir (expected Pcdmis2016*x64.exe)" $sharePath = $siteConfig.pcProfiles.CMM.cmmSharePath
} }
# --- 3. Install PC-DMIS 2019 R2 --- Write-Host " Share: $sharePath"
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 # Credential lookup - reads from HKLM:\SOFTWARE\GE\SFLD\Credentials\*
Write-Host " PC-DMIS 2019 exit code: $($p.ExitCode)" # Written by SetupCredentials.ps1 during the PPKG phase. We scan all
} else { # credential entries and find one whose TargetHost matches the share's
Write-Warning "PC-DMIS 2019 installer not found in $hexDir (expected Pcdmis2019*x64.exe)" # server name.
} # ============================================================================
function Get-SFLDCredential {
Write-Host "=== CMM Setup Complete ===" 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 ==="

View File

@@ -91,6 +91,7 @@
"CMM": { "CMM": {
"_comment": "TODO: add PC-DMIS, CLM License, Hexagon CMM tools when app details are known", "_comment": "TODO: add PC-DMIS, CLM License, Hexagon CMM tools when app details are known",
"cmmSharePath": "\\\\tsgwp00525.wjs.geaerospace.net\\shared\\dt\\shopfloor\\cmm\\hexagon\\machineapps",
"startupItems": [ "startupItems": [
{ "label": "WJ Shopfloor", "type": "existing", "sourceLnk": "WJ Shopfloor.lnk" } { "label": "WJ Shopfloor", "type": "existing", "sourceLnk": "WJ Shopfloor.lnk" }
], ],