Files
shopdb/scripts/Update-PC-CompleteAsset.ps1
cproudlock ced4a444dc Fix printer mapping to strip underscore suffix from port name
Port names like 10.80.92.53_2 are now cleaned to 10.80.92.53 before
sending to the API for printer lookup.

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 14:55:07 -05:00

1407 lines
61 KiB
PowerShell

# Admin not required for data collection - WinRM setup will be skipped if not admin
<#
.SYNOPSIS
Complete PC asset collection and database update via hybrid proxy/dashboard architecture.
.DESCRIPTION
This script performs comprehensive PC asset management:
1. Collects system information (hostname, serial, manufacturer, user, etc.)
2. Determines PC type (Engineer/Shopfloor/Standard)
3. For shopfloor PCs: Collects machine assignment and network/comm configurations
4. Gets Dell warranty information via proxy server (bypasses network restrictions)
5. Stores all collected data in database via dashboard API
.NOTES
Author: System Administrator
Date: 2025
Version: 1.0
Architecture: PowerShell -> Proxy (warranty) -> Dashboard API (storage)
#>
param(
[Parameter(Mandatory=$false)]
[string]$ProxyURL = "http://10.48.130.158/vendor-api-proxy.php",
[Parameter(Mandatory=$false)]
[string]$DashboardURL = "https://tsgwp00525.rd.ds.ge.com/shopdb/api.asp",
[Parameter(Mandatory=$false)]
[switch]$SkipWarranty = $true, # DEFAULT TO TRUE - Skip warranty lookups
[Parameter(Mandatory=$false)]
[switch]$TestConnections = $false
)
# =============================================================================
# SSL/TLS Certificate Bypass for HTTPS connections
# =============================================================================
# This allows connections to servers with self-signed or untrusted certificates
try {
# For PowerShell 5.x - use .NET callback
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 {
# Silently continue if already set
}
# Set TLS 1.2 as minimum (required for modern HTTPS)
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
# Import shopfloor configuration functions
. "$PSScriptRoot\Get-ShopfloorConfig.ps1"
# Setup logging
$script:LogFile = "$PSScriptRoot\logs\Update-PC-CompleteAsset-$(Get-Date -Format 'yyyy-MM-dd').log"
$script:LogDir = "$PSScriptRoot\logs"
function Write-Log {
param(
[string]$Message,
[string]$Level = "INFO",
[string]$ForegroundColor = "White"
)
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$logMessage = "[$timestamp] [$Level] $Message"
# Write to console
Write-Host $Message -ForegroundColor $ForegroundColor
# Write to log file
try {
if (-not (Test-Path $script:LogDir)) {
New-Item -ItemType Directory -Path $script:LogDir -Force | Out-Null
}
Add-Content -Path $script:LogFile -Value $logMessage -ErrorAction SilentlyContinue
} catch {
# Silently continue if logging fails
}
}
function Reset-WinRMConfiguration {
<#
.SYNOPSIS
Resets and configures WinRM for HTTP remote management
.DESCRIPTION
Removes existing WinRM listeners and configures fresh HTTP listener on port 5985
#>
Write-Log " Resetting WinRM configuration..." -Level "INFO" -ForegroundColor Yellow
try {
# First, check and fix network profile if set to Public
Write-Log " Checking network profile..." -Level "INFO" -ForegroundColor Gray
$profiles = Get-NetConnectionProfile
foreach ($profile in $profiles) {
Write-Log " Interface '$($profile.Name)': $($profile.NetworkCategory)" -Level "INFO" -ForegroundColor Gray
}
# Fix #1: Set machine network interfaces (192.168.x.x) to Private
# These shouldn't try to detect domain - they're for machine communication
Write-Log " Checking for machine network interfaces..." -Level "INFO" -ForegroundColor Gray
$adapters = Get-NetAdapter | Where-Object { $_.Status -eq 'Up' }
foreach ($adapter in $adapters) {
$ipConfig = Get-NetIPAddress -InterfaceIndex $adapter.ifIndex -AddressFamily IPv4 -ErrorAction SilentlyContinue
if ($ipConfig.IPAddress -match '^192\.168\.') {
Write-Log " Found machine network: $($adapter.Name) ($($ipConfig.IPAddress))" -Level "INFO" -ForegroundColor Cyan
$profile = Get-NetConnectionProfile -InterfaceIndex $adapter.ifIndex -ErrorAction SilentlyContinue
if ($profile -and $profile.NetworkCategory -ne 'Private') {
Write-Log " Setting machine network '$($adapter.Name)' to Private..." -Level "INFO" -ForegroundColor Gray
Set-NetConnectionProfile -InterfaceIndex $adapter.ifIndex -NetworkCategory Private -ErrorAction SilentlyContinue
Write-Log " [OK] Machine network set to Private" -Level "SUCCESS" -ForegroundColor Green
}
}
}
# Fix #5: Check and repair machine account trust relationship
Write-Log " Checking domain trust relationship..." -Level "INFO" -ForegroundColor Gray
$secureChannel = Test-ComputerSecureChannel -ErrorAction SilentlyContinue
if ($secureChannel) {
Write-Log " [OK] Domain trust relationship is healthy" -Level "SUCCESS" -ForegroundColor Green
} else {
Write-Log " [WARN] Domain trust may be broken, attempting repair..." -Level "WARN" -ForegroundColor Yellow
try {
# This requires domain admin creds or machine account to still be somewhat valid
$repairResult = Test-ComputerSecureChannel -Repair -ErrorAction SilentlyContinue
if ($repairResult) {
Write-Log " [OK] Domain trust repaired successfully" -Level "SUCCESS" -ForegroundColor Green
} else {
Write-Log " [WARN] Could not auto-repair trust - may need manual rejoin to domain" -Level "WARN" -ForegroundColor Yellow
}
} catch {
Write-Log " [WARN] Trust repair failed: $($_.Exception.Message)" -Level "WARN" -ForegroundColor Yellow
}
}
# Now handle remaining Public profiles on corporate network
$publicProfiles = Get-NetConnectionProfile | Where-Object { $_.NetworkCategory -eq 'Public' }
if ($publicProfiles) {
Write-Log " Found Public network profile(s), attempting to fix..." -Level "INFO" -ForegroundColor Yellow
# Restart NLA service to re-detect domain
Write-Log " Restarting NLA service to detect domain..." -Level "INFO" -ForegroundColor Gray
Restart-Service NlaSvc -Force -ErrorAction SilentlyContinue
Start-Sleep -Seconds 5
# Re-check profiles after NLA restart
$publicProfiles = Get-NetConnectionProfile | Where-Object { $_.NetworkCategory -eq 'Public' }
foreach ($profile in $publicProfiles) {
# Check if this is a corporate network (not 192.168.x.x)
$adapter = Get-NetAdapter -InterfaceIndex $profile.InterfaceIndex -ErrorAction SilentlyContinue
$ipConfig = Get-NetIPAddress -InterfaceIndex $profile.InterfaceIndex -AddressFamily IPv4 -ErrorAction SilentlyContinue
if ($ipConfig.IPAddress -notmatch '^192\.168\.') {
Write-Log " Corporate interface '$($profile.Name)' still Public after NLA restart" -Level "WARN" -ForegroundColor Yellow
}
# Set to Private as fallback (can't manually set Domain)
Write-Log " Setting '$($profile.Name)' to Private..." -Level "INFO" -ForegroundColor Gray
Set-NetConnectionProfile -InterfaceIndex $profile.InterfaceIndex -NetworkCategory Private -ErrorAction SilentlyContinue
Write-Log " [OK] '$($profile.Name)' set to Private" -Level "SUCCESS" -ForegroundColor Green
}
} else {
Write-Log " [OK] All network profiles are Private/Domain" -Level "SUCCESS" -ForegroundColor Green
}
# Stop WinRM service first
Write-Log " Stopping WinRM service..." -Level "INFO" -ForegroundColor Gray
Stop-Service WinRM -Force -ErrorAction SilentlyContinue
Start-Sleep -Seconds 2
Write-Log " WinRM service stopped" -Level "INFO" -ForegroundColor Gray
# Delete all existing listeners
Write-Log " Removing existing WinRM listeners..." -Level "INFO" -ForegroundColor Gray
Remove-Item -Path WSMan:\localhost\Listener\* -Recurse -Force -ErrorAction SilentlyContinue
Write-Log " Existing listeners removed" -Level "INFO" -ForegroundColor Gray
# Start WinRM service
Write-Log " Starting WinRM service..." -Level "INFO" -ForegroundColor Gray
Start-Service WinRM -ErrorAction Stop
Set-Service WinRM -StartupType Automatic
Write-Log " WinRM service started and set to Automatic" -Level "INFO" -ForegroundColor Gray
# Run quick config to set defaults
Write-Log " Running WinRM quickconfig..." -Level "INFO" -ForegroundColor Gray
$quickConfigResult = winrm quickconfig -quiet 2>&1
Write-Log " WinRM quickconfig completed" -Level "INFO" -ForegroundColor Gray
# Create HTTP listener on all addresses
Write-Log " Creating HTTP listener on port 5985..." -Level "INFO" -ForegroundColor Gray
$existingHttp = Get-ChildItem WSMan:\localhost\Listener -ErrorAction SilentlyContinue |
Where-Object { $_.Keys -contains "Transport=HTTP" }
if (-not $existingHttp) {
New-Item -Path WSMan:\localhost\Listener -Transport HTTP -Address * -Force | Out-Null
Write-Log " HTTP listener created" -Level "INFO" -ForegroundColor Gray
} else {
Write-Log " HTTP listener already exists" -Level "INFO" -ForegroundColor Gray
}
# Configure WinRM settings
Write-Log " Configuring WinRM authentication settings..." -Level "INFO" -ForegroundColor Gray
Set-Item WSMan:\localhost\Service\Auth\Basic -Value $false
Set-Item WSMan:\localhost\Service\Auth\Negotiate -Value $true
Set-Item WSMan:\localhost\Service\Auth\Kerberos -Value $true
Set-Item WSMan:\localhost\Service\Auth\CredSSP -Value $false
Set-Item WSMan:\localhost\Service\AllowUnencrypted -Value $false
Write-Log " Auth: Basic=false, Negotiate=true, Kerberos=true, CredSSP=false" -Level "INFO" -ForegroundColor Gray
# Set MaxMemoryPerShellMB for better performance
Set-Item WSMan:\localhost\Shell\MaxMemoryPerShellMB -Value 1024 -ErrorAction SilentlyContinue
Write-Log " MaxMemoryPerShellMB set to 1024" -Level "INFO" -ForegroundColor Gray
# Enable LocalAccountTokenFilterPolicy for remote admin access
Write-Log " Enabling LocalAccountTokenFilterPolicy..." -Level "INFO" -ForegroundColor Gray
$regPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"
Set-ItemProperty -Path $regPath -Name "LocalAccountTokenFilterPolicy" -Value 1 -Type DWord -Force -ErrorAction SilentlyContinue
Write-Log " LocalAccountTokenFilterPolicy enabled" -Level "INFO" -ForegroundColor Gray
# Grant WinRM access to Remote Management Users and Administrators
Write-Log " Configuring WinRM security descriptor..." -Level "INFO" -ForegroundColor Gray
try {
# Get current SDDL
$sddl = (Get-Item WSMan:\localhost\Service\RootSDDL).Value
Write-Log " Current SDDL: $sddl" -Level "INFO" -ForegroundColor Gray
# Enable PSRemoting to set proper permissions
Enable-PSRemoting -Force -SkipNetworkProfileCheck 2>&1 | Out-Null
Write-Log " PSRemoting enabled" -Level "INFO" -ForegroundColor Gray
} catch {
Write-Log " Note: Could not update SDDL directly, using Enable-PSRemoting" -Level "INFO" -ForegroundColor Gray
}
# Restart WinRM to apply all changes
Write-Log " Restarting WinRM service to apply changes..." -Level "INFO" -ForegroundColor Gray
Restart-Service WinRM -Force
Start-Sleep -Seconds 2
Write-Log " WinRM service restarted" -Level "INFO" -ForegroundColor Gray
# Configure firewall rule
Write-Log " Configuring firewall rule..." -Level "INFO" -ForegroundColor Gray
$ruleName = "Windows Remote Management (HTTP-In)"
$existingRule = Get-NetFirewallRule -DisplayName $ruleName -ErrorAction SilentlyContinue
if (-not $existingRule) {
New-NetFirewallRule -DisplayName $ruleName `
-Name "WINRM-HTTP-In-TCP" `
-Profile Domain,Private `
-LocalPort 5985 `
-Protocol TCP `
-Direction Inbound `
-Action Allow `
-Enabled True | Out-Null
Write-Log " Firewall rule '$ruleName' created" -Level "INFO" -ForegroundColor Gray
} else {
Enable-NetFirewallRule -DisplayName $ruleName -ErrorAction SilentlyContinue
Write-Log " Firewall rule '$ruleName' enabled" -Level "INFO" -ForegroundColor Gray
}
# Verify listener is working
Write-Log " Verifying WinRM listener..." -Level "INFO" -ForegroundColor Gray
$listeners = winrm enumerate winrm/config/listener 2>&1
if ($listeners -match "Transport = HTTP" -and $listeners -match "Port = 5985") {
Write-Log " [OK] WinRM HTTP listener configured on port 5985" -Level "SUCCESS" -ForegroundColor Green
# Show listener details
$portCheck = netstat -an | Select-String ":5985.*LISTENING"
if ($portCheck) {
Write-Log " [OK] Port 5985 is listening" -Level "SUCCESS" -ForegroundColor Green
}
return $true
} else {
Write-Log " [WARN] WinRM listener may not be configured correctly" -Level "WARN" -ForegroundColor Yellow
return $false
}
}
catch {
Write-Log " [FAIL] Error configuring WinRM: $($_.Exception.Message)" -Level "ERROR" -ForegroundColor Red
return $false
}
}
function Add-WinRMAdminGroup {
<#
.SYNOPSIS
Adds the WinRM management security group to local Administrators and Remote Management Users
.DESCRIPTION
Adds logon\g03078610 to both local Administrators and Remote Management Users groups
to enable WinRM remote management
#>
param(
[string]$GroupToAdd = "logon\g03078610"
)
Write-Log " Configuring WinRM access groups..." -Level "INFO" -ForegroundColor Yellow
Write-Log " Target group: $GroupToAdd" -Level "INFO" -ForegroundColor Gray
$overallSuccess = $true
# Add to Administrators group
try {
Write-Log " Checking local Administrators group..." -Level "INFO" -ForegroundColor Gray
$adminGroup = [ADSI]"WinNT://./Administrators,group"
$members = @($adminGroup.Invoke("Members")) | ForEach-Object {
$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)
}
Write-Log " Current Administrators members: $($members -join ', ')" -Level "INFO" -ForegroundColor Gray
$groupName = $GroupToAdd.Split('\')[-1]
if ($members -contains $groupName) {
Write-Log " [OK] $GroupToAdd is already in Administrators" -Level "SUCCESS" -ForegroundColor Green
} else {
Write-Log " Adding $GroupToAdd to Administrators..." -Level "INFO" -ForegroundColor Yellow
$result = net localgroup Administrators $GroupToAdd /add 2>&1
if ($LASTEXITCODE -eq 0 -or $result -match "already a member") {
Write-Log " [OK] Added $GroupToAdd to Administrators" -Level "SUCCESS" -ForegroundColor Green
} else {
Write-Log " [FAIL] Failed to add to Administrators: $result" -Level "ERROR" -ForegroundColor Red
$overallSuccess = $false
}
}
}
catch {
Write-Log " [FAIL] Error with Administrators group: $($_.Exception.Message)" -Level "ERROR" -ForegroundColor Red
$overallSuccess = $false
}
# Add to Remote Management Users group
try {
Write-Log " Checking Remote Management Users group..." -Level "INFO" -ForegroundColor Gray
$rmGroup = [ADSI]"WinNT://./Remote Management Users,group"
$rmMembers = @($rmGroup.Invoke("Members")) | ForEach-Object {
$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)
}
Write-Log " Current Remote Management Users members: $($rmMembers -join ', ')" -Level "INFO" -ForegroundColor Gray
$groupName = $GroupToAdd.Split('\')[-1]
if ($rmMembers -contains $groupName) {
Write-Log " [OK] $GroupToAdd is already in Remote Management Users" -Level "SUCCESS" -ForegroundColor Green
} else {
Write-Log " Adding $GroupToAdd to Remote Management Users..." -Level "INFO" -ForegroundColor Yellow
$result = net localgroup "Remote Management Users" $GroupToAdd /add 2>&1
if ($LASTEXITCODE -eq 0 -or $result -match "already a member") {
Write-Log " [OK] Added $GroupToAdd to Remote Management Users" -Level "SUCCESS" -ForegroundColor Green
} else {
Write-Log " [FAIL] Failed to add to Remote Management Users: $result" -Level "ERROR" -ForegroundColor Red
$overallSuccess = $false
}
}
}
catch {
Write-Log " [FAIL] Error with Remote Management Users group: $($_.Exception.Message)" -Level "ERROR" -ForegroundColor Red
$overallSuccess = $false
}
return $overallSuccess
}
function Get-DashboardURL {
param([string]$ProvidedURL)
if (-not [string]::IsNullOrEmpty($ProvidedURL)) {
Write-Host " Using provided URL: $ProvidedURL" -ForegroundColor Gray
return $ProvidedURL
}
# Check environment variable
$envURL = [Environment]::GetEnvironmentVariable("ASSET_DASHBOARD_URL", "User")
if (-not [string]::IsNullOrEmpty($envURL)) {
Write-Host " Using environment variable URL: $envURL" -ForegroundColor Gray
return $envURL
}
# Check for config file
$configPath = "$PSScriptRoot\dashboard-config.json"
if (Test-Path $configPath) {
try {
$config = Get-Content $configPath | ConvertFrom-Json
if ($config.DashboardURL) {
return $config.DashboardURL
}
}
catch {
Write-Verbose "Could not read dashboard config file: $_"
}
}
# Auto-discovery with verbose logging
Write-Host " Starting dashboard URL auto-discovery..." -ForegroundColor Yellow
$candidates = @(
"https://tsgwp00525.rd.ds.ge.com/shopdb/api.asp",
"http://192.168.122.151:8080/api.asp",
"http://localhost:8080/api.asp",
"http://10.48.130.197/dashboard-v2/api.php",
"http://localhost/test/dashboard/api.php",
"http://127.0.0.1/test/dashboard/api.php",
"http://10.48.130.197/api.php",
"http://localhost/api.php",
"http://127.0.0.1/api.php"
)
foreach ($url in $candidates) {
try {
Write-Host " Testing: $url" -ForegroundColor Gray
$testResponse = Invoke-RestMethod -Uri "$url?action=getDashboardData" -Method Get -TimeoutSec 5 -ErrorAction Stop
if ($testResponse.success) {
Write-Host " [SUCCESS] Dashboard found at: $url" -ForegroundColor Green
return $url
} else {
Write-Host " [FAIL] Dashboard responded but not successful" -ForegroundColor Yellow
}
}
catch {
Write-Host " [FAIL] Cannot reach: $($_.Exception.Message)" -ForegroundColor Red
}
}
# If auto-discovery fails, default to the expected URL
$defaultUrl = "https://tsgwp00525.rd.ds.ge.com/shopdb/api.asp"
Write-Host " [FALLBACK] Using default URL: $defaultUrl" -ForegroundColor Yellow
return $defaultUrl
}
function Test-ProxyConnection {
param([string]$ProxyURL)
try {
Write-Host "Testing proxy connection..." -ForegroundColor Yellow
$uri = "$ProxyURL" + "?vendor=dell&action=test-config"
$response = Invoke-RestMethod -Uri $uri -Method Get -TimeoutSec 15
if ($response.success) {
Write-Host "[OK] Proxy server accessible and Dell API configured" -ForegroundColor Green
return $true
} else {
Write-Host "[FAIL] Proxy issue: $($response.error)" -ForegroundColor Red
return $false
}
}
catch {
Write-Host "[FAIL] Cannot reach proxy: $($_.Exception.Message)" -ForegroundColor Red
return $false
}
}
function Test-DashboardConnection {
param([string]$DashboardURL)
try {
Write-Host "Testing dashboard connection..." -ForegroundColor Yellow
$response = Invoke-RestMethod -Uri "$DashboardURL?action=getDashboardData" -Method Get -TimeoutSec 10
if ($response.success) {
Write-Host "[OK] Dashboard API accessible" -ForegroundColor Green
return $true
} else {
Write-Host "[FAIL] Dashboard not responding properly" -ForegroundColor Red
return $false
}
}
catch {
Write-Host "[FAIL] Cannot reach dashboard: $($_.Exception.Message)" -ForegroundColor Red
return $false
}
}
function Test-AppsFolder {
return Test-Path "C:\Apps"
}
function Test-VDriveAccess {
try {
$vDrive = Get-PSDrive -Name V -ErrorAction SilentlyContinue
if ($vDrive) {
$null = Get-ChildItem V:\ -ErrorAction Stop | Select-Object -First 1
return $true
}
return $false
}
catch {
return $false
}
}
function Test-WindowsLTSC {
try {
$os = Get-CimInstance -ClassName CIM_OperatingSystem
$osCaption = $os.Caption
if ($osCaption -match "LTSC|LTSB") {
return $true
}
$productName = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name ProductName -ErrorAction SilentlyContinue).ProductName
if ($productName -match "LTSC|LTSB") {
return $true
}
return $false
}
catch {
return $false
}
}
function Get-TrackedApplications {
try {
$csvPath = "$PSScriptRoot\applications.csv"
if (-not (Test-Path $csvPath)) {
Write-Warning "Applications CSV not found at $csvPath - using fallback patterns"
return @(
@{ app_name = "UDC"; search_patterns = "Universal Data Collection"; enabled = $true }
@{ app_name = "PPDCS"; search_patterns = "PPDCS"; enabled = $true }
@{ app_name = "Oracle"; search_patterns = "Oracle.*Database"; enabled = $true }
@{ app_name = "Tanium"; search_patterns = "Tanium"; enabled = $true }
@{ app_name = "eDNC"; search_patterns = "eDNC"; enabled = $true }
)
}
$trackedApps = @()
$csvContent = Import-Csv -Path $csvPath
foreach ($row in $csvContent) {
if ($row.enabled -eq "1") {
$trackedApps += @{
app_name = $row.app_name
app_id = $row.app_id
search_patterns = $row.search_patterns
description = $row.description
}
}
}
Write-Host " Loaded $($trackedApps.Count) enabled applications from CSV" -ForegroundColor Cyan
return $trackedApps
}
catch {
Write-Warning "Failed to read applications CSV: $($_.Exception.Message) - using fallback patterns"
return @(
@{ app_name = "UDC"; app_id = "2"; search_patterns = "Universal Data Collection"; enabled = $true }
@{ app_name = "PPDCS"; app_id = "4"; search_patterns = "PPDCS"; enabled = $true }
@{ app_name = "Oracle"; app_id = "7"; search_patterns = "Oracle.*Database"; enabled = $true }
@{ app_name = "Tanium"; app_id = "30"; search_patterns = "Tanium"; enabled = $true }
@{ app_name = "eDNC"; app_id = ""; search_patterns = "eDNC"; enabled = $true }
)
}
}
function Get-GEMachineNumber {
param([string]$Hostname)
# Check GE Aircraft Engines registry paths for MachineNo
$gePaths = @(
"HKLM:\Software\GE Aircraft Engines\DNC\General",
"HKLM:\Software\WOW6432Node\GE Aircraft Engines\DNC\General"
)
foreach ($gePath in $gePaths) {
if (Test-Path $gePath) {
try {
$machineNo = Get-ItemProperty -Path $gePath -Name "MachineNo" -ErrorAction Stop
if ($machineNo.MachineNo) {
return $machineNo.MachineNo
}
}
catch {
# Continue to next path
}
}
}
# Check if hostname indicates a specific GE machine
if ($Hostname -match '[HG](\d{3})') {
$machineNum = $Matches[1]
return "M$machineNum"
}
return $null
}
function Get-PCType {
param(
[bool]$HasAppsFolder,
[bool]$HasVDriveAccess
)
# Check if on logon.ds.ge.com domain (Shopfloor PCs)
try {
$domain = (Get-WmiObject Win32_ComputerSystem).Domain
Write-Host " Domain detected: $domain" -ForegroundColor Gray
if ($domain -eq "logon.ds.ge.com") {
Write-Host " [OK] Shopfloor domain detected" -ForegroundColor Green
# Check for specific machine type applications
$installedApps = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*",
"HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" -ErrorAction SilentlyContinue |
Where-Object { $_.DisplayName } |
Select-Object -ExpandProperty DisplayName
# ================================================================
# PC Type Detection based on installed software
# Priority: CMM > Wax Trace > Keyence > EAS1000 > Genspect > Heat Treat > Shopfloor
# ================================================================
# CMM Detection: PC-DMIS, goCMM, DODA
$hasPcDmis = $installedApps -match "PC-DMIS|PCDMIS"
$hasGoCMM = $installedApps -match "^goCMM"
$hasDODA = $installedApps -match "Dovetail Digital Analysis|DODA"
# Also check common PC-DMIS installation paths
if (-not $hasPcDmis) {
$pcDmisPaths = @(
"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*",
"C:\ProgramData\Hexagon\PC-DMIS*"
)
foreach ($dmisPath in $pcDmisPaths) {
if (Test-Path $dmisPath) { $hasPcDmis = $true; break }
}
}
if ($hasPcDmis -or $hasGoCMM -or $hasDODA) {
$detected = @()
if ($hasPcDmis) { $detected += "PC-DMIS" }
if ($hasGoCMM) { $detected += "goCMM" }
if ($hasDODA) { $detected += "DODA" }
Write-Host " [OK] CMM software detected ($($detected -join ', ')) - CMM PC" -ForegroundColor Cyan
return "CMM"
}
# Wax Trace Detection: FormTracePak, FormStatusMonitor
$hasFormTracePak = $installedApps -match "FormTracePak|Formtracepak|Form Trace|FormTrace"
$hasFormStatusMonitor = $installedApps -match "FormStatusMonitor"
# Check file path fallback for FormTracePak
if (-not $hasFormTracePak) {
$ftPaths = @("C:\Program Files\MitutoyoApp*", "C:\Program Files (x86)\MitutoyoApp*")
foreach ($ftPath in $ftPaths) {
if (Test-Path $ftPath) { $hasFormTracePak = $true; break }
}
}
if ($hasFormTracePak -or $hasFormStatusMonitor) {
$detected = @()
if ($hasFormTracePak) { $detected += "FormTracePak" }
if ($hasFormStatusMonitor) { $detected += "FormStatusMonitor" }
Write-Host " [OK] Wax Trace software detected ($($detected -join ', ')) - Wax Trace PC" -ForegroundColor Cyan
return "Wax Trace"
}
# Keyence Detection: VR Series, Keyence VR USB Driver
$hasKeyence = $installedApps -match "VR-3000|VR-5000|VR-6000|KEYENCE VR"
if ($hasKeyence) {
Write-Host " [OK] Keyence VR Series detected - Keyence PC" -ForegroundColor Cyan
return "Keyence"
}
# EAS1000 Detection: GageCal, NI Software (National Instruments)
$hasGageCal = $installedApps -match "^GageCal"
$hasNISoftware = $installedApps -match "^NI-|National Instruments|NI System|NI Measurement|NI LabVIEW"
if ($hasGageCal -or $hasNISoftware) {
$detected = @()
if ($hasGageCal) { $detected += "GageCal" }
if ($hasNISoftware) { $detected += "NI Software" }
Write-Host " [OK] EAS1000 software detected ($($detected -join ', ')) - EAS1000 PC" -ForegroundColor Cyan
return "EAS1000"
}
# Genspect detection (could be Keyence or EAS1000 - default to Measuring)
$hasGenspect = $installedApps -match "^Genspect"
if ($hasGenspect) {
Write-Host " [OK] Genspect detected - Measuring Tool PC" -ForegroundColor Cyan
return "Genspect"
}
# Heat Treat Detection: HeatTreat application
$hasHeatTreat = $installedApps -match "^HeatTreat"
if ($hasHeatTreat) {
Write-Host " [OK] HeatTreat software detected - Heat Treat PC" -ForegroundColor Cyan
return "Heat Treat"
}
# Part Marker 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)
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"
}
}
# Also check for Part Marker 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"
}
return "Shopfloor"
}
} catch {
Write-Host " [WARN] Could not detect domain: $($_.Exception.Message)" -ForegroundColor Yellow
}
if ($HasAppsFolder -and $HasVDriveAccess) {
return "Engineer"
}
else {
return "Standard"
}
}
function Collect-SystemInfo {
Write-Host "Collecting comprehensive system information..." -ForegroundColor Green
$systemInfo = @{}
# Basic system info
$systemInfo.Hostname = $env:COMPUTERNAME
try {
$computerSystem = Get-CimInstance -Class CIM_ComputerSystem -ErrorAction Stop
$bios = Get-CimInstance -Class CIM_BIOSElement -ErrorAction Stop
$os = Get-CimInstance -Class CIM_OperatingSystem -ErrorAction Stop
$systemInfo.Manufacturer = $computerSystem.Manufacturer
$systemInfo.Model = $computerSystem.Model
$systemInfo.SerialNumber = $bios.SerialNumber
$systemInfo.ServiceTag = $bios.SerialNumber # Often same as serial for Dell
$systemInfo.TotalPhysicalMemory = [Math]::Round($computerSystem.TotalPhysicalMemory / 1GB, 2)
$systemInfo.DomainRole = $computerSystem.DomainRole
# OS Information
$systemInfo.OSVersion = $os.Caption
$systemInfo.LastBootUpTime = $os.LastBootUpTime
$systemInfo.CurrentTimeZone = (Get-TimeZone).Id
# Logged-in user
if ($computerSystem.UserName) {
$systemInfo.LoggedInUser = $computerSystem.UserName.Split('\')[-1]
} else {
$systemInfo.LoggedInUser = "No user logged in"
}
}
catch {
Write-Warning "Failed to retrieve WMI information: $_"
$systemInfo.Manufacturer = "Unknown"
$systemInfo.Model = "Unknown"
$systemInfo.SerialNumber = "Unknown"
$systemInfo.ServiceTag = "Unknown"
$systemInfo.LoggedInUser = "Unknown"
$systemInfo.OSVersion = "Unknown"
}
# PC Type determination
$hasApps = Test-AppsFolder
$hasVDrive = Test-VDriveAccess
$systemInfo.PCType = Get-PCType -HasAppsFolder $hasApps -HasVDriveAccess $hasVDrive
# Add application detection for shopfloor PCs
if ($systemInfo.PCType -eq "Shopfloor") {
Write-Host " Detecting shopfloor applications (UDC/CLM)..." -ForegroundColor Yellow
$systemInfo.InstalledApplications = Get-InstalledApplications
} else {
Write-Host " Skipping application detection (PC Type: $($systemInfo.PCType))" -ForegroundColor Gray
$systemInfo.InstalledApplications = @()
}
# GE Machine Number
$systemInfo.MachineNo = Get-GEMachineNumber -Hostname $systemInfo.Hostname
# Collect installed applications for logging and database tracking
Write-Host " Collecting installed applications..." -ForegroundColor Yellow
try {
$installedApps = @()
$installedApps += Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Where-Object {$_.DisplayName}
$installedApps += Get-ItemProperty HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Where-Object {$_.DisplayName}
$filteredApps = $installedApps | Select-Object DisplayName, DisplayVersion | Sort-Object DisplayName -Unique
Write-Host " Found $($filteredApps.Count) installed applications:" -ForegroundColor Gray
foreach ($app in $filteredApps) {
$version = if ($app.DisplayVersion) { " (v$($app.DisplayVersion))" } else { "" }
Write-Host " - $($app.DisplayName)$version" -ForegroundColor Gray
}
# Prepare application data for database tracking (specific apps only)
$trackedApps = @()
$csvTrackedApps = Get-TrackedApplications
# Track which appids we've already added to avoid duplicates
$seenAppIds = @{}
foreach ($app in $filteredApps) {
$appName = $app.DisplayName
$appVersion = $app.DisplayVersion
# Check against CSV-defined applications
foreach ($csvApp in $csvTrackedApps) {
# Skip if no app_id defined in CSV
if (-not $csvApp.app_id -or $csvApp.app_id -eq "") { continue }
if ($appName -match $csvApp.search_patterns) {
$appId = [int]$csvApp.app_id
# Skip if we've already tracked this appid
if ($seenAppIds.ContainsKey($appId)) {
Write-Host " Skipping duplicate: $($csvApp.app_name) (ID:$appId) = $appName" -ForegroundColor DarkGray
break
}
$seenAppIds[$appId] = $true
$trackedApps += @{
appid = $appId # Database appid
appname = $csvApp.app_name # Short name from CSV (e.g., "Tanium")
version = $appVersion # Detected version
displayname = $appName # Full registry name for reference
}
Write-Host " Matched: $($csvApp.app_name) (ID:$appId) = $appName v$appVersion" -ForegroundColor Cyan
break # Found a match, no need to check other patterns
}
}
}
$systemInfo.TrackedApplications = $trackedApps
Write-Host " Found $($trackedApps.Count) tracked applications for database" -ForegroundColor Cyan
}
catch {
Write-Host " [WARN] Failed to collect installed applications: $($_.Exception.Message)" -ForegroundColor Yellow
$systemInfo.TrackedApplications = @()
}
# Collect running processes (for log analysis)
Write-Host " Running processes:" -ForegroundColor Yellow
try {
$processes = Get-Process | Select-Object -ExpandProperty Name | Sort-Object -Unique
Write-Host " $($processes -join ', ')" -ForegroundColor Gray
}
catch {
Write-Host " [WARN] Failed to collect running processes: $($_.Exception.Message)" -ForegroundColor Yellow
}
# Display collected info
Write-Host " System Details:" -ForegroundColor Cyan
Write-Host " Hostname: $($systemInfo.Hostname)"
Write-Host " Manufacturer: $($systemInfo.Manufacturer)"
Write-Host " Model: $($systemInfo.Model)"
Write-Host " Serial: $($systemInfo.SerialNumber)"
Write-Host " PC Type: $($systemInfo.PCType)"
Write-Host " User: $($systemInfo.LoggedInUser)"
if ($systemInfo.MachineNo) {
Write-Host " Machine No: $($systemInfo.MachineNo)"
}
Write-Host " Memory: $($systemInfo.TotalPhysicalMemory) GB"
Write-Host " OS: $($systemInfo.OSVersion)"
return $systemInfo
}
function Collect-ShopfloorInfo {
param([hashtable]$SystemInfo)
if ($SystemInfo.PCType -ne "Shopfloor") {
return $null
}
Write-Host ""
Write-Host "Collecting shopfloor-specific configurations..." -ForegroundColor Yellow
try {
$shopfloorConfigs = Get-ShopfloorConfigurations
Write-Host " Shopfloor Configuration Summary:" -ForegroundColor Cyan
Write-Host " Network Interfaces: $($shopfloorConfigs.NetworkInterfaces.Count)"
Write-Host " Communication Configs: $($shopfloorConfigs.CommConfigs.Count)"
Write-Host " DNC Config: $(if ($shopfloorConfigs.DNCConfig) { 'Yes' } else { 'No' })"
return $shopfloorConfigs
}
catch {
Write-Warning "Failed to collect shopfloor configurations: $_"
return $null
}
}
function Get-DefaultPrinterFQDN {
try {
Write-Host " Collecting default printer information..." -ForegroundColor Yellow
$defaultPrinter = Get-WmiObject -Query "SELECT * FROM Win32_Printer WHERE Default=$true" -ErrorAction Stop
if ($defaultPrinter -and $defaultPrinter.PortName) {
$portName = $defaultPrinter.PortName
Write-Host " Default Printer: $($defaultPrinter.Name)" -ForegroundColor Gray
Write-Host " Port Name: $portName" -ForegroundColor Gray
# Check if this is a network printer (not a local/virtual printer)
$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 ($isLocalPrinter) {
Write-Host " [SKIP] Local/virtual printer detected (port: $portName) - not sending to database" -ForegroundColor Yellow
return $null
}
# Strip anything after and including underscore (e.g., 10.80.92.53_2 -> 10.80.92.53)
$cleanPort = $portName -replace '_.*$', ''
Write-Host " [OK] Network printer detected - will send to database" -ForegroundColor Green
Write-Host " Clean port: $cleanPort" -ForegroundColor Gray
return $cleanPort
} else {
Write-Host " No default printer found or no port available" -ForegroundColor Yellow
return $null
}
}
catch {
Write-Warning "Failed to get default printer information: $_"
return $null
}
}
function Send-PrinterMappingToDashboard {
param(
[string]$Hostname,
[string]$PrinterFQDN,
[string]$DashboardURL
)
if ([string]::IsNullOrEmpty($PrinterFQDN)) {
Write-Host " No printer FQDN to send - skipping printer mapping" -ForegroundColor Gray
return $true
}
try {
Write-Host " Sending printer mapping to dashboard..." -ForegroundColor Yellow
Write-Host " Hostname: $Hostname" -ForegroundColor Gray
Write-Host " Printer FQDN: $PrinterFQDN" -ForegroundColor Gray
$postData = @{
action = 'updatePrinterMapping'
hostname = $Hostname
printerFQDN = $PrinterFQDN
}
$headers = @{
'Content-Type' = 'application/x-www-form-urlencoded'
}
$response = Invoke-RestMethod -Uri $DashboardURL -Method Post -Body $postData -Headers $headers -TimeoutSec 30
# Debug: Show raw response structure
Write-Host " DEBUG Response: $($response | ConvertTo-Json -Compress)" -ForegroundColor Magenta
if ($response.success) {
Write-Host " [OK] Printer mapping updated successfully!" -ForegroundColor Green
Write-Host " Printer ID: $($response.data.printerId)" -ForegroundColor Gray
Write-Host " Machines Updated: $($response.data.machinesUpdated)" -ForegroundColor Gray
Write-Host " Match Method: $($response.data.matchMethod)" -ForegroundColor Gray
return $true
} else {
Write-Host " [WARN] Printer mapping failed: $($response.message)" -ForegroundColor Yellow
Write-Host " DEBUG Error Response: $($response | ConvertTo-Json)" -ForegroundColor Red
return $false
}
}
catch {
Write-Host " [WARN] Error sending printer mapping: $($_.Exception.Message)" -ForegroundColor Yellow
return $false
}
}
function Send-InstalledAppsToDashboard {
param(
[string]$Hostname,
[array]$TrackedApps,
[string]$DashboardURL
)
if (!$TrackedApps -or $TrackedApps.Count -eq 0) {
Write-Host " No tracked applications to send - skipping app mapping" -ForegroundColor Gray
return $true
}
try {
Write-Host " Sending tracked applications to dashboard..." -ForegroundColor Yellow
Write-Host " Hostname: $Hostname" -ForegroundColor Gray
Write-Host " Tracked Apps: $($TrackedApps.Count)" -ForegroundColor Gray
# Debug: Show each app with version
foreach ($app in $TrackedApps) {
Write-Host " -> appid=$($app.appid), appname='$($app.appname)', version='$($app.version)'" -ForegroundColor Magenta
}
$appsJson = $TrackedApps | ConvertTo-Json -Compress
Write-Host " DEBUG JSON: $appsJson" -ForegroundColor Magenta
$postData = @{
action = 'updateInstalledApps'
hostname = $Hostname
installedApps = $appsJson
}
$headers = @{
'Content-Type' = 'application/x-www-form-urlencoded'
}
$response = Invoke-RestMethod -Uri $DashboardURL -Method Post -Body $postData -Headers $headers -TimeoutSec 30
if ($response.success) {
Write-Host " [OK] Installed applications updated successfully!" -ForegroundColor Green
Write-Host " Apps Processed: $($response.appsProcessed)" -ForegroundColor Gray
Write-Host " Machine ID: $($response.machineid)" -ForegroundColor Gray
if ($response.debugError) {
Write-Host " DEBUG ERROR: $($response.debugError)" -ForegroundColor Red
}
return $true
} else {
Write-Host " [WARN] Application mapping failed: $($response.message)" -ForegroundColor Yellow
return $false
}
}
catch {
Write-Host " [WARN] Error sending application mapping: $($_.Exception.Message)" -ForegroundColor Yellow
return $false
}
}
function Get-WarrantyFromProxy {
param(
[string]$ServiceTag,
[string]$ProxyURL
)
if ([string]::IsNullOrEmpty($ServiceTag) -or $ServiceTag -eq "Unknown") {
Write-Host " No valid service tag - skipping warranty lookup" -ForegroundColor Gray
return $null
}
try {
Write-Host "Getting warranty data from proxy server..." -ForegroundColor Yellow
$uri = "$ProxyURL" + "?vendor=dell&action=warranty&servicetag=$ServiceTag"
$response = Invoke-RestMethod -Uri $uri -Method Get -TimeoutSec 30
if ($response.success -and $response.warranties -and $response.warranties.Count -gt 0) {
$warranty = $response.warranties[0]
Write-Host " [OK] Warranty data retrieved:" -ForegroundColor Green
Write-Host " Status: $($warranty.warrantyStatus)"
Write-Host " End Date: $($warranty.warrantyEndDate)"
Write-Host " Days Remaining: $($warranty.daysRemaining)"
Write-Host " Service Level: $($warranty.serviceLevel)"
return $warranty
} else {
Write-Host " [WARN] No warranty data found for service tag: $ServiceTag" -ForegroundColor Yellow
return $null
}
}
catch {
Write-Host " [WARN] Error getting warranty from proxy: $($_.Exception.Message)" -ForegroundColor Yellow
return $null
}
}
function Send-CompleteDataToDashboard {
param(
[hashtable]$SystemInfo,
[object]$ShopfloorInfo,
[object]$WarrantyData,
[string]$DashboardURL
)
try {
Write-Host "Sending complete asset data to dashboard..." -ForegroundColor Yellow
Write-Host " Dashboard URL: $DashboardURL" -ForegroundColor Gray
# Prepare comprehensive data package
$postData = @{
action = 'updateCompleteAsset'
# Basic system information
hostname = $SystemInfo.Hostname
serialNumber = $SystemInfo.SerialNumber
serviceTag = $SystemInfo.ServiceTag
manufacturer = $SystemInfo.Manufacturer
model = $SystemInfo.Model
pcType = $SystemInfo.PCType
loggedInUser = $SystemInfo.LoggedInUser
machineNo = $SystemInfo.MachineNo
osVersion = $SystemInfo.OSVersion
totalPhysicalMemory = $SystemInfo.TotalPhysicalMemory
domainRole = $SystemInfo.DomainRole
currentTimeZone = $SystemInfo.CurrentTimeZone
# Format lastBootUpTime as MySQL datetime (YYYY-MM-DD HH:MM:SS)
lastBootUpTime = if ($SystemInfo.LastBootUpTime) {
$SystemInfo.LastBootUpTime.ToString("yyyy-MM-dd HH:mm:ss")
} else { $null }
}
# Add warranty data if available
if ($WarrantyData) {
$postData.warrantyEndDate = $WarrantyData.warrantyEndDate
$postData.warrantyStatus = $WarrantyData.warrantyStatus
$postData.warrantyServiceLevel = $WarrantyData.serviceLevel
$postData.warrantyDaysRemaining = $WarrantyData.daysRemaining
}
# Add shopfloor data if available
if ($ShopfloorInfo) {
Write-Host " ShopfloorInfo object contains DNCConfig: $(if ($ShopfloorInfo.DNCConfig) { 'YES' } else { 'NO' })" -ForegroundColor Gray
Write-Host " ShopfloorInfo object contains GERegistryInfo: $(if ($ShopfloorInfo.GERegistryInfo) { 'YES' } else { 'NO' })" -ForegroundColor Gray
$postData.networkInterfaces = $ShopfloorInfo.NetworkInterfaces | ConvertTo-Json -Compress
$postData.commConfigs = $ShopfloorInfo.CommConfigs | ConvertTo-Json -Compress
if ($ShopfloorInfo.DNCConfig) {
$postData.dncConfig = $ShopfloorInfo.DNCConfig | ConvertTo-Json -Compress
Write-Host " Sending DNC Config: $(($ShopfloorInfo.DNCConfig | ConvertTo-Json -Compress).Substring(0, 100))..." -ForegroundColor Cyan
} else {
Write-Host " No DNC Config to send (ShopfloorInfo.DNCConfig is null or empty)" -ForegroundColor Yellow
}
# Add GE Aircraft Engines registry information
if ($ShopfloorInfo.GERegistryInfo) {
$geInfo = $ShopfloorInfo.GERegistryInfo
$postData.dncDualPathEnabled = if ($geInfo.DualPathEnabled -ne $null) { $geInfo.DualPathEnabled } else { $null }
$postData.dncPath1Name = $geInfo.Path1Name
$postData.dncPath2Name = $geInfo.Path2Name
$postData.dncGeRegistry32Bit = $geInfo.Registry32Bit
$postData.dncGeRegistry64Bit = $geInfo.Registry64Bit
$postData.dncGeRegistryNotes = $geInfo.RegistryNotes | ConvertTo-Json -Compress
Write-Host " Sending GE Registry Info:" -ForegroundColor Cyan
Write-Host " 32-bit: $($geInfo.Registry32Bit), 64-bit: $($geInfo.Registry64Bit)" -ForegroundColor Cyan
Write-Host " DualPath: $(if ($geInfo.DualPathEnabled -ne $null) { $geInfo.DualPathEnabled } else { 'Not Found' })" -ForegroundColor Cyan
if ($geInfo.Path1Name) { Write-Host " Path1Name: $($geInfo.Path1Name)" -ForegroundColor Cyan }
if ($geInfo.Path2Name) { Write-Host " Path2Name: $($geInfo.Path2Name)" -ForegroundColor Cyan }
} else {
Write-Host " No GE Registry Info to send" -ForegroundColor Yellow
}
} else {
Write-Host " No ShopfloorInfo available" -ForegroundColor Yellow
}
# Add installed applications data for shopfloor PCs
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) {
Write-Host " - $($app.AppName) (AppID: $($app.AppID)) - ACTIVE (PID: $($app.ProcessID))" -ForegroundColor Green
}
} else {
Write-Host " - No active applications detected" -ForegroundColor Gray
}
} else {
Write-Host " No installed applications to send" -ForegroundColor Gray
}
# Send to dashboard API
$headers = @{
'Content-Type' = 'application/x-www-form-urlencoded'
}
$response = Invoke-RestMethod -Uri $DashboardURL -Method Post -Body $postData -Headers $headers -TimeoutSec 30
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' })"
return $true
} else {
Write-Host " [FAIL] Dashboard could not store data: $($response.error)" -ForegroundColor Red
if ($response.data -and $response.data.debug) {
Write-Host " Debug - DNC Config Received: $($response.data.debug.dncConfigReceived)" -ForegroundColor Yellow
} elseif ($response.debug) {
Write-Host " Debug - DNC Config Received: $($response.debug.dncConfigReceived)" -ForegroundColor Yellow
}
return $false
}
}
catch {
Write-Host " [FAIL] Error sending data to dashboard: $($_.Exception.Message)" -ForegroundColor Red
# Try to get more details from the response
if ($_.Exception -is [System.Net.WebException]) {
$response = $_.Exception.Response
if ($response) {
$responseStream = $response.GetResponseStream()
$reader = New-Object System.IO.StreamReader($responseStream)
$responseBody = $reader.ReadToEnd()
$reader.Close()
Write-Host " Server Response:" -ForegroundColor Yellow
try {
$errorData = $responseBody | ConvertFrom-Json
if ($errorData.details) {
Write-Host " Error: $($errorData.details.message)" -ForegroundColor Red
Write-Host " File: $($errorData.details.file):$($errorData.details.line)" -ForegroundColor Gray
} else {
Write-Host " $responseBody" -ForegroundColor Gray
}
} catch {
Write-Host " $responseBody" -ForegroundColor Gray
}
}
}
return $false
}
}
# Main execution
try {
# Log startup
Write-Log "========================================" -Level "INFO" -ForegroundColor Green
Write-Log "Complete PC Asset Collection & Storage" -Level "INFO" -ForegroundColor Green
Write-Log "========================================" -Level "INFO" -ForegroundColor Green
Write-Log "Computer: $env:COMPUTERNAME" -Level "INFO" -ForegroundColor White
Write-Log "Log file: $script:LogFile" -Level "INFO" -ForegroundColor Gray
# Get dashboard URL
$dashboardURL = Get-DashboardURL -ProvidedURL $DashboardURL
Write-Log "Dashboard: $dashboardURL" -Level "INFO" -ForegroundColor Gray
Write-Log "Note: Warranty lookups disabled (handled by dashboard)" -Level "INFO" -ForegroundColor Gray
Write-Log "" -Level "INFO" -ForegroundColor White
# Test connections if requested
if ($TestConnections) {
Write-Host "=== CONNECTION TESTS ===" -ForegroundColor Cyan
# Only test dashboard connection since proxy is not accessible from PCs
Write-Host "Skipping proxy test (not accessible from client PCs)" -ForegroundColor Gray
$dashboardOK = Test-DashboardConnection -DashboardURL $dashboardURL
Write-Host ""
if ($dashboardOK) {
Write-Host "[OK] Dashboard connection working!" -ForegroundColor Green
exit 0
} else {
Write-Host "[FAIL] Dashboard connection failed" -ForegroundColor Red
exit 1
}
}
# Step 1: Collect system information
Write-Host "=== STEP 1: COLLECT SYSTEM INFO ===" -ForegroundColor Cyan
$systemInfo = Collect-SystemInfo
# Step 2: Collect shopfloor-specific info (if applicable)
Write-Host ""
Write-Host "=== STEP 2: COLLECT SHOPFLOOR INFO ===" -ForegroundColor Cyan
$shopfloorInfo = Collect-ShopfloorInfo -SystemInfo $systemInfo
# Step 3: Get warranty data from proxy (if not skipped and Dell system)
$warrantyData = $null
$isDellSystem = $systemInfo.Manufacturer -match "Dell"
Write-Host ""
Write-Host "=== STEP 3: WARRANTY DATA ===" -ForegroundColor Cyan
Write-Host "Warranty lookups disabled - Dashboard will handle warranty updates" -ForegroundColor Yellow
Write-Host "PCs cannot reach proxy server from this network" -ForegroundColor Gray
# Step 4: Send all data to dashboard for storage
Write-Host ""
Write-Host "=== STEP 4: STORE IN DATABASE ===" -ForegroundColor Cyan
$storeSuccess = Send-CompleteDataToDashboard -SystemInfo $systemInfo -ShopfloorInfo $shopfloorInfo -WarrantyData $warrantyData -DashboardURL $dashboardURL
if (-not $storeSuccess) {
Write-Error "Failed to store asset data in database"
exit 1
}
# Step 5: Collect and send default printer mapping
Write-Host ""
Write-Host "=== STEP 5: PRINTER MAPPING ===" -ForegroundColor Cyan
$defaultPrinterFQDN = Get-DefaultPrinterFQDN
$printerMappingSuccess = Send-PrinterMappingToDashboard -Hostname $systemInfo.Hostname -PrinterFQDN $defaultPrinterFQDN -DashboardURL $dashboardURL
# Step 6: Send tracked applications to database
Write-Host ""
Write-Host "=== STEP 6: APPLICATION MAPPING ===" -ForegroundColor Cyan
$appMappingSuccess = Send-InstalledAppsToDashboard -Hostname $systemInfo.Hostname -TrackedApps $systemInfo.TrackedApplications -DashboardURL $dashboardURL
# Check if running as admin for Steps 7 & 8
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")
# Step 7: Reset and configure WinRM for remote management (requires admin)
Write-Log "" -Level "INFO" -ForegroundColor White
Write-Log "=== STEP 7: WINRM CONFIGURATION ===" -Level "INFO" -ForegroundColor Cyan
if ($isAdmin) {
$winrmSuccess = Reset-WinRMConfiguration
} else {
Write-Log " [SKIP] Not running as admin - WinRM configuration skipped" -Level "WARN" -ForegroundColor Yellow
$winrmSuccess = $false
}
# Step 8: Add WinRM management group to local Administrators (requires admin)
Write-Log "" -Level "INFO" -ForegroundColor White
Write-Log "=== STEP 8: WINRM ADMIN GROUP ===" -Level "INFO" -ForegroundColor Cyan
if ($isAdmin) {
$adminGroupSuccess = Add-WinRMAdminGroup
} else {
Write-Log " [SKIP] Not running as admin - Admin group setup skipped" -Level "WARN" -ForegroundColor Yellow
$adminGroupSuccess = $false
}
# Final Summary
Write-Log "" -Level "INFO" -ForegroundColor White
Write-Log "=== COMPLETE ASSET UPDATE SUCCESS ===" -Level "INFO" -ForegroundColor Green
Write-Log "Computer: $($systemInfo.Hostname)" -Level "INFO" -ForegroundColor White
Write-Log "Type: $($systemInfo.PCType)" -Level "INFO" -ForegroundColor White
Write-Log "Serial: $($systemInfo.SerialNumber)" -Level "INFO" -ForegroundColor White
if ($systemInfo.MachineNo) {
Write-Log "Machine: $($systemInfo.MachineNo)" -Level "INFO" -ForegroundColor White
}
Write-Log "" -Level "INFO" -ForegroundColor White
Write-Log "Data Collected & Stored:" -Level "INFO" -ForegroundColor Cyan
Write-Log "[OK] Basic system information" -Level "SUCCESS" -ForegroundColor Green
if ($defaultPrinterFQDN) {
Write-Log "[OK] Default printer mapping ($defaultPrinterFQDN)" -Level "SUCCESS" -ForegroundColor Green
} else {
Write-Log "[--] Default printer mapping (no printer found)" -Level "INFO" -ForegroundColor Gray
}
if ($systemInfo.TrackedApplications -and $systemInfo.TrackedApplications.Count -gt 0) {
Write-Log "[OK] Application mapping ($($systemInfo.TrackedApplications.Count) tracked apps)" -Level "SUCCESS" -ForegroundColor Green
} else {
Write-Log "[--] Application mapping (no tracked apps found)" -Level "INFO" -ForegroundColor Gray
}
if ($shopfloorInfo) {
Write-Log "[OK] Shopfloor configurations ($($shopfloorInfo.NetworkInterfaces.Count) network, $($shopfloorInfo.CommConfigs.Count) comm)" -Level "SUCCESS" -ForegroundColor Green
}
if ($warrantyData) {
Write-Log "[OK] Warranty information ($($warrantyData.warrantyStatus), $($warrantyData.daysRemaining) days)" -Level "SUCCESS" -ForegroundColor Green
} elseif (-not $SkipWarranty -and $isDellSystem) {
Write-Log "[WARN] Warranty information (lookup failed)" -Level "WARN" -ForegroundColor Yellow
}
if ($winrmSuccess) {
Write-Log "[OK] WinRM HTTP listener (port 5985)" -Level "SUCCESS" -ForegroundColor Green
Write-Log " Note: If remote access still fails, a reboot may be required" -Level "INFO" -ForegroundColor Gray
} else {
Write-Log "[WARN] WinRM configuration (may need manual setup)" -Level "WARN" -ForegroundColor Yellow
}
if ($adminGroupSuccess) {
Write-Log "[OK] WinRM admin group (logon\g03078610)" -Level "SUCCESS" -ForegroundColor Green
} else {
Write-Log "[WARN] WinRM admin group (failed to add)" -Level "WARN" -ForegroundColor Yellow
}
Write-Log "" -Level "INFO" -ForegroundColor White
Write-Log "[OK] Complete PC asset collection finished!" -Level "SUCCESS" -ForegroundColor Green
Write-Log "All data stored in database via dashboard API." -Level "INFO" -ForegroundColor Gray
Write-Log "Log file: $script:LogFile" -Level "INFO" -ForegroundColor Gray
} catch {
Write-Log "Complete asset collection failed: $($_.Exception.Message)" -Level "ERROR" -ForegroundColor Red
Write-Error "Complete asset collection failed: $($_.Exception.Message)"
exit 1
}