Update PowerShell scripts for production API and SSL bypass
- Changed Invoke-RemoteAssetCollection.ps1 default URL to production: https://tsgwp00525.rd.ds.ge.com/shopdb/api.asp - Added SSL/TLS certificate bypass for HTTPS connections in both: - Update-PC-CompleteAsset.ps1 - Invoke-RemoteAssetCollection.ps1 - Set TLS 1.2 as minimum protocol version - Security group logon\g03078610 confirmed correct 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
480
scripts/Get-ShopfloorConfig.ps1
Normal file
480
scripts/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 @()
|
||||
}
|
||||
}
|
||||
484
scripts/Invoke-RemoteAssetCollection.ps1
Normal file
484
scripts/Invoke-RemoteAssetCollection.ps1
Normal file
@@ -0,0 +1,484 @@
|
||||
#Requires -RunAsAdministrator
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Remotely executes asset collection script on shopfloor PCs using WinRM.
|
||||
|
||||
.DESCRIPTION
|
||||
This script uses WinRM to remotely execute the Update-PC-CompleteAsset.ps1 script
|
||||
on multiple shopfloor PCs. It handles:
|
||||
1. WinRM configuration and trusted hosts setup
|
||||
2. Credential management for remote connections
|
||||
3. Parallel or sequential execution across multiple PCs
|
||||
4. Error handling and logging for remote operations
|
||||
5. Collection of results from each remote PC
|
||||
|
||||
.PARAMETER ComputerList
|
||||
Array of computer names or IP addresses to collect data from.
|
||||
|
||||
.PARAMETER ComputerListFile
|
||||
Path to a text file containing computer names/IPs (one per line).
|
||||
|
||||
.PARAMETER Credential
|
||||
PSCredential object for authenticating to remote computers.
|
||||
If not provided, will prompt for credentials.
|
||||
|
||||
.PARAMETER MaxConcurrent
|
||||
Maximum number of concurrent remote sessions (default: 5).
|
||||
|
||||
.PARAMETER ProxyURL
|
||||
URL for the warranty proxy server (passed to remote script).
|
||||
|
||||
.PARAMETER DashboardURL
|
||||
URL for the dashboard API (passed to remote script).
|
||||
|
||||
.PARAMETER SkipWarranty
|
||||
Skip warranty lookups on remote PCs (passed to remote script).
|
||||
|
||||
.PARAMETER LogPath
|
||||
Path for log files (default: .\logs\remote-collection.log).
|
||||
|
||||
.PARAMETER TestConnections
|
||||
Test remote connections without running the full collection.
|
||||
|
||||
.PARAMETER ScriptPath
|
||||
Path to the Update-PC-CompleteAsset.ps1 script on remote computers.
|
||||
Default: C:\Scripts\Update-PC-CompleteAsset.ps1
|
||||
|
||||
.EXAMPLE
|
||||
# Collect from specific computers with prompted credentials
|
||||
.\Invoke-RemoteAssetCollection.ps1 -ComputerList @("10.48.130.100", "10.48.130.101")
|
||||
|
||||
.EXAMPLE
|
||||
# Collect from computers listed in file with stored credentials
|
||||
$cred = Get-Credential
|
||||
.\Invoke-RemoteAssetCollection.ps1 -ComputerListFile ".\shopfloor-pcs.txt" -Credential $cred
|
||||
|
||||
.EXAMPLE
|
||||
# Test connections only
|
||||
.\Invoke-RemoteAssetCollection.ps1 -ComputerList @("10.48.130.100") -TestConnections
|
||||
|
||||
.NOTES
|
||||
Author: System Administrator
|
||||
Date: 2025-09-26
|
||||
Version: 1.0
|
||||
|
||||
Prerequisites:
|
||||
1. WinRM must be enabled on target computers
|
||||
2. PowerShell remoting must be enabled on target computers
|
||||
3. Update-PC-CompleteAsset.ps1 must be present on target computers
|
||||
4. Credentials with admin rights on target computers
|
||||
|
||||
WinRM Setup Commands (run on management server):
|
||||
Enable-PSRemoting -Force
|
||||
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "*" -Force
|
||||
|
||||
WinRM Setup Commands (run on target computers):
|
||||
Enable-PSRemoting -Force
|
||||
Set-NetFirewallRule -DisplayName "Windows Remote Management (HTTP-In)" -Enabled True
|
||||
#>
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string[]]$ComputerList = @(),
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$ComputerListFile,
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[PSCredential]$Credential,
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[int]$MaxConcurrent = 5,
|
||||
|
||||
[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,
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$LogPath = ".\logs\remote-collection.log",
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[switch]$TestConnections = $false,
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$ScriptPath = "C:\Scripts\Update-PC-CompleteAsset.ps1"
|
||||
)
|
||||
|
||||
# =============================================================================
|
||||
# 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
|
||||
|
||||
# Initialize logging
|
||||
function Initialize-Logging {
|
||||
param([string]$LogPath)
|
||||
|
||||
$logDir = Split-Path $LogPath -Parent
|
||||
if (-not (Test-Path $logDir)) {
|
||||
New-Item -ItemType Directory -Path $logDir -Force | Out-Null
|
||||
}
|
||||
|
||||
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
||||
Add-Content -Path $LogPath -Value "[$timestamp] Remote asset collection started"
|
||||
}
|
||||
|
||||
function Write-Log {
|
||||
param([string]$Message, [string]$LogPath, [string]$Level = "INFO")
|
||||
|
||||
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
||||
$logEntry = "[$timestamp] [$Level] $Message"
|
||||
|
||||
Add-Content -Path $LogPath -Value $logEntry
|
||||
|
||||
switch ($Level) {
|
||||
"ERROR" { Write-Host $logEntry -ForegroundColor Red }
|
||||
"WARN" { Write-Host $logEntry -ForegroundColor Yellow }
|
||||
"SUCCESS" { Write-Host $logEntry -ForegroundColor Green }
|
||||
default { Write-Host $logEntry -ForegroundColor White }
|
||||
}
|
||||
}
|
||||
|
||||
function Get-ComputerTargets {
|
||||
param([string[]]$ComputerList, [string]$ComputerListFile)
|
||||
|
||||
$targets = @()
|
||||
|
||||
# Add computers from direct list
|
||||
if ($ComputerList.Count -gt 0) {
|
||||
$targets += $ComputerList
|
||||
}
|
||||
|
||||
# Add computers from file
|
||||
if (-not [string]::IsNullOrEmpty($ComputerListFile)) {
|
||||
if (Test-Path $ComputerListFile) {
|
||||
$fileTargets = Get-Content $ComputerListFile | Where-Object { $_.Trim() -ne "" -and -not $_.StartsWith("#") }
|
||||
$targets += $fileTargets
|
||||
} else {
|
||||
Write-Log "Computer list file not found: $ComputerListFile" $LogPath "ERROR"
|
||||
}
|
||||
}
|
||||
|
||||
# Remove duplicates and return
|
||||
return ($targets | Sort-Object -Unique)
|
||||
}
|
||||
|
||||
function Test-WinRMConnection {
|
||||
param([string]$ComputerName, [PSCredential]$Credential)
|
||||
|
||||
try {
|
||||
$session = New-PSSession -ComputerName $ComputerName -Credential $Credential -ErrorAction Stop
|
||||
Remove-PSSession $session
|
||||
return $true
|
||||
}
|
||||
catch {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
function Test-RemoteScriptExists {
|
||||
param([string]$ComputerName, [PSCredential]$Credential, [string]$ScriptPath)
|
||||
|
||||
try {
|
||||
$result = Invoke-Command -ComputerName $ComputerName -Credential $Credential -ScriptBlock {
|
||||
param($Path)
|
||||
Test-Path $Path
|
||||
} -ArgumentList $ScriptPath
|
||||
|
||||
return $result
|
||||
}
|
||||
catch {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
function Invoke-RemoteAssetScript {
|
||||
param(
|
||||
[string]$ComputerName,
|
||||
[PSCredential]$Credential,
|
||||
[string]$ScriptPath,
|
||||
[string]$ProxyURL,
|
||||
[string]$DashboardURL,
|
||||
[bool]$SkipWarranty,
|
||||
[string]$LogPath
|
||||
)
|
||||
|
||||
try {
|
||||
Write-Log "Starting asset collection on $ComputerName" $LogPath "INFO"
|
||||
|
||||
# Execute the script remotely
|
||||
$result = Invoke-Command -ComputerName $ComputerName -Credential $Credential -ScriptBlock {
|
||||
param($ScriptPath, $ProxyURL, $DashboardURL, $SkipWarranty)
|
||||
|
||||
# Change to script directory
|
||||
$scriptDir = Split-Path $ScriptPath -Parent
|
||||
Set-Location $scriptDir
|
||||
|
||||
# Build parameters
|
||||
$params = @{
|
||||
ProxyURL = $ProxyURL
|
||||
DashboardURL = $DashboardURL
|
||||
}
|
||||
|
||||
if ($SkipWarranty) {
|
||||
$params.SkipWarranty = $true
|
||||
}
|
||||
|
||||
# Execute the script and capture output
|
||||
try {
|
||||
& $ScriptPath @params
|
||||
return @{
|
||||
Success = $true
|
||||
Output = "Script completed successfully"
|
||||
Error = $null
|
||||
}
|
||||
}
|
||||
catch {
|
||||
return @{
|
||||
Success = $false
|
||||
Output = $null
|
||||
Error = $_.Exception.Message
|
||||
}
|
||||
}
|
||||
} -ArgumentList $ScriptPath, $ProxyURL, $DashboardURL, $SkipWarranty
|
||||
|
||||
if ($result.Success) {
|
||||
Write-Log "Asset collection completed successfully on $ComputerName" $LogPath "SUCCESS"
|
||||
|
||||
# Update WinRM status in database - WinRM connection was successful
|
||||
# Get the actual hostname from the remote PC (in case we connected via IP)
|
||||
try {
|
||||
$remoteHostname = Invoke-Command -ComputerName $ComputerName -Credential $Credential -ScriptBlock {
|
||||
$env:COMPUTERNAME
|
||||
} -ErrorAction SilentlyContinue
|
||||
|
||||
if ([string]::IsNullOrEmpty($remoteHostname)) {
|
||||
$remoteHostname = $ComputerName
|
||||
}
|
||||
|
||||
$winrmBody = @{
|
||||
action = "updateWinRMStatus"
|
||||
hostname = $remoteHostname
|
||||
hasWinRM = "1"
|
||||
}
|
||||
Write-Log "Updating WinRM status for hostname: $remoteHostname (connected as: $ComputerName)" $LogPath "INFO"
|
||||
$winrmResponse = Invoke-RestMethod -Uri $DashboardURL -Method Post -Body $winrmBody -ErrorAction Stop
|
||||
if ($winrmResponse.success) {
|
||||
Write-Log "WinRM status updated for $remoteHostname" $LogPath "INFO"
|
||||
} else {
|
||||
Write-Log "WinRM update response: $($winrmResponse | ConvertTo-Json -Compress)" $LogPath "WARN"
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Log "Failed to update WinRM status for $ComputerName - $($_.Exception.Message)" $LogPath "WARN"
|
||||
}
|
||||
|
||||
return @{ Success = $true; Computer = $ComputerName; Message = $result.Output }
|
||||
} else {
|
||||
Write-Log "Asset collection failed on $ComputerName: $($result.Error)" $LogPath "ERROR"
|
||||
return @{ Success = $false; Computer = $ComputerName; Message = $result.Error }
|
||||
}
|
||||
}
|
||||
catch {
|
||||
$errorMsg = "Failed to execute on $ComputerName: $($_.Exception.Message)"
|
||||
Write-Log $errorMsg $LogPath "ERROR"
|
||||
return @{ Success = $false; Computer = $ComputerName; Message = $errorMsg }
|
||||
}
|
||||
}
|
||||
|
||||
function Show-WinRMSetupInstructions {
|
||||
Write-Host "=== WinRM Setup Instructions ===" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host "On Management Server (this computer):" -ForegroundColor Yellow
|
||||
Write-Host " Enable-PSRemoting -Force" -ForegroundColor White
|
||||
Write-Host " Set-Item WSMan:\localhost\Client\TrustedHosts -Value '*' -Force" -ForegroundColor White
|
||||
Write-Host ""
|
||||
Write-Host "On Target Computers:" -ForegroundColor Yellow
|
||||
Write-Host " Enable-PSRemoting -Force" -ForegroundColor White
|
||||
Write-Host " Set-NetFirewallRule -DisplayName 'Windows Remote Management (HTTP-In)' -Enabled True" -ForegroundColor White
|
||||
Write-Host ""
|
||||
Write-Host "For specific computer trust:" -ForegroundColor Yellow
|
||||
Write-Host " Set-Item WSMan:\localhost\Client\TrustedHosts -Value '10.48.130.100,10.48.130.101' -Force" -ForegroundColor White
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
# Main execution
|
||||
try {
|
||||
Write-Host "=== Remote Asset Collection Script ===" -ForegroundColor Cyan
|
||||
Write-Host "Starting at $(Get-Date)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
|
||||
# Initialize logging
|
||||
Initialize-Logging -LogPath $LogPath
|
||||
|
||||
# Get target computers
|
||||
$computers = Get-ComputerTargets -ComputerList $ComputerList -ComputerListFile $ComputerListFile
|
||||
|
||||
if ($computers.Count -eq 0) {
|
||||
Write-Log "No target computers specified. Use -ComputerList or -ComputerListFile parameter." $LogPath "ERROR"
|
||||
Show-WinRMSetupInstructions
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Log "Target computers: $($computers -join ', ')" $LogPath "INFO"
|
||||
|
||||
# Get credentials if not provided
|
||||
if (-not $Credential) {
|
||||
Write-Host "Enter credentials for remote computer access:" -ForegroundColor Yellow
|
||||
$Credential = Get-Credential
|
||||
if (-not $Credential) {
|
||||
Write-Log "No credentials provided" $LogPath "ERROR"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# Test connections if requested
|
||||
if ($TestConnections) {
|
||||
Write-Host "`nTesting connections only..." -ForegroundColor Yellow
|
||||
foreach ($computer in $computers) {
|
||||
Write-Host "Testing $computer..." -NoNewline
|
||||
if (Test-WinRMConnection -ComputerName $computer -Credential $Credential) {
|
||||
Write-Host " [OK]" -ForegroundColor Green
|
||||
Write-Log "Connection test successful for $computer" $LogPath "SUCCESS"
|
||||
} else {
|
||||
Write-Host " [FAIL]" -ForegroundColor Red
|
||||
Write-Log "Connection test failed for $computer" $LogPath "ERROR"
|
||||
}
|
||||
}
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Validate all connections and script existence before starting collection
|
||||
Write-Host "`nValidating remote connections and script availability..." -ForegroundColor Yellow
|
||||
$validComputers = @()
|
||||
|
||||
foreach ($computer in $computers) {
|
||||
Write-Host "Validating $computer..." -NoNewline
|
||||
|
||||
if (-not (Test-WinRMConnection -ComputerName $computer -Credential $Credential)) {
|
||||
Write-Host " [CONNECTION FAILED]" -ForegroundColor Red
|
||||
Write-Log "Cannot connect to $computer via WinRM" $LogPath "ERROR"
|
||||
continue
|
||||
}
|
||||
|
||||
if (-not (Test-RemoteScriptExists -ComputerName $computer -Credential $Credential -ScriptPath $ScriptPath)) {
|
||||
Write-Host " [SCRIPT NOT FOUND]" -ForegroundColor Red
|
||||
Write-Log "Script not found on $computer at $ScriptPath" $LogPath "ERROR"
|
||||
continue
|
||||
}
|
||||
|
||||
Write-Host " [OK]" -ForegroundColor Green
|
||||
$validComputers += $computer
|
||||
}
|
||||
|
||||
if ($validComputers.Count -eq 0) {
|
||||
Write-Log "No valid computers found for data collection" $LogPath "ERROR"
|
||||
Show-WinRMSetupInstructions
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Log "Valid computers for collection: $($validComputers -join ', ')" $LogPath "INFO"
|
||||
|
||||
# Execute asset collection
|
||||
Write-Host "`nStarting asset collection on $($validComputers.Count) computers..." -ForegroundColor Cyan
|
||||
Write-Host "Max concurrent sessions: $MaxConcurrent" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
|
||||
$results = @()
|
||||
$jobs = @()
|
||||
$completed = 0
|
||||
|
||||
# Process computers in batches
|
||||
for ($i = 0; $i -lt $validComputers.Count; $i += $MaxConcurrent) {
|
||||
$batch = $validComputers[$i..($i + $MaxConcurrent - 1)]
|
||||
|
||||
Write-Host "Processing batch: $($batch -join ', ')" -ForegroundColor Yellow
|
||||
|
||||
# Start jobs for current batch
|
||||
foreach ($computer in $batch) {
|
||||
$job = Start-Job -ScriptBlock {
|
||||
param($Computer, $Credential, $ScriptPath, $ProxyURL, $DashboardURL, $SkipWarranty, $LogPath, $Functions)
|
||||
|
||||
# Import functions into job scope
|
||||
Invoke-Expression $Functions
|
||||
|
||||
Invoke-RemoteAssetScript -ComputerName $Computer -Credential $Credential `
|
||||
-ScriptPath $ScriptPath -ProxyURL $ProxyURL -DashboardURL $DashboardURL `
|
||||
-SkipWarranty $SkipWarranty -LogPath $LogPath
|
||||
|
||||
} -ArgumentList $computer, $Credential, $ScriptPath, $ProxyURL, $DashboardURL, $SkipWarranty, $LogPath, (Get-Content $PSCommandPath | Out-String)
|
||||
|
||||
$jobs += $job
|
||||
}
|
||||
|
||||
# Wait for batch to complete
|
||||
$jobs | Wait-Job | Out-Null
|
||||
|
||||
# Collect results
|
||||
foreach ($job in $jobs) {
|
||||
$result = Receive-Job $job
|
||||
$results += $result
|
||||
Remove-Job $job
|
||||
$completed++
|
||||
|
||||
$computer = $result.Computer
|
||||
if ($result.Success) {
|
||||
Write-Host "[✓] $computer - Completed successfully" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "[✗] $computer - Failed: $($result.Message)" -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
|
||||
$jobs = @()
|
||||
Write-Host "Batch completed. Progress: $completed/$($validComputers.Count)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
# Summary
|
||||
$successful = ($results | Where-Object { $_.Success }).Count
|
||||
$failed = ($results | Where-Object { -not $_.Success }).Count
|
||||
|
||||
Write-Host "=== Collection Summary ===" -ForegroundColor Cyan
|
||||
Write-Host "Total computers: $($validComputers.Count)" -ForegroundColor White
|
||||
Write-Host "Successful: $successful" -ForegroundColor Green
|
||||
Write-Host "Failed: $failed" -ForegroundColor Red
|
||||
|
||||
if ($failed -gt 0) {
|
||||
Write-Host "`nFailed computers:" -ForegroundColor Yellow
|
||||
$results | Where-Object { -not $_.Success } | ForEach-Object {
|
||||
Write-Host " $($_.Computer): $($_.Message)" -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
|
||||
Write-Log "Collection completed. Success: $successful, Failed: $failed" $LogPath "INFO"
|
||||
|
||||
} catch {
|
||||
Write-Log "Fatal error: $($_.Exception.Message)" $LogPath "ERROR"
|
||||
exit 1
|
||||
}
|
||||
1384
scripts/Update-PC-CompleteAsset.ps1
Normal file
1384
scripts/Update-PC-CompleteAsset.ps1
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user