diff --git a/complete-asset/Get-ShopfloorConfig.ps1 b/complete-asset/Get-ShopfloorConfig.ps1 index 35f21ef..0a40903 100644 --- a/complete-asset/Get-ShopfloorConfig.ps1 +++ b/complete-asset/Get-ShopfloorConfig.ps1 @@ -17,9 +17,11 @@ function Get-NetworkInterfaceConfig { 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\.' - + # Determine if this is a machine network (192.168.*.* or 100.0.0.* for CMM) + $isMachineNetwork = $ip.IPAddress -match '^192\.168\.' -or $ip.IPAddress -match '^100\.0\.0\.' + # Determine if this is the primary network (10.134.*.*) + $isPrimary = $ip.IPAddress -match '^10\.134\.' + $interface = @{ InterfaceName = $adapter.Name IPAddress = $ip.IPAddress @@ -29,11 +31,15 @@ function Get-NetworkInterfaceConfig { IsDHCP = if ($ipConfig.NetIPv4Interface.Dhcp -eq 'Enabled') { 1 } else { 0 } IsActive = 1 IsMachineNetwork = if ($isMachineNetwork) { 1 } else { 0 } + IsPrimary = if ($isPrimary) { 1 } else { 0 } } - + $interfaces += $interface - - if ($isMachineNetwork) { + + if ($isPrimary) { + Write-Host " Found PRIMARY network: $($ip.IPAddress) on $($adapter.Name)" -ForegroundColor Green + } + elseif ($isMachineNetwork) { Write-Host " Found machine network: $($ip.IPAddress) on $($adapter.Name)" -ForegroundColor Cyan } else { @@ -60,8 +66,9 @@ function Get-NetworkInterfaceConfig { # Skip IPv6 addresses if ($ip -match ':') { continue } - $isMachineNetwork = $ip -match '^192\.168\.' - + $isMachineNetwork = $ip -match '^192\.168\.' -or $ip -match '^100\.0\.0\.' + $isPrimary = $ip -match '^10\.134\.' + $interface = @{ InterfaceName = $adapter.Description IPAddress = $ip @@ -71,11 +78,15 @@ function Get-NetworkInterfaceConfig { IsDHCP = $adapter.DHCPEnabled IsActive = 1 IsMachineNetwork = if ($isMachineNetwork) { 1 } else { 0 } + IsPrimary = if ($isPrimary) { 1 } else { 0 } } - + $interfaces += $interface - - if ($isMachineNetwork) { + + if ($isPrimary) { + Write-Host " Found PRIMARY network: $ip on $($adapter.Description)" -ForegroundColor Green + } + elseif ($isMachineNetwork) { Write-Host " Found machine network: $ip on $($adapter.Description)" -ForegroundColor Cyan } } diff --git a/complete-asset/Update-PC-CompleteAsset.ps1 b/complete-asset/Update-PC-CompleteAsset.ps1 index 6443856..f0dec63 100644 --- a/complete-asset/Update-PC-CompleteAsset.ps1 +++ b/complete-asset/Update-PC-CompleteAsset.ps1 @@ -622,9 +622,23 @@ function Get-PCType { # ================================================================ # PC Type Detection based on installed software - # Priority: CMM > Wax Trace > Keyence > EAS1000 > Genspect > Heat Treat > Shopfloor + # Priority: Dashboard > Lobby Display > CMM > Wax Trace > Keyence > EAS1000 > Genspect > Heat Treat > Shopfloor # ================================================================ + # Dashboard Detection (GE Aerospace Dashboard kiosk installer) - HIGHEST PRIORITY + $hasDashboard = $installedApps -match "^GE Aerospace Dashboard" + if ($hasDashboard) { + Write-Host " [OK] Dashboard software detected - Dashboard PC" -ForegroundColor Cyan + return "Dashboard" + } + + # Lobby Display Detection (GE Aerospace Lobby Display kiosk installer) + $hasLobbyDisplay = $installedApps -match "^GE Aerospace Lobby Display" + if ($hasLobbyDisplay) { + Write-Host " [OK] Lobby Display software detected - Lobby Display PC" -ForegroundColor Cyan + return "Lobby Display" + } + # CMM Detection: PC-DMIS, goCMM, DODA $hasPcDmis = $installedApps -match "PC-DMIS|PCDMIS" $hasGoCMM = $installedApps -match "^goCMM" @@ -707,23 +721,23 @@ function Get-PCType { return "Heat Treat" } - # Part Marker Detection: By machine number (0612, 0613, 0615, 8003) or software + # Inspection Detection: By machine number (0612, 0613, 0615, 8003) or software $machineNo = Get-GEMachineNumber -Hostname $env:COMPUTERNAME $isPartMarkerMachine = $false if ($machineNo) { - # Check if machine number matches Part Marker machines (0612, 0613, 0615, 8003) + # Check if machine number matches Inspection machines (0612, 0613, 0615, 8003) if ($machineNo -match "^0?(612|613|615|8003)$" -or $machineNo -match "^M?(612|613|615|8003)$") { $isPartMarkerMachine = $true - Write-Host " [OK] Part Marker machine detected (Machine #$machineNo) - Part Marker PC" -ForegroundColor Cyan - return "Part Marker" + Write-Host " [OK] Inspection machine detected (Machine #$machineNo) - Inspection PC" -ForegroundColor Cyan + return "Inspection" } } - # Also check for Part Marker software + # Also check for Inspection software $hasPartMarker = $installedApps -match "Part\s*Mark|PartMark|Telesis|MECCO|Pryor|Gravotech|SIC Marking" if ($hasPartMarker) { - Write-Host " [OK] Part Marker software detected - Part Marker PC" -ForegroundColor Cyan - return "Part Marker" + Write-Host " [OK] Inspection software detected - Inspection PC" -ForegroundColor Cyan + return "Inspection" } return "Shopfloor" @@ -886,6 +900,137 @@ function Collect-SystemInfo { $systemInfo.TrackedApplications = @() } + # ================================================================ + # Collect serial port configuration (for parity with remote script) + # ================================================================ + Write-Host " Collecting serial port configuration..." -ForegroundColor Yellow + try { + $comPorts = @() + $serialPorts = Get-CimInstance -ClassName Win32_SerialPort -ErrorAction SilentlyContinue + foreach ($port in $serialPorts) { + $comPorts += @{ + PortName = $port.DeviceID + Description = $port.Description + } + Write-Host " Found COM port: $($port.DeviceID) - $($port.Description)" -ForegroundColor Gray + } + $systemInfo.SerialPorts = $comPorts + if ($comPorts.Count -eq 0) { + Write-Host " No serial ports found" -ForegroundColor Gray + } else { + Write-Host " [OK] Found $($comPorts.Count) serial port(s)" -ForegroundColor Cyan + } + } + catch { + Write-Host " [WARN] Failed to collect serial ports: $($_.Exception.Message)" -ForegroundColor Yellow + $systemInfo.SerialPorts = @() + } + + # ================================================================ + # Check for VNC installation (for parity with remote script) + # ================================================================ + Write-Host " Checking for VNC installation..." -ForegroundColor Yellow + try { + $hasVnc = $false + $regPaths = @( + "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", + "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*", + "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" + ) + foreach ($path in $regPaths) { + if (Test-Path $path) { + $vncApps = Get-ItemProperty $path -ErrorAction SilentlyContinue | + Where-Object { $_.DisplayName -like "*VNC Server*" -or $_.DisplayName -like "*VNC Connect*" -or $_.DisplayName -like "*RealVNC*" } + if ($vncApps) { + $hasVnc = $true + Write-Host " [OK] VNC software detected in registry" -ForegroundColor Cyan + break + } + } + } + if (-not $hasVnc) { + $vncService = Get-Service -Name "vncserver*" -ErrorAction SilentlyContinue + if ($vncService) { + $hasVnc = $true + Write-Host " [OK] VNC service detected" -ForegroundColor Cyan + } + } + if (-not $hasVnc) { + Write-Host " No VNC installation found" -ForegroundColor Gray + } + $systemInfo.HasVnc = $hasVnc + } + catch { + Write-Host " [WARN] Failed to check for VNC: $($_.Exception.Message)" -ForegroundColor Yellow + $systemInfo.HasVnc = $false + } + + # ================================================================ + # Collect ALL installed applications including HKU (per-user) registry + # This provides complete app list for parity with remote script + # ================================================================ + Write-Host " Collecting complete application list (including per-user)..." -ForegroundColor Yellow + try { + $allApps = @() + + # Get from HKLM (machine-wide) + $hklmPaths = @( + "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", + "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" + ) + foreach ($path in $hklmPaths) { + if (Test-Path $path) { + $apps = Get-ItemProperty $path -ErrorAction SilentlyContinue | + Where-Object { $_.DisplayName -and $_.DisplayName.Trim() -ne "" } + foreach ($app in $apps) { + if ($app.DisplayName -notin $allApps) { + $allApps += $app.DisplayName + } + } + } + } + + # Get from HKCU (current user) + $hkcuPath = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" + if (Test-Path $hkcuPath) { + $apps = Get-ItemProperty $hkcuPath -ErrorAction SilentlyContinue | + Where-Object { $_.DisplayName -and $_.DisplayName.Trim() -ne "" } + foreach ($app in $apps) { + if ($app.DisplayName -notin $allApps) { + $allApps += $app.DisplayName + } + } + } + + # Check per-user installed apps by enumerating loaded hives in HKU + $hkuKeys = Get-ChildItem "Registry::HKU" -ErrorAction SilentlyContinue + foreach ($key in $hkuKeys) { + $sid = $key.PSChildName + # Only check real user SIDs (S-1-5-21-*), skip _Classes entries + if ($sid -match "^S-1-5-21-" -and $sid -notmatch "_Classes$") { + $userUninstallPath = "Registry::HKU\$sid\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" + if (Test-Path $userUninstallPath -ErrorAction SilentlyContinue) { + $apps = Get-ItemProperty $userUninstallPath -ErrorAction SilentlyContinue | + Where-Object { $_.DisplayName -and $_.DisplayName.Trim() -ne "" } + foreach ($app in $apps) { + if ($app.DisplayName -notin $allApps) { + $allApps += $app.DisplayName + } + } + } + } + } + + $systemInfo.AllInstalledApps = ($allApps | Sort-Object) -join "|" + $systemInfo.AllInstalledAppsCount = $allApps.Count + Write-Host " [OK] Collected $($allApps.Count) total applications (including per-user)" -ForegroundColor Cyan + } + catch { + Write-Host " [WARN] Failed to collect complete application list: $($_.Exception.Message)" -ForegroundColor Yellow + $systemInfo.AllInstalledApps = "" + $systemInfo.AllInstalledAppsCount = 0 + } + # Collect running processes (for log analysis) Write-Host " Running processes:" -ForegroundColor Yellow try { @@ -1210,7 +1355,7 @@ function Send-CompleteDataToDashboard { if ($SystemInfo.InstalledApplications -and $SystemInfo.InstalledApplications.Count -gt 0) { $postData.installedApplications = $SystemInfo.InstalledApplications | ConvertTo-Json -Compress Write-Host " Sending installed applications data:" -ForegroundColor Cyan - + $activeApps = $SystemInfo.InstalledApplications | Where-Object { $_.IsActive -eq $true } if ($activeApps.Count -gt 0) { foreach ($app in $activeApps) { @@ -1222,7 +1367,32 @@ function Send-CompleteDataToDashboard { } else { Write-Host " No installed applications to send" -ForegroundColor Gray } - + + # ================================================================ + # Add VNC status (for parity with remote script) + # ================================================================ + if ($SystemInfo.HasVnc -ne $null) { + $postData.hasVnc = if ($SystemInfo.HasVnc) { "1" } else { "0" } + Write-Host " VNC Status: $(if ($SystemInfo.HasVnc) { 'Installed' } else { 'Not Installed' })" -ForegroundColor $(if ($SystemInfo.HasVnc) { 'Cyan' } else { 'Gray' }) + } + + # ================================================================ + # Add serial ports (for parity with remote script) + # ================================================================ + if ($SystemInfo.SerialPorts -and $SystemInfo.SerialPorts.Count -gt 0) { + $postData.serialPorts = $SystemInfo.SerialPorts | ConvertTo-Json -Compress + Write-Host " Serial Ports: $($SystemInfo.SerialPorts.Count) port(s)" -ForegroundColor Cyan + } + + # ================================================================ + # Add complete installed apps list (for parity with remote script) + # ================================================================ + if ($SystemInfo.AllInstalledApps) { + $postData.allInstalledApps = $SystemInfo.AllInstalledApps + $postData.allInstalledAppsCount = $SystemInfo.AllInstalledAppsCount + Write-Host " Complete Apps List: $($SystemInfo.AllInstalledAppsCount) total applications" -ForegroundColor Cyan + } + # Send to dashboard API $headers = @{ 'Content-Type' = 'application/x-www-form-urlencoded' @@ -1232,10 +1402,19 @@ function Send-CompleteDataToDashboard { if ($response.success) { Write-Host " [OK] Complete asset data stored in database!" -ForegroundColor Green - $data = $response.data - Write-Host " PCID: $(if($data.pcid) { $data.pcid } else { 'Unknown' })" - Write-Host " Updated/Created: $(if($data.operation) { $data.operation } else { 'Unknown' })" - Write-Host " Records affected: $(if($data.recordsAffected) { $data.recordsAffected } else { 'Unknown' })" + Write-Host " PCID: $(if($response.machineid) { $response.machineid } else { 'Unknown' })" + Write-Host " Operation: $(if($response.operation) { $response.operation } else { 'Unknown' })" + Write-Host " Network Interfaces: $(if($response.networkInterfacesCount -ne $null) { $response.networkInterfacesCount } else { 'Unknown' })" + Write-Host " Comm Configs: $(if($response.commConfigsCount -ne $null) { $response.commConfigsCount } else { 'Unknown' })" + Write-Host " DNC Config: $(if($response.dncConfigSuccess -ne $null) { $response.dncConfigSuccess } else { 'Unknown' })" + Write-Host " Installed Apps: $(if($response.installedAppsCount -ne $null) { $response.installedAppsCount } else { 'Unknown' })" + if ($response.relationshipCreated) { + Write-Host " Machine Relationship: Created" -ForegroundColor Green + } elseif ($SystemInfo.MachineNo) { + Write-Host " Machine Relationship: FAILED (machineNo=$($SystemInfo.MachineNo))" -ForegroundColor Red + } else { + Write-Host " Machine Relationship: Skipped (no machine number)" -ForegroundColor Gray + } return $true } else { Write-Host " [FAIL] Dashboard could not store data: $($response.error)" -ForegroundColor Red diff --git a/docs/DATA_COLLECTION_PARITY.html b/docs/DATA_COLLECTION_PARITY.html new file mode 100644 index 0000000..19f6bf0 --- /dev/null +++ b/docs/DATA_COLLECTION_PARITY.html @@ -0,0 +1,1115 @@ + + +
+ + +Comprehensive comparison of data fields collected by the remote and local PowerShell scripts, including collection methods and API mapping.
+Both the remote and local collection scripts are designed to collect the same data fields for shopfloor PCs. This document provides a comprehensive reference for what data is collected, how it's collected, and any differences between the two approaches.
+Goal: Any field collected by one script should also be collected by the other (where technically feasible).
+| Aspect | +Remote Script | +Local Script | +
|---|---|---|
| Name | +Update-ShopfloorPCs-Remote.ps1 | +Update-PC-CompleteAsset.ps1 | +
| Location | +S:\dt\shopfloor\scripts\remote-execution\ |
+S:\dt\shopfloor\scripts\complete-asset\ |
+
| Execution | +From admin workstation via WinRM | +Directly on target PC | +
| Context | +SYSTEM via WinRM | +Local user or SYSTEM | +
| Batch Support | +Yes (many PCs) | +No (one PC at a time) | +
| WinRM Required | +Yes | +No | +
| Category | +Field | +Remote | +Local | +Parity | +
|---|---|---|---|---|
| System | +Hostname | +✓ | +✓ | +✓ | +
| + | Serial Number | +✓ | +✓ | +✓ | +
| + | Service Tag | +✓ | +✓ | +✓ | +
| + | Manufacturer | +✓ | +✓ | +✓ | +
| + | Model | +✓ | +✓ | +✓ | +
| + | Total Physical Memory | +✓ | +✓ | +✓ | +
| + | Domain Role | +✓ | +✓ | +✓ | +
| + | OS Version | +✓ | +✓ | +✓ | +
| + | Last Boot Time | +✓ | +✓ | +✓ | +
| + | Current Time Zone | +✓ | +✓ | +✓ | +
| + | Logged In User | +✓ | +✓ | +✓ | +
| + | PC Type | +✓ | +✓ | +✓ | +
| + | Machine No | +✓ | +✓ | +✓ | +
| DNC | +Site | +✓ | +✓ | +✓ | +
| + | CNC | +✓ | +✓ | +✓ | +
| + | NcIF | +✓ | +✓ | +✓ | +
| + | Host Type | +✓ | +✓ | +✓ | +
| + | FTP Primary | +✓ | +✓ | +✓ | +
| + | FTP Secondary | +✓ | +✓ | +✓ | +
| GE Registry | +32-bit Present | +✓ | +✓ | +✓ | +
| + | 64-bit Present | +✓ | +✓ | +✓ | +
| + | Dual Path Enabled | +✓ | +✓ | +✓ | +
| + | Path 1 Name | +✓ | +✓ | +✓ | +
| + | Path 2 Name | +✓ | +✓ | +✓ | +
| Network | +Interface Name | +✓ | +✓ | +✓ | +
| + | IP Address | +✓ | +✓ | +✓ | +
| + | Subnet Mask | +✓ | +✓ | +✓ | +
| + | Default Gateway | +✓ | +✓ | +✓ | +
| + | MAC Address | +✓ | +✓ | +✓ | +
| + | Is DHCP | +✓ | +✓ | +✓ | +
| + | Is Active | +✓ | +✓ | +✓ | +
| + | Is Machine Network | +✓ | +✓ | +✓ | +
| + | Is Primary | +✓ | +✓ | +✓ | +
| Apps | +Serial Ports | +✓ | +✓ | +✓ | +
| + | Has VNC | +✓ | +✓ | +✓ | +
| + | All Installed Apps | +✓ | +✓ | +✓ | +
| + | Tracked Applications | +✓ | +✓ | +✓ | +
| + | UDC Running | +✓ | +✓ | +✓ | +
| + | CLM Running | +✓ | +✓ | +✓ | +
| Printer | +Default Printer FQDN | +✓ | +✓ | +✓ | +
| Local Only | +V-Drive Access | +✗ | +✓ | +N/A | +
| + | C:\Apps Folder | +✗ | +✓ | +N/A | +
Legend: ✓ = Collected, ✗ = Not collected, N/A = Not applicable
+$env:COMPUTERNAME inside Invoke-Command scriptblock$env:COMPUTERNAMEhostnameSHOPFLOOR-PC01(Get-CimInstance -Class CIM_BIOSElement).SerialNumber(Get-CimInstance -Class CIM_BIOSElement).SerialNumberserialNumberABC1234567serviceTagABC1234567[Math]::Round($computerSystem.TotalPhysicalMemory / 1GB, 2)[Math]::Round($computerSystem.TotalPhysicalMemory / 1GB, 2)totalPhysicalMemory16.0$computerSystem.DomainRole$computerSystem.DomainRoledomainRole(Get-TimeZone).Id(Get-TimeZone).IdcurrentTimeZoneEastern Standard TimeGet-PCType functionpcTypeHKLM:\SOFTWARE\[WOW6432Node\]GE Aircraft Engines\DNC\GeneralGet-DNCConfigdncConfig (JSON object)DNC Config Fields:
+| Field | +Registry Key | +API Key | +
|---|---|---|
| Site | +Site | +dncConfig.Site | +
| CNC | +Cnc | +dncConfig.CNC | +
| NcIF | +NcIF | +dncConfig.NcIF | +
| Machine No | +MachineNo | +dncConfig.MachineNo | +
| Host Type | +HostType | +dncConfig.HostType | +
| FTP Primary | +FtpHostPrimary | +dncConfig.FtpHostPrimary | +
| FTP Secondary | +FtpHostSecondary | +dncConfig.FtpHostSecondary | +
HKLM:\SOFTWARE\GE Aircraft EnginesHKLM:\SOFTWARE\WOW6432Node\GE Aircraft EnginesdncGeRegistry32Bit (1 or 0)dncGeRegistry64Bit (1 or 0)...\DNC\eFocasdncDualPathEnabled (1, 0, or null)dncPath1Name (string)dncPath2Name (string)Both scripts collect all active network interfaces with these fields:
+| Field | +Description | +API Key | +
|---|---|---|
| InterfaceName | +Adapter name | +interfaceName | +
| IPAddress | +IPv4 address | +ipAddress | +
| SubnetMask | +CIDR prefix length | +subnetMask | +
| DefaultGateway | +Gateway address | +defaultGateway | +
| MACAddress | +Physical address | +macAddress | +
| IsDHCP | +DHCP enabled | +isDhcp | +
| IsActive | +Interface is up | +isActive | +
| IsMachineNetwork | +192.168.. or 100.0.0.* address | +isMachineNetwork | +
| IsPrimary | +10.134.. address | +isPrimary | +
Network Classification:
+^10\.134\. (corporate network)^192\.168\. or ^100\.0\.0\. (machine network, includes CMM cases)Get-CimInstance -ClassName Win32_SerialPortserialPorts (JSON array) [
+ {"PortName": "COM1", "Description": "Communications Port"},
+ {"PortName": "COM3", "Description": "USB Serial Port"}
+ ]
+vncserver* serviceshasVnc (1 or 0)HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*Registry::HKU\<SID>\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*allInstalledApps (pipe-delimited string)allInstalledAppsCount (integer)applications.csvinstalledApplications (JSON array) [
+ {"appid": 2, "appname": "UDC", "version": "2.1.0", "isactive": 1},
+ {"appid": 15, "appname": "Tanium", "version": "7.4.2", "isactive": 1}
+ ]
+Get-WmiObject -Query "SELECT * FROM Win32_Printer WHERE Default=$true"10.80.92.53_2 → 10.80.92.53)defaultPrinterFQDNAdmin Workstation Target PC
+ │ │
+ │ Invoke-Command (WinRM) │
+ ├───────────────────────────────→│
+ │ │ ┌─────────────────────┐
+ │ │ │ Collect data: │
+ │ │ │ - CIM instances │
+ │ │ │ - Registry │
+ │ │ │ - Processes │
+ │ │ │ - Network config │
+ │ │ └─────────────────────┘
+ │ │
+ │ Return $result hashtable │
+ │←───────────────────────────────┤
+ │ │
+ │ ┌──────────────────────────┐ │
+ │ │ Send-PCDataToApi │ │
+ │ │ POST to ShopDB API │ │
+ │ └──────────────────────────┘ │
+ │ │
+ │ HTTP POST to API │
+ ├───────────────────────────────→│ ShopDB Server
+Target PC
+ │
+ │ ┌────────────────────────────────┐
+ │ │ Collect-SystemInfo │
+ │ │ - CIM instances │
+ │ │ - Registry │
+ │ │ - Processes │
+ │ └────────────────────────────────┘
+ │
+ │ ┌────────────────────────────────┐
+ │ │ Get-ShopfloorConfigurations │
+ │ │ - Network interfaces │
+ │ │ - DNC config │
+ │ │ - GE Registry │
+ │ └────────────────────────────────┘
+ │
+ │ ┌────────────────────────────────┐
+ │ │ Send-CompleteDataToDashboard │
+ │ │ POST to ShopDB API │
+ │ └────────────────────────────────┘
+ │
+ │ HTTP POST to API
+ ├───────────────────────────────────→ ShopDB Server
+| Category | +API Parameter | +Remote Source | +Local Source | +
|---|---|---|---|
| Basic | +hostname | +$result.Hostname | +$systemInfo.Hostname | +
| + | serialNumber | +$result.SerialNumber | +$systemInfo.SerialNumber | +
| + | serviceTag | +$result.ServiceTag | +$systemInfo.ServiceTag | +
| + | manufacturer | +$result.Manufacturer | +$systemInfo.Manufacturer | +
| + | model | +$result.Model | +$systemInfo.Model | +
| + | pcType | +$result.PCType | +$systemInfo.PCType | +
| + | loggedInUser | +$result.LoggedInUser | +$systemInfo.LoggedInUser | +
| + | machineNo | +$result.MachineNo | +$systemInfo.MachineNo | +
| + | osVersion | +$result.OSVersion | +$systemInfo.OSVersion | +
| + | lastBootUpTime | +$result.LastBootUpTime | +$systemInfo.LastBootUpTime | +
| + | totalPhysicalMemory | +$result.TotalPhysicalMemory | +$systemInfo.TotalPhysicalMemory | +
| + | domainRole | +$result.DomainRole | +$systemInfo.DomainRole | +
| + | currentTimeZone | +$result.CurrentTimeZone | +$systemInfo.CurrentTimeZone | +
| VNC | +hasVnc | +$result.HasVnc | +$systemInfo.HasVnc | +
| Serial | +serialPorts | +$result.SerialPorts (JSON) | +$systemInfo.SerialPorts (JSON) | +
| Apps | +allInstalledApps | +$result.AllInstalledApps | +$systemInfo.AllInstalledApps | +
| + | allInstalledAppsCount | +$result.AllInstalledAppsCount | +$systemInfo.AllInstalledAppsCount | +
| Printer | +defaultPrinterFQDN | +$result.DefaultPrinterFQDN | +Get-DefaultPrinterFQDN | +
| Network | +networkInterfaces | +$result.NetworkInterfaces (JSON) | +$shopfloorInfo.NetworkInterfaces (JSON) | +
| Comm | +commConfigs | +$result.CommConfigs (JSON) | +$shopfloorInfo.CommConfigs (JSON) | +
| DNC | +dncConfig | +$result.DNCConfig (JSON) | +$shopfloorInfo.DNCConfig (JSON) | +
| + | dncGeRegistry32Bit | +$result.GERegistryInfo.Registry32Bit | +$shopfloorInfo.GERegistryInfo.Registry32Bit | +
| + | dncGeRegistry64Bit | +$result.GERegistryInfo.Registry64Bit | +$shopfloorInfo.GERegistryInfo.Registry64Bit | +
| + | dncDualPathEnabled | +$result.GERegistryInfo.DualPathEnabled | +$shopfloorInfo.GERegistryInfo.DualPathEnabled | +
| + | dncPath1Name | +$result.GERegistryInfo.Path1Name | +$shopfloorInfo.GERegistryInfo.Path1Name | +
| + | dncPath2Name | +$result.GERegistryInfo.Path2Name | +$shopfloorInfo.GERegistryInfo.Path2Name | +
Run both scripts on the same PC and compare results:
+Step 1: Run Local Script
+# On target PC
+.\Update-PC-CompleteAsset.ps1 -DashboardURL "http://dev-server/api.asp" > local-output.txt
+Step 2: Run Remote Script
+# From admin workstation
+.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "TARGET-PC" -ApiUrl "http://dev-server/api.asp" > remote-output.txt
+Step 3: Compare Database Records
+-- Check if both created/updated the same record
+SELECT * FROM machines WHERE hostname = 'TARGET-PC' ORDER BY lastupdated DESC LIMIT 2;
+
+-- Compare specific fields
+SELECT hostname, serialnumber, pctype, totalphysicalmemory, domainrole
+FROM machines WHERE hostname = 'TARGET-PC';
+# parity-test.ps1
+param(
+ [Parameter(Mandatory)]
+ [string]$ComputerName,
+ [PSCredential]$Credential
+)
+
+# Run remote collection
+$remoteData = .\Update-ShopfloorPCs-Remote.ps1 -ComputerName $ComputerName -Credential $Credential -WhatIf
+
+# Fields to compare
+$fields = @(
+ 'Hostname', 'SerialNumber', 'ServiceTag', 'Manufacturer', 'Model',
+ 'TotalPhysicalMemory', 'DomainRole', 'CurrentTimeZone', 'PCType',
+ 'HasVnc', 'AllInstalledAppsCount'
+)
+
+# Output comparison
+foreach ($field in $fields) {
+ Write-Host "$field : $($remoteData.$field)"
+}
+These fields can only be collected by the local script:
+| Field | +Reason | +
|---|---|
| V-Drive Access | +Requires user's mapped network drives | +
| C:\Apps Folder Access | +Network permissions differ in WinRM context | +
| Aspect | +Remote | +Local | +
|---|---|---|
| User context | +SYSTEM (via WinRM) | +Logged-in user or SYSTEM | +
| Network drives | +Not accessible | +Accessible | +
| User registry (HKCU) | +SYSTEM's HKCU | +User's HKCU | +
| Per-user apps | +Via HKU enumeration | +Via HKU + HKCU | +
Both scripts use the same detection priority:
+Additional local-only types:
+Remote maintenance toolkit for executing maintenance tasks on shopfloor PCs via WinRM.
+This script provides a comprehensive remote maintenance toolkit for managing shopfloor PCs. It executes maintenance tasks via WinRM (Windows Remote Management) and can target PCs individually, by type, by business unit, or all at once.
+Location: S:\dt\shopfloor\scripts\remote-execution\Invoke-RemoteMaintenance.ps1
Key Features:
+When using -All, -PcType, or -BusinessUnit targeting, the script retrieves PC lists from the ShopDB API:
GET /api.asp?action=getShopfloorPCs
+GET /api.asp?action=getShopfloorPCs&pctypeid=2 # CMM PCs only
+GET /api.asp?action=getShopfloorPCs&businessunitid=1 # Specific business unit
+PC Type IDs:
+| ID | +Type | +ID | +Type | +
|---|---|---|---|
| 1 | +Shopfloor | +7 | +Heat Treat | +
| 2 | +CMM | +8 | +Engineer | +
| 3 | +Wax Trace | +9 | +Standard | +
| 4 | +Keyence | +10 | +Inspection | +
| 5 | +EAS1000 | +11 | +Dashboard | +
| 6 | +Genspect | +12 | +Lobby Display | +
See: ShopDB API Reference for complete API documentation.
+Enable-PSRemoting -Force)# Test WinRM connectivity
+Test-WSMan -ComputerName "SHOPFLOOR-PC01"
+
+# Test with credentials
+$cred = Get-Credential
+Test-WSMan -ComputerName "SHOPFLOOR-PC01" -Credential $cred
+$cred = Get-Credential -Message "Enter domain admin credentials"
+# Flush DNS on a single PC
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "SHOPFLOOR-PC01" -Task FlushDNS -Credential $cred
+The script outputs status for each PC:
+[SHOPFLOOR-PC01] FlushDNS: SUCCESS
+ DNS Resolver Cache flushed successfully
+| Parameter | +Type | +Description | +
|---|---|---|
-ComputerName |
+string[] | +One or more computer names or IPs | +
-ComputerListFile |
+string | +Path to text file with hostnames | +
-All |
+switch | +Target all shopfloor PCs from ShopDB | +
-PcType |
+string | +Target by PC type (see PC Types) | +
-BusinessUnit |
+string | +Target by business unit (see Business Units) | +
| Parameter | +Type | +Description | +
|---|---|---|
-Task |
+string | +Maintenance task to execute | +
| Parameter | +Type | +Default | +Description | +
|---|---|---|---|
-Credential |
+PSCredential | +Prompt | +Remote authentication | +
-ApiUrl |
+string | +Production | +ShopDB API endpoint | +
-ThrottleLimit |
+int | +5 | +Max concurrent sessions | +
-DnsSuffix |
+string | +logon.ds.ge.com | +DNS suffix for resolution | +
Standard, Engineer, Shopfloor, CMM, Wax / Trace, Keyence,
+Genspect, Heat Treat, Inspection, Dashboard, Lobby Display, Uncategorized
+TBD, Blisk, HPT, Spools, Inspection, Venture, Turn/Burn, DT
+| Task | +Description | +Duration | +Impact | +
|---|---|---|---|
DISM |
+Repair Windows component store | +15-60 min | +Low | +
SFC |
+System File Checker scan | +10-30 min | +Low | +
| Task | +Description | +Duration | +Impact | +
|---|---|---|---|
OptimizeDisk |
+TRIM (SSD) or Defrag (HDD) | +5-60 min | +Medium | +
DiskCleanup |
+Remove temp files, updates | +5-15 min | +Low | +
ClearUpdateCache |
+Clear Windows Update cache | +1-2 min | +Low | +
ClearBrowserCache |
+Clear Chrome/Edge cache | +1-2 min | +Low | +
| Task | +Description | +Duration | +Impact | +
|---|---|---|---|
RestartSpooler |
+Restart Print Spooler | +<1 min | +Low | +
FlushDNS |
+Clear DNS cache | +<1 min | +None | +
RestartWinRM |
+Restart WinRM service | +<1 min | +Temp disconnect | +
| Task | +Description | +Duration | +Impact | +
|---|---|---|---|
SetTimezone |
+Set to Eastern Time | +<1 min | +None | +
SyncTime |
+Force time sync with DC | +<1 min | +None | +
| Task | +Description | +Duration | +Impact | +
|---|---|---|---|
UpdateEMxAuthToken |
+Update eMx auth from share | +1-2 min | +None | +
DeployUDCWebServerConfig |
+Deploy UDC config | +1-2 min | +None | +
| Task | +Description | +Duration | +Impact | +
|---|---|---|---|
Reboot |
+Restart PC (30s delay) | +2-5 min | +High | +
| Task | +Description | +Duration | +Impact | +
|---|---|---|---|
InstallDashboard |
+Install GE Dashboard app | +2-5 min | +Medium | +
InstallLobbyDisplay |
+Install Lobby Display app | +2-5 min | +Medium | +
UninstallDashboard |
+Remove GE Dashboard | +1-2 min | +Low | +
UninstallLobbyDisplay |
+Remove Lobby Display | +1-2 min | +Low | +
Deployment tasks require source files to be available before execution:
+| Task | +Source File Path | +
|---|---|
InstallDashboard |
+\\tsgwp00525.wjs.geaerospace.net\dt\shopfloor\scripts\Dashboard\GEAerospaceDashboardSetup.exe |
+
InstallLobbyDisplay |
+\\tsgwp00525.wjs.geaerospace.net\dt\shopfloor\scripts\LobbyDisplay\GEAerospaceLobbyDisplaySetup.exe |
+
UpdateEMxAuthToken |
+\\tsgwp00525.wjs.geaerospace.net\dt\shopfloor\scripts\eMx\eMxInfo.txt |
+
DeployUDCWebServerConfig |
+\\tsgwp00525.wjs.geaerospace.net\dt\shopfloor\scripts\UDC\udc_webserver_settings.json |
+
C:\Windows\Temp\ on remote PC+---------------------+ WinRM +---------------------+
+| Your Workstation | ------------> | Target PC |
+| | | |
+| Source Files: | Push File | Temp Location: |
+| - Setup.exe | ------------> | C:\Windows\Temp |
+| - config.json | | |
+| - eMxInfo.txt | Execute | Final Location: |
+| (network) | ------------> | C:\Program Files |
++---------------------+ +---------------------+
+Ensure your script directory contains the required files:
+S:\dt\shopfloor\scripts\remote-execution\
+├── Invoke-RemoteMaintenance.ps1
+├── GEAerospaceDashboardSetup.exe # For InstallDashboard
+├── GEAerospaceLobbyDisplaySetup.exe # For InstallLobbyDisplay
+└── udc_webserver_settings.json # For DeployUDCWebServerConfig
+The UpdateEMxAuthToken task:
\\tsgwp00525.wjs.geaerospace.net\dt\shopfloor\scripts\eMx\eMxInfo.txtC:\Program Files\GE Aircraft Engines\DNC\eMxInfo.txtC:\Program Files (x86)\GE Aircraft Engines\DNC\eMxInfo.txteMxInfo-old-YYYYMMDD-HHMMSS.txt before overwritingLDnc.exe)The DeployUDCWebServerConfig task:
C:\Program Files\UDC exists)C:\ProgramData\UDC\udc_webserver_settings.jsonBoth kiosk app installers:
+/VERYSILENT)Uninstall GUIDs:
+{9D9EEE25-4D24-422D-98AF-2ADEDA4745ED}{42FFB952-0B72-493F-8869-D957344CA305}To add a new application for deployment, edit the script in two places:
+Step 1: Add to $KioskAppConfig hashtable (~line 1388)
$KioskAppConfig = @{
+ # Existing entries...
+
+ # Add new application
+ 'InstallNewApp' = @{
+ Action = 'Install'
+ InstallerPath = '\\tsgwp00525.wjs.geaerospace.net\dt\shopfloor\scripts\NewApp\NewAppSetup.exe'
+ InstallerName = 'NewAppSetup.exe'
+ AppName = 'New Application Name'
+ UninstallGuid = '{YOUR-GUID-HERE}' # Find in registry after manual install
+ }
+ 'UninstallNewApp' = @{
+ Action = 'Uninstall'
+ InstallerName = 'NewAppSetup.exe'
+ AppName = 'New Application Name'
+ UninstallGuid = '{YOUR-GUID-HERE}'
+ }
+}
+Step 2: Add task names to ValidateSet (~line 142)
+[ValidateSet(
+ 'DISM', 'SFC', 'OptimizeDisk', 'DiskCleanup', 'ClearUpdateCache',
+ 'RestartSpooler', 'FlushDNS', 'RestartWinRM', 'ClearBrowserCache',
+ 'SetTimezone', 'SyncTime', 'UpdateEMxAuthToken', 'DeployUDCWebServerConfig', 'Reboot',
+ 'InstallDashboard', 'InstallLobbyDisplay', 'UninstallDashboard', 'UninstallLobbyDisplay',
+ 'InstallNewApp', 'UninstallNewApp' # Add new tasks here
+)]
+[string]$Task
+Step 3: Place installer on network share
+\\tsgwp00525.wjs.geaerospace.net\dt\shopfloor\scripts\NewApp\NewAppSetup.exe
+Finding the Uninstall GUID:
+After manually installing the application on a test PC, find the GUID in registry:
+# Search for app in registry
+Get-ChildItem "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" |
+ Get-ItemProperty | Where-Object { $_.DisplayName -like "*AppName*" } |
+ Select-Object DisplayName, PSChildName, UninstallString
+The PSChildName is typically the GUID (e.g., {9D9EEE25-4D24-422D-98AF-2ADEDA4745ED}).
Installer Requirements:
+/VERYSILENT /SUPPRESSMSGBOXES /NORESTART/qn /norestart/SIf your installer uses different flags, modify the InstallKioskApp scriptblock.
Scenario: A PC has corrupted system files causing crashes or errors.
+# Run DISM repair on a single PC
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "PROBLEM-PC" -Task DISM -Credential $cred
+What it does:
+Expected output:
+[PROBLEM-PC] DISM: SUCCESS
+ Deployment Image Servicing and Management tool
+ The restore operation completed successfully.
+# Run SFC after DISM
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "PROBLEM-PC" -Task SFC -Credential $cred
+What it does:
+C:\Windows\Logs\CBS\CBS.logBest Practice - Full Repair Sequence:
+# Step 1: Run DISM first
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "PROBLEM-PC" -Task DISM -Credential $cred
+
+# Step 2: Run SFC after DISM completes
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "PROBLEM-PC" -Task SFC -Credential $cred
+
+# Step 3: Reboot to apply changes
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "PROBLEM-PC" -Task Reboot -Credential $cred
+Scenario: PCs are running slow due to disk fragmentation or lack of TRIM.
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "SLOW-PC" -Task OptimizeDisk -Credential $cred
+What it does:
+# CMM PCs often have large files - optimize overnight
+.\Invoke-RemoteMaintenance.ps1 -PcType CMM -Task OptimizeDisk -Credential $cred -ThrottleLimit 3
+# Step 1: Clear update cache
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "PC01" -Task ClearUpdateCache -Credential $cred
+
+# Step 2: Run disk cleanup
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "PC01" -Task DiskCleanup -Credential $cred
+
+# Step 3: Optimize disk
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "PC01" -Task OptimizeDisk -Credential $cred
+Scenario: Windows Update is stuck or failing repeatedly.
+# Clear the Windows Update cache
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "UPDATE-STUCK-PC" -Task ClearUpdateCache -Credential $cred
+What it does:
+C:\Windows\SoftwareDistribution\DownloadAfter clearing, trigger new update check:
+# On the target PC (optional follow-up)
+wuauclt /detectnow
+Scenario: CMM or inspection PCs have slow browser performance.
+# Single PC
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "CMM-PC01" -Task ClearBrowserCache -Credential $cred
+
+# All CMM PCs
+.\Invoke-RemoteMaintenance.ps1 -PcType CMM -Task ClearBrowserCache -Credential $cred
+What it does:
+# Restart print spooler on a PC with stuck print jobs
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "PRINT-PROBLEM-PC" -Task RestartSpooler -Credential $cred
+What it does:
+# Flush DNS cache when a PC can't resolve hostnames
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "DNS-ISSUE-PC" -Task FlushDNS -Credential $cred
+
+# Flush DNS on all PCs in a business unit
+.\Invoke-RemoteMaintenance.ps1 -BusinessUnit Blisk -Task FlushDNS -Credential $cred
+# Restart WinRM if subsequent remote commands fail
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "WINRM-ISSUE-PC" -Task RestartWinRM -Credential $cred
+Note: Connection will briefly drop during restart.
+Scenario: PC clock is wrong, causing certificate errors or login issues.
+# Single PC
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "WRONG-TIME-PC" -Task SetTimezone -Credential $cred
+
+# All shopfloor PCs
+.\Invoke-RemoteMaintenance.ps1 -All -Task SetTimezone -Credential $cred
+Sets timezone to: Eastern Standard Time
+# Sync time with domain controller
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "WRONG-TIME-PC" -Task SyncTime -Credential $cred
+Full time fix sequence:
+# Step 1: Set correct timezone
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "PC01" -Task SetTimezone -Credential $cred
+
+# Step 2: Sync time
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "PC01" -Task SyncTime -Credential $cred
+Scenario: eMx authentication is failing on DNC PCs.
+# Single PC
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "DNC-PC01" -Task UpdateEMxAuthToken -Credential $cred
+
+# All shopfloor PCs
+.\Invoke-RemoteMaintenance.ps1 -All -Task UpdateEMxAuthToken -Credential $cred
+What it does:
+eMxInfo.txt with timestampScenario: UDC web server settings need to be updated.
+# Deploy to PCs with UDC installed
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "UDC-PC01","UDC-PC02" -Task DeployUDCWebServerConfig -Credential $cred
+What it does:
+Scenario: Convert a PC to a Dashboard kiosk.
+# Single PC installation
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "NEWKIOSK-01" -Task InstallDashboard -Credential $cred
+
+# Multiple PCs from a list
+$kiosks = @("KIOSK-01", "KIOSK-02", "KIOSK-03")
+.\Invoke-RemoteMaintenance.ps1 -ComputerName $kiosks -Task InstallDashboard -Credential $cred
+What it does:
+After installation:
+# Complete Dashboard deployment sequence
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "KIOSK-01" -Task InstallDashboard -Credential $cred
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "KIOSK-01" -Task Reboot -Credential $cred
+
+# After reboot, update ShopDB
+.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "KIOSK-01" -Credential $cred
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "LOBBY-01" -Task InstallLobbyDisplay -Credential $cred
+# Remove Dashboard
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "OLD-KIOSK" -Task UninstallDashboard -Credential $cred
+
+# Remove Lobby Display
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "OLD-LOBBY" -Task UninstallLobbyDisplay -Credential $cred
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "PC-TO-REBOOT" -Task Reboot -Credential $cred
+Note: Reboot has a 30-second delay to allow graceful shutdown.
+# Reboot all Dashboard PCs (e.g., for software update)
+.\Invoke-RemoteMaintenance.ps1 -PcType Dashboard -Task Reboot -Credential $cred
+.\Invoke-RemoteMaintenance.ps1 -PcType "Lobby Display" -Task Reboot -Credential $cred
+# Reboot all HPT PCs during maintenance window
+.\Invoke-RemoteMaintenance.ps1 -BusinessUnit HPT -Task Reboot -Credential $cred
+Create a text file with one hostname per line:
+# shopfloor-pcs.txt
+PC001
+PC002
+PC003
+PC004
+PC005
+Run tasks against the list:
+.\Invoke-RemoteMaintenance.ps1 -ComputerListFile ".\shopfloor-pcs.txt" -Task FlushDNS -Credential $cred
+# Maintenance routine for a PC
+$pc = "SHOPFLOOR-PC01"
+
+# Step 1: Clear caches
+.\Invoke-RemoteMaintenance.ps1 -ComputerName $pc -Task ClearUpdateCache -Credential $cred
+.\Invoke-RemoteMaintenance.ps1 -ComputerName $pc -Task ClearBrowserCache -Credential $cred
+
+# Step 2: Disk cleanup
+.\Invoke-RemoteMaintenance.ps1 -ComputerName $pc -Task DiskCleanup -Credential $cred
+
+# Step 3: Repair
+.\Invoke-RemoteMaintenance.ps1 -ComputerName $pc -Task DISM -Credential $cred
+.\Invoke-RemoteMaintenance.ps1 -ComputerName $pc -Task SFC -Credential $cred
+
+# Step 4: Sync time
+.\Invoke-RemoteMaintenance.ps1 -ComputerName $pc -Task SetTimezone -Credential $cred
+.\Invoke-RemoteMaintenance.ps1 -ComputerName $pc -Task SyncTime -Credential $cred
+
+# Step 5: Reboot
+.\Invoke-RemoteMaintenance.ps1 -ComputerName $pc -Task Reboot -Credential $cred
+Best for: Specific troubleshooting, targeted fixes
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "PROBLEM-PC" -Task DISM -Credential $cred
+Best for: Type-specific maintenance, software updates
+# All CMM PCs
+.\Invoke-RemoteMaintenance.ps1 -PcType CMM -Task DiskCleanup -Credential $cred
+
+# All Dashboard kiosks
+.\Invoke-RemoteMaintenance.ps1 -PcType Dashboard -Task Reboot -Credential $cred
+Best for: Department-specific maintenance windows
+# All Blisk area PCs
+.\Invoke-RemoteMaintenance.ps1 -BusinessUnit Blisk -Task SyncTime -Credential $cred
+Best for: Global maintenance, security updates
+# Flush DNS everywhere
+.\Invoke-RemoteMaintenance.ps1 -All -Task FlushDNS -Credential $cred -ThrottleLimit 10
+Best for: Custom groups, staged rollouts
+.\Invoke-RemoteMaintenance.ps1 -ComputerListFile ".\phase1-pcs.txt" -Task DISM -Credential $cred
+Cause: Task takes longer than session timeout.
+Solution: DISM and SFC can take a long time. Check if task completed on target:
+# Check DISM log
+Invoke-Command -ComputerName "PC01" -Credential $cred -ScriptBlock {
+ Get-Content "C:\Windows\Logs\DISM\dism.log" -Tail 50
+}
+Cause: Credentials don't have admin rights on that PC.
+Solutions:
+Cause: Network share not accessible or installer missing.
+Solutions:
+Cause: User cancelled shutdown or application blocked it.
+Solutions:
+# Force immediate reboot (no 30-second delay)
+Invoke-Command -ComputerName "PC01" -Credential $cred -ScriptBlock {
+ Restart-Computer -Force
+}
+Test on one PC before running against groups:
+# Test on single PC first
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "TEST-PC" -Task DISM -Credential $cred
+| Scenario | +Recommended ThrottleLimit | +
|---|---|
| Fast network, light tasks | +10-25 | +
| Normal operations | +5 (default) | +
| Heavy tasks (DISM, Defrag) | +2-3 | +
| Slow network | +2-3 | +
Run reboots and heavy tasks during maintenance windows:
+Always confirm which PCs will be affected:
+# Check PC type before reboot
+.\Update-ShopfloorPCs-Remote.ps1 -PcType Dashboard -WhatIf
+Redirect output for audit trail:
+.\Invoke-RemoteMaintenance.ps1 -All -Task SyncTime -Credential $cred | Tee-Object -FilePath "maintenance-log-$(Get-Date -Format 'yyyyMMdd').txt"
+
+
\ No newline at end of file
diff --git a/docs/Invoke-RemoteMaintenance.md b/docs/Invoke-RemoteMaintenance.md
new file mode 100644
index 0000000..8c7bd00
--- /dev/null
+++ b/docs/Invoke-RemoteMaintenance.md
@@ -0,0 +1,866 @@
+# Invoke-RemoteMaintenance.ps1
+
+Remote maintenance toolkit for executing maintenance tasks on shopfloor PCs via WinRM.
+
+## Table of Contents
+
+- [Overview](#overview)
+- [API Integration](#api-integration)
+- [Prerequisites](#prerequisites)
+- [Quick Start](#quick-start)
+- [Parameters Reference](#parameters-reference)
+- [Available Tasks](#available-tasks)
+- [Software Deployment Mechanism](#software-deployment-mechanism)
+- [How-To Guides](#how-to-guides)
+ - [System Repair](#how-to-repair-system-files)
+ - [Disk Optimization](#how-to-optimize-disks)
+ - [Service Management](#how-to-manage-services)
+ - [Time Synchronization](#how-to-fix-time-sync-issues)
+ - [DNC Configuration](#how-to-update-dnc-configurations)
+ - [Software Deployment](#how-to-deploy-software)
+ - [Batch Operations](#how-to-run-batch-operations)
+- [Targeting Strategies](#targeting-strategies)
+- [Troubleshooting](#troubleshooting)
+- [Best Practices](#best-practices)
+
+---
+
+## Overview
+
+This script provides a comprehensive remote maintenance toolkit for managing shopfloor PCs. It executes maintenance tasks via WinRM (Windows Remote Management) and can target PCs individually, by type, by business unit, or all at once.
+
+**Location:** `S:\dt\shopfloor\scripts\remote-execution\Invoke-RemoteMaintenance.ps1`
+
+**Key Features:**
+- 19 maintenance tasks available
+- Multiple targeting options (by name, type, business unit, or all)
+- Concurrent execution with configurable throttling
+- Integration with ShopDB for PC discovery
+
+---
+
+## API Integration
+
+When using `-All`, `-PcType`, or `-BusinessUnit` targeting, the script retrieves PC lists from the ShopDB API:
+
+```
+GET /api.asp?action=getShopfloorPCs
+GET /api.asp?action=getShopfloorPCs&pctypeid=2 # CMM PCs only
+GET /api.asp?action=getShopfloorPCs&businessunitid=1 # Specific business unit
+```
+
+**PC Type IDs:**
+
+| ID | Type | ID | Type |
+|----|------|----|------|
+| 1 | Shopfloor | 7 | Heat Treat |
+| 2 | CMM | 8 | Engineer |
+| 3 | Wax Trace | 9 | Standard |
+| 4 | Keyence | 10 | Inspection |
+| 5 | EAS1000 | 11 | Dashboard |
+| 6 | Genspect | 12 | Lobby Display |
+
+**See:** [ShopDB API Reference](ShopDB-API.html) for complete API documentation.
+
+---
+
+## Prerequisites
+
+### On Your Workstation
+
+1. **PowerShell 5.1 or higher**
+2. **Network access to target PCs** (TCP port 5985)
+3. **Admin credentials** for target PCs
+
+### On Target PCs
+
+1. **WinRM enabled** (`Enable-PSRemoting -Force`)
+2. **Firewall rules** allowing WinRM traffic
+
+### Verify Connectivity
+
+```powershell
+# Test WinRM connectivity
+Test-WSMan -ComputerName "SHOPFLOOR-PC01"
+
+# Test with credentials
+$cred = Get-Credential
+Test-WSMan -ComputerName "SHOPFLOOR-PC01" -Credential $cred
+```
+
+---
+
+## Quick Start
+
+### Step 1: Get Credentials
+
+```powershell
+$cred = Get-Credential -Message "Enter domain admin credentials"
+```
+
+### Step 2: Run a Simple Task
+
+```powershell
+# Flush DNS on a single PC
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "SHOPFLOOR-PC01" -Task FlushDNS -Credential $cred
+```
+
+### Step 3: Check Results
+
+The script outputs status for each PC:
+```
+[SHOPFLOOR-PC01] FlushDNS: SUCCESS
+ DNS Resolver Cache flushed successfully
+```
+
+---
+
+## Parameters Reference
+
+### Targeting Parameters (Mutually Exclusive)
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `-ComputerName` | string[] | One or more computer names or IPs |
+| `-ComputerListFile` | string | Path to text file with hostnames |
+| `-All` | switch | Target all shopfloor PCs from ShopDB |
+| `-PcType` | string | Target by PC type (see PC Types) |
+| `-BusinessUnit` | string | Target by business unit (see Business Units) |
+
+### Task Parameter (Required)
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `-Task` | string | Maintenance task to execute |
+
+### Optional Parameters
+
+| Parameter | Type | Default | Description |
+|-----------|------|---------|-------------|
+| `-Credential` | PSCredential | Prompt | Remote authentication |
+| `-ApiUrl` | string | Production | ShopDB API endpoint |
+| `-ThrottleLimit` | int | 5 | Max concurrent sessions |
+| `-DnsSuffix` | string | logon.ds.ge.com | DNS suffix for resolution |
+
+### PC Types
+
+```
+Standard, Engineer, Shopfloor, CMM, Wax / Trace, Keyence,
+Genspect, Heat Treat, Inspection, Dashboard, Lobby Display, Uncategorized
+```
+
+### Business Units
+
+```
+TBD, Blisk, HPT, Spools, Inspection, Venture, Turn/Burn, DT
+```
+
+---
+
+## Available Tasks
+
+### Repair Tasks
+
+| Task | Description | Duration | Impact |
+|------|-------------|----------|--------|
+| `DISM` | Repair Windows component store | 15-60 min | Low |
+| `SFC` | System File Checker scan | 10-30 min | Low |
+
+### Optimization Tasks
+
+| Task | Description | Duration | Impact |
+|------|-------------|----------|--------|
+| `OptimizeDisk` | TRIM (SSD) or Defrag (HDD) | 5-60 min | Medium |
+| `DiskCleanup` | Remove temp files, updates | 5-15 min | Low |
+| `ClearUpdateCache` | Clear Windows Update cache | 1-2 min | Low |
+| `ClearBrowserCache` | Clear Chrome/Edge cache | 1-2 min | Low |
+
+### Service Tasks
+
+| Task | Description | Duration | Impact |
+|------|-------------|----------|--------|
+| `RestartSpooler` | Restart Print Spooler | <1 min | Low |
+| `FlushDNS` | Clear DNS cache | <1 min | None |
+| `RestartWinRM` | Restart WinRM service | <1 min | Temp disconnect |
+
+### Time/Date Tasks
+
+| Task | Description | Duration | Impact |
+|------|-------------|----------|--------|
+| `SetTimezone` | Set to Eastern Time | <1 min | None |
+| `SyncTime` | Force time sync with DC | <1 min | None |
+
+### DNC Tasks
+
+| Task | Description | Duration | Impact |
+|------|-------------|----------|--------|
+| `UpdateEMxAuthToken` | Update eMx auth from share | 1-2 min | None |
+| `DeployUDCWebServerConfig` | Deploy UDC config | 1-2 min | None |
+
+### System Tasks
+
+| Task | Description | Duration | Impact |
+|------|-------------|----------|--------|
+| `Reboot` | Restart PC (30s delay) | 2-5 min | High |
+
+### Software Deployment Tasks
+
+| Task | Description | Duration | Impact |
+|------|-------------|----------|--------|
+| `InstallDashboard` | Install GE Dashboard app | 2-5 min | Medium |
+| `InstallLobbyDisplay` | Install Lobby Display app | 2-5 min | Medium |
+| `UninstallDashboard` | Remove GE Dashboard | 1-2 min | Low |
+| `UninstallLobbyDisplay` | Remove Lobby Display | 1-2 min | Low |
+
+---
+
+## Software Deployment Mechanism
+
+### Source File Locations
+
+Deployment tasks require source files to be available before execution:
+
+| Task | Source File Path |
+|------|------------------|
+| `InstallDashboard` | `\\tsgwp00525.wjs.geaerospace.net\dt\shopfloor\scripts\Dashboard\GEAerospaceDashboardSetup.exe` |
+| `InstallLobbyDisplay` | `\\tsgwp00525.wjs.geaerospace.net\dt\shopfloor\scripts\LobbyDisplay\GEAerospaceLobbyDisplaySetup.exe` |
+| `UpdateEMxAuthToken` | `\\tsgwp00525.wjs.geaerospace.net\dt\shopfloor\scripts\eMx\eMxInfo.txt` |
+| `DeployUDCWebServerConfig` | `\\tsgwp00525.wjs.geaerospace.net\dt\shopfloor\scripts\UDC\udc_webserver_settings.json` |
+
+### How Deployment Works
+
+1. **Pre-flight Check:** Script verifies source file exists
+2. **WinRM Session:** Opens remote session to target PC
+3. **File Push:** Copies source file to `C:\Windows\Temp\` on remote PC
+4. **Execution:** Runs install/copy task using pushed file
+5. **Cleanup:** Removes temp file from remote PC
+
+```
++---------------------+ WinRM +---------------------+
+| Your Workstation | ------------> | Target PC |
+| | | |
+| Source Files: | Push File | Temp Location: |
+| - Setup.exe | ------------> | C:\Windows\Temp |
+| - config.json | | |
+| - eMxInfo.txt | Execute | Final Location: |
+| (network) | ------------> | C:\Program Files |
++---------------------+ +---------------------+
+```
+
+### Directory Structure
+
+Ensure your script directory contains the required files:
+
+```
+S:\dt\shopfloor\scripts\remote-execution\
+├── Invoke-RemoteMaintenance.ps1
+├── GEAerospaceDashboardSetup.exe # For InstallDashboard
+├── GEAerospaceLobbyDisplaySetup.exe # For InstallLobbyDisplay
+└── udc_webserver_settings.json # For DeployUDCWebServerConfig
+```
+
+### eMx Auth Token Details
+
+The `UpdateEMxAuthToken` task:
+
+1. **Source:** `\\tsgwp00525.wjs.geaerospace.net\dt\shopfloor\scripts\eMx\eMxInfo.txt`
+2. **Destinations:** (both paths if they exist)
+ - `C:\Program Files\GE Aircraft Engines\DNC\eMxInfo.txt`
+ - `C:\Program Files (x86)\GE Aircraft Engines\DNC\eMxInfo.txt`
+3. **Backup:** Creates `eMxInfo-old-YYYYMMDD-HHMMSS.txt` before overwriting
+4. **Post-action:** Restarts DNC service (`LDnc.exe`)
+
+### UDC Web Server Config Details
+
+The `DeployUDCWebServerConfig` task:
+
+1. **Pre-check:** Verifies UDC is installed (`C:\Program Files\UDC` exists)
+2. **Skip:** PCs without UDC are skipped (not counted as failures)
+3. **Destination:** `C:\ProgramData\UDC\udc_webserver_settings.json`
+4. **Backup:** Creates backup before overwriting
+
+### Dashboard/Lobby Display Install Details
+
+Both kiosk app installers:
+
+1. **Installer type:** Inno Setup (supports `/VERYSILENT`)
+2. **Execution:** Silent install with no user prompts
+3. **Cleanup:** Installer removed from temp after execution
+
+**Uninstall GUIDs:**
+- Dashboard: `{9D9EEE25-4D24-422D-98AF-2ADEDA4745ED}`
+- Lobby Display: `{42FFB952-0B72-493F-8869-D957344CA305}`
+
+### Adding New Deployable Applications
+
+To add a new application for deployment, edit the script in two places:
+
+**Step 1: Add to `$KioskAppConfig` hashtable (~line 1388)**
+
+```powershell
+$KioskAppConfig = @{
+ # Existing entries...
+
+ # Add new application
+ 'InstallNewApp' = @{
+ Action = 'Install'
+ InstallerPath = '\\tsgwp00525.wjs.geaerospace.net\dt\shopfloor\scripts\NewApp\NewAppSetup.exe'
+ InstallerName = 'NewAppSetup.exe'
+ AppName = 'New Application Name'
+ UninstallGuid = '{YOUR-GUID-HERE}' # Find in registry after manual install
+ }
+ 'UninstallNewApp' = @{
+ Action = 'Uninstall'
+ InstallerName = 'NewAppSetup.exe'
+ AppName = 'New Application Name'
+ UninstallGuid = '{YOUR-GUID-HERE}'
+ }
+}
+```
+
+**Step 2: Add task names to ValidateSet (~line 142)**
+
+```powershell
+[ValidateSet(
+ 'DISM', 'SFC', 'OptimizeDisk', 'DiskCleanup', 'ClearUpdateCache',
+ 'RestartSpooler', 'FlushDNS', 'RestartWinRM', 'ClearBrowserCache',
+ 'SetTimezone', 'SyncTime', 'UpdateEMxAuthToken', 'DeployUDCWebServerConfig', 'Reboot',
+ 'InstallDashboard', 'InstallLobbyDisplay', 'UninstallDashboard', 'UninstallLobbyDisplay',
+ 'InstallNewApp', 'UninstallNewApp' # Add new tasks here
+)]
+[string]$Task
+```
+
+**Step 3: Place installer on network share**
+
+```
+\\tsgwp00525.wjs.geaerospace.net\dt\shopfloor\scripts\NewApp\NewAppSetup.exe
+```
+
+**Finding the Uninstall GUID:**
+
+After manually installing the application on a test PC, find the GUID in registry:
+
+```powershell
+# Search for app in registry
+Get-ChildItem "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" |
+ Get-ItemProperty | Where-Object { $_.DisplayName -like "*AppName*" } |
+ Select-Object DisplayName, PSChildName, UninstallString
+```
+
+The `PSChildName` is typically the GUID (e.g., `{9D9EEE25-4D24-422D-98AF-2ADEDA4745ED}`).
+
+**Installer Requirements:**
+
+- Must support silent installation flags
+- Inno Setup: `/VERYSILENT /SUPPRESSMSGBOXES /NORESTART`
+- MSI: `/qn /norestart`
+- NSIS: `/S`
+
+If your installer uses different flags, modify the `InstallKioskApp` scriptblock.
+
+---
+
+## How-To Guides
+
+### How to Repair System Files
+
+**Scenario:** A PC has corrupted system files causing crashes or errors.
+
+#### Option 1: DISM (Component Store Repair)
+
+```powershell
+# Run DISM repair on a single PC
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "PROBLEM-PC" -Task DISM -Credential $cred
+```
+
+**What it does:**
+- Downloads missing/corrupted files from Windows Update
+- Repairs the Windows component store
+- Required before SFC if component store is damaged
+
+**Expected output:**
+```
+[PROBLEM-PC] DISM: SUCCESS
+ Deployment Image Servicing and Management tool
+ The restore operation completed successfully.
+```
+
+#### Option 2: SFC (System File Checker)
+
+```powershell
+# Run SFC after DISM
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "PROBLEM-PC" -Task SFC -Credential $cred
+```
+
+**What it does:**
+- Scans all protected system files
+- Replaces corrupted files from component store
+- Creates log at `C:\Windows\Logs\CBS\CBS.log`
+
+**Best Practice - Full Repair Sequence:**
+```powershell
+# Step 1: Run DISM first
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "PROBLEM-PC" -Task DISM -Credential $cred
+
+# Step 2: Run SFC after DISM completes
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "PROBLEM-PC" -Task SFC -Credential $cred
+
+# Step 3: Reboot to apply changes
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "PROBLEM-PC" -Task Reboot -Credential $cred
+```
+
+---
+
+### How to Optimize Disks
+
+**Scenario:** PCs are running slow due to disk fragmentation or lack of TRIM.
+
+#### Single PC Optimization
+
+```powershell
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "SLOW-PC" -Task OptimizeDisk -Credential $cred
+```
+
+**What it does:**
+- Detects drive type (SSD vs HDD)
+- For SSDs: Runs TRIM to reclaim deleted blocks
+- For HDDs: Runs defragmentation
+
+#### Optimize All CMM PCs (After Hours)
+
+```powershell
+# CMM PCs often have large files - optimize overnight
+.\Invoke-RemoteMaintenance.ps1 -PcType CMM -Task OptimizeDisk -Credential $cred -ThrottleLimit 3
+```
+
+#### Full Cleanup Sequence
+
+```powershell
+# Step 1: Clear update cache
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "PC01" -Task ClearUpdateCache -Credential $cred
+
+# Step 2: Run disk cleanup
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "PC01" -Task DiskCleanup -Credential $cred
+
+# Step 3: Optimize disk
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "PC01" -Task OptimizeDisk -Credential $cred
+```
+
+---
+
+### How to Fix Stuck Windows Updates
+
+**Scenario:** Windows Update is stuck or failing repeatedly.
+
+```powershell
+# Clear the Windows Update cache
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "UPDATE-STUCK-PC" -Task ClearUpdateCache -Credential $cred
+```
+
+**What it does:**
+1. Stops Windows Update service
+2. Stops BITS service
+3. Clears `C:\Windows\SoftwareDistribution\Download`
+4. Restarts services
+
+**After clearing, trigger new update check:**
+```powershell
+# On the target PC (optional follow-up)
+wuauclt /detectnow
+```
+
+---
+
+### How to Clear Browser Cache
+
+**Scenario:** CMM or inspection PCs have slow browser performance.
+
+```powershell
+# Single PC
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "CMM-PC01" -Task ClearBrowserCache -Credential $cred
+
+# All CMM PCs
+.\Invoke-RemoteMaintenance.ps1 -PcType CMM -Task ClearBrowserCache -Credential $cred
+```
+
+**What it does:**
+- Clears Chrome cache directories
+- Clears Edge cache directories
+- Does NOT clear saved passwords or bookmarks
+
+---
+
+### How to Manage Services
+
+#### Fix Printing Issues
+
+```powershell
+# Restart print spooler on a PC with stuck print jobs
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "PRINT-PROBLEM-PC" -Task RestartSpooler -Credential $cred
+```
+
+**What it does:**
+1. Stops Print Spooler service
+2. Clears print queue
+3. Restarts Print Spooler service
+
+#### Fix DNS Resolution Issues
+
+```powershell
+# Flush DNS cache when a PC can't resolve hostnames
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "DNS-ISSUE-PC" -Task FlushDNS -Credential $cred
+
+# Flush DNS on all PCs in a business unit
+.\Invoke-RemoteMaintenance.ps1 -BusinessUnit Blisk -Task FlushDNS -Credential $cred
+```
+
+#### Fix Remote Management Issues
+
+```powershell
+# Restart WinRM if subsequent remote commands fail
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "WINRM-ISSUE-PC" -Task RestartWinRM -Credential $cred
+```
+
+**Note:** Connection will briefly drop during restart.
+
+---
+
+### How to Fix Time Sync Issues
+
+**Scenario:** PC clock is wrong, causing certificate errors or login issues.
+
+#### Set Correct Timezone
+
+```powershell
+# Single PC
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "WRONG-TIME-PC" -Task SetTimezone -Credential $cred
+
+# All shopfloor PCs
+.\Invoke-RemoteMaintenance.ps1 -All -Task SetTimezone -Credential $cred
+```
+
+**Sets timezone to:** Eastern Standard Time
+
+#### Force Time Synchronization
+
+```powershell
+# Sync time with domain controller
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "WRONG-TIME-PC" -Task SyncTime -Credential $cred
+```
+
+**Full time fix sequence:**
+```powershell
+# Step 1: Set correct timezone
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "PC01" -Task SetTimezone -Credential $cred
+
+# Step 2: Sync time
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "PC01" -Task SyncTime -Credential $cred
+```
+
+---
+
+### How to Update DNC Configurations
+
+#### Update eMx Authentication Token
+
+**Scenario:** eMx authentication is failing on DNC PCs.
+
+```powershell
+# Single PC
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "DNC-PC01" -Task UpdateEMxAuthToken -Credential $cred
+
+# All shopfloor PCs
+.\Invoke-RemoteMaintenance.ps1 -All -Task UpdateEMxAuthToken -Credential $cred
+```
+
+**What it does:**
+1. Backs up existing `eMxInfo.txt` with timestamp
+2. Copies new token file from network share
+3. Verifies file was updated
+
+#### Deploy UDC Web Server Configuration
+
+**Scenario:** UDC web server settings need to be updated.
+
+```powershell
+# Deploy to PCs with UDC installed
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "UDC-PC01","UDC-PC02" -Task DeployUDCWebServerConfig -Credential $cred
+```
+
+**What it does:**
+1. Checks if UDC is installed
+2. Backs up existing configuration
+3. Deploys new web server settings
+4. Does NOT restart UDC (requires manual restart)
+
+---
+
+### How to Deploy Software
+
+#### Install GE Aerospace Dashboard
+
+**Scenario:** Convert a PC to a Dashboard kiosk.
+
+```powershell
+# Single PC installation
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "NEWKIOSK-01" -Task InstallDashboard -Credential $cred
+
+# Multiple PCs from a list
+$kiosks = @("KIOSK-01", "KIOSK-02", "KIOSK-03")
+.\Invoke-RemoteMaintenance.ps1 -ComputerName $kiosks -Task InstallDashboard -Credential $cred
+```
+
+**What it does:**
+1. Copies installer from network share
+2. Runs silent installation
+3. Configures auto-start
+4. Cleans up installer
+
+**After installation:**
+- Run data collection to update PC type
+- Reboot PC to complete setup
+
+```powershell
+# Complete Dashboard deployment sequence
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "KIOSK-01" -Task InstallDashboard -Credential $cred
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "KIOSK-01" -Task Reboot -Credential $cred
+
+# After reboot, update ShopDB
+.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "KIOSK-01" -Credential $cred
+```
+
+#### Install Lobby Display
+
+```powershell
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "LOBBY-01" -Task InstallLobbyDisplay -Credential $cred
+```
+
+#### Uninstall Dashboard or Lobby Display
+
+```powershell
+# Remove Dashboard
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "OLD-KIOSK" -Task UninstallDashboard -Credential $cred
+
+# Remove Lobby Display
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "OLD-LOBBY" -Task UninstallLobbyDisplay -Credential $cred
+```
+
+---
+
+### How to Reboot PCs
+
+#### Single PC Reboot
+
+```powershell
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "PC-TO-REBOOT" -Task Reboot -Credential $cred
+```
+
+**Note:** Reboot has a 30-second delay to allow graceful shutdown.
+
+#### Reboot All Dashboard PCs
+
+```powershell
+# Reboot all Dashboard PCs (e.g., for software update)
+.\Invoke-RemoteMaintenance.ps1 -PcType Dashboard -Task Reboot -Credential $cred
+```
+
+#### Reboot All Lobby Display PCs
+
+```powershell
+.\Invoke-RemoteMaintenance.ps1 -PcType "Lobby Display" -Task Reboot -Credential $cred
+```
+
+#### Reboot PCs by Business Unit
+
+```powershell
+# Reboot all HPT PCs during maintenance window
+.\Invoke-RemoteMaintenance.ps1 -BusinessUnit HPT -Task Reboot -Credential $cred
+```
+
+---
+
+### How to Run Batch Operations
+
+#### Using a Computer List File
+
+Create a text file with one hostname per line:
+
+```text
+# shopfloor-pcs.txt
+PC001
+PC002
+PC003
+PC004
+PC005
+```
+
+Run tasks against the list:
+
+```powershell
+.\Invoke-RemoteMaintenance.ps1 -ComputerListFile ".\shopfloor-pcs.txt" -Task FlushDNS -Credential $cred
+```
+
+#### Running Multiple Tasks in Sequence
+
+```powershell
+# Maintenance routine for a PC
+$pc = "SHOPFLOOR-PC01"
+
+# Step 1: Clear caches
+.\Invoke-RemoteMaintenance.ps1 -ComputerName $pc -Task ClearUpdateCache -Credential $cred
+.\Invoke-RemoteMaintenance.ps1 -ComputerName $pc -Task ClearBrowserCache -Credential $cred
+
+# Step 2: Disk cleanup
+.\Invoke-RemoteMaintenance.ps1 -ComputerName $pc -Task DiskCleanup -Credential $cred
+
+# Step 3: Repair
+.\Invoke-RemoteMaintenance.ps1 -ComputerName $pc -Task DISM -Credential $cred
+.\Invoke-RemoteMaintenance.ps1 -ComputerName $pc -Task SFC -Credential $cred
+
+# Step 4: Sync time
+.\Invoke-RemoteMaintenance.ps1 -ComputerName $pc -Task SetTimezone -Credential $cred
+.\Invoke-RemoteMaintenance.ps1 -ComputerName $pc -Task SyncTime -Credential $cred
+
+# Step 5: Reboot
+.\Invoke-RemoteMaintenance.ps1 -ComputerName $pc -Task Reboot -Credential $cred
+```
+
+---
+
+## Targeting Strategies
+
+### By Individual PCs
+
+**Best for:** Specific troubleshooting, targeted fixes
+
+```powershell
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "PROBLEM-PC" -Task DISM -Credential $cred
+```
+
+### By PC Type
+
+**Best for:** Type-specific maintenance, software updates
+
+```powershell
+# All CMM PCs
+.\Invoke-RemoteMaintenance.ps1 -PcType CMM -Task DiskCleanup -Credential $cred
+
+# All Dashboard kiosks
+.\Invoke-RemoteMaintenance.ps1 -PcType Dashboard -Task Reboot -Credential $cred
+```
+
+### By Business Unit
+
+**Best for:** Department-specific maintenance windows
+
+```powershell
+# All Blisk area PCs
+.\Invoke-RemoteMaintenance.ps1 -BusinessUnit Blisk -Task SyncTime -Credential $cred
+```
+
+### All Shopfloor PCs
+
+**Best for:** Global maintenance, security updates
+
+```powershell
+# Flush DNS everywhere
+.\Invoke-RemoteMaintenance.ps1 -All -Task FlushDNS -Credential $cred -ThrottleLimit 10
+```
+
+### Using a List File
+
+**Best for:** Custom groups, staged rollouts
+
+```powershell
+.\Invoke-RemoteMaintenance.ps1 -ComputerListFile ".\phase1-pcs.txt" -Task DISM -Credential $cred
+```
+
+---
+
+## Troubleshooting
+
+### Task Times Out
+
+**Cause:** Task takes longer than session timeout.
+
+**Solution:** DISM and SFC can take a long time. Check if task completed on target:
+```powershell
+# Check DISM log
+Invoke-Command -ComputerName "PC01" -Credential $cred -ScriptBlock {
+ Get-Content "C:\Windows\Logs\DISM\dism.log" -Tail 50
+}
+```
+
+### "Access Denied" on Some PCs
+
+**Cause:** Credentials don't have admin rights on that PC.
+
+**Solutions:**
+1. Use different credentials
+2. Add account to local Administrators group on target
+3. Check if UAC is blocking remote admin
+
+### Software Installation Fails
+
+**Cause:** Network share not accessible or installer missing.
+
+**Solutions:**
+1. Verify network share path is accessible
+2. Check installer exists at expected location
+3. Verify credentials can access the share
+
+### Reboot Doesn't Happen
+
+**Cause:** User cancelled shutdown or application blocked it.
+
+**Solutions:**
+```powershell
+# Force immediate reboot (no 30-second delay)
+Invoke-Command -ComputerName "PC01" -Credential $cred -ScriptBlock {
+ Restart-Computer -Force
+}
+```
+
+---
+
+## Best Practices
+
+### 1. Start Small
+
+Test on one PC before running against groups:
+```powershell
+# Test on single PC first
+.\Invoke-RemoteMaintenance.ps1 -ComputerName "TEST-PC" -Task DISM -Credential $cred
+```
+
+### 2. Use Appropriate Throttle Limits
+
+| Scenario | Recommended ThrottleLimit |
+|----------|--------------------------|
+| Fast network, light tasks | 10-25 |
+| Normal operations | 5 (default) |
+| Heavy tasks (DISM, Defrag) | 2-3 |
+| Slow network | 2-3 |
+
+### 3. Schedule Disruptive Tasks
+
+Run reboots and heavy tasks during maintenance windows:
+- DISM/SFC: After hours
+- Disk optimization: After hours
+- Reboots: During shift changes or maintenance windows
+
+### 4. Verify Before Rebooting
+
+Always confirm which PCs will be affected:
+```powershell
+# Check PC type before reboot
+.\Update-ShopfloorPCs-Remote.ps1 -PcType Dashboard -WhatIf
+```
+
+### 5. Keep Logs
+
+Redirect output for audit trail:
+```powershell
+.\Invoke-RemoteMaintenance.ps1 -All -Task SyncTime -Credential $cred | Tee-Object -FilePath "maintenance-log-$(Get-Date -Format 'yyyyMMdd').txt"
+```
diff --git a/docs/ShopDB-API.html b/docs/ShopDB-API.html
new file mode 100644
index 0000000..d15dd07
--- /dev/null
+++ b/docs/ShopDB-API.html
@@ -0,0 +1,876 @@
+
+
+
+
+
+ REST API for PowerShell data collection scripts and ShopDB integrations.
+The ShopDB API (api.asp) provides endpoints for:
Technology: Classic ASP (VBScript) with MySQL database
+| Environment | +URL | +
|---|---|
| Production | +https://tsgwp00525.rd.ds.ge.com/shopdb/api.asp |
+
| Development | +http://192.168.122.151:8080/api.asp |
+
Currently no authentication required. API is accessible from internal network only.
+Health check endpoint to verify API is online.
+Request:
+GET /api.asp?action=getDashboardData
+Response:
+{
+ "success": true,
+ "message": "ShopDB API is online - v13 (inlined all queries)",
+ "version": "1.0",
+ "schema": "Phase 2",
+ "connStatus": "objConn is Open"
+}
+Used By: Health monitoring, connectivity tests
+Returns list of all active shopfloor PCs for remote management operations.
+Request:
+GET /api.asp?action=getShopfloorPCs
+GET /api.asp?action=getShopfloorPCs&pctypeid=1
+GET /api.asp?action=getShopfloorPCs&businessunitid=2
+Query Parameters:
+| Parameter | +Type | +Description | +
|---|---|---|
pctypeid |
+int | +Filter by PC type (optional) | +
businessunitid |
+int | +Filter by business unit (optional) | +
PC Type IDs:
+| ID | +Type | +
|---|---|
| 1 | +Shopfloor | +
| 2 | +CMM | +
| 3 | +Wax Trace | +
| 4 | +Keyence | +
| 5 | +EAS1000 | +
| 6 | +Genspect | +
| 7 | +Heat Treat | +
| 8 | +Engineer | +
| 9 | +Standard | +
| 10 | +Inspection | +
| 11 | +Dashboard | +
| 12 | +Lobby Display | +
Response:
+{
+ "success": true,
+ "count": 45,
+ "data": [
+ {
+ "machineid": 1234,
+ "hostname": "G1ZTNCX3ESF",
+ "machinenumber": "M0612, M0613",
+ "serialnumber": "ABC1234567",
+ "ipaddress": "10.134.50.101",
+ "loggedinuser": "DOMAIN\\jsmith",
+ "pctype": "Shopfloor",
+ "pctypeid": 1,
+ "businessunit": "Rotor",
+ "businessunitid": 2,
+ "lastupdated": "1/15/2025 8:30 AM"
+ }
+ ]
+}
+Notes:
+Used By: Update-ShopfloorPCs-Remote.ps1 -All, Invoke-RemoteMaintenance.ps1 -All
Returns PCs that haven't been rebooted in specified number of days.
+Request:
+GET /api.asp?action=getHighUptimePCs&minUptime=30
+Query Parameters:
+| Parameter | +Type | +Default | +Description | +
|---|---|---|---|
minUptime |
+int | +10 | +Minimum uptime in days | +
Response:
+{
+ "success": true,
+ "count": 5,
+ "minUptime": 30,
+ "data": [
+ {
+ "machineid": 1234,
+ "hostname": "SHOPFLOOR-01",
+ "machinenumber": "M0612",
+ "serialnumber": "ABC1234567",
+ "ipaddress": "10.134.50.101",
+ "loggedinuser": "DOMAIN\\jsmith",
+ "pctype": "Shopfloor",
+ "uptime_days": 45,
+ "lastboottime": "2024-12-01 08:00:00",
+ "pctypeid": 1,
+ "businessunit": "Rotor",
+ "businessunitid": 2,
+ "lastupdated": "1/15/2025 8:30 AM"
+ }
+ ]
+}
+Used By: Update-ShopfloorPCs-Remote.ps1 -Reboot -MinUptimeDays 30
Get the recorded IP address for a specific hostname.
+Request:
+GET /api.asp?action=getRecordedIP&hostname=G1ZTNCX3ESF
+Query Parameters:
+| Parameter | +Type | +Description | +
|---|---|---|
hostname |
+string | +Computer name to look up | +
Response:
+{
+ "success": true,
+ "hostname": "G1ZTNCX3ESF",
+ "ipaddress": "10.134.50.101"
+}
+Returns PCs that have relationships to equipment (machines).
+Request:
+GET /api.asp?action=getPCMachineRelationships
+Response:
+{
+ "success": true,
+ "count": 25,
+ "data": [
+ {
+ "pc_machineid": 1234,
+ "pc_hostname": "G1ZTNCX3ESF",
+ "equipment_machineid": 5678,
+ "equipment_machinenumber": "M0612"
+ }
+ ]
+}
+Main endpoint for PC data collection. Receives comprehensive asset data from PowerShell scripts.
+Request:
+POST /api.asp
+Content-Type: application/x-www-form-urlencoded
+
+action=updateCompleteAsset
+&hostname=G1ZTNCX3ESF
+&serialNumber=ABC1234567
+&manufacturer=Dell Inc.
+&model=OptiPlex 7080
+&pcType=Shopfloor
+&loggedInUser=DOMAIN\jsmith
+&machineNo=M0612
+&osVersion=Microsoft Windows 10 Enterprise
+&lastBootTime=2025-01-15 08:30:00
+&hasVnc=1
+&hasWinRM=1
+&networkInterfaces=[...]
+&dncConfig=[...]
+&installedApps=[...]
+Required Parameters:
+| Parameter | +Type | +Description | +
|---|---|---|
hostname |
+string | +Computer name | +
serialNumber |
+string | +BIOS serial number | +
Optional Parameters:
+| Parameter | +Type | +Description | +
|---|---|---|
manufacturer |
+string | +System manufacturer | +
model |
+string | +System model | +
pcType |
+string | +PC classification (Shopfloor, CMM, etc.) | +
loggedInUser |
+string | +Currently logged in user | +
machineNo |
+string | +Associated machine number(s) | +
osVersion |
+string | +Windows version | +
lastBootTime |
+datetime | +Last boot timestamp | +
hasVnc |
+int | +VNC installed (0/1) | +
hasWinRM |
+int | +WinRM enabled (0/1) | +
networkInterfaces |
+JSON | +Network adapter configurations | +
dncConfig |
+JSON | +DNC/FTP settings | +
installedApps |
+JSON | +Tracked applications | +
warrantyEndDate |
+date | +Dell warranty expiration | +
warrantyStatus |
+string | +Warranty status text | +
dncDualPathEnabled |
+int | +Dual path enabled (0/1) | +
dncPath1Name |
+string | +Path 1 name | +
dncPath2Name |
+string | +Path 2 name | +
Network Interfaces JSON Format:
+[
+ {
+ "interfaceName": "Ethernet0",
+ "ipAddress": "10.134.50.101",
+ "subnetMask": "24",
+ "defaultGateway": "10.134.50.1",
+ "macAddress": "00-11-22-33-44-55",
+ "isDhcp": 0,
+ "isActive": 1,
+ "isMachineNetwork": 0,
+ "isPrimary": 1
+ }
+]
+DNC Config JSON Format:
+{
+ "site": "WJF",
+ "cnc": "FANUC",
+ "ncif": "FOCAS2",
+ "machineNo": "M0612",
+ "ftpPrimary": "10.134.50.10",
+ "ftpSecondary": "10.134.50.11"
+}
+Installed Apps JSON Format:
+[
+ {
+ "appid": 5,
+ "appname": "PC-DMIS",
+ "version": "2023.1",
+ "isactive": 1
+ }
+]
+Response:
+{
+ "success": true,
+ "message": "PC data stored successfully",
+ "pcid": 1234,
+ "hostname": "G1ZTNCX3ESF",
+ "debugMsg": "PCType=Shopfloor, DNC=YES, Net=YES"
+}
+Used By: Update-ShopfloorPCs-Remote.ps1, Update-PC-CompleteAsset.ps1
Links a PC to its default printer.
+Request:
+POST /api.asp
+Content-Type: application/x-www-form-urlencoded
+
+action=updatePrinterMapping
+&hostname=G1ZTNCX3ESF
+&printerFQDN=printer01.domain.com
+Parameters:
+| Parameter | +Type | +Description | +
|---|---|---|
hostname |
+string | +PC hostname | +
printerFQDN |
+string | +Printer FQDN, Windows name, or IP | +
Response:
+{
+ "success": true,
+ "message": "Printer mapping updated",
+ "printerId": 45,
+ "machinesUpdated": 1,
+ "matchMethod": "fqdn"
+}
+Match Methods: fqdn, windowsname, ip
Updates the list of tracked applications installed on a PC.
+Request:
+POST /api.asp
+Content-Type: application/x-www-form-urlencoded
+
+action=updateInstalledApps
+&hostname=G1ZTNCX3ESF
+&installedApps=[{"appid":5,"appname":"PC-DMIS","version":"2023.1","isactive":1}]
+Parameters:
+| Parameter | +Type | +Description | +
|---|---|---|
hostname |
+string | +PC hostname | +
installedApps |
+JSON | +Array of tracked applications | +
Response:
+{
+ "success": true,
+ "message": "Installed apps updated",
+ "appsUpdated": 3
+}
+Updates the WinRM enabled status for a PC.
+Request:
+POST /api.asp
+Content-Type: application/x-www-form-urlencoded
+
+action=updateWinRMStatus
+&hostname=G1ZTNCX3ESF
+&hasWinRM=1
+Parameters:
+| Parameter | +Type | +Description | +
|---|---|---|
hostname |
+string | +PC hostname | +
hasWinRM |
+int | +WinRM status (0=disabled, 1=enabled) | +
Response:
+{
+ "success": true,
+ "message": "WinRM status updated",
+ "hostname": "G1ZTNCX3ESF",
+ "iswinrm": 1
+}
+Bulk update machine positions on the floor map.
+Request:
+POST /api.asp
+Content-Type: application/x-www-form-urlencoded
+
+action=updateMachinePositions
+&changes=[{"machineid":1234,"mapleft":100,"maptop":200}]
+Parameters:
+| Parameter | +Type | +Description | +
|---|---|---|
changes |
+JSON | +Array of position updates | +
Response:
+{
+ "success": true,
+ "updated": 5
+}
+All responses are JSON with consistent structure:
+Success Response:
+{
+ "success": true,
+ "message": "Operation completed",
+ "data": [...]
+}
+Error Response:
+{
+ "success": false,
+ "error": "Error description"
+}
+| Error | +Cause | +Solution | +
|---|---|---|
hostname and serialNumber are required |
+Missing required fields | +Include all required parameters | +
PC not found: hostname |
+Hostname not in database | +Verify hostname or run initial collection | +
Printer not found: printerFQDN |
+Printer not in database | +Add printer to ShopDB first | +
Invalid action: xyz |
+Unknown action parameter | +Check action spelling | +
Database error: ... |
+MySQL error | +Check database connectivity | +
# Build POST body
+$body = @{
+ action = "updateCompleteAsset"
+ hostname = $env:COMPUTERNAME
+ serialNumber = (Get-CimInstance Win32_BIOS).SerialNumber
+ manufacturer = (Get-CimInstance Win32_ComputerSystem).Manufacturer
+ model = (Get-CimInstance Win32_ComputerSystem).Model
+ pcType = "Shopfloor"
+}
+
+# Send to API
+$response = Invoke-RestMethod -Uri "https://server/shopdb/api.asp" -Method POST -Body $body
+# Get all shopfloor PCs
+$response = Invoke-RestMethod -Uri "https://server/shopdb/api.asp?action=getShopfloorPCs"
+$pcs = $response.data
+
+# Get CMM PCs only
+$response = Invoke-RestMethod -Uri "https://server/shopdb/api.asp?action=getShopfloorPCs&pctypeid=2"
+
+# Get high uptime PCs
+$response = Invoke-RestMethod -Uri "https://server/shopdb/api.asp?action=getHighUptimePCs&minUptime=30"
+# Update-ShopfloorPCs-Remote.ps1 uses getShopfloorPCs
+.\Update-ShopfloorPCs-Remote.ps1 -All -Credential $cred
+# Internally calls: GET /api.asp?action=getShopfloorPCs
+
+# Reboot mode uses getHighUptimePCs
+.\Update-ShopfloorPCs-Remote.ps1 -Reboot -MinUptimeDays 30
+# Internally calls: GET /api.asp?action=getHighUptimePCs&minUptime=30
+
+# Invoke-RemoteMaintenance.ps1 filters by PC type
+.\Invoke-RemoteMaintenance.ps1 -PcType CMM -Task DiskCleanup
+# Internally calls: GET /api.asp?action=getShopfloorPCs&pctypeid=2
+The API interacts with these primary tables:
+| Table | +Purpose | +
|---|---|
machines |
+All PCs and equipment (pctypeid IS NOT NULL for PCs) | +
communications |
+Network interfaces (IP, MAC, gateway) | +
dncconfig |
+DNC/FTP configurations | +
commconfig |
+Communication port settings | +
installedapps |
+Application tracking | +
pctype |
+PC type definitions | +
businessunits |
+Business unit definitions | +
printers |
+Printer inventory | +
PC Identification:
+machinetypeid IN (33, 34, 35)pctypeid IS NOT NULLisprimary = 1 in communications tableLocal data collection script that runs directly on shopfloor PCs to collect comprehensive system information and send it to the ShopDB database.
+This script runs locally on individual shopfloor PCs to collect comprehensive system information and send it to the ShopDB API. Unlike the remote collection script, this script runs in the local user context, allowing it to collect additional data like mapped drives and user-specific settings.
+Location: S:\dt\shopfloor\scripts\complete-asset\Update-PC-CompleteAsset.ps1
Use Cases:
+Advantages over Remote Collection:
+This script sends collected data to the ShopDB API:
+POST /api.asp?action=updateCompleteAsset
+Parameters include:
+hostname, serialNumber (required)manufacturer, model, osVersionpcType - Auto-detected based on installed softwarenetworkInterfaces - JSON array of network configurationsdncConfig - DNC/FTP settings (if applicable)installedApps - Tracked applications with versionshasVnc, hasWinRM - Feature detection flagsIf a default printer is detected:
+POST /api.asp?action=updatePrinterMapping
+Links the PC to its default network printer in ShopDB.
+POST /api.asp?action=updateInstalledApps
+Updates the list of tracked applications (matched against applications.csv).
See: ShopDB API Reference for complete API documentation.
+ $PSVersionTable.PSVersion
+The script depends on a helper file that should be in the same directory:
+complete-asset/
+├── Update-PC-CompleteAsset.ps1 # Main script
+├── Get-ShopfloorConfig.ps1 # Helper functions (auto-loaded)
+And the applications tracking file should be at:
+powershell/
+└── applications.csv # Application definitions
+Copy the complete-asset folder to the target PC:
C:\Scripts\complete-asset\
+├── Update-PC-CompleteAsset.ps1
+├── Get-ShopfloorConfig.ps1
+Right-click PowerShell and select "Run as administrator"
+cd C:\Scripts\complete-asset
+.\Update-PC-CompleteAsset.ps1
+The script will display collection progress and API response:
+========================================
+Complete PC Asset Collection & Storage
+========================================
+Computer: SHOPFLOOR-PC01
+Dashboard: https://production-server/shopdb/api.asp
+
+=== STEP 1: COLLECT SYSTEM INFO ===
+Collecting comprehensive system information...
+ System Details:
+ Hostname: SHOPFLOOR-PC01
+ Manufacturer: Dell Inc.
+ Model: OptiPlex 7080
+ Serial: ABC1234
+ PC Type: Shopfloor
+ ...
+
+=== STEP 4: SEND TO DATABASE ===
+ [OK] Complete asset data stored in database!
+ PCID: 1234
+ Operation: update
+| Parameter | +Type | +Required | +Default | +Description | +
|---|---|---|---|---|
-DashboardURL |
+string | +No | +Auto-detect | +Override the API endpoint URL | +
-TestConnections |
+switch | +No | +False | +Test connectivity only, no data collection | +
# Navigate to script directory
+cd C:\Scripts\complete-asset
+
+# Run with default settings (auto-detects production API)
+.\Update-PC-CompleteAsset.ps1
+# Use development server
+.\Update-PC-CompleteAsset.ps1 -DashboardURL "http://192.168.122.151:8080/api.asp"
+
+# Use staging server
+.\Update-PC-CompleteAsset.ps1 -DashboardURL "https://staging-server/shopdb/api.asp"
+# Full path execution
+& "C:\Scripts\complete-asset\Update-PC-CompleteAsset.ps1"
+
+# With UNC path
+& "\\server\share\scripts\Update-PC-CompleteAsset.ps1"
+Before deploying widely, test that the PC can reach the API:
+.\Update-PC-CompleteAsset.ps1 -TestConnections
+Expected Output (Success):
+=== CONNECTION TESTS ===
+Skipping proxy test (not accessible from client PCs)
+Testing dashboard connection...
+ Dashboard URL: https://production-server/shopdb/api.asp
+ [OK] Dashboard responded successfully
+
+[OK] Dashboard connection working!
+Expected Output (Failure):
+=== CONNECTION TESTS ===
+Testing dashboard connection...
+ Dashboard URL: https://production-server/shopdb/api.asp
+ [FAIL] Could not connect to dashboard
+
+[FAIL] Dashboard connection failed
+Troubleshooting Failed Connections:
+ping production-server-DashboardURL "http://..."Win + R, type taskschd.msc, press EnterShopDB PC CollectionCollects PC data and sends to ShopDBpowershell.exe-ExecutionPolicy Bypass -WindowStyle Hidden -File "C:\Scripts\complete-asset\Update-PC-CompleteAsset.ps1"# Run this on target PC as administrator
+$action = New-ScheduledTaskAction -Execute "powershell.exe" `
+ -Argument '-ExecutionPolicy Bypass -WindowStyle Hidden -File "C:\Scripts\complete-asset\Update-PC-CompleteAsset.ps1"'
+
+$trigger = New-ScheduledTaskTrigger -AtStartup -RandomDelay (New-TimeSpan -Minutes 5)
+
+$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
+
+$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries `
+ -StartWhenAvailable -ExecutionTimeLimit (New-TimeSpan -Hours 1)
+
+Register-ScheduledTask -TaskName "ShopDB PC Collection" `
+ -Action $action -Trigger $trigger -Principal $principal -Settings $settings `
+ -Description "Collects PC data and sends to ShopDB"
+# Run daily at 6:00 AM
+$trigger = New-ScheduledTaskTrigger -Daily -At 6am
+
+Register-ScheduledTask -TaskName "ShopDB PC Collection" `
+ -Action $action -Trigger $trigger -Principal $principal -Settings $settings
+# List the task
+Get-ScheduledTask -TaskName "ShopDB PC Collection"
+
+# Run the task manually to test
+Start-ScheduledTask -TaskName "ShopDB PC Collection"
+
+# Check task history
+Get-ScheduledTaskInfo -TaskName "ShopDB PC Collection"
+Create a network share accessible to all shopfloor PCs:
+\\fileserver\shopdb-scripts\
+├── complete-asset\
+│ ├── Update-PC-CompleteAsset.ps1
+│ └── Get-ShopfloorConfig.ps1
+└── applications.csv
+Set permissions:
+Navigate to:
+Computer Configuration > Policies > Windows Settings > Scripts > Startup
+Add PowerShell script:
+\\fileserver\shopdb-scripts\complete-asset\Update-PC-CompleteAsset.ps1Or create a batch wrapper:
+startup-collection.bat:
+@echo off
+REM Wait for network
+ping -n 30 127.0.0.1 > nul
+
+REM Run collection script
+powershell.exe -ExecutionPolicy Bypass -WindowStyle Hidden -File "\\fileserver\shopdb-scripts\complete-asset\Update-PC-CompleteAsset.ps1"
+On target PC:
+gpupdate /force
+Then restart to trigger startup script.
+ # Detect if last collection was within 24 hours
+ $logPath = "C:\Logs\CompleteAsset"
+ $recentLog = Get-ChildItem $logPath -Filter "*.log" |
+ Where-Object { $_.LastWriteTime -gt (Get-Date).AddHours(-24) }
+ if ($recentLog) { Write-Output "Installed" }
+ powershell.exe -ExecutionPolicy Bypass -File "Update-PC-CompleteAsset.ps1"
+Check 1: API Response Look at script output for API errors:
+[FAIL] Dashboard could not store data: Invalid hostname
+Check 2: Network Connectivity
+.\Update-PC-CompleteAsset.ps1 -TestConnections
+Check 3: Log Files
+# Find recent log files
+Get-ChildItem "C:\Logs\CompleteAsset" -Recurse | Sort-Object LastWriteTime -Descending | Select -First 5
+Check installed applications:
+# List installed apps the script sees
+Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* |
+ Where-Object { $_.DisplayName } |
+ Select-Object DisplayName |
+ Sort-Object DisplayName
+Verify detection criteria:
+Check registry paths:
+# Check 32-bit registry
+Test-Path "HKLM:\SOFTWARE\GE Aircraft Engines"
+
+# Check 64-bit registry
+Test-Path "HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines"
+
+# List DNC settings
+Get-ChildItem "HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines\DNC" -Recurse
+Check Win32_SerialPort:
+Get-CimInstance -ClassName Win32_SerialPort | Select DeviceID, Description
+If empty, serial ports may be virtual or use different drivers.
+Check manually:
+# Check registry
+Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" |
+ Where-Object { $_.DisplayName -like "*VNC*" }
+
+# Check service
+Get-Service -Name "vncserver*"
+Check execution policy:
+Get-ExecutionPolicy
+# Should be RemoteSigned or Bypass
+
+# Fix:
+Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine
+Check script signing: If policy requires signed scripts, sign the script or use:
+powershell.exe -ExecutionPolicy Bypass -File "script.ps1"
+| Field | +Source | +Example | +
|---|---|---|
| Hostname | +$env:COMPUTERNAME |
+SHOPFLOOR-PC01 |
+
| Serial Number | +CIM_BIOSElement | +ABC1234 |
+
| Service Tag | +CIM_BIOSElement | +ABC1234 |
+
| Manufacturer | +CIM_ComputerSystem | +Dell Inc. |
+
| Model | +CIM_ComputerSystem | +OptiPlex 7080 |
+
| Total Physical Memory | +CIM_ComputerSystem | +16.0 GB |
+
| Domain Role | +CIM_ComputerSystem | +1 (Member Workstation) |
+
| OS Version | +CIM_OperatingSystem | +Windows 10 Enterprise |
+
| Last Boot Time | +CIM_OperatingSystem | +2025-01-15 08:30:00 |
+
| Current Time Zone | +Get-TimeZone | +Eastern Standard Time |
+
| Logged In User | +CIM_ComputerSystem | +DOMAIN\jsmith |
+
| PC Type | +Software Detection | +Shopfloor |
+
| Machine No | +Hostname/Registry | +M0612 |
+
| Field | +Registry Path | +Example | +
|---|---|---|
| Site | +DNC\General\Site |
+WJF |
+
| CNC | +DNC\General\Cnc |
+FANUC |
+
| NcIF | +DNC\General\NcIF |
+FOCAS2 |
+
| Machine No | +DNC\General\MachineNo |
+M0612 |
+
| Host Type | +DNC\General\HostType |
+MX |
+
| FTP Primary | +DNC\MX\FtpHostPrimary |
+10.134.50.10 |
+
| FTP Secondary | +DNC\MX\FtpHostSecondary |
+10.134.50.11 |
+
| Field | +Source | +Example | +
|---|---|---|
| Registry 32-bit | +Path exists check | +true |
+
| Registry 64-bit | +Path exists check | +true |
+
| Dual Path Enabled | +eFocas registry | +true |
+
| Path 1 Name | +eFocas registry | +Primary |
+
| Path 2 Name | +eFocas registry | +Backup |
+
| Field | +Source | +Example | +
|---|---|---|
| Interface Name | +Get-NetAdapter | +Ethernet0 |
+
| IP Address | +Get-NetIPConfiguration | +10.134.50.101 |
+
| Subnet Mask | +Get-NetIPConfiguration | +24 |
+
| Default Gateway | +Get-NetIPConfiguration | +10.134.50.1 |
+
| MAC Address | +Get-NetAdapter | +00-11-22-33-44-55 |
+
| Is DHCP | +Get-NetIPConfiguration | +false |
+
| Is Active | +Get-NetAdapter | +true |
+
| Is Machine Network | +IP pattern match | +false (192.168. or 100.0.0. for CMM) |
+
| Is Primary | +IP pattern match | +true (10.134.*) |
+
| Field | +Source | +Example | +
|---|---|---|
| Serial Ports | +Win32_SerialPort | +COM1, COM2 |
+
| Has VNC | +Registry + Service check | +true |
+
| Default Printer FQDN | +Win32_Printer | +10.80.92.53 |
+
| All Installed Apps | +Registry (HKLM + HKU) | +127 apps | +
| Tracked Applications | +CSV matching | +UDC v2.1, Tanium v7.4 |
+
The script detects PC type based on installed software in this priority order:
+| Priority | +Type | +Detection Method | +
|---|---|---|
| 1 | +Dashboard | +GE Aerospace Dashboard installed |
+
| 2 | +Lobby Display | +GE Aerospace Lobby Display installed |
+
| 3 | +CMM | +PC-DMIS, goCMM, or DODA software | +
| 4 | +Wax Trace | +FormTracePak or FormStatusMonitor | +
| 5 | +Keyence | +VR-3000, VR-5000, or VR-6000 | +
| 6 | +EAS1000 | +GageCal or NI Software | +
| 7 | +Genspect | +Genspect measuring software | +
| 8 | +Heat Treat | +HeatTreat application | +
| 9 | +Inspection | +Machine #: 0612, 0613, 0615, 8003 | +
| 10 | +Shopfloor | +Default for domain shop PCs | +
| 11 | +Engineer | +Has C:\Apps AND V-Drive access | +
| 12 | +Standard | +Default for other domain PCs | +
Note: Priority matters - a PC with both Dashboard and CMM software will be classified as "Dashboard".
+S:\dt\shopfloor\scripts\complete-asset\
+├── Update-PC-CompleteAsset.ps1 # Main script
+└── Get-ShopfloorConfig.ps1 # Helper functions (REQUIRED)
+Important: Both files must be in the same directory. The main script dot-sources the helper:
+. "$PSScriptRoot\Get-ShopfloorConfig.ps1"
+Helper script providing these functions:
+| Function | +Purpose | +
|---|---|
Get-NetworkInterfaceConfig |
+Network adapters with IsPrimary/IsMachineNetwork | +
Get-SerialPortConfig |
+DNC serial port settings | +
Get-GERegistryInfo |
+GE Aircraft Engines registry (DualPath, paths) | +
Get-DNCConfig |
+DNC general configuration | +
Get-ShopfloorConfigurations |
+Combines all above into one call | +
Get-InstalledApplications |
+Detects UDC/CLM processes | +
Defines tracked applications for version tracking:
+app_id,app_name,search_patterns
+2,UDC,"Universal Data Collector"
+4,CLM,"Cell Level Manager|ppdcs"
+77,HeatTreat,"HeatTreat"
+82,GE Aerospace Dashboard,"GE Aerospace Dashboard"
+83,GE Aerospace Lobby Display,"GE Aerospace Lobby Display"
+Location: S:\dt\shopfloor\scripts\applications.csv
| Feature | +Local Script | +Remote Script | +
|---|---|---|
| Execution | +On target PC | +From admin workstation | +
| WinRM Required | +No | +Yes | +
| V-Drive Detection | +Yes | +No | +
| C:\Apps Detection | +Yes | +Limited | +
| Batch Operations | +No (one PC) | +Yes (many PCs) | +
| User Context | +Local user | +WinRM context | +
| Admin Rights | +Needed locally | +Needed remotely | +
Remote data collection script that gathers PC information from shopfloor PCs via WinRM and updates the ShopDB database.
+This script remotely connects to shopfloor PCs using Windows Remote Management (WinRM) to collect comprehensive system information including hardware details, network configuration, DNC settings, and installed applications. The collected data is then sent to the ShopDB API for asset tracking.
+Location: S:\dt\shopfloor\scripts\remote-execution\Update-ShopfloorPCs-Remote.ps1
Use Cases:
+This script interacts with the ShopDB API (api.asp) for both retrieving PC lists and storing collected data.
When using -All, the script queries the API to get the list of shopfloor PCs:
GET /api.asp?action=getShopfloorPCs
+This returns all active PCs with 10.134.. IP addresses. Optional filters:
+pctypeid - Filter by PC type (1=Shopfloor, 2=CMM, etc.)businessunitid - Filter by business unitWhen using -Reboot, the script queries:
GET /api.asp?action=getHighUptimePCs&minUptime=30
+This returns PCs that haven't been rebooted in the specified number of days.
+After collecting data from each PC, the script POSTs to:
+POST /api.asp?action=updateCompleteAsset
+With parameters including hostname, serial number, network interfaces, DNC config, and installed applications.
+See: ShopDB API Reference for complete API documentation.
+ $PSVersionTable.PSVersion
+ # Check if WinRM is running
+ Get-Service WinRM
+
+ # Enable WinRM (run as admin on target PC)
+ Enable-PSRemoting -Force
+If your workstation is not domain-joined or targets are in a different domain:
+# Option 1: Use the script's built-in setup
+.\Update-ShopfloorPCs-Remote.ps1 -SetupTrustedHosts
+
+# Option 2: Manual setup (run as admin)
+Set-Item WSMan:\localhost\Client\TrustedHosts -Value "192.168.*" -Force
+Set-Item WSMan:\localhost\Client\TrustedHosts -Value "10.134.*" -Concatenate -Force
+# Navigate to script directory
+cd C:\Path\To\powershell\remote-execution
+# Store credentials for the session
+$cred = Get-Credential -Message "Enter domain admin credentials"
+# Test with a single PC
+.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "SHOPFLOOR-PC01" -Credential $cred
+Check the ShopDB database or web interface to confirm the PC data was updated.
+| Parameter | +Type | +Description | +
|---|---|---|
-ComputerName |
+string[] | +One or more computer names to target | +
-All |
+switch | +Query ShopDB for all shopfloor PCs | +
| Parameter | +Type | +Default | +Description | +
|---|---|---|---|
-Credential |
+PSCredential | +Prompt | +Admin credentials for remote access | +
-UseSSL |
+switch | +False | +Use HTTPS (port 5986) instead of HTTP | +
| Parameter | +Type | +Default | +Description | +
|---|---|---|---|
-ApiUrl |
+string | +Production URL | +ShopDB API endpoint | +
| Parameter | +Type | +Default | +Description | +
|---|---|---|---|
-DnsSuffix |
+string | +logon.ds.ge.com | +DNS suffix for FQDN resolution | +
-SkipDnsLookup |
+switch | +False | +Use hostnames as-is without DNS | +
-ThrottleLimit |
+int | +25 | +Max concurrent remote sessions | +
| Parameter | +Type | +Description | +
|---|---|---|
-Reboot |
+switch | +Enable reboot mode | +
-MinUptimeDays |
+int | +Minimum uptime threshold for reboot | +
-Force |
+switch | +Skip confirmation prompts | +
-WhatIf |
+switch | +Preview without executing | +
| Parameter | +Type | +Description | +
|---|---|---|
-SetupTrustedHosts |
+switch | +Configure WinRM trusted hosts | +
Scenario: You need to update asset data for one specific PC.
+# Basic usage
+.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "G1ZTNCX3ESF"
+
+# With credentials (avoids prompt)
+$cred = Get-Credential
+.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "G1ZTNCX3ESF" -Credential $cred
+
+# Using IP address instead of hostname
+.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "10.134.50.101" -SkipDnsLookup
+Expected Output:
+Connecting to G1ZTNCX3ESF...
+ [OK] Connected successfully
+ Collecting system information...
+ Hostname: G1ZTNCX3ESF
+ Serial: ABC1234
+ PC Type: Shopfloor
+ Sending data to API...
+ [OK] Data stored successfully (PCID: 1234)
+Scenario: You have a list of PCs that need updating.
+# Array of computer names
+.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "PC01","PC02","PC03","PC04"
+
+# From a variable
+$pcs = @("SHOPFLOOR-01", "SHOPFLOOR-02", "SHOPFLOOR-03")
+.\Update-ShopfloorPCs-Remote.ps1 -ComputerName $pcs -Credential $cred
+
+# From a text file (one hostname per line)
+$pcs = Get-Content "C:\Lists\shopfloor-pcs.txt"
+.\Update-ShopfloorPCs-Remote.ps1 -ComputerName $pcs -Credential $cred
+Adjusting Concurrency:
+# Slower network - reduce concurrent connections
+.\Update-ShopfloorPCs-Remote.ps1 -ComputerName $pcs -ThrottleLimit 5
+
+# Fast network - increase concurrent connections
+.\Update-ShopfloorPCs-Remote.ps1 -ComputerName $pcs -ThrottleLimit 50
+Scenario: Scheduled full inventory update of all shopfloor PCs.
+# Update all PCs from ShopDB database
+.\Update-ShopfloorPCs-Remote.ps1 -All -Credential $cred
+
+# With lower throttle for off-hours
+.\Update-ShopfloorPCs-Remote.ps1 -All -Credential $cred -ThrottleLimit 10
+Scheduling with Task Scheduler:
+run-collection.bat: @echo off
+ powershell.exe -ExecutionPolicy Bypass -File "C:\Scripts\Update-ShopfloorPCs-Remote.ps1" -All
+run-collection.batScenario: Reboot PCs that haven't been restarted in 30+ days.
+# Step 1: Preview which PCs would be rebooted
+.\Update-ShopfloorPCs-Remote.ps1 -Reboot -MinUptimeDays 30 -WhatIf
+
+# Output shows:
+# Would reboot: SHOPFLOOR-01 (Uptime: 45 days)
+# Would reboot: SHOPFLOOR-02 (Uptime: 62 days)
+# Would skip: SHOPFLOOR-03 (Uptime: 12 days)
+
+# Step 2: Execute with confirmation
+.\Update-ShopfloorPCs-Remote.ps1 -Reboot -MinUptimeDays 30 -Credential $cred
+# Prompts: "Reboot 2 PCs? [Y/N]"
+
+# Step 3: Or execute without confirmation
+.\Update-ShopfloorPCs-Remote.ps1 -Reboot -MinUptimeDays 30 -Force -Credential $cred
+Best Practices for Reboots:
+-WhatIf firstScenario: Your workstation can't connect to shopfloor PCs.
+# Use built-in setup (configures common shopfloor subnets)
+.\Update-ShopfloorPCs-Remote.ps1 -SetupTrustedHosts
+
+# Verify configuration
+Get-Item WSMan:\localhost\Client\TrustedHosts
+
+# Manual addition of specific subnet
+Set-Item WSMan:\localhost\Client\TrustedHosts -Value "10.134.*" -Force
+Scenario: Testing against development or staging environments.
+# Development environment
+.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "TEST-PC" -ApiUrl "http://192.168.122.151:8080/api.asp"
+
+# Staging environment
+.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "TEST-PC" -ApiUrl "https://staging-server/shopdb/api.asp"
+Scenario: PC hostnames aren't resolving correctly.
+# Skip DNS and use hostnames as-is
+.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "SHOPFLOOR-01" -SkipDnsLookup
+
+# Use different DNS suffix
+.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "SHOPFLOOR-01" -DnsSuffix "shopfloor.local"
+
+# Use IP addresses directly
+.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "10.134.50.101" -SkipDnsLookup
+Scenario: Security requirements mandate encrypted WinRM connections.
+# Enable SSL for WinRM (uses port 5986)
+.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "SECURE-PC" -UseSSL -Credential $cred
+Prerequisites for SSL:
+| Field | +Example | +Description | +
|---|---|---|
| Hostname | +G1ZTNCX3ESF |
+Computer name | +
| Serial Number | +ABC1234567 |
+BIOS serial | +
| Service Tag | +ABC1234567 |
+Dell service tag | +
| Manufacturer | +Dell Inc. |
+System manufacturer | +
| Model | +OptiPlex 7080 |
+System model | +
| OS Version | +Microsoft Windows 10 Enterprise |
+Windows edition | +
| Last Boot Time | +2025-01-15 08:30:00 |
+Last restart | +
| Total Physical Memory | +16.0 |
+RAM in GB | +
| Domain Role | +1 |
+0=Standalone, 1=Member Workstation | +
| Current Time Zone | +Eastern Standard Time |
+System timezone | +
| Logged In User | +DOMAIN\jsmith |
+Current user | +
| Field | +Example | +Description | +
|---|---|---|
| Site | +WJF |
+GE site code | +
| CNC | +FANUC |
+CNC controller type | +
| NcIF | +FOCAS2 |
+NC interface protocol | +
| Machine No | +M0612 |
+GE machine number | +
| FTP Primary | +10.134.50.10 |
+Primary FTP server | +
| FTP Secondary | +10.134.50.11 |
+Backup FTP server | +
| Field | +Example | +Description | +
|---|---|---|
| Interface Name | +Ethernet0 |
+Adapter name | +
| IP Address | +10.134.50.101 |
+IPv4 address | +
| Subnet Mask | +24 |
+CIDR prefix | +
| Default Gateway | +10.134.50.1 |
+Gateway | +
| MAC Address | +00-11-22-33-44-55 |
+Physical address | +
| Is Primary | +1 |
+10.134.. network | +
| Is Machine Network | +0 |
+192.168.. or 100.0.0.* network (CMM) | +
| Field | +Example | +Description | +
|---|---|---|
| Serial Ports | +COM1, COM2 |
+Available COM ports | +
| Has VNC | +1 |
+VNC Server installed | +
| Default Printer | +10.80.92.53 |
+Network printer port | +
| All Installed Apps | +Microsoft Office... |
+Complete app list | +
The script automatically classifies PCs based on installed software:
+| Priority | +Type | +Detection Criteria | +
|---|---|---|
| 1 | +Dashboard | +GE Aerospace Dashboard installed |
+
| 2 | +Lobby Display | +GE Aerospace Lobby Display installed |
+
| 3 | +CMM | +PC-DMIS, goCMM, or DODA software | +
| 4 | +Wax Trace | +FormTracePak or FormStatusMonitor | +
| 5 | +Keyence | +VR-3000, VR-5000, or VR-6000 | +
| 6 | +EAS1000 | +GageCal or NI Software | +
| 7 | +Genspect | +Genspect measuring software | +
| 8 | +Heat Treat | +HeatTreat application | +
| 9 | +Inspection | +Machine #: 0612, 0613, 0615, 8003 | +
| 10 | +Shopfloor | +Default for domain shop PCs | +
Cause: WinRM not enabled on target PC.
+Solution:
+# On target PC (as admin)
+Enable-PSRemoting -Force
+Set-Service WinRM -StartupType Automatic
+Start-Service WinRM
+Cause: Insufficient credentials or UAC blocking remote admin.
+Solutions:
+# 1. Use explicit domain credentials
+$cred = Get-Credential -UserName "DOMAIN\AdminUser" -Message "Enter password"
+
+# 2. On target PC, enable remote UAC (as admin)
+Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" -Name "LocalAccountTokenFilterPolicy" -Value 1 -Type DWord
+Cause: Target not in trusted hosts list.
+Solution:
+.\Update-ShopfloorPCs-Remote.ps1 -SetupTrustedHosts
+# Or manually:
+Set-Item WSMan:\localhost\Client\TrustedHosts -Value "10.134.*" -Force
+Cause: TLS/SSL configuration mismatch.
+Solution: The script automatically sets TLS 1.2/1.3. If issues persist:
+# Force TLS 1.2 before running
+[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
+Cause: Hostname not resolving.
+Solutions:
+# 1. Skip DNS resolution
+.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "PC01" -SkipDnsLookup
+
+# 2. Use IP address
+.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "10.134.50.101" -SkipDnsLookup
+
+# 3. Use different DNS suffix
+.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "PC01" -DnsSuffix "yourdomain.local"
+Cause: Network bandwidth or target PC load.
+Solutions:
+# Reduce concurrent connections
+.\Update-ShopfloorPCs-Remote.ps1 -All -ThrottleLimit 5
+
+# Run in batches
+$allPCs = Get-Content "all-pcs.txt"
+$batch1 = $allPCs[0..49]
+$batch2 = $allPCs[50..99]
+
+.\Update-ShopfloorPCs-Remote.ps1 -ComputerName $batch1 -Credential $cred
+.\Update-ShopfloorPCs-Remote.ps1 -ComputerName $batch2 -Credential $cred
+# Collect data first, then run maintenance
+.\Update-ShopfloorPCs-Remote.ps1 -All -Credential $cred
+.\Invoke-RemoteMaintenance.ps1 -All -Task SyncTime -Credential $cred
+# Capture output to file
+.\Update-ShopfloorPCs-Remote.ps1 -All -Credential $cred | Tee-Object -FilePath "collection-log.txt"
+S:\dt\shopfloor\scripts\
+├── remote-execution\
+│ ├── Update-ShopfloorPCs-Remote.ps1 # Remote data collection (this script)
+│ └── Invoke-RemoteMaintenance.ps1 # Remote maintenance tasks
+│
+└── complete-asset\
+ ├── Update-PC-CompleteAsset.ps1 # Local data collection
+ └── Get-ShopfloorConfig.ps1 # Helper functions (required by above)
+The following scripts in remote-execution\ are legacy and have been replaced:
| Deprecated Script | +Replaced By | +
|---|---|
Invoke-RemoteAssetCollection.ps1 |
+Update-ShopfloorPCs-Remote.ps1 |
+
Invoke-RemoteAssetCollection-HTTPS.ps1 |
+Update-ShopfloorPCs-Remote.ps1 -UseSSL |
+
Install-KioskApp.ps1 |
+Invoke-RemoteMaintenance.ps1 -Task InstallDashboard |
+
Test-UserRegistryDetection.ps1 |
+Functionality integrated into main scripts | +
These deprecated scripts can be archived or deleted.
+ + \ No newline at end of file diff --git a/docs/Update-ShopfloorPCs-Remote.md b/docs/Update-ShopfloorPCs-Remote.md new file mode 100644 index 0000000..a79ebdd --- /dev/null +++ b/docs/Update-ShopfloorPCs-Remote.md @@ -0,0 +1,582 @@ +# Update-ShopfloorPCs-Remote.ps1 + +Remote data collection script that gathers PC information from shopfloor PCs via WinRM and updates the ShopDB database. + +## Table of Contents + +- [Overview](#overview) +- [API Integration](#api-integration) +- [Prerequisites](#prerequisites) +- [Quick Start](#quick-start) +- [Parameters Reference](#parameters-reference) +- [How-To Guides](#how-to-guides) +- [Data Collected](#data-collected) +- [PC Type Detection](#pc-type-detection) +- [Troubleshooting](#troubleshooting) +- [Advanced Usage](#advanced-usage) +- [Script Files](#script-files) + +--- + +## Overview + +This script remotely connects to shopfloor PCs using Windows Remote Management (WinRM) to collect comprehensive system information including hardware details, network configuration, DNC settings, and installed applications. The collected data is then sent to the ShopDB API for asset tracking. + +**Location:** `S:\dt\shopfloor\scripts\remote-execution\Update-ShopfloorPCs-Remote.ps1` + +**Use Cases:** +- Bulk asset inventory updates +- Automated PC discovery and classification +- Scheduled data collection from all shopfloor PCs +- Targeted updates for specific machines or groups + +--- + +## API Integration + +This script interacts with the ShopDB API (`api.asp`) for both retrieving PC lists and storing collected data. + +### Retrieving PC Lists + +When using `-All`, the script queries the API to get the list of shopfloor PCs: + +``` +GET /api.asp?action=getShopfloorPCs +``` + +This returns all active PCs with 10.134.*.* IP addresses. Optional filters: +- `pctypeid` - Filter by PC type (1=Shopfloor, 2=CMM, etc.) +- `businessunitid` - Filter by business unit + +### Retrieving High Uptime PCs + +When using `-Reboot`, the script queries: + +``` +GET /api.asp?action=getHighUptimePCs&minUptime=30 +``` + +This returns PCs that haven't been rebooted in the specified number of days. + +### Storing Collected Data + +After collecting data from each PC, the script POSTs to: + +``` +POST /api.asp?action=updateCompleteAsset +``` + +With parameters including hostname, serial number, network interfaces, DNC config, and installed applications. + +**See:** [ShopDB API Reference](ShopDB-API.html) for complete API documentation. + +--- + +## Prerequisites + +### On Your Workstation (Where You Run the Script) + +1. **PowerShell 5.1 or higher** + ```powershell + $PSVersionTable.PSVersion + ``` + +2. **Network access to target PCs** on port 5985 (HTTP) or 5986 (HTTPS) + +3. **Domain admin or local admin credentials** for target PCs + +### On Target PCs + +1. **WinRM must be enabled** + ```powershell + # Check if WinRM is running + Get-Service WinRM + + # Enable WinRM (run as admin on target PC) + Enable-PSRemoting -Force + ``` + +2. **Firewall rules** allowing WinRM traffic (TCP 5985/5986) + +### WinRM Trusted Hosts Setup + +If your workstation is not domain-joined or targets are in a different domain: + +```powershell +# Option 1: Use the script's built-in setup +.\Update-ShopfloorPCs-Remote.ps1 -SetupTrustedHosts + +# Option 2: Manual setup (run as admin) +Set-Item WSMan:\localhost\Client\TrustedHosts -Value "192.168.*" -Force +Set-Item WSMan:\localhost\Client\TrustedHosts -Value "10.134.*" -Concatenate -Force +``` + +--- + +## Quick Start + +### Step 1: Open PowerShell as Administrator + +```powershell +# Navigate to script directory +cd C:\Path\To\powershell\remote-execution +``` + +### Step 2: Get Credentials + +```powershell +# Store credentials for the session +$cred = Get-Credential -Message "Enter domain admin credentials" +``` + +### Step 3: Run Your First Collection + +```powershell +# Test with a single PC +.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "SHOPFLOOR-PC01" -Credential $cred +``` + +### Step 4: Verify Results + +Check the ShopDB database or web interface to confirm the PC data was updated. + +--- + +## Parameters Reference + +### Targeting Parameters + +| Parameter | Type | Description | +|-----------|------|-------------| +| `-ComputerName` | string[] | One or more computer names to target | +| `-All` | switch | Query ShopDB for all shopfloor PCs | + +### Authentication Parameters + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `-Credential` | PSCredential | Prompt | Admin credentials for remote access | +| `-UseSSL` | switch | False | Use HTTPS (port 5986) instead of HTTP | + +### API Parameters + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `-ApiUrl` | string | Production URL | ShopDB API endpoint | + +### Network Parameters + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `-DnsSuffix` | string | logon.ds.ge.com | DNS suffix for FQDN resolution | +| `-SkipDnsLookup` | switch | False | Use hostnames as-is without DNS | +| `-ThrottleLimit` | int | 25 | Max concurrent remote sessions | + +### Reboot Parameters + +| Parameter | Type | Description | +|-----------|------|-------------| +| `-Reboot` | switch | Enable reboot mode | +| `-MinUptimeDays` | int | Minimum uptime threshold for reboot | +| `-Force` | switch | Skip confirmation prompts | +| `-WhatIf` | switch | Preview without executing | + +### Setup Parameters + +| Parameter | Type | Description | +|-----------|------|-------------| +| `-SetupTrustedHosts` | switch | Configure WinRM trusted hosts | + +--- + +## How-To Guides + +### How to Update a Single PC + +**Scenario:** You need to update asset data for one specific PC. + +```powershell +# Basic usage +.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "G1ZTNCX3ESF" + +# With credentials (avoids prompt) +$cred = Get-Credential +.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "G1ZTNCX3ESF" -Credential $cred + +# Using IP address instead of hostname +.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "10.134.50.101" -SkipDnsLookup +``` + +**Expected Output:** +``` +Connecting to G1ZTNCX3ESF... + [OK] Connected successfully + Collecting system information... + Hostname: G1ZTNCX3ESF + Serial: ABC1234 + PC Type: Shopfloor + Sending data to API... + [OK] Data stored successfully (PCID: 1234) +``` + +--- + +### How to Update Multiple PCs + +**Scenario:** You have a list of PCs that need updating. + +```powershell +# Array of computer names +.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "PC01","PC02","PC03","PC04" + +# From a variable +$pcs = @("SHOPFLOOR-01", "SHOPFLOOR-02", "SHOPFLOOR-03") +.\Update-ShopfloorPCs-Remote.ps1 -ComputerName $pcs -Credential $cred + +# From a text file (one hostname per line) +$pcs = Get-Content "C:\Lists\shopfloor-pcs.txt" +.\Update-ShopfloorPCs-Remote.ps1 -ComputerName $pcs -Credential $cred +``` + +**Adjusting Concurrency:** +```powershell +# Slower network - reduce concurrent connections +.\Update-ShopfloorPCs-Remote.ps1 -ComputerName $pcs -ThrottleLimit 5 + +# Fast network - increase concurrent connections +.\Update-ShopfloorPCs-Remote.ps1 -ComputerName $pcs -ThrottleLimit 50 +``` + +--- + +### How to Update All Shopfloor PCs + +**Scenario:** Scheduled full inventory update of all shopfloor PCs. + +```powershell +# Update all PCs from ShopDB database +.\Update-ShopfloorPCs-Remote.ps1 -All -Credential $cred + +# With lower throttle for off-hours +.\Update-ShopfloorPCs-Remote.ps1 -All -Credential $cred -ThrottleLimit 10 +``` + +**Scheduling with Task Scheduler:** + +1. Create a batch file `run-collection.bat`: + ```batch + @echo off + powershell.exe -ExecutionPolicy Bypass -File "C:\Scripts\Update-ShopfloorPCs-Remote.ps1" -All + ``` + +2. Create scheduled task: + - Trigger: Daily at 2:00 AM + - Action: Run `run-collection.bat` + - Run as: Service account with admin rights + +--- + +### How to Reboot PCs with High Uptime + +**Scenario:** Reboot PCs that haven't been restarted in 30+ days. + +```powershell +# Step 1: Preview which PCs would be rebooted +.\Update-ShopfloorPCs-Remote.ps1 -Reboot -MinUptimeDays 30 -WhatIf + +# Output shows: +# Would reboot: SHOPFLOOR-01 (Uptime: 45 days) +# Would reboot: SHOPFLOOR-02 (Uptime: 62 days) +# Would skip: SHOPFLOOR-03 (Uptime: 12 days) + +# Step 2: Execute with confirmation +.\Update-ShopfloorPCs-Remote.ps1 -Reboot -MinUptimeDays 30 -Credential $cred +# Prompts: "Reboot 2 PCs? [Y/N]" + +# Step 3: Or execute without confirmation +.\Update-ShopfloorPCs-Remote.ps1 -Reboot -MinUptimeDays 30 -Force -Credential $cred +``` + +**Best Practices for Reboots:** +- Always run `-WhatIf` first +- Schedule during maintenance windows +- Start with higher threshold (60 days) then reduce +- Monitor for production impact + +--- + +### How to Set Up WinRM Trusted Hosts + +**Scenario:** Your workstation can't connect to shopfloor PCs. + +```powershell +# Use built-in setup (configures common shopfloor subnets) +.\Update-ShopfloorPCs-Remote.ps1 -SetupTrustedHosts + +# Verify configuration +Get-Item WSMan:\localhost\Client\TrustedHosts + +# Manual addition of specific subnet +Set-Item WSMan:\localhost\Client\TrustedHosts -Value "10.134.*" -Force +``` + +--- + +### How to Use Different API Endpoints + +**Scenario:** Testing against development or staging environments. + +```powershell +# Development environment +.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "TEST-PC" -ApiUrl "http://192.168.122.151:8080/api.asp" + +# Staging environment +.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "TEST-PC" -ApiUrl "https://staging-server/shopdb/api.asp" +``` + +--- + +### How to Handle DNS Resolution Issues + +**Scenario:** PC hostnames aren't resolving correctly. + +```powershell +# Skip DNS and use hostnames as-is +.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "SHOPFLOOR-01" -SkipDnsLookup + +# Use different DNS suffix +.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "SHOPFLOOR-01" -DnsSuffix "shopfloor.local" + +# Use IP addresses directly +.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "10.134.50.101" -SkipDnsLookup +``` + +--- + +### How to Use Secure Connections (SSL) + +**Scenario:** Security requirements mandate encrypted WinRM connections. + +```powershell +# Enable SSL for WinRM (uses port 5986) +.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "SECURE-PC" -UseSSL -Credential $cred +``` + +**Prerequisites for SSL:** +- Valid certificate on target PC +- WinRM HTTPS listener configured +- Port 5986 open in firewall + +--- + +## Data Collected + +### Basic System Information + +| Field | Example | Description | +|-------|---------|-------------| +| Hostname | `G1ZTNCX3ESF` | Computer name | +| Serial Number | `ABC1234567` | BIOS serial | +| Service Tag | `ABC1234567` | Dell service tag | +| Manufacturer | `Dell Inc.` | System manufacturer | +| Model | `OptiPlex 7080` | System model | +| OS Version | `Microsoft Windows 10 Enterprise` | Windows edition | +| Last Boot Time | `2025-01-15 08:30:00` | Last restart | +| Total Physical Memory | `16.0` | RAM in GB | +| Domain Role | `1` | 0=Standalone, 1=Member Workstation | +| Current Time Zone | `Eastern Standard Time` | System timezone | +| Logged In User | `DOMAIN\jsmith` | Current user | + +### DNC Configuration + +| Field | Example | Description | +|-------|---------|-------------| +| Site | `WJF` | GE site code | +| CNC | `FANUC` | CNC controller type | +| NcIF | `FOCAS2` | NC interface protocol | +| Machine No | `M0612` | GE machine number | +| FTP Primary | `10.134.50.10` | Primary FTP server | +| FTP Secondary | `10.134.50.11` | Backup FTP server | + +### Network Interfaces + +| Field | Example | Description | +|-------|---------|-------------| +| Interface Name | `Ethernet0` | Adapter name | +| IP Address | `10.134.50.101` | IPv4 address | +| Subnet Mask | `24` | CIDR prefix | +| Default Gateway | `10.134.50.1` | Gateway | +| MAC Address | `00-11-22-33-44-55` | Physical address | +| Is Primary | `1` | 10.134.*.* network | +| Is Machine Network | `0` | 192.168.*.* or 100.0.0.* network (CMM) | + +### Additional Data + +| Field | Example | Description | +|-------|---------|-------------| +| Serial Ports | `COM1, COM2` | Available COM ports | +| Has VNC | `1` | VNC Server installed | +| Default Printer | `10.80.92.53` | Network printer port | +| All Installed Apps | `Microsoft Office...` | Complete app list | + +--- + +## PC Type Detection + +The script automatically classifies PCs based on installed software: + +| Priority | Type | Detection Criteria | +|----------|------|-------------------| +| 1 | Dashboard | `GE Aerospace Dashboard` installed | +| 2 | Lobby Display | `GE Aerospace Lobby Display` installed | +| 3 | CMM | PC-DMIS, goCMM, or DODA software | +| 4 | Wax Trace | FormTracePak or FormStatusMonitor | +| 5 | Keyence | VR-3000, VR-5000, or VR-6000 | +| 6 | EAS1000 | GageCal or NI Software | +| 7 | Genspect | Genspect measuring software | +| 8 | Heat Treat | HeatTreat application | +| 9 | Inspection | Machine #: 0612, 0613, 0615, 8003 | +| 10 | Shopfloor | Default for domain shop PCs | + +--- + +## Troubleshooting + +### Error: "WinRM cannot process the request" + +**Cause:** WinRM not enabled on target PC. + +**Solution:** +```powershell +# On target PC (as admin) +Enable-PSRemoting -Force +Set-Service WinRM -StartupType Automatic +Start-Service WinRM +``` + +--- + +### Error: "Access is denied" + +**Cause:** Insufficient credentials or UAC blocking remote admin. + +**Solutions:** +```powershell +# 1. Use explicit domain credentials +$cred = Get-Credential -UserName "DOMAIN\AdminUser" -Message "Enter password" + +# 2. On target PC, enable remote UAC (as admin) +Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" -Name "LocalAccountTokenFilterPolicy" -Value 1 -Type DWord +``` + +--- + +### Error: "The WinRM client cannot process the request... not in TrustedHosts" + +**Cause:** Target not in trusted hosts list. + +**Solution:** +```powershell +.\Update-ShopfloorPCs-Remote.ps1 -SetupTrustedHosts +# Or manually: +Set-Item WSMan:\localhost\Client\TrustedHosts -Value "10.134.*" -Force +``` + +--- + +### Error: "The underlying connection was closed" + +**Cause:** TLS/SSL configuration mismatch. + +**Solution:** The script automatically sets TLS 1.2/1.3. If issues persist: +```powershell +# Force TLS 1.2 before running +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 +``` + +--- + +### Error: "Cannot find computer" or DNS failures + +**Cause:** Hostname not resolving. + +**Solutions:** +```powershell +# 1. Skip DNS resolution +.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "PC01" -SkipDnsLookup + +# 2. Use IP address +.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "10.134.50.101" -SkipDnsLookup + +# 3. Use different DNS suffix +.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "PC01" -DnsSuffix "yourdomain.local" +``` + +--- + +### Slow Performance with Many PCs + +**Cause:** Network bandwidth or target PC load. + +**Solutions:** +```powershell +# Reduce concurrent connections +.\Update-ShopfloorPCs-Remote.ps1 -All -ThrottleLimit 5 + +# Run in batches +$allPCs = Get-Content "all-pcs.txt" +$batch1 = $allPCs[0..49] +$batch2 = $allPCs[50..99] + +.\Update-ShopfloorPCs-Remote.ps1 -ComputerName $batch1 -Credential $cred +.\Update-ShopfloorPCs-Remote.ps1 -ComputerName $batch2 -Credential $cred +``` + +--- + +## Advanced Usage + +### Combining with Other Scripts + +```powershell +# Collect data first, then run maintenance +.\Update-ShopfloorPCs-Remote.ps1 -All -Credential $cred +.\Invoke-RemoteMaintenance.ps1 -All -Task SyncTime -Credential $cred +``` + +### Exporting Results for Analysis + +```powershell +# Capture output to file +.\Update-ShopfloorPCs-Remote.ps1 -All -Credential $cred | Tee-Object -FilePath "collection-log.txt" +``` + +--- + +## Script Files + +### Current Scripts (Active) + +``` +S:\dt\shopfloor\scripts\ +├── remote-execution\ +│ ├── Update-ShopfloorPCs-Remote.ps1 # Remote data collection (this script) +│ └── Invoke-RemoteMaintenance.ps1 # Remote maintenance tasks +│ +└── complete-asset\ + ├── Update-PC-CompleteAsset.ps1 # Local data collection + └── Get-ShopfloorConfig.ps1 # Helper functions (required by above) +``` + +### Deprecated Scripts (Can Be Removed) + +The following scripts in `remote-execution\` are legacy and have been replaced: + +| Deprecated Script | Replaced By | +|-------------------|-------------| +| `Invoke-RemoteAssetCollection.ps1` | `Update-ShopfloorPCs-Remote.ps1` | +| `Invoke-RemoteAssetCollection-HTTPS.ps1` | `Update-ShopfloorPCs-Remote.ps1 -UseSSL` | +| `Install-KioskApp.ps1` | `Invoke-RemoteMaintenance.ps1 -Task InstallDashboard` | +| `Test-UserRegistryDetection.ps1` | Functionality integrated into main scripts | + +These deprecated scripts can be archived or deleted. diff --git a/docs/convert_to_html.py b/docs/convert_to_html.py new file mode 100644 index 0000000..72d3553 --- /dev/null +++ b/docs/convert_to_html.py @@ -0,0 +1,411 @@ +#!/usr/bin/env python3 +""" +Convert Markdown documentation to styled HTML +""" + +import re +import os +import html + +def convert_md_to_html(md_content, title="Documentation"): + """Convert markdown content to styled HTML.""" + + # HTML template with CSS styling + html_template = ''' + + + + +{code_content}')
+ else:
+ html_lines.append(f'{code_content}')
+ i += 1 # Skip closing ```
+
+ # Tables
+ elif '|' in line and i + 1 < len(lines) and '---' in lines[i + 1]:
+ if in_list:
+ html_lines.append(f'{list_type}>')
+ in_list = False
+ html_lines.append('| {process_inline(cell)} | ') + html_lines.append('
|---|
| {process_inline(cell)} | ') + html_lines.append('
{text}') + i += 1 + + # Regular paragraph + else: + if in_list: + html_lines.append(f'{list_type}>') + in_list = False + para_lines = [line.strip()] + i += 1 + while i < len(lines) and lines[i].strip() and not lines[i].startswith('#') and not lines[i].startswith('```') and not lines[i].strip().startswith('- ') and not lines[i].strip().startswith('* ') and '|' not in lines[i] and not re.match(r'^\d+\.\s', lines[i].strip()) and lines[i].strip() != '---': + para_lines.append(lines[i].strip()) + i += 1 + text = process_inline(' '.join(para_lines)) + html_lines.append(f'
{text}
') + + # Close any remaining list + if in_list: + html_lines.append(f'{list_type}>') + + content = '\n'.join(html_lines) + return html_template.format(title=html.escape(title), content=content) + +def process_inline(text): + """Process inline markdown formatting.""" + # Escape HTML first + # But we need to be careful not to double-escape + + # Bold + text = re.sub(r'\*\*([^*]+)\*\*', r'\1', text) + + # Italic + text = re.sub(r'\*([^*]+)\*', r'\1', text) + + # Inline code (before links to avoid conflicts) + text = re.sub(r'`([^`]+)`', lambda m: f'{html.escape(m.group(1))}', text)
+
+ # Links
+ text = re.sub(r'\[([^\]]+)\]\(([^)]+)\)', r'\1', text)
+
+ # Checkmarks and X marks
+ text = text.replace('✓', '✓')
+ text = text.replace('✗', '✗')
+
+ return text
+
+def slugify(text):
+ """Convert text to URL-friendly slug."""
+ text = text.lower()
+ text = re.sub(r'[^a-z0-9\s-]', '', text)
+ text = re.sub(r'[\s]+', '-', text)
+ return text
+
+def convert_file(md_path, html_path):
+ """Convert a markdown file to HTML."""
+ print(f"Converting {os.path.basename(md_path)} -> {os.path.basename(html_path)}")
+
+ with open(md_path, 'r', encoding='utf-8') as f:
+ content = f.read()
+
+ # Extract title from first h1
+ title_match = re.search(r'^# (.+)$', content, re.MULTILINE)
+ title = title_match.group(1) if title_match else os.path.basename(md_path)
+
+ html_content = convert_md_to_html(content, title)
+
+ with open(html_path, 'w', encoding='utf-8') as f:
+ f.write(html_content)
+
+def main():
+ docs_dir = '/home/camp/projects/powershell/docs'
+
+ md_files = [
+ 'Update-ShopfloorPCs-Remote.md',
+ 'Invoke-RemoteMaintenance.md',
+ 'Update-PC-CompleteAsset.md',
+ 'DATA_COLLECTION_PARITY.md',
+ 'ShopDB-API.md'
+ ]
+
+ for md_file in md_files:
+ md_path = os.path.join(docs_dir, md_file)
+ html_path = os.path.join(docs_dir, md_file.replace('.md', '.html'))
+
+ if os.path.exists(md_path):
+ convert_file(md_path, html_path)
+ else:
+ print(f"Warning: {md_path} not found")
+
+ print("\nConversion complete!")
+ print(f"HTML files saved to: {docs_dir}")
+
+if __name__ == '__main__':
+ main()
diff --git a/remote-execution/Invoke-RemoteMaintenance.ps1 b/remote-execution/Invoke-RemoteMaintenance.ps1
index d9daa95..13cd28e 100644
--- a/remote-execution/Invoke-RemoteMaintenance.ps1
+++ b/remote-execution/Invoke-RemoteMaintenance.ps1
@@ -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"
diff --git a/remote-execution/Update-ShopfloorPCs-Remote.ps1 b/remote-execution/Update-ShopfloorPCs-Remote.ps1
index b475312..4719e15 100644
--- a/remote-execution/Update-ShopfloorPCs-Remote.ps1
+++ b/remote-execution/Update-ShopfloorPCs-Remote.ps1
@@ -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