# Minimal PC data collection script # For locked-down PCs with restricted permissions # SSL/TLS Certificate Bypass for HTTPS connections try { if (-not ([System.Management.Automation.PSTypeName]'TrustAllCertsPolicy').Type) { Add-Type @" using System.Net; using System.Security.Cryptography.X509Certificates; public class TrustAllCertsPolicy : ICertificatePolicy { public bool CheckValidationResult( ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) { return true; } } "@ } [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy } catch { } [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $apiUrl = "https://tsgwp00525.rd.ds.ge.com/shopdb/api.asp" $logFile = "$env:TEMP\shopdb-update.log" # Start fresh log "$(Get-Date) - Starting minimal PC update" | Out-File $logFile $data = @{ action = 'updateCompleteAsset' hostname = $env:COMPUTERNAME manufacturer = 'Unknown' model = 'Unknown' serialNumber = 'Unknown' pcType = 'Measuring' # Default, will be updated if PC-DMIS is found } "Hostname: $($data.hostname)" | Tee-Object -FilePath $logFile -Append # Try to get serial number try { $bios = Get-CimInstance -ClassName Win32_BIOS -ErrorAction Stop $data.serialNumber = $bios.SerialNumber "Serial: $($data.serialNumber)" | Tee-Object -FilePath $logFile -Append } catch { "ERROR getting serial: $_" | Tee-Object -FilePath $logFile -Append } # Try to get manufacturer/model try { $cs = Get-CimInstance -ClassName Win32_ComputerSystem -ErrorAction Stop $data.manufacturer = $cs.Manufacturer $data.model = $cs.Model "Manufacturer: $($data.manufacturer)" | Tee-Object -FilePath $logFile -Append "Model: $($data.model)" | Tee-Object -FilePath $logFile -Append } catch { "ERROR getting system info: $_" | Tee-Object -FilePath $logFile -Append } # Get IP address using ipconfig (no elevated permissions required) $interfaces = @() try { $ipconfig = ipconfig /all $currentIP = "" $currentMAC = "" foreach ($line in $ipconfig) { if ($line -match '^\S') { # New adapter section - save previous if valid if ($currentIP -and $currentIP -notlike '127.*' -and $currentIP -notlike '169.254.*') { $interfaces += @{ IPAddress = $currentIP MACAddress = $currentMAC } "IP: $currentIP | MAC: $currentMAC" | Tee-Object -FilePath $logFile -Append } $currentIP = "" $currentMAC = "" } elseif ($line -match 'IPv4 Address.*:\s*(\d+\.\d+\.\d+\.\d+)') { $currentIP = $matches[1] -replace '\(Preferred\)','' } elseif ($line -match 'Physical Address.*:\s*([0-9A-F-]+)') { $currentMAC = $matches[1] -replace '-',':' } } # Don't forget the last adapter if ($currentIP -and $currentIP -notlike '127.*' -and $currentIP -notlike '169.254.*') { $interfaces += @{ IPAddress = $currentIP MACAddress = $currentMAC } "IP: $currentIP | MAC: $currentMAC" | Tee-Object -FilePath $logFile -Append } } catch { "ERROR getting network info: $_" | Tee-Object -FilePath $logFile -Append } if ($interfaces.Count -gt 0) { $data.networkInterfaces = ($interfaces | ConvertTo-Json -Compress) } # Try to get OS and last boot time try { $os = Get-CimInstance -ClassName Win32_OperatingSystem -ErrorAction Stop $data.osVersion = $os.Caption "OS: $($data.osVersion)" | Tee-Object -FilePath $logFile -Append # Get last boot time if ($os.LastBootUpTime) { $data.lastBootUpTime = $os.LastBootUpTime.ToString("yyyy-MM-dd HH:mm:ss") "Last Boot: $($data.lastBootUpTime)" | Tee-Object -FilePath $logFile -Append } } catch { "ERROR getting OS: $_" | Tee-Object -FilePath $logFile -Append } # Try to get logged in user try { $data.loggedInUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name "User: $($data.loggedInUser)" | Tee-Object -FilePath $logFile -Append } catch { "ERROR getting user: $_" | Tee-Object -FilePath $logFile -Append } # Try to get machine number (no admin required for reading HKLM) try { $machineNo = $null # Primary location: GE Aircraft Engines DNC registry (64-bit and 32-bit) $regPaths = @( "HKLM:\SOFTWARE\GE Aircraft Engines\DNC\General", "HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines\DNC\General" ) foreach ($regPath in $regPaths) { if (Test-Path $regPath) { $regValue = (Get-ItemProperty -Path $regPath -Name "MachineNo" -ErrorAction SilentlyContinue).MachineNo if ($regValue) { $machineNo = $regValue "Machine # from registry ($regPath): $machineNo" | Tee-Object -FilePath $logFile -Append break } } } # Fall back to DNC.ini file if (-not $machineNo) { $dncIniPath = "C:\DNC\DNC.ini" if (Test-Path $dncIniPath) { $iniContent = Get-Content $dncIniPath -Raw -ErrorAction SilentlyContinue if ($iniContent -match 'MachineNo\s*=\s*(.+)') { $machineNo = $matches[1].Trim() "Machine # from DNC.ini: $machineNo" | Tee-Object -FilePath $logFile -Append } } } if ($machineNo) { # Check if machine number is a generic/placeholder value # These should not be sent to API - must be set manually # Generic machine numbers - don't send to API but can help identify PC type $genericMachineTypes = @{ "^WJPRT" = "Measuring" # Generic printer/measuring tool "^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 "^TEST" = $null # Test machines - no type hint "^TEMP" = $null # Temporary - no type hint "^DEFAULT"= $null # Default value - no type hint "^0+$" = $null # All zeros - no type hint } $isGeneric = $false $genericTypeHint = $null foreach ($pattern in $genericMachineTypes.Keys) { if ($machineNo -match $pattern) { $isGeneric = $true $genericTypeHint = $genericMachineTypes[$pattern] break } } if ($isGeneric) { if ($genericTypeHint) { "Machine # '$machineNo' is generic ($genericTypeHint) - NOT sending to API (requires manual assignment)" | Tee-Object -FilePath $logFile -Append # Store the type hint for later use in PC type detection $script:genericTypeHint = $genericTypeHint } else { "Machine # '$machineNo' is generic/placeholder - NOT sending to API (requires manual assignment)" | Tee-Object -FilePath $logFile -Append } # Don't set $data.machineNo - leave it out of API call } else { $data.machineNo = $machineNo } } else { "No machine number found" | Tee-Object -FilePath $logFile -Append } } catch { "ERROR getting machine number: $_" | Tee-Object -FilePath $logFile -Append } # Check for VNC installation try { $hasVnc = $false # Check registry for installed programs (both 32-bit and 64-bit) $regPaths = @( "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" ) foreach ($path in $regPaths) { if (Test-Path $path) { $apps = Get-ItemProperty $path -ErrorAction SilentlyContinue | Where-Object { $_.DisplayName -like "*VNC Server*" -or $_.DisplayName -like "*VNC Connect*" -or $_.DisplayName -like "*RealVNC*" } if ($apps) { $hasVnc = $true "VNC detected: $($apps.DisplayName -join ', ')" | Tee-Object -FilePath $logFile -Append break } } } # Also check for VNC service if (-not $hasVnc) { $vncService = Get-Service -Name "vncserver*" -ErrorAction SilentlyContinue if ($vncService) { $hasVnc = $true "VNC service detected: $($vncService.Name)" | Tee-Object -FilePath $logFile -Append } } if ($hasVnc) { $data.hasVnc = "1" } else { $data.hasVnc = "0" "No VNC detected" | Tee-Object -FilePath $logFile -Append } } catch { "ERROR checking VNC: $_" | Tee-Object -FilePath $logFile -Append $data.hasVnc = "0" } # Check for WinRM status try { $hasWinRM = $false # Check if WinRM service is running $winrmService = Get-Service -Name "WinRM" -ErrorAction SilentlyContinue if ($winrmService -and $winrmService.Status -eq "Running") { # Also verify WinRM is configured to accept connections try { $winrmConfig = winrm get winrm/config/service 2>$null if ($winrmConfig -match "AllowRemoteAccess\s*=\s*true") { $hasWinRM = $true "WinRM enabled and accepting connections" | Tee-Object -FilePath $logFile -Append } else { "WinRM service running but remote access not enabled" | Tee-Object -FilePath $logFile -Append } } catch { # If we can't check config, assume it's enabled if service is running $hasWinRM = $true "WinRM service running (config check skipped)" | Tee-Object -FilePath $logFile -Append } } else { "WinRM service not running" | Tee-Object -FilePath $logFile -Append } if ($hasWinRM) { $data.hasWinRM = "1" } else { $data.hasWinRM = "0" } } catch { "ERROR checking WinRM: $_" | Tee-Object -FilePath $logFile -Append $data.hasWinRM = "0" } # Load applications.csv for app matching $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path $csvPath = Join-Path $scriptDir "applications.csv" $appMappings = @() if (Test-Path $csvPath) { try { $appMappings = Import-Csv $csvPath | Where-Object { $_.enabled -eq "1" -and $_.app_id } "Loaded $($appMappings.Count) app mappings from CSV" | Tee-Object -FilePath $logFile -Append } catch { "ERROR loading applications.csv: $_" | Tee-Object -FilePath $logFile -Append } } else { "WARNING: applications.csv not found at $csvPath" | Tee-Object -FilePath $logFile -Append } # Get installed applications from registry and match against CSV $matchedApps = @() $hasPcDmis = $false $hasFormTracePak = $false $hasKeyence = $false $hasEAS1000 = $false $hasGoCMM = $false $hasDODA = $false $hasFormStatusMonitor = $false $hasGageCal = $false $hasNISoftware = $false $hasGenspect = $false $hasHeatTreat = $false try { $regPaths = @( "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" ) # Get all installed apps $installedApps = @() foreach ($path in $regPaths) { if (Test-Path $path) { $apps = Get-ItemProperty $path -ErrorAction SilentlyContinue | Where-Object { $_.DisplayName -and $_.DisplayName.Trim() -ne "" } foreach ($app in $apps) { $installedApps += @{ DisplayName = $app.DisplayName.Trim() Version = if ($app.DisplayVersion) { $app.DisplayVersion.Trim() } else { "" } } } } } "Found $($installedApps.Count) installed applications" | Tee-Object -FilePath $logFile -Append # Match against CSV patterns foreach ($mapping in $appMappings) { $patterns = $mapping.search_patterns -split '\|' foreach ($installedApp in $installedApps) { $matched = $false foreach ($pattern in $patterns) { if ($installedApp.DisplayName -match $pattern) { $matched = $true break } } if ($matched) { # Avoid duplicates if (-not ($matchedApps | Where-Object { $_.appid -eq $mapping.app_id })) { $matchedApps += @{ appid = [int]$mapping.app_id appname = $mapping.app_name version = $installedApp.Version } "$($mapping.app_name) (ID:$($mapping.app_id)) detected: $($installedApp.DisplayName)" | Tee-Object -FilePath $logFile -Append # Check for PC type indicators switch ($mapping.app_name) { "PC-DMIS" { $hasPcDmis = $true } "goCMM" { $hasGoCMM = $true } "DODA" { $hasDODA = $true } "FormTracePak" { $hasFormTracePak = $true } "FormStatusMonitor" { $hasFormStatusMonitor = $true } "Keyence VR Series" { $hasKeyence = $true } "GageCal" { $hasGageCal = $true } "NI Software" { $hasNISoftware = $true } "Genspect" { $hasGenspect = $true } "HeatTreat" { $hasHeatTreat = $true } } } break } } } "Matched $($matchedApps.Count) tracked applications" | Tee-Object -FilePath $logFile -Append if ($matchedApps.Count -gt 0) { $data.installedApps = ($matchedApps | ConvertTo-Json -Compress) } } catch { "ERROR getting installed apps: $_" | Tee-Object -FilePath $logFile -Append } # File path fallbacks for apps that may not be in registry # Check PC-DMIS if (-not $hasPcDmis) { try { $pcDmisPaths = @( "C:\ProgramData\Hexagon\PC-DMIS*", "C:\Program Files\Hexagon\PC-DMIS*", "C:\Program Files (x86)\Hexagon\PC-DMIS*", "C:\Program Files\WAI\PC-DMIS*", "C:\Program Files (x86)\WAI\PC-DMIS*" ) foreach ($dmisPath in $pcDmisPaths) { if (Test-Path $dmisPath) { $hasPcDmis = $true "PC-DMIS found at: $dmisPath" | Tee-Object -FilePath $logFile -Append break } } } catch { "ERROR checking PC-DMIS paths: $_" | Tee-Object -FilePath $logFile -Append } } # Check UDC if not already matched if (-not ($matchedApps | Where-Object { $_.appid -eq 2 })) { if (Test-Path "C:\Program Files\UDC") { $matchedApps += @{ appid = 2; appname = "UDC"; version = "" } "UDC found at: C:\Program Files\UDC" | Tee-Object -FilePath $logFile -Append } } # Check eDNC if not already matched if (-not ($matchedApps | Where-Object { $_.appid -eq 8 })) { if (Test-Path "C:\Program Files (x86)\DNC") { $matchedApps += @{ appid = 8; appname = "eDNC"; version = "" } "eDNC found at: C:\Program Files (x86)\DNC" | Tee-Object -FilePath $logFile -Append } } # Check FormTracePak if not already matched if (-not $hasFormTracePak) { try { $formTracePaths = @( "C:\Program Files\MitutoyoApp*", "C:\Program Files (x86)\MitutoyoApp*" ) foreach ($ftPath in $formTracePaths) { if (Test-Path $ftPath) { $hasFormTracePak = $true if (-not ($matchedApps | Where-Object { $_.appid -eq 76 })) { $matchedApps += @{ appid = 76; appname = "FormTracePak"; version = "" } } "FormTracePak found at: $ftPath" | Tee-Object -FilePath $logFile -Append break } } } catch { "ERROR checking FormTracePak paths: $_" | Tee-Object -FilePath $logFile -Append } } # Update installedApps data if we found more apps via file paths if ($matchedApps.Count -gt 0) { $data.installedApps = ($matchedApps | ConvertTo-Json -Compress) } # Set PC type based on application detection # Priority: CMM > Wax Trace > Keyence > EAS1000 > Genspect > Heat Treat > Generic hint > default Shopfloor $isCMM = ($hasPcDmis -or $hasGoCMM -or $hasDODA) $isWaxTrace = ($hasFormTracePak -or $hasFormStatusMonitor) $isEAS1000 = ($hasGageCal -or $hasNISoftware) if ($isCMM) { $data.pcType = "CMM" $detected = @() if ($hasPcDmis) { $detected += "PC-DMIS" } if ($hasGoCMM) { $detected += "goCMM" } if ($hasDODA) { $detected += "DODA" } "PC Type set to: CMM ($($detected -join ', '))" | Tee-Object -FilePath $logFile -Append } elseif ($isWaxTrace) { $data.pcType = "Wax Trace" $detected = @() if ($hasFormTracePak) { $detected += "FormTracePak" } if ($hasFormStatusMonitor) { $detected += "FormStatusMonitor" } "PC Type set to: Wax Trace ($($detected -join ', '))" | Tee-Object -FilePath $logFile -Append } elseif ($hasKeyence) { $data.pcType = "Keyence" "PC Type set to: Keyence (Keyence VR Series)" | Tee-Object -FilePath $logFile -Append } elseif ($isEAS1000) { $data.pcType = "EAS1000" $detected = @() if ($hasGageCal) { $detected += "GageCal" } if ($hasNISoftware) { $detected += "NI Software" } "PC Type set to: EAS1000 ($($detected -join ', '))" | Tee-Object -FilePath $logFile -Append } elseif ($hasGenspect) { $data.pcType = "Genspect" "PC Type set to: Genspect" | Tee-Object -FilePath $logFile -Append } elseif ($hasHeatTreat) { $data.pcType = "Heat Treat" "PC Type set to: Heat Treat" | Tee-Object -FilePath $logFile -Append } elseif ($script:genericTypeHint) { # Use generic machine number hint when no software detected $data.pcType = $script:genericTypeHint "PC Type set to: $($script:genericTypeHint) (from generic machine # - requires manual assignment)" | Tee-Object -FilePath $logFile -Append } else { $data.pcType = "Shopfloor" "No specialized apps detected, defaulting to: Shopfloor" | Tee-Object -FilePath $logFile -Append } # Send to API "Sending to API: $apiUrl" | Tee-Object -FilePath $logFile -Append try { $response = Invoke-RestMethod -Uri $apiUrl -Method Post -Body $data -ErrorAction Stop "API Response: $($response | ConvertTo-Json -Compress)" | Tee-Object -FilePath $logFile -Append if ($response.success) { "SUCCESS - MachineID: $($response.machineid)" | Tee-Object -FilePath $logFile -Append } else { "FAILED - $($response.message)" | Tee-Object -FilePath $logFile -Append } } catch { "ERROR calling API: $_" | Tee-Object -FilePath $logFile -Append } "$(Get-Date) - Done" | Tee-Object -FilePath $logFile -Append