Files
shopdb/scripts/Invoke-RemoteAssetCollection.ps1
cproudlock 179d39eb99 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>
2025-12-09 13:12:49 -05:00

484 lines
17 KiB
PowerShell

#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
}