Initial commit: Organized PowerShell scripts for ShopDB asset collection
Structure: - asset-collection/: Local PC data collection scripts - remote-execution/: WinRM remote execution scripts - setup-utilities/: Configuration and testing utilities - registry-backup/: GE registry backup scripts - winrm-https/: WinRM HTTPS certificate setup - docs/: Complete documentation Each folder includes a README with detailed documentation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
3
asset-collection/Get-InstalledApps.bat
Normal file
3
asset-collection/Get-InstalledApps.bat
Normal file
@@ -0,0 +1,3 @@
|
||||
@echo off
|
||||
wmic product get name,version
|
||||
pause
|
||||
5
asset-collection/Get-InstalledApps.ps1
Normal file
5
asset-collection/Get-InstalledApps.ps1
Normal file
@@ -0,0 +1,5 @@
|
||||
Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" |
|
||||
Where-Object { $_.DisplayName } |
|
||||
Select-Object DisplayName, DisplayVersion, Publisher |
|
||||
Sort-Object DisplayName |
|
||||
Format-Table -AutoSize
|
||||
480
asset-collection/Get-ShopfloorConfig.ps1
Normal file
480
asset-collection/Get-ShopfloorConfig.ps1
Normal file
@@ -0,0 +1,480 @@
|
||||
# Functions to collect shopfloor PC network and communication configurations
|
||||
|
||||
# Function to get all network interfaces and their configurations
|
||||
function Get-NetworkInterfaceConfig {
|
||||
Write-Host " Collecting network interface information..." -ForegroundColor Yellow
|
||||
|
||||
$interfaces = @()
|
||||
|
||||
try {
|
||||
# Get all network adapters with IP configurations
|
||||
$adapters = Get-NetAdapter | Where-Object { $_.Status -eq 'Up' }
|
||||
|
||||
foreach ($adapter in $adapters) {
|
||||
$ipConfig = Get-NetIPConfiguration -InterfaceIndex $adapter.ifIndex -ErrorAction SilentlyContinue
|
||||
|
||||
if ($ipConfig -and $ipConfig.IPv4Address) {
|
||||
foreach ($ip in $ipConfig.IPv4Address) {
|
||||
$gateway = if ($ipConfig.IPv4DefaultGateway) { $ipConfig.IPv4DefaultGateway[0].NextHop } else { $null }
|
||||
|
||||
# Determine if this is a machine network (192.168.*.*)
|
||||
$isMachineNetwork = $ip.IPAddress -match '^192\.168\.'
|
||||
|
||||
$interface = @{
|
||||
InterfaceName = $adapter.Name
|
||||
IPAddress = $ip.IPAddress
|
||||
SubnetMask = $ip.PrefixLength # Will need conversion
|
||||
DefaultGateway = $gateway
|
||||
MACAddress = $adapter.MacAddress
|
||||
IsDHCP = if ($ipConfig.NetIPv4Interface.Dhcp -eq 'Enabled') { 1 } else { 0 }
|
||||
IsActive = 1
|
||||
IsMachineNetwork = if ($isMachineNetwork) { 1 } else { 0 }
|
||||
}
|
||||
|
||||
$interfaces += $interface
|
||||
|
||||
if ($isMachineNetwork) {
|
||||
Write-Host " Found machine network: $($ip.IPAddress) on $($adapter.Name)" -ForegroundColor Cyan
|
||||
}
|
||||
else {
|
||||
Write-Host " Found network: $($ip.IPAddress) on $($adapter.Name)" -ForegroundColor Gray
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Host " Error collecting network info: $_" -ForegroundColor Red
|
||||
}
|
||||
|
||||
# Alternative method using WMI if NetAdapter cmdlets fail
|
||||
if ($interfaces.Count -eq 0) {
|
||||
try {
|
||||
$wmiAdapters = Get-WmiObject Win32_NetworkAdapterConfiguration | Where-Object { $_.IPEnabled -eq $true }
|
||||
|
||||
foreach ($adapter in $wmiAdapters) {
|
||||
if ($adapter.IPAddress) {
|
||||
foreach ($i in 0..($adapter.IPAddress.Count - 1)) {
|
||||
$ip = $adapter.IPAddress[$i]
|
||||
|
||||
# Skip IPv6 addresses
|
||||
if ($ip -match ':') { continue }
|
||||
|
||||
$isMachineNetwork = $ip -match '^192\.168\.'
|
||||
|
||||
$interface = @{
|
||||
InterfaceName = $adapter.Description
|
||||
IPAddress = $ip
|
||||
SubnetMask = $adapter.IPSubnet[$i]
|
||||
DefaultGateway = if ($adapter.DefaultIPGateway) { $adapter.DefaultIPGateway[0] } else { $null }
|
||||
MACAddress = $adapter.MACAddress
|
||||
IsDHCP = $adapter.DHCPEnabled
|
||||
IsActive = 1
|
||||
IsMachineNetwork = if ($isMachineNetwork) { 1 } else { 0 }
|
||||
}
|
||||
|
||||
$interfaces += $interface
|
||||
|
||||
if ($isMachineNetwork) {
|
||||
Write-Host " Found machine network: $ip on $($adapter.Description)" -ForegroundColor Cyan
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Host " WMI method also failed: $_" -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
|
||||
return $interfaces
|
||||
}
|
||||
|
||||
# Function to get serial port configurations from registry
|
||||
function Get-SerialPortConfig {
|
||||
Write-Host " Collecting serial port configurations..." -ForegroundColor Yellow
|
||||
|
||||
$configs = @()
|
||||
|
||||
# Registry paths to check
|
||||
$registryPaths = @{
|
||||
'Serial' = @('HKLM:\SOFTWARE\GE Aircraft Engines\DNC\Serial', 'HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines\DNC\Serial')
|
||||
'Mark' = @('HKLM:\SOFTWARE\GE Aircraft Engines\DNC\Mark', 'HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines\DNC\Mark')
|
||||
'PPDCS' = @('HKLM:\SOFTWARE\GE Aircraft Engines\DNC\PPDCS', 'HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines\DNC\PPDCS')
|
||||
'TQM9030' = @('HKLM:\SOFTWARE\GE Aircraft Engines\DNC\TQM9030', 'HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines\DNC\TQM9030')
|
||||
'TQMCaron' = @('HKLM:\SOFTWARE\GE Aircraft Engines\DNC\TQMCaron', 'HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines\DNC\TQMCaron')
|
||||
}
|
||||
|
||||
foreach ($configType in $registryPaths.Keys) {
|
||||
foreach ($path in $registryPaths[$configType]) {
|
||||
if (Test-Path $path) {
|
||||
try {
|
||||
$regValues = Get-ItemProperty -Path $path -ErrorAction SilentlyContinue
|
||||
|
||||
if ($regValues) {
|
||||
$config = @{
|
||||
ConfigType = $configType
|
||||
PortID = $regValues.'Port Id' -replace 'Port Id2', ''
|
||||
Baud = $regValues.Baud
|
||||
DataBits = $regValues.'Data Bits'
|
||||
StopBits = $regValues.'Stop Bits'
|
||||
Parity = $regValues.Parity
|
||||
CRLF = $regValues.CRLF
|
||||
IPAddress = $null
|
||||
SocketNo = $null
|
||||
AdditionalSettings = @{}
|
||||
}
|
||||
|
||||
# Collect any additional settings
|
||||
$standardKeys = @('Port Id', 'Baud', 'Data Bits', 'Stop Bits', 'Parity', 'CRLF', 'PSPath', 'PSParentPath', 'PSChildName', 'PSProvider')
|
||||
foreach ($prop in $regValues.PSObject.Properties) {
|
||||
if ($prop.Name -notin $standardKeys -and $prop.Value) {
|
||||
$config.AdditionalSettings[$prop.Name] = $prop.Value
|
||||
}
|
||||
}
|
||||
|
||||
# Convert additional settings to JSON
|
||||
if ($config.AdditionalSettings.Count -gt 0) {
|
||||
$config.AdditionalSettings = $config.AdditionalSettings | ConvertTo-Json -Compress
|
||||
}
|
||||
else {
|
||||
$config.AdditionalSettings = $null
|
||||
}
|
||||
|
||||
if ($config.PortID) {
|
||||
$configs += $config
|
||||
Write-Host " Found $configType config: Port $($config.PortID), Baud $($config.Baud)" -ForegroundColor Cyan
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Host " Error reading $configType registry: $_" -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Check for eFocas configuration (network-based)
|
||||
$efocasPaths = @('HKLM:\SOFTWARE\GE Aircraft Engines\DNC\eFocas', 'HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines\DNC\eFocas')
|
||||
foreach ($path in $efocasPaths) {
|
||||
if (Test-Path $path) {
|
||||
try {
|
||||
$regValues = Get-ItemProperty -Path $path -ErrorAction SilentlyContinue
|
||||
|
||||
if ($regValues -and $regValues.IpAddr) {
|
||||
$config = @{
|
||||
ConfigType = 'eFocas'
|
||||
PortID = $null
|
||||
Baud = $null
|
||||
DataBits = $null
|
||||
StopBits = $null
|
||||
Parity = $null
|
||||
CRLF = $null
|
||||
IPAddress = $regValues.IpAddr
|
||||
SocketNo = $regValues.SocketNo
|
||||
AdditionalSettings = @{
|
||||
DualPath = $regValues.DualPath
|
||||
Path1Name = $regValues.Path1Name
|
||||
Path2Name = $regValues.Path2Name
|
||||
Danobat = $regValues.Danobat
|
||||
DataServer = $regValues.DataServer
|
||||
} | ConvertTo-Json -Compress
|
||||
}
|
||||
|
||||
$configs += $config
|
||||
Write-Host " Found eFocas config: IP $($config.IPAddress), Socket $($config.SocketNo)" -ForegroundColor Cyan
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Host " Error reading eFocas registry: $_" -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $configs
|
||||
}
|
||||
|
||||
# Function to get GE Aircraft Engines registry information and DualPath configuration
|
||||
function Get-GERegistryInfo {
|
||||
Write-Host " Collecting GE Aircraft Engines registry information..." -ForegroundColor Yellow
|
||||
|
||||
$geInfo = @{
|
||||
Registry32Bit = $false
|
||||
Registry64Bit = $false
|
||||
DualPathEnabled = $null
|
||||
Path1Name = $null
|
||||
Path2Name = $null
|
||||
RegistryNotes = @{}
|
||||
}
|
||||
|
||||
# Check both 32-bit and 64-bit registry paths
|
||||
$registryPaths = @{
|
||||
'32bit' = 'HKLM:\SOFTWARE\GE Aircraft Engines'
|
||||
'64bit' = 'HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines'
|
||||
}
|
||||
|
||||
foreach ($pathType in $registryPaths.Keys) {
|
||||
$basePath = $registryPaths[$pathType]
|
||||
Write-Host " Checking $pathType registry: $basePath" -ForegroundColor Gray
|
||||
|
||||
if (Test-Path $basePath) {
|
||||
Write-Host " [FOUND] GE Aircraft Engines in $pathType registry" -ForegroundColor Green
|
||||
|
||||
if ($pathType -eq '32bit') {
|
||||
$geInfo.Registry32Bit = $true
|
||||
} else {
|
||||
$geInfo.Registry64Bit = $true
|
||||
}
|
||||
|
||||
# Collect information about what's under GE Aircraft Engines
|
||||
try {
|
||||
$subKeys = Get-ChildItem -Path $basePath -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Name | ForEach-Object { Split-Path $_ -Leaf }
|
||||
$geInfo.RegistryNotes[$pathType] = @{
|
||||
BasePath = $basePath
|
||||
SubKeys = $subKeys -join ', '
|
||||
Found = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
||||
}
|
||||
Write-Host " Sub-keys found: $($subKeys -join ', ')" -ForegroundColor Cyan
|
||||
}
|
||||
catch {
|
||||
Write-Host " Error reading sub-keys: $_" -ForegroundColor Red
|
||||
$geInfo.RegistryNotes[$pathType] = @{
|
||||
Error = $_.Exception.Message
|
||||
}
|
||||
}
|
||||
|
||||
# Check for DualPath configuration in eFocas
|
||||
$efocasPath = "$basePath\DNC\eFocas"
|
||||
if (Test-Path $efocasPath) {
|
||||
Write-Host " Checking eFocas configuration for DualPath..." -ForegroundColor Yellow
|
||||
try {
|
||||
$efocasValues = Get-ItemProperty -Path $efocasPath -ErrorAction SilentlyContinue
|
||||
|
||||
if ($efocasValues.DualPath) {
|
||||
Write-Host " [FOUND] DualPath = $($efocasValues.DualPath)" -ForegroundColor Green
|
||||
|
||||
# Handle case where both registry locations exist - prioritize settings from first found
|
||||
if ($geInfo.DualPathEnabled -eq $null) {
|
||||
$geInfo.DualPathEnabled = $efocasValues.DualPath -eq 'YES'
|
||||
Write-Host " Setting DualPath from $pathType registry: $($geInfo.DualPathEnabled)" -ForegroundColor Cyan
|
||||
} else {
|
||||
Write-Host " DualPath already set from other registry location, keeping existing value" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
# Handle Path1Name - use first non-empty value found
|
||||
if (!$geInfo.Path1Name -and $efocasValues.Path1Name) {
|
||||
$geInfo.Path1Name = $efocasValues.Path1Name
|
||||
Write-Host " Path1Name = $($efocasValues.Path1Name)" -ForegroundColor Cyan
|
||||
}
|
||||
|
||||
# Handle Path2Name - use first non-empty value found
|
||||
if (!$geInfo.Path2Name -and $efocasValues.Path2Name) {
|
||||
$geInfo.Path2Name = $efocasValues.Path2Name
|
||||
Write-Host " Path2Name = $($efocasValues.Path2Name)" -ForegroundColor Cyan
|
||||
}
|
||||
|
||||
# Store additional eFocas settings
|
||||
$geInfo.RegistryNotes["$pathType-eFocas"] = @{
|
||||
DualPath = $efocasValues.DualPath
|
||||
Path1Name = $efocasValues.Path1Name
|
||||
Path2Name = $efocasValues.Path2Name
|
||||
IpAddr = $efocasValues.IpAddr
|
||||
SocketNo = $efocasValues.SocketNo
|
||||
Danobat = $efocasValues.Danobat
|
||||
DataServer = $efocasValues.DataServer
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Host " Error reading eFocas configuration: $_" -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Write-Host " [NOT FOUND] No GE Aircraft Engines in $pathType registry" -ForegroundColor Gray
|
||||
}
|
||||
}
|
||||
|
||||
# Summary
|
||||
Write-Host " GE Registry Summary:" -ForegroundColor Green
|
||||
Write-Host " 32-bit registry: $(if ($geInfo.Registry32Bit) { 'YES' } else { 'NO' })" -ForegroundColor Cyan
|
||||
Write-Host " 64-bit registry: $(if ($geInfo.Registry64Bit) { 'YES' } else { 'NO' })" -ForegroundColor Cyan
|
||||
Write-Host " DualPath enabled: $(if ($geInfo.DualPathEnabled -eq $null) { 'NOT FOUND' } elseif ($geInfo.DualPathEnabled) { 'YES' } else { 'NO' })" -ForegroundColor Cyan
|
||||
if ($geInfo.Path1Name) { Write-Host " Path1Name: $($geInfo.Path1Name)" -ForegroundColor Cyan }
|
||||
if ($geInfo.Path2Name) { Write-Host " Path2Name: $($geInfo.Path2Name)" -ForegroundColor Cyan }
|
||||
|
||||
return $geInfo
|
||||
}
|
||||
|
||||
# Function to get DNC configuration from registry
|
||||
function Get-DNCConfig {
|
||||
Write-Host " Collecting DNC configuration..." -ForegroundColor Yellow
|
||||
|
||||
$dncConfig = $null
|
||||
$paths = @('HKLM:\SOFTWARE\GE Aircraft Engines\DNC\General', 'HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines\DNC\General')
|
||||
|
||||
Write-Host " Checking registry paths for DNC config..." -ForegroundColor Gray
|
||||
foreach ($path in $paths) {
|
||||
Write-Host " Checking path: $path" -ForegroundColor Gray
|
||||
if (Test-Path $path) {
|
||||
Write-Host " Path exists! Reading values..." -ForegroundColor Green
|
||||
try {
|
||||
$general = Get-ItemProperty -Path $path -ErrorAction SilentlyContinue
|
||||
$mxPath = $path -replace 'General', 'MX'
|
||||
$mx = Get-ItemProperty -Path $mxPath -ErrorAction SilentlyContinue
|
||||
$fmsPath = $path -replace 'General', 'FMS'
|
||||
$fms = Get-ItemProperty -Path $fmsPath -ErrorAction SilentlyContinue
|
||||
|
||||
if ($general) {
|
||||
Write-Host " Found General config values!" -ForegroundColor Green
|
||||
$dncConfig = @{
|
||||
Site = $general.Site
|
||||
CNC = $general.Cnc
|
||||
NcIF = $general.NcIF
|
||||
MachineNo = $general.MachineNo
|
||||
HostType = $general.HostType
|
||||
FtpHostPrimary = if ($mx) { $mx.FtpHostPrimary } else { $null }
|
||||
FtpHostSecondary = if ($mx) { $mx.FtpHostSecondary } else { $null }
|
||||
FtpAccount = if ($mx) { $mx.FtpAccount } else { $null }
|
||||
Debug = $general.Debug
|
||||
Uploads = $general.Uploads
|
||||
Scanner = $general.Scanner
|
||||
Dripfeed = $general.Dripfeed
|
||||
AdditionalSettings = @{
|
||||
Mode = $general.Mode
|
||||
'Unit/Area' = $general.'Unit/Area'
|
||||
DvUpldDir = $general.DvUpldDir
|
||||
Ncedt = $general.Ncedt
|
||||
Maint = $general.Maint
|
||||
ChangeWorkstation = $general.ChangeWorkstation
|
||||
FMSHostPrimary = if ($fms) { $fms.FMSHostPrimary } else { $null }
|
||||
FMSHostSecondary = if ($fms) { $fms.FMSHostSecondary } else { $null }
|
||||
} | ConvertTo-Json -Compress
|
||||
}
|
||||
|
||||
Write-Host " Found DNC config: Site=$($dncConfig.Site), MachineNo=$($dncConfig.MachineNo), CNC=$($dncConfig.CNC)" -ForegroundColor Cyan
|
||||
Write-Host " DNC Config JSON: $($dncConfig | ConvertTo-Json -Compress)" -ForegroundColor Gray
|
||||
break
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Host " Error reading DNC registry: $_" -ForegroundColor Red
|
||||
}
|
||||
} else {
|
||||
Write-Host " Path does not exist" -ForegroundColor Yellow
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $dncConfig) {
|
||||
Write-Host " No DNC configuration found in registry" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
return $dncConfig
|
||||
}
|
||||
|
||||
# Main function to collect all shopfloor configurations
|
||||
function Get-ShopfloorConfigurations {
|
||||
Write-Host "`nCollecting shopfloor-specific configurations..." -ForegroundColor Yellow
|
||||
|
||||
$configurations = @{
|
||||
NetworkInterfaces = Get-NetworkInterfaceConfig
|
||||
CommConfigs = Get-SerialPortConfig
|
||||
DNCConfig = Get-DNCConfig
|
||||
GERegistryInfo = Get-GERegistryInfo
|
||||
}
|
||||
|
||||
# Summary
|
||||
Write-Host "`n Configuration Summary:" -ForegroundColor Green
|
||||
Write-Host " Network Interfaces: $($configurations.NetworkInterfaces.Count)" -ForegroundColor Cyan
|
||||
Write-Host " Comm Configs: $($configurations.CommConfigs.Count)" -ForegroundColor Cyan
|
||||
Write-Host " DNC Config: $(if ($configurations.DNCConfig) { 'Yes' } else { 'No' })" -ForegroundColor Cyan
|
||||
Write-Host " GE Registry (32-bit): $(if ($configurations.GERegistryInfo.Registry32Bit) { 'Yes' } else { 'No' })" -ForegroundColor Cyan
|
||||
Write-Host " GE Registry (64-bit): $(if ($configurations.GERegistryInfo.Registry64Bit) { 'Yes' } else { 'No' })" -ForegroundColor Cyan
|
||||
Write-Host " DualPath Enabled: $(if ($configurations.GERegistryInfo.DualPathEnabled -eq $null) { 'Not Found' } elseif ($configurations.GERegistryInfo.DualPathEnabled) { 'Yes' } else { 'No' })" -ForegroundColor Cyan
|
||||
|
||||
return $configurations
|
||||
}
|
||||
|
||||
function Get-InstalledApplications {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Detects UDC and CLM applications and their active status on shopfloor PCs
|
||||
.DESCRIPTION
|
||||
Checks for UDC (UDC.exe) and CLM (ppdcs.exe) processes and returns data
|
||||
compatible with your existing installedapps table structure.
|
||||
#>
|
||||
|
||||
Write-Host " Scanning for UDC and CLM applications..." -ForegroundColor Yellow
|
||||
|
||||
$detectedApps = @()
|
||||
|
||||
try {
|
||||
# Define the two applications we're looking for
|
||||
$appsToCheck = @{
|
||||
'UDC' = @{
|
||||
AppID = 2 # Universal Data Collector
|
||||
ProcessName = 'UDC' # UDC.exe shows as 'UDC' in Get-Process
|
||||
Description = 'Universal Data Collector'
|
||||
}
|
||||
'CLM' = @{
|
||||
AppID = 4 # Legacy UDC (CLM)
|
||||
ProcessName = 'ppdcs' # ppdcs.exe shows as 'ppdcs' in Get-Process
|
||||
Description = 'Legacy UDC (Cell Level Manager)'
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($appName in $appsToCheck.Keys) {
|
||||
$app = $appsToCheck[$appName]
|
||||
|
||||
Write-Host " Checking for $appName (AppID: $($app.AppID))..." -ForegroundColor Gray
|
||||
|
||||
# Check if the process is running
|
||||
$isActive = $false
|
||||
$processInfo = $null
|
||||
|
||||
try {
|
||||
$processes = Get-Process -Name $app.ProcessName -ErrorAction SilentlyContinue
|
||||
if ($processes) {
|
||||
$isActive = $true
|
||||
$processInfo = $processes[0] # Take first instance if multiple
|
||||
Write-Host " [ACTIVE] Found running process: $($app.ProcessName).exe (PID: $($processInfo.Id))" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host " [NOT ACTIVE] Process $($app.ProcessName).exe not running" -ForegroundColor Gray
|
||||
}
|
||||
} catch {
|
||||
Write-Host " [ERROR] Failed to check process $($app.ProcessName): $($_.Exception.Message)" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
# Always return app info (both active and inactive)
|
||||
$detectedApps += @{
|
||||
AppID = $app.AppID
|
||||
AppName = $appName
|
||||
Description = $app.Description
|
||||
ProcessName = $app.ProcessName
|
||||
IsActive = $isActive
|
||||
ProcessID = if ($processInfo) { $processInfo.Id } else { $null }
|
||||
ProcessStartTime = if ($processInfo) { $processInfo.StartTime } else { $null }
|
||||
}
|
||||
}
|
||||
|
||||
# Business rule validation: Only one should be active
|
||||
$activeApps = $detectedApps | Where-Object { $_.IsActive -eq $true }
|
||||
|
||||
if ($activeApps.Count -gt 1) {
|
||||
Write-Host " [WARNING] Multiple applications active simultaneously:" -ForegroundColor Red
|
||||
foreach ($activeApp in $activeApps) {
|
||||
Write-Host " - $($activeApp.AppName) (PID: $($activeApp.ProcessID))" -ForegroundColor Red
|
||||
}
|
||||
} elseif ($activeApps.Count -eq 1) {
|
||||
$activeApp = $activeApps[0]
|
||||
Write-Host " [OK] Single active application: $($activeApp.AppName) (PID: $($activeApp.ProcessID))" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host " [INFO] No UDC or CLM applications currently running" -ForegroundColor Gray
|
||||
}
|
||||
|
||||
return $detectedApps
|
||||
|
||||
} catch {
|
||||
Write-Host " [ERROR] Failed to scan for applications: $($_.Exception.Message)" -ForegroundColor Red
|
||||
return @()
|
||||
}
|
||||
}
|
||||
125
asset-collection/README.md
Normal file
125
asset-collection/README.md
Normal file
@@ -0,0 +1,125 @@
|
||||
# Asset Collection Scripts
|
||||
|
||||
Scripts for collecting PC asset data and sending it to the ShopDB database.
|
||||
|
||||
## Scripts
|
||||
|
||||
### Update-PC-CompleteAsset.ps1
|
||||
**Primary asset collection script** - Comprehensive data collection for all PC types.
|
||||
|
||||
**What it collects:**
|
||||
- System information (hostname, serial number, manufacturer, model)
|
||||
- Operating system details
|
||||
- Network interface configurations
|
||||
- For shopfloor PCs: DNC/machine configurations from GE registry
|
||||
- Dell warranty information (optional, via proxy)
|
||||
|
||||
**Usage:**
|
||||
```powershell
|
||||
# Standard execution (requires administrator)
|
||||
.\Update-PC-CompleteAsset.ps1
|
||||
|
||||
# Test connectivity only
|
||||
.\Update-PC-CompleteAsset.ps1 -TestConnections
|
||||
|
||||
# With warranty lookup enabled
|
||||
.\Update-PC-CompleteAsset.ps1 -SkipWarranty:$false
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
| Parameter | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `-ProxyURL` | `http://10.48.130.158/vendor-api-proxy.php` | Warranty API proxy |
|
||||
| `-DashboardURL` | `https://tsgwp00525.rd.ds.ge.com/shopdb/api.asp` | ShopDB API endpoint |
|
||||
| `-SkipWarranty` | `$true` | Skip warranty lookups |
|
||||
| `-TestConnections` | `$false` | Test API connectivity only |
|
||||
|
||||
---
|
||||
|
||||
### Get-ShopfloorConfig.ps1
|
||||
**Shopfloor configuration library** - Functions for collecting manufacturing-specific data.
|
||||
|
||||
**Functions provided:**
|
||||
- `Get-NetworkInterfaceConfig` - Collects all network adapter information
|
||||
- `Get-SerialPortConfig` - Enumerates COM port configurations
|
||||
- `Get-DNCConfig` - Extracts DNC registry settings
|
||||
- `Get-GERegistryConfig` - Reads GE Aircraft Engines registry keys
|
||||
|
||||
**Note:** This script is sourced by `Update-PC-CompleteAsset.ps1` and not run directly.
|
||||
|
||||
---
|
||||
|
||||
### Update-PC-Minimal.ps1
|
||||
**Lightweight collection script** - For locked-down PCs with restricted permissions.
|
||||
|
||||
**What it collects:**
|
||||
- Basic system info without requiring admin privileges
|
||||
- Uses only non-elevated WMI/CIM queries
|
||||
- Detects PC-DMIS software for measuring machine classification
|
||||
|
||||
**Usage:**
|
||||
```powershell
|
||||
.\Update-PC-Minimal.ps1
|
||||
```
|
||||
|
||||
**When to use:**
|
||||
- PCs where users cannot run as administrator
|
||||
- Measuring machines with restricted permissions
|
||||
- Quick data collection without full registry access
|
||||
|
||||
---
|
||||
|
||||
### Get-InstalledApps.ps1
|
||||
**Application inventory script** - Collects list of installed applications.
|
||||
|
||||
**Usage:**
|
||||
```powershell
|
||||
.\Get-InstalledApps.ps1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Batch File Launchers
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `Update-PC-CompleteAsset.bat` | Standard launcher with visible window |
|
||||
| `Update-PC-CompleteAsset-Silent.bat` | Silent launcher for scheduled tasks |
|
||||
| `Update-PC-Minimal.bat` | Launcher for minimal collection |
|
||||
| `Get-InstalledApps.bat` | Launcher for app inventory |
|
||||
| `Run-GetInstalledApps.bat` | Alternative app inventory launcher |
|
||||
|
||||
---
|
||||
|
||||
## Requirements
|
||||
|
||||
- PowerShell 5.1 or later
|
||||
- Administrator privileges (for full collection)
|
||||
- Network access to ShopDB API
|
||||
- Windows 10/11 or Windows Server
|
||||
|
||||
## Data Flow
|
||||
|
||||
```
|
||||
PC Local Execution
|
||||
│
|
||||
▼
|
||||
┌──────────────────┐
|
||||
│ Update-PC- │
|
||||
│ CompleteAsset.ps1│
|
||||
│ + │
|
||||
│ Get-Shopfloor- │
|
||||
│ Config.ps1 │
|
||||
└────────┬─────────┘
|
||||
│ HTTPS POST
|
||||
▼
|
||||
┌──────────────────┐
|
||||
│ ShopDB API │
|
||||
│ (api.asp) │
|
||||
└────────┬─────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────┐
|
||||
│ MySQL Database │
|
||||
└──────────────────┘
|
||||
```
|
||||
3
asset-collection/Run-GetInstalledApps.bat
Normal file
3
asset-collection/Run-GetInstalledApps.bat
Normal file
@@ -0,0 +1,3 @@
|
||||
@echo off
|
||||
powershell.exe -ExecutionPolicy Bypass -File "%~dp0Get-InstalledApps.ps1"
|
||||
pause
|
||||
76
asset-collection/Update-PC-CompleteAsset-Silent.bat
Normal file
76
asset-collection/Update-PC-CompleteAsset-Silent.bat
Normal file
@@ -0,0 +1,76 @@
|
||||
@echo off
|
||||
REM =====================================================
|
||||
REM Complete PC Asset Collection - SILENT MODE
|
||||
REM Runs Update-PC-CompleteAsset.ps1 with all output to log
|
||||
REM =====================================================
|
||||
|
||||
REM Change to script directory
|
||||
cd /d "%~dp0"
|
||||
|
||||
REM Set network share log directory
|
||||
set "logdir=S:\dt\cameron\scan\logs"
|
||||
|
||||
REM Create log directory if it doesn't exist (network share should already exist)
|
||||
if not exist "%logdir%" (
|
||||
set "logdir=Logs"
|
||||
if not exist "Logs" mkdir "Logs"
|
||||
)
|
||||
|
||||
REM Generate log filename with timestamp
|
||||
for /f "tokens=2 delims==" %%a in ('wmic OS Get localdatetime /value') do set "dt=%%a"
|
||||
set "YY=%dt:~2,2%" & set "YYYY=%dt:~0,4%" & set "MM=%dt:~4,2%" & set "DD=%dt:~6,2%"
|
||||
set "HH=%dt:~8,2%" & set "Min=%dt:~10,2%" & set "Sec=%dt:~12,2%"
|
||||
set "datestamp=%YYYY%-%MM%-%DD%_%HH%-%Min%-%Sec%"
|
||||
set "logfile=%logdir%\CompleteAsset-%COMPUTERNAME%-%datestamp%.log"
|
||||
|
||||
REM Log start information
|
||||
echo ===================================== >> "%logfile%" 2>&1
|
||||
echo Complete PC Asset Collection - %date% %time% >> "%logfile%" 2>&1
|
||||
echo Computer: %COMPUTERNAME% >> "%logfile%" 2>&1
|
||||
echo User Context: %USERNAME% >> "%logfile%" 2>&1
|
||||
echo Script Directory: %CD% >> "%logfile%" 2>&1
|
||||
echo Proxy: http://10.48.130.158/vendor-api-proxy.php >> "%logfile%" 2>&1
|
||||
echo Dashboard: https://tsgwp00525.rd.ds.ge.com/shopdb/api.asp >> "%logfile%" 2>&1
|
||||
echo Network Load Balancing: Disabled >> "%logfile%" 2>&1
|
||||
echo ===================================== >> "%logfile%" 2>&1
|
||||
echo. >> "%logfile%" 2>&1
|
||||
|
||||
REM Check if PowerShell script exists
|
||||
if not exist "Update-PC-CompleteAsset.ps1" (
|
||||
echo ERROR: Update-PC-CompleteAsset.ps1 not found! >> "%logfile%" 2>&1
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
if not exist "Get-ShopfloorConfig.ps1" (
|
||||
echo WARNING: Get-ShopfloorConfig.ps1 not found - shopfloor config may fail >> "%logfile%" 2>&1
|
||||
)
|
||||
|
||||
REM Load balancing disabled - no random delay
|
||||
REM powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -WindowStyle Hidden -Command "Start-Sleep -Seconds (Get-Random -Minimum 0 -Maximum 600)" >> "%logfile%" 2>&1
|
||||
|
||||
REM Backup GE Aircraft Engines registry if it exists (silent mode)
|
||||
echo Checking for GE Aircraft Engines registry... >> "%logfile%" 2>&1
|
||||
if exist "Backup-GERegistry.ps1" (
|
||||
powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -WindowStyle Hidden -File "%~dp0Backup-GERegistry.ps1" -Silent >> "%logfile%" 2>&1
|
||||
if %ERRORLEVEL% equ 0 (
|
||||
echo GE registry backup completed successfully >> "%logfile%" 2>&1
|
||||
) else (
|
||||
echo GE registry not found or backup skipped >> "%logfile%" 2>&1
|
||||
)
|
||||
) else (
|
||||
echo Backup-GERegistry.ps1 not found - skipping registry backup >> "%logfile%" 2>&1
|
||||
)
|
||||
echo. >> "%logfile%" 2>&1
|
||||
|
||||
REM Run PowerShell script directly
|
||||
echo. >> "%logfile%" 2>&1
|
||||
echo === Running PowerShell script === >> "%logfile%" 2>&1
|
||||
echo. >> "%logfile%" 2>&1
|
||||
|
||||
powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -WindowStyle Hidden -File "%~dp0Update-PC-CompleteAsset.ps1" -ProxyURL "http://10.48.130.158/vendor-api-proxy.php" -DashboardURL "https://tsgwp00525.rd.ds.ge.com/shopdb/api.asp" >> "%logfile%" 2>&1
|
||||
|
||||
echo. >> "%logfile%" 2>&1
|
||||
echo === Script completed === >> "%logfile%" 2>&1
|
||||
echo Exit code: %ERRORLEVEL% >> "%logfile%" 2>&1
|
||||
echo End time: %date% %time% >> "%logfile%" 2>&1
|
||||
echo. >> "%logfile%" 2>&1
|
||||
83
asset-collection/Update-PC-CompleteAsset.bat
Normal file
83
asset-collection/Update-PC-CompleteAsset.bat
Normal file
@@ -0,0 +1,83 @@
|
||||
@echo off
|
||||
REM =====================================================
|
||||
REM Complete PC Asset Collection - Batch Launcher
|
||||
REM Runs Update-PC-CompleteAsset.ps1 with execution policy bypass
|
||||
REM =====================================================
|
||||
|
||||
echo.
|
||||
echo Complete PC Asset Collection - Starting...
|
||||
echo ========================================
|
||||
echo.
|
||||
|
||||
REM Check if running as administrator
|
||||
net session >nul 2>&1
|
||||
if %errorLevel% == 0 (
|
||||
echo Running as Administrator: YES
|
||||
) else (
|
||||
echo.
|
||||
echo ERROR: This script must be run as Administrator!
|
||||
echo Right-click and select "Run as administrator"
|
||||
echo.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo.
|
||||
echo Dashboard: http://10.48.130.197/test/dashboard/api.php
|
||||
echo PC: %COMPUTERNAME%
|
||||
echo User: %USERNAME%
|
||||
echo Note: Warranty lookups handled by dashboard server
|
||||
echo.
|
||||
|
||||
REM Change to script directory
|
||||
cd /d "%~dp0"
|
||||
|
||||
REM Check if PowerShell script exists
|
||||
if not exist "Update-PC-CompleteAsset.ps1" (
|
||||
echo.
|
||||
echo ERROR: Update-PC-CompleteAsset.ps1 not found in current directory!
|
||||
echo Current directory: %CD%
|
||||
echo.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
REM Check if shopfloor config script exists
|
||||
if not exist "Get-ShopfloorConfig.ps1" (
|
||||
echo.
|
||||
echo WARNING: Get-ShopfloorConfig.ps1 not found!
|
||||
echo Shopfloor configuration collection may fail.
|
||||
echo.
|
||||
)
|
||||
|
||||
echo Starting complete asset collection...
|
||||
echo.
|
||||
|
||||
REM Run PowerShell script with bypass execution policy
|
||||
powershell.exe -ExecutionPolicy Bypass -NoLogo -File "%~dp0Update-PC-CompleteAsset.ps1"
|
||||
|
||||
REM Capture the exit code from PowerShell
|
||||
set PS_EXIT_CODE=%ERRORLEVEL%
|
||||
|
||||
echo.
|
||||
echo ========================================
|
||||
if %PS_EXIT_CODE% == 0 (
|
||||
echo Complete asset collection SUCCESS!
|
||||
echo Exit code: %PS_EXIT_CODE%
|
||||
echo.
|
||||
echo All data has been collected and stored:
|
||||
echo - System information ^(hostname, serial, type, user^)
|
||||
echo - Shopfloor configurations ^(if applicable^)
|
||||
echo - Dell warranty information ^(if Dell system^)
|
||||
) else (
|
||||
echo Complete asset collection FAILED!
|
||||
echo Exit code: %PS_EXIT_CODE%
|
||||
echo.
|
||||
echo Check the output above for error details.
|
||||
)
|
||||
|
||||
echo.
|
||||
echo Press any key to close this window...
|
||||
pause >nul
|
||||
|
||||
exit /b %PS_EXIT_CODE%
|
||||
1431
asset-collection/Update-PC-CompleteAsset.ps1
Normal file
1431
asset-collection/Update-PC-CompleteAsset.ps1
Normal file
File diff suppressed because it is too large
Load Diff
6
asset-collection/Update-PC-Minimal.bat
Normal file
6
asset-collection/Update-PC-Minimal.bat
Normal file
@@ -0,0 +1,6 @@
|
||||
@echo off
|
||||
powershell -ExecutionPolicy Bypass -File "%~dp0Update-PC-Minimal.ps1"
|
||||
echo.
|
||||
echo Log saved to: %TEMP%\shopdb-update.log
|
||||
echo.
|
||||
pause
|
||||
510
asset-collection/Update-PC-Minimal.ps1
Normal file
510
asset-collection/Update-PC-Minimal.ps1
Normal file
@@ -0,0 +1,510 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user