Add comprehensive documentation and update deployment paths

Documentation:
- Add ShopDB-API.md with full API reference (all GET/POST endpoints)
- Add detailed docs for Update-ShopfloorPCs-Remote, Invoke-RemoteMaintenance, Update-PC-CompleteAsset
- Add DATA_COLLECTION_PARITY.md comparing local vs remote data collection
- Add HTML versions of all documentation with styled code blocks
- Document software deployment mechanism and how to add new apps
- Document deprecated scripts (Invoke-RemoteAssetCollection, Install-KioskApp)

Script Updates:
- Update deployment source paths to network share (tsgwp00525.wjs.geaerospace.net)
  - InstallDashboard: \\...\scripts\Dashboard\GEAerospaceDashboardSetup.exe
  - InstallLobbyDisplay: \\...\scripts\LobbyDisplay\GEAerospaceLobbyDisplaySetup.exe
  - UpdateEMxAuthToken: \\...\scripts\eMx\eMxInfo.txt
  - DeployUDCWebServerConfig: \\...\scripts\UDC\udc_webserver_settings.json
- Update machine network detection to include 100.0.0.* for CMM cases
- Rename PC Type #9 from "Part Marker" to "Inspection"

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-02-06 11:45:00 -05:00
parent f40b79c087
commit 7d3519f613
15 changed files with 8774 additions and 40 deletions

View File

