Files
powershell-scripts/minimal-asset/Update-PC-Minimal.ps1
cproudlock 0b470ef177 Fix Part Marker machine number detection in minimal script
- Separate valid machine type indicators from generic placeholders
- Part Marker numbers (0612, 0613, 0615, 8003) are now sent to API
- Wax Trace (0600) also sent as valid machine number
- Only WJPRT, WJCMM, WJMEAS prefixes treated as generic/placeholder
- Add machineTypeHint for PC type detection from valid machine numbers

Previously these valid machine numbers were incorrectly treated as
generic placeholders and not submitted to the API.

Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 11:29:51 -05:00

523 lines
20 KiB
PowerShell

# 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) {
# Machine numbers that indicate specific PC types (these ARE valid machine numbers)
$machineTypeIndicators = @{
"^0?600$" = "Wax Trace" # Wax trace machines
"^0?(612|613|615)$" = "Part Marker" # Part marker machines
"^M?(612|613|615)$" = "Part Marker" # Part marker machines (M prefix)
"^8003$" = "Part Marker" # Part marker machines
}
# Check if machine number indicates a specific PC type
$script:machineTypeHint = $null
foreach ($pattern in $machineTypeIndicators.Keys) {
if ($machineNo -match $pattern) {
$script:machineTypeHint = $machineTypeIndicators[$pattern]
"Machine # '$machineNo' indicates PC type: $($script:machineTypeHint)" | Tee-Object -FilePath $logFile -Append
break
}
}
# Generic/placeholder machine numbers - don't send to API
$genericPatterns = @{
"^WJPRT" = "Measuring" # Generic printer/measuring tool
"^WJCMM" = "CMM" # Generic CMM
"^WJMEAS" = "Measuring" # Generic measuring
"^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 $genericPatterns.Keys) {
if ($machineNo -match $pattern) {
$isGeneric = $true
$genericTypeHint = $genericPatterns[$pattern]
break
}
}
if ($isGeneric) {
if ($genericTypeHint) {
"Machine # '$machineNo' is generic ($genericTypeHint) - NOT sending to API (requires manual assignment)" | Tee-Object -FilePath $logFile -Append
if (-not $script:machineTypeHint) {
$script:machineTypeHint = $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