# Functions to collect shopfloor PC network and communication configurations # Function to get all network interfaces and their configurations function Get-NetworkInterfaceConfig { Write-Host " Collecting network interface information..." -ForegroundColor Yellow $interfaces = @() try { # Get all network adapters with IP configurations $adapters = Get-NetAdapter | Where-Object { $_.Status -eq 'Up' } foreach ($adapter in $adapters) { $ipConfig = Get-NetIPConfiguration -InterfaceIndex $adapter.ifIndex -ErrorAction SilentlyContinue if ($ipConfig -and $ipConfig.IPv4Address) { foreach ($ip in $ipConfig.IPv4Address) { $gateway = if ($ipConfig.IPv4DefaultGateway) { $ipConfig.IPv4DefaultGateway[0].NextHop } else { $null } # Determine if this is a machine network (192.168.*.*) $isMachineNetwork = $ip.IPAddress -match '^192\.168\.' $interface = @{ InterfaceName = $adapter.Name IPAddress = $ip.IPAddress SubnetMask = $ip.PrefixLength # Will need conversion DefaultGateway = $gateway MACAddress = $adapter.MacAddress IsDHCP = if ($ipConfig.NetIPv4Interface.Dhcp -eq 'Enabled') { 1 } else { 0 } IsActive = 1 IsMachineNetwork = if ($isMachineNetwork) { 1 } else { 0 } } $interfaces += $interface if ($isMachineNetwork) { Write-Host " Found machine network: $($ip.IPAddress) on $($adapter.Name)" -ForegroundColor Cyan } else { Write-Host " Found network: $($ip.IPAddress) on $($adapter.Name)" -ForegroundColor Gray } } } } } catch { Write-Host " Error collecting network info: $_" -ForegroundColor Red } # Alternative method using WMI if NetAdapter cmdlets fail if ($interfaces.Count -eq 0) { try { $wmiAdapters = Get-WmiObject Win32_NetworkAdapterConfiguration | Where-Object { $_.IPEnabled -eq $true } foreach ($adapter in $wmiAdapters) { if ($adapter.IPAddress) { foreach ($i in 0..($adapter.IPAddress.Count - 1)) { $ip = $adapter.IPAddress[$i] # Skip IPv6 addresses if ($ip -match ':') { continue } $isMachineNetwork = $ip -match '^192\.168\.' $interface = @{ InterfaceName = $adapter.Description IPAddress = $ip SubnetMask = $adapter.IPSubnet[$i] DefaultGateway = if ($adapter.DefaultIPGateway) { $adapter.DefaultIPGateway[0] } else { $null } MACAddress = $adapter.MACAddress IsDHCP = $adapter.DHCPEnabled IsActive = 1 IsMachineNetwork = if ($isMachineNetwork) { 1 } else { 0 } } $interfaces += $interface if ($isMachineNetwork) { Write-Host " Found machine network: $ip on $($adapter.Description)" -ForegroundColor Cyan } } } } } catch { Write-Host " WMI method also failed: $_" -ForegroundColor Red } } return $interfaces } # Function to get serial port configurations from registry function Get-SerialPortConfig { Write-Host " Collecting serial port configurations..." -ForegroundColor Yellow $configs = @() # Registry paths to check $registryPaths = @{ 'Serial' = @('HKLM:\SOFTWARE\GE Aircraft Engines\DNC\Serial', 'HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines\DNC\Serial') 'Mark' = @('HKLM:\SOFTWARE\GE Aircraft Engines\DNC\Mark', 'HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines\DNC\Mark') 'PPDCS' = @('HKLM:\SOFTWARE\GE Aircraft Engines\DNC\PPDCS', 'HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines\DNC\PPDCS') 'TQM9030' = @('HKLM:\SOFTWARE\GE Aircraft Engines\DNC\TQM9030', 'HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines\DNC\TQM9030') 'TQMCaron' = @('HKLM:\SOFTWARE\GE Aircraft Engines\DNC\TQMCaron', 'HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines\DNC\TQMCaron') } foreach ($configType in $registryPaths.Keys) { foreach ($path in $registryPaths[$configType]) { if (Test-Path $path) { try { $regValues = Get-ItemProperty -Path $path -ErrorAction SilentlyContinue if ($regValues) { $config = @{ ConfigType = $configType PortID = $regValues.'Port Id' -replace 'Port Id2', '' Baud = $regValues.Baud DataBits = $regValues.'Data Bits' StopBits = $regValues.'Stop Bits' Parity = $regValues.Parity CRLF = $regValues.CRLF IPAddress = $null SocketNo = $null AdditionalSettings = @{} } # Collect any additional settings $standardKeys = @('Port Id', 'Baud', 'Data Bits', 'Stop Bits', 'Parity', 'CRLF', 'PSPath', 'PSParentPath', 'PSChildName', 'PSProvider') foreach ($prop in $regValues.PSObject.Properties) { if ($prop.Name -notin $standardKeys -and $prop.Value) { $config.AdditionalSettings[$prop.Name] = $prop.Value } } # Convert additional settings to JSON if ($config.AdditionalSettings.Count -gt 0) { $config.AdditionalSettings = $config.AdditionalSettings | ConvertTo-Json -Compress } else { $config.AdditionalSettings = $null } if ($config.PortID) { $configs += $config Write-Host " Found $configType config: Port $($config.PortID), Baud $($config.Baud)" -ForegroundColor Cyan } } } catch { Write-Host " Error reading $configType registry: $_" -ForegroundColor Red } } } } # Check for eFocas configuration (network-based) $efocasPaths = @('HKLM:\SOFTWARE\GE Aircraft Engines\DNC\eFocas', 'HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines\DNC\eFocas') foreach ($path in $efocasPaths) { if (Test-Path $path) { try { $regValues = Get-ItemProperty -Path $path -ErrorAction SilentlyContinue if ($regValues -and $regValues.IpAddr) { $config = @{ ConfigType = 'eFocas' PortID = $null Baud = $null DataBits = $null StopBits = $null Parity = $null CRLF = $null IPAddress = $regValues.IpAddr SocketNo = $regValues.SocketNo AdditionalSettings = @{ DualPath = $regValues.DualPath Path1Name = $regValues.Path1Name Path2Name = $regValues.Path2Name Danobat = $regValues.Danobat DataServer = $regValues.DataServer } | ConvertTo-Json -Compress } $configs += $config Write-Host " Found eFocas config: IP $($config.IPAddress), Socket $($config.SocketNo)" -ForegroundColor Cyan } } catch { Write-Host " Error reading eFocas registry: $_" -ForegroundColor Red } } } return $configs } # Function to get GE Aircraft Engines registry information and DualPath configuration function Get-GERegistryInfo { Write-Host " Collecting GE Aircraft Engines registry information..." -ForegroundColor Yellow $geInfo = @{ Registry32Bit = $false Registry64Bit = $false DualPathEnabled = $null Path1Name = $null Path2Name = $null RegistryNotes = @{} } # Check both 32-bit and 64-bit registry paths $registryPaths = @{ '32bit' = 'HKLM:\SOFTWARE\GE Aircraft Engines' '64bit' = 'HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines' } foreach ($pathType in $registryPaths.Keys) { $basePath = $registryPaths[$pathType] Write-Host " Checking $pathType registry: $basePath" -ForegroundColor Gray if (Test-Path $basePath) { Write-Host " [FOUND] GE Aircraft Engines in $pathType registry" -ForegroundColor Green if ($pathType -eq '32bit') { $geInfo.Registry32Bit = $true } else { $geInfo.Registry64Bit = $true } # Collect information about what's under GE Aircraft Engines try { $subKeys = Get-ChildItem -Path $basePath -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Name | ForEach-Object { Split-Path $_ -Leaf } $geInfo.RegistryNotes[$pathType] = @{ BasePath = $basePath SubKeys = $subKeys -join ', ' Found = Get-Date -Format "yyyy-MM-dd HH:mm:ss" } Write-Host " Sub-keys found: $($subKeys -join ', ')" -ForegroundColor Cyan } catch { Write-Host " Error reading sub-keys: $_" -ForegroundColor Red $geInfo.RegistryNotes[$pathType] = @{ Error = $_.Exception.Message } } # Check for DualPath configuration in eFocas $efocasPath = "$basePath\DNC\eFocas" if (Test-Path $efocasPath) { Write-Host " Checking eFocas configuration for DualPath..." -ForegroundColor Yellow try { $efocasValues = Get-ItemProperty -Path $efocasPath -ErrorAction SilentlyContinue if ($efocasValues.DualPath) { Write-Host " [FOUND] DualPath = $($efocasValues.DualPath)" -ForegroundColor Green # Handle case where both registry locations exist - prioritize settings from first found if ($geInfo.DualPathEnabled -eq $null) { $geInfo.DualPathEnabled = $efocasValues.DualPath -eq 'YES' Write-Host " Setting DualPath from $pathType registry: $($geInfo.DualPathEnabled)" -ForegroundColor Cyan } else { Write-Host " DualPath already set from other registry location, keeping existing value" -ForegroundColor Yellow } # Handle Path1Name - use first non-empty value found if (!$geInfo.Path1Name -and $efocasValues.Path1Name) { $geInfo.Path1Name = $efocasValues.Path1Name Write-Host " Path1Name = $($efocasValues.Path1Name)" -ForegroundColor Cyan } # Handle Path2Name - use first non-empty value found if (!$geInfo.Path2Name -and $efocasValues.Path2Name) { $geInfo.Path2Name = $efocasValues.Path2Name Write-Host " Path2Name = $($efocasValues.Path2Name)" -ForegroundColor Cyan } # Store additional eFocas settings $geInfo.RegistryNotes["$pathType-eFocas"] = @{ DualPath = $efocasValues.DualPath Path1Name = $efocasValues.Path1Name Path2Name = $efocasValues.Path2Name IpAddr = $efocasValues.IpAddr SocketNo = $efocasValues.SocketNo Danobat = $efocasValues.Danobat DataServer = $efocasValues.DataServer } } } catch { Write-Host " Error reading eFocas configuration: $_" -ForegroundColor Red } } } else { Write-Host " [NOT FOUND] No GE Aircraft Engines in $pathType registry" -ForegroundColor Gray } } # Summary Write-Host " GE Registry Summary:" -ForegroundColor Green Write-Host " 32-bit registry: $(if ($geInfo.Registry32Bit) { 'YES' } else { 'NO' })" -ForegroundColor Cyan Write-Host " 64-bit registry: $(if ($geInfo.Registry64Bit) { 'YES' } else { 'NO' })" -ForegroundColor Cyan Write-Host " DualPath enabled: $(if ($geInfo.DualPathEnabled -eq $null) { 'NOT FOUND' } elseif ($geInfo.DualPathEnabled) { 'YES' } else { 'NO' })" -ForegroundColor Cyan if ($geInfo.Path1Name) { Write-Host " Path1Name: $($geInfo.Path1Name)" -ForegroundColor Cyan } if ($geInfo.Path2Name) { Write-Host " Path2Name: $($geInfo.Path2Name)" -ForegroundColor Cyan } return $geInfo } # Function to get DNC configuration from registry function Get-DNCConfig { Write-Host " Collecting DNC configuration..." -ForegroundColor Yellow $dncConfig = $null $paths = @('HKLM:\SOFTWARE\GE Aircraft Engines\DNC\General', 'HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines\DNC\General') Write-Host " Checking registry paths for DNC config..." -ForegroundColor Gray foreach ($path in $paths) { Write-Host " Checking path: $path" -ForegroundColor Gray if (Test-Path $path) { Write-Host " Path exists! Reading values..." -ForegroundColor Green try { $general = Get-ItemProperty -Path $path -ErrorAction SilentlyContinue $mxPath = $path -replace 'General', 'MX' $mx = Get-ItemProperty -Path $mxPath -ErrorAction SilentlyContinue $fmsPath = $path -replace 'General', 'FMS' $fms = Get-ItemProperty -Path $fmsPath -ErrorAction SilentlyContinue if ($general) { Write-Host " Found General config values!" -ForegroundColor Green $dncConfig = @{ Site = $general.Site CNC = $general.Cnc NcIF = $general.NcIF MachineNo = $general.MachineNo HostType = $general.HostType FtpHostPrimary = if ($mx) { $mx.FtpHostPrimary } else { $null } FtpHostSecondary = if ($mx) { $mx.FtpHostSecondary } else { $null } FtpAccount = if ($mx) { $mx.FtpAccount } else { $null } Debug = $general.Debug Uploads = $general.Uploads Scanner = $general.Scanner Dripfeed = $general.Dripfeed AdditionalSettings = @{ Mode = $general.Mode 'Unit/Area' = $general.'Unit/Area' DvUpldDir = $general.DvUpldDir Ncedt = $general.Ncedt Maint = $general.Maint ChangeWorkstation = $general.ChangeWorkstation FMSHostPrimary = if ($fms) { $fms.FMSHostPrimary } else { $null } FMSHostSecondary = if ($fms) { $fms.FMSHostSecondary } else { $null } } | ConvertTo-Json -Compress } Write-Host " Found DNC config: Site=$($dncConfig.Site), MachineNo=$($dncConfig.MachineNo), CNC=$($dncConfig.CNC)" -ForegroundColor Cyan Write-Host " DNC Config JSON: $($dncConfig | ConvertTo-Json -Compress)" -ForegroundColor Gray break } } catch { Write-Host " Error reading DNC registry: $_" -ForegroundColor Red } } else { Write-Host " Path does not exist" -ForegroundColor Yellow } } if (-not $dncConfig) { Write-Host " No DNC configuration found in registry" -ForegroundColor Yellow } return $dncConfig } # Main function to collect all shopfloor configurations function Get-ShopfloorConfigurations { Write-Host "`nCollecting shopfloor-specific configurations..." -ForegroundColor Yellow $configurations = @{ NetworkInterfaces = Get-NetworkInterfaceConfig CommConfigs = Get-SerialPortConfig DNCConfig = Get-DNCConfig GERegistryInfo = Get-GERegistryInfo } # Summary Write-Host "`n Configuration Summary:" -ForegroundColor Green Write-Host " Network Interfaces: $($configurations.NetworkInterfaces.Count)" -ForegroundColor Cyan Write-Host " Comm Configs: $($configurations.CommConfigs.Count)" -ForegroundColor Cyan Write-Host " DNC Config: $(if ($configurations.DNCConfig) { 'Yes' } else { 'No' })" -ForegroundColor Cyan Write-Host " GE Registry (32-bit): $(if ($configurations.GERegistryInfo.Registry32Bit) { 'Yes' } else { 'No' })" -ForegroundColor Cyan Write-Host " GE Registry (64-bit): $(if ($configurations.GERegistryInfo.Registry64Bit) { 'Yes' } else { 'No' })" -ForegroundColor Cyan Write-Host " DualPath Enabled: $(if ($configurations.GERegistryInfo.DualPathEnabled -eq $null) { 'Not Found' } elseif ($configurations.GERegistryInfo.DualPathEnabled) { 'Yes' } else { 'No' })" -ForegroundColor Cyan return $configurations } function Get-InstalledApplications { <# .SYNOPSIS Detects UDC and CLM applications and their active status on shopfloor PCs .DESCRIPTION Checks for UDC (UDC.exe) and CLM (ppdcs.exe) processes and returns data compatible with your existing installedapps table structure. #> Write-Host " Scanning for UDC and CLM applications..." -ForegroundColor Yellow $detectedApps = @() try { # Define the two applications we're looking for $appsToCheck = @{ 'UDC' = @{ AppID = 2 # Universal Data Collector ProcessName = 'UDC' # UDC.exe shows as 'UDC' in Get-Process Description = 'Universal Data Collector' } 'CLM' = @{ AppID = 4 # Legacy UDC (CLM) ProcessName = 'ppdcs' # ppdcs.exe shows as 'ppdcs' in Get-Process Description = 'Legacy UDC (Cell Level Manager)' } } foreach ($appName in $appsToCheck.Keys) { $app = $appsToCheck[$appName] Write-Host " Checking for $appName (AppID: $($app.AppID))..." -ForegroundColor Gray # Check if the process is running $isActive = $false $processInfo = $null try { $processes = Get-Process -Name $app.ProcessName -ErrorAction SilentlyContinue if ($processes) { $isActive = $true $processInfo = $processes[0] # Take first instance if multiple Write-Host " [ACTIVE] Found running process: $($app.ProcessName).exe (PID: $($processInfo.Id))" -ForegroundColor Green } else { Write-Host " [NOT ACTIVE] Process $($app.ProcessName).exe not running" -ForegroundColor Gray } } catch { Write-Host " [ERROR] Failed to check process $($app.ProcessName): $($_.Exception.Message)" -ForegroundColor Yellow } # Always return app info (both active and inactive) $detectedApps += @{ AppID = $app.AppID AppName = $appName Description = $app.Description ProcessName = $app.ProcessName IsActive = $isActive ProcessID = if ($processInfo) { $processInfo.Id } else { $null } ProcessStartTime = if ($processInfo) { $processInfo.StartTime } else { $null } } } # Business rule validation: Only one should be active $activeApps = $detectedApps | Where-Object { $_.IsActive -eq $true } if ($activeApps.Count -gt 1) { Write-Host " [WARNING] Multiple applications active simultaneously:" -ForegroundColor Red foreach ($activeApp in $activeApps) { Write-Host " - $($activeApp.AppName) (PID: $($activeApp.ProcessID))" -ForegroundColor Red } } elseif ($activeApps.Count -eq 1) { $activeApp = $activeApps[0] Write-Host " [OK] Single active application: $($activeApp.AppName) (PID: $($activeApp.ProcessID))" -ForegroundColor Green } else { Write-Host " [INFO] No UDC or CLM applications currently running" -ForegroundColor Gray } return $detectedApps } catch { Write-Host " [ERROR] Failed to scan for applications: $($_.Exception.Message)" -ForegroundColor Red return @() } }