@@ -19,7 +19,7 @@
.PARAMETER PcType
Target PCs by type (e.g., Dashboard, Lobby Display, CMM, Shopfloor).
Valid values: Standard, Engineer, Shopfloor, CMM, Wax / Trace, Keyence,
Genspect, Heat Treat, Part Marker, Dashboard, Lobby Display, Uncategorized
Genspect, Heat Treat, Inspection, Dashboard, Lobby Display, Uncategorized
.PARAMETER BusinessUnit
Target PCs by business unit (e.g., Blisk, HPT, Spools).
@@ -128,7 +128,7 @@ param(
[Parameter(ParameterSetName='ByPcType')]
[ValidateSet('Standard', 'Engineer', 'Shopfloor', 'CMM', 'Wax / Trace', 'Keyence',
'Genspect', 'Heat Treat', 'Part Marker', 'Dashboard', 'Lobby Display', 'Uncategorized')]
'Genspect', 'Heat Treat', 'Inspection', 'Dashboard', 'Lobby Display', 'Uncategorized')]
[string]$PcType,
[Parameter(ParameterSetName='ByBusinessUnit')]
@@ -222,7 +222,7 @@ function Get-ShopfloorPCsFromApi {
$PcTypeLookup = @{
'Standard' = 1; 'Engineer' = 2; 'Shopfloor' = 3; 'Uncategorized' = 4;
'CMM' = 5; 'Wax / Trace' = 6; 'Keyence' = 7; 'Genspect' = 8;
'Heat Treat' = 9; 'Part Marker' = 10; 'Dashboard' = 11; 'Lobby Display' = 12
'Heat Treat' = 9; 'Inspection' = 10; 'Dashboard' = 11; 'Lobby Display' = 12
}
$BusinessUnitLookup = @{
@@ -778,7 +778,7 @@ $TaskScripts = @{
}
$destFile = "eMxInfo.txt"
$tempPath = "C:\Windows\Temp\eMxInfo-2026.txt"
$tempPath = "C:\Windows\Temp\eMxInfo.txt"
# Check both possible DNC installation paths
$destDirs = @(
@@ -1234,8 +1234,8 @@ $sessionOption = New-PSSessionOption -OpenTimeout 30000 -OperationTimeout 600000
# Special handling for UpdateEMxAuthToken - requires pushing file first
if ($Task -eq 'UpdateEMxAuthToken') {
$sourcePath = "\\tsgwp00525.rd.ds.ge.com\shared\cameron\eMxInfo-2026.txt"
$remoteTempPath = "C:\Windows\Temp\eMxInfo-2026.txt"
$sourcePath = "\\tsgwp00525.wjs.geaerospace.net\dt\shopfloor\scripts\eMx\eMxInfo.txt"
$remoteTempPath = "C:\Windows\Temp\eMxInfo.txt"
Write-Log "UpdateEMxAuthToken: Checking source file..." -Level "INFO"
@@ -1307,7 +1307,7 @@ if ($Task -eq 'UpdateEMxAuthToken') {
# Special handling for DeployUDCWebServerConfig - check for UDC installation, then push config file
if ($Task -eq 'DeployUDCWebServerConfig') {
$sourcePath = Join-Path $PSScriptRoot "udc_webserver_settings.json"
$sourcePath = "\\tsgwp00525.wjs.geaerospace.net\dt\shopfloor\scripts\UDC\udc_webserver_settings.json"
$remoteTempPath = "C:\Windows\Temp\udc_webserver_settings.json"
Write-Log "DeployUDCWebServerConfig: Checking source file..." -Level "INFO"
@@ -1388,12 +1388,14 @@ if ($Task -eq 'DeployUDCWebServerConfig') {
$KioskAppConfig = @{
'InstallDashboard' = @{
Action = 'Install'
InstallerPath = '\\tsgwp00525.wjs.geaerospace.net\dt\shopfloor\scripts\Dashboard\GEAerospaceDashboardSetup.exe'
InstallerName = 'GEAerospaceDashboardSetup.exe'
AppName = 'GE Aerospace Dashboard'
UninstallGuid = '{9D9EEE25-4D24-422D-98AF-2ADEDA4745ED}'
}
'InstallLobbyDisplay' = @{
Action = 'Install'
InstallerPath = '\\tsgwp00525.wjs.geaerospace.net\dt\shopfloor\scripts\LobbyDisplay\GEAerospaceLobbyDisplaySetup.exe'
InstallerName = 'GEAerospaceLobbyDisplaySetup.exe'
AppName = 'GE Aerospace Lobby Display'
UninstallGuid = '{42FFB952-0B72-493F-8869-D957344CA305}'
@@ -1414,14 +1416,13 @@ $KioskAppConfig = @{
if ($KioskAppConfig.ContainsKey($Task)) {
$appConfig = $KioskAppConfig[$Task]
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
if ($appConfig.Action -eq 'Install') {
# Find installer
$installerPath = Join-Path $scriptDir $appConfig.InstallerName
# Find installer from network share
$installerPath = $appConfig.InstallerPath
if (-not (Test-Path $installerPath)) {
Write-Log "Installer not found: $installerPath" -Level "ERROR"
Write-Log "Place $($appConfig.InstallerName) in the script directory" -Level "ERROR"
Write-Log "Ensure the installer exists on the network share" -Level "ERROR"
exit 1
}
Write-Log "$($appConfig.Action): $($appConfig.AppName)" -Level "INFO"

View File

@@ -482,11 +482,15 @@ function Get-RemotePCInfo {
$os = Get-CimInstance -ClassName Win32_OperatingSystem
$result.SerialNumber = $bios.SerialNumber
$result.ServiceTag = $bios.SerialNumber # Same as serial for Dell
$result.Manufacturer = $computerSystem.Manufacturer
$result.Model = $computerSystem.Model
$result.LoggedInUser = $computerSystem.UserName
$result.OSVersion = $os.Caption
$result.LastBootUpTime = if ($os.LastBootUpTime) { $os.LastBootUpTime.ToString("yyyy-MM-dd HH:mm:ss") } else { $null }
$result.TotalPhysicalMemory = [Math]::Round($computerSystem.TotalPhysicalMemory / 1GB, 2)
$result.DomainRole = $computerSystem.DomainRole
$result.CurrentTimeZone = (Get-TimeZone).Id
# Get network interfaces
$networkAdapters = Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration |
@@ -564,10 +568,10 @@ function Get-RemotePCInfo {
"^WJCMM" = "CMM" # Generic CMM
"^WJMEAS" = "Measuring" # Generic measuring
"^0600$" = "Wax Trace" # Wax trace machines
"^0612$" = "Part Marker" # Part markers
"^0613$" = "Part Marker" # Part markers
"^0615" = "Part Marker" # Part markers
"^8003$" = "Part Marker" # Part markers
"^0612$" = "Inspection" # Part markers
"^0613$" = "Inspection" # Part markers
"^0615" = "Inspection" # Part markers
"^8003$" = "Inspection" # Part markers
"^TEST" = $null # Test machines
"^TEMP" = $null # Temporary
"^DEFAULT"= $null # Default value
@@ -586,6 +590,41 @@ function Get-RemotePCInfo {
}
$result.MachineNo = $machineNo
# Get GE Aircraft Engines registry info (DualPath configuration)
$geInfo = @{
Registry32Bit = $false
Registry64Bit = $false
DualPathEnabled = $null
Path1Name = $null
Path2Name = $null
}
$gePaths = @{
'32bit' = 'HKLM:\SOFTWARE\GE Aircraft Engines'
'64bit' = 'HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines'
}
foreach ($pathType in $gePaths.Keys) {
$basePath = $gePaths[$pathType]
if (Test-Path $basePath) {
if ($pathType -eq '32bit') { $geInfo.Registry32Bit = $true }
else { $geInfo.Registry64Bit = $true }
$efocasPath = "$basePath\DNC\eFocas"
if (Test-Path $efocasPath) {
$efocasValues = Get-ItemProperty -Path $efocasPath -ErrorAction SilentlyContinue
if ($efocasValues.DualPath -and $geInfo.DualPathEnabled -eq $null) {
$geInfo.DualPathEnabled = ($efocasValues.DualPath -eq 'YES')
}
if (-not $geInfo.Path1Name -and $efocasValues.Path1Name) {
$geInfo.Path1Name = $efocasValues.Path1Name
}
if (-not $geInfo.Path2Name -and $efocasValues.Path2Name) {
$geInfo.Path2Name = $efocasValues.Path2Name
}
}
}
}
$result.GERegistryInfo = $geInfo
# Get serial port configuration
$comPorts = @()
$serialPorts = Get-CimInstance -ClassName Win32_SerialPort -ErrorAction SilentlyContinue
@@ -620,6 +659,26 @@ function Get-RemotePCInfo {
}
$result.HasVnc = $hasVnc
# Get default printer FQDN (network printers only)
$defaultPrinterFQDN = $null
try {
$defaultPrinter = Get-WmiObject -Query "SELECT * FROM Win32_Printer WHERE Default=$true" -ErrorAction SilentlyContinue
if ($defaultPrinter -and $defaultPrinter.PortName) {
$portName = $defaultPrinter.PortName
# Skip local/virtual printers
$localPorts = @('USB', 'LPT', 'COM', 'PORTPROMPT:', 'FILE:', 'NUL:', 'XPS', 'PDF', 'FOXIT', 'Microsoft')
$isLocalPrinter = $false
foreach ($localPort in $localPorts) {
if ($portName -like "$localPort*") { $isLocalPrinter = $true; break }
}
if (-not $isLocalPrinter) {
# Strip anything after underscore (e.g., 10.80.92.53_2 -> 10.80.92.53)
$defaultPrinterFQDN = $portName -replace '_.*$', ''
}
}
} catch { }
$result.DefaultPrinterFQDN = $defaultPrinterFQDN
# ================================================================
# Detect installed applications for PC type classification
# ================================================================
@@ -955,6 +1014,40 @@ function Send-PCDataToApi {
$postData.hasVnc = "0"
}
# Add new parity fields
if ($PCData.ServiceTag) {
$postData.serviceTag = $PCData.ServiceTag
}
if ($PCData.TotalPhysicalMemory) {
$postData.totalPhysicalMemory = $PCData.TotalPhysicalMemory
}
if ($PCData.DomainRole -ne $null) {
$postData.domainRole = $PCData.DomainRole
}
if ($PCData.CurrentTimeZone) {
$postData.currentTimeZone = $PCData.CurrentTimeZone
}
# Add GE Registry info (DualPath configuration)
if ($PCData.GERegistryInfo) {
$postData.dncGeRegistry32Bit = if ($PCData.GERegistryInfo.Registry32Bit) { "1" } else { "0" }
$postData.dncGeRegistry64Bit = if ($PCData.GERegistryInfo.Registry64Bit) { "1" } else { "0" }
if ($PCData.GERegistryInfo.DualPathEnabled -ne $null) {
$postData.dncDualPathEnabled = if ($PCData.GERegistryInfo.DualPathEnabled) { "1" } else { "0" }
}
if ($PCData.GERegistryInfo.Path1Name) {
$postData.dncPath1Name = $PCData.GERegistryInfo.Path1Name
}
if ($PCData.GERegistryInfo.Path2Name) {
$postData.dncPath2Name = $PCData.GERegistryInfo.Path2Name
}
}
# Add default printer FQDN
if ($PCData.DefaultPrinterFQDN) {
$postData.defaultPrinterFQDN = $PCData.DefaultPrinterFQDN
}
# Add network interfaces as JSON
if ($PCData.NetworkInterfaces -and $PCData.NetworkInterfaces.Count -gt 0) {
$postData.networkInterfaces = ($PCData.NetworkInterfaces | ConvertTo-Json -Compress)
@@ -988,10 +1081,14 @@ function Send-PCDataToApi {
# Send to API
$response = Invoke-RestMethod @restParams
# Debug: log full API response for relationship troubleshooting
Write-Log " API Response: $($response | ConvertTo-Json -Compress)" -Level "INFO"
return @{
Success = $response.success
Message = $response.message
MachineId = $response.machineid
RelationshipCreated = $response.relationshipCreated
}
} catch {
$errMsg = $_.Exception.Message
@@ -1016,6 +1113,7 @@ function Send-PCDataToApi {
Success = $response.success
Message = $response.message
MachineId = $response.machineid
RelationshipCreated = $response.relationshipCreated
}
} catch {
# WebClient also failed
@@ -1317,6 +1415,12 @@ foreach ($result in $results) {
Write-Log " IPs: $ips" -Level "INFO"
}
if ($result.LoggedInUser) {
Write-Log " Logged In: $($result.LoggedInUser)" -Level "INFO"
} else {
Write-Log " Logged In: (none)" -Level "INFO"
}
if ($result.MachineNo) {
Write-Log " Machine #: $($result.MachineNo)" -Level "INFO"
} elseif ($result.IsGenericMachineNo) {
@@ -1358,6 +1462,11 @@ foreach ($result in $results) {
if ($apiResult.Success) {
Write-Log " -> Updated in ShopDB (MachineID: $($apiResult.MachineId))" -Level "SUCCESS"
if ($apiResult.RelationshipCreated) {
Write-Log " -> Machine Relationship: Created" -Level "SUCCESS"
} elseif ($result.MachineNo) {
Write-Log " -> Machine Relationship: FAILED (machineNo=$($result.MachineNo))" -Level "ERROR"
}
# Update WinRM status - since we successfully connected via WinRM, mark it as enabled
try {
@@ -1492,6 +1601,11 @@ if ($connectionFailures.Count -gt 0) {
if ($apiResult.Success) {
Write-Log " -> Updated in ShopDB (MachineID: $($apiResult.MachineId))" -Level "SUCCESS"
if ($apiResult.RelationshipCreated) {
Write-Log " -> Machine Relationship: Created" -Level "SUCCESS"
} elseif ($ipResult.MachineNo) {
Write-Log " -> Machine Relationship: FAILED (machineNo=$($ipResult.MachineNo))" -Level "ERROR"
}
$successCount++
$successPCs += @{
Hostname = $ipResult.Hostname