Update Invoke-RemoteAssetCollection-HTTPS.ps1 for production
- Changed DashboardURL to production: https://tsgwp00525.rd.ds.ge.com/shopdb/api.asp - Added SSL/TLS certificate bypass - Added TLS 1.2 protocol requirement 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
559
scripts/Invoke-RemoteAssetCollection-HTTPS.ps1
Normal file
559
scripts/Invoke-RemoteAssetCollection-HTTPS.ps1
Normal file
@@ -0,0 +1,559 @@
|
||||
#Requires -RunAsAdministrator
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Remotely executes asset collection script on shopfloor PCs using WinRM over HTTPS.
|
||||
|
||||
.DESCRIPTION
|
||||
This script uses WinRM HTTPS to securely execute the Update-PC-CompleteAsset.ps1 script
|
||||
on multiple shopfloor PCs. It handles:
|
||||
1. Secure HTTPS connections using wildcard certificates
|
||||
2. Automatic FQDN resolution from hostnames
|
||||
3. Credential management for remote connections
|
||||
4. Parallel execution across multiple PCs
|
||||
5. Error handling and logging for remote operations
|
||||
6. Collection of results from each remote PC
|
||||
|
||||
.PARAMETER HostnameList
|
||||
Array of computer hostnames (without domain suffix).
|
||||
|
||||
.PARAMETER HostnameListFile
|
||||
Path to a text file containing hostnames (one per line, without domain suffix).
|
||||
|
||||
.PARAMETER Domain
|
||||
Domain suffix for FQDNs (e.g., "logon.ds.ge.com").
|
||||
Will construct FQDNs as: hostname.domain
|
||||
|
||||
.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 Port
|
||||
HTTPS port for WinRM (default: 5986).
|
||||
|
||||
.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-https.log).
|
||||
|
||||
.PARAMETER TestConnections
|
||||
Test remote HTTPS 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
|
||||
|
||||
.PARAMETER SkipCertificateCheck
|
||||
Skip SSL certificate validation (not recommended for production).
|
||||
|
||||
.EXAMPLE
|
||||
# Collect from specific hostnames
|
||||
.\Invoke-RemoteAssetCollection-HTTPS.ps1 -HostnameList @("PC001", "PC002") -Domain "logon.ds.ge.com"
|
||||
|
||||
.EXAMPLE
|
||||
# Collect from hostnames in file
|
||||
.\Invoke-RemoteAssetCollection-HTTPS.ps1 -HostnameListFile ".\shopfloor-hostnames.txt" -Domain "logon.ds.ge.com"
|
||||
|
||||
.EXAMPLE
|
||||
# Test HTTPS connections only
|
||||
.\Invoke-RemoteAssetCollection-HTTPS.ps1 -HostnameList @("PC001") -Domain "logon.ds.ge.com" -TestConnections
|
||||
|
||||
.EXAMPLE
|
||||
# Use stored credentials
|
||||
$cred = Get-Credential
|
||||
.\Invoke-RemoteAssetCollection-HTTPS.ps1 -HostnameListFile ".\shopfloor-hostnames.txt" `
|
||||
-Domain "logon.ds.ge.com" -Credential $cred
|
||||
|
||||
.NOTES
|
||||
Author: System Administrator
|
||||
Date: 2025-10-17
|
||||
Version: 1.0
|
||||
|
||||
Prerequisites:
|
||||
1. WinRM HTTPS must be configured on target computers (use Setup-WinRM-HTTPS.ps1)
|
||||
2. Wildcard certificate installed on target computers
|
||||
3. PowerShell 5.1 or later
|
||||
4. Update-PC-CompleteAsset.ps1 must be present on target computers
|
||||
5. Credentials with admin rights on target computers
|
||||
6. Network connectivity to target computers on port 5986
|
||||
|
||||
Advantages over HTTP WinRM:
|
||||
- Encrypted traffic (credentials and data)
|
||||
- No TrustedHosts configuration required
|
||||
- Better security posture for production environments
|
||||
#>
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string[]]$HostnameList = @(),
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$HostnameListFile,
|
||||
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$Domain,
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[PSCredential]$Credential,
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[int]$MaxConcurrent = 5,
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[int]$Port = 5986,
|
||||
|
||||
[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-https.log",
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[switch]$TestConnections = $false,
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$ScriptPath = "C:\Scripts\Update-PC-CompleteAsset.ps1",
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[switch]$SkipCertificateCheck = $false
|
||||
)
|
||||
|
||||
# =============================================================================
|
||||
# SSL/TLS Certificate Bypass for HTTPS connections
|
||||
# =============================================================================
|
||||
try {
|
||||
if (-not ([System.Management.Automation.PSTypeName]'TrustAllCertsPolicy').Type) {
|
||||
Add-Type @"
|
||||
using System.Net;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
public class TrustAllCertsPolicy : ICertificatePolicy {
|
||||
public bool CheckValidationResult(
|
||||
ServicePoint srvPoint, X509Certificate certificate,
|
||||
WebRequest request, int certificateProblem) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
"@
|
||||
}
|
||||
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
|
||||
} catch { }
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||
|
||||
# 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 (HTTPS) 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[]]$HostnameList, [string]$HostnameListFile, [string]$Domain)
|
||||
|
||||
$hostnames = @()
|
||||
|
||||
# Add hostnames from direct list
|
||||
if ($HostnameList.Count -gt 0) {
|
||||
$hostnames += $HostnameList
|
||||
}
|
||||
|
||||
# Add hostnames from file
|
||||
if (-not [string]::IsNullOrEmpty($HostnameListFile)) {
|
||||
if (Test-Path $HostnameListFile) {
|
||||
$fileHostnames = Get-Content $HostnameListFile |
|
||||
Where-Object { $_.Trim() -ne "" -and -not $_.StartsWith("#") } |
|
||||
ForEach-Object { $_.Trim() }
|
||||
$hostnames += $fileHostnames
|
||||
} else {
|
||||
Write-Log "Hostname list file not found: $HostnameListFile" $LogPath "ERROR"
|
||||
}
|
||||
}
|
||||
|
||||
# Remove duplicates and construct FQDNs
|
||||
$fqdns = $hostnames |
|
||||
Sort-Object -Unique |
|
||||
ForEach-Object {
|
||||
$hostname = $_.Trim()
|
||||
# Remove domain if already present
|
||||
if ($hostname -like "*.$Domain") {
|
||||
$hostname
|
||||
} else {
|
||||
"$hostname.$Domain"
|
||||
}
|
||||
}
|
||||
|
||||
return $fqdns
|
||||
}
|
||||
|
||||
function Resolve-ComputerIP {
|
||||
param([string]$FQDN)
|
||||
|
||||
try {
|
||||
$result = Resolve-DnsName -Name $FQDN -Type A -ErrorAction Stop
|
||||
if ($result -and $result[0].IPAddress) {
|
||||
return $result[0].IPAddress
|
||||
}
|
||||
return $null
|
||||
}
|
||||
catch {
|
||||
return $null
|
||||
}
|
||||
}
|
||||
|
||||
function Test-WinRMHTTPSConnection {
|
||||
param([string]$ComputerName, [PSCredential]$Credential, [int]$Port, [bool]$SkipCertCheck)
|
||||
|
||||
try {
|
||||
$sessionOptions = New-PSSessionOption -SkipCACheck:$SkipCertCheck -SkipCNCheck:$SkipCertCheck
|
||||
|
||||
$session = New-PSSession -ComputerName $ComputerName `
|
||||
-Credential $Credential `
|
||||
-UseSSL `
|
||||
-Port $Port `
|
||||
-SessionOption $sessionOptions `
|
||||
-ErrorAction Stop
|
||||
|
||||
Remove-PSSession $session
|
||||
return $true
|
||||
}
|
||||
catch {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
function Test-RemoteScriptExists {
|
||||
param([string]$ComputerName, [PSCredential]$Credential, [string]$ScriptPath, [int]$Port, [bool]$SkipCertCheck)
|
||||
|
||||
try {
|
||||
$sessionOptions = New-PSSessionOption -SkipCACheck:$SkipCertCheck -SkipCNCheck:$SkipCertCheck
|
||||
|
||||
$result = Invoke-Command -ComputerName $ComputerName `
|
||||
-Credential $Credential `
|
||||
-UseSSL `
|
||||
-Port $Port `
|
||||
-SessionOption $sessionOptions `
|
||||
-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,
|
||||
[int]$Port,
|
||||
[bool]$SkipCertCheck,
|
||||
[string]$LogPath
|
||||
)
|
||||
|
||||
try {
|
||||
Write-Log "Starting asset collection on $ComputerName (HTTPS)" $LogPath "INFO"
|
||||
|
||||
$sessionOptions = New-PSSessionOption -SkipCACheck:$SkipCertCheck -SkipCNCheck:$SkipCertCheck
|
||||
|
||||
# Execute the script remotely
|
||||
$result = Invoke-Command -ComputerName $ComputerName `
|
||||
-Credential $Credential `
|
||||
-UseSSL `
|
||||
-Port $Port `
|
||||
-SessionOption $sessionOptions `
|
||||
-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"
|
||||
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-SetupInstructions {
|
||||
param([string]$Domain)
|
||||
|
||||
Write-Host "`n=== WinRM HTTPS Setup Instructions ===" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host "On each target computer, run the Setup-WinRM-HTTPS.ps1 script:" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
Write-Host " # With certificate PFX file:" -ForegroundColor Gray
|
||||
Write-Host " `$certPass = ConvertTo-SecureString 'Password' -AsPlainText -Force" -ForegroundColor White
|
||||
Write-Host " .\Setup-WinRM-HTTPS.ps1 -CertificatePath 'C:\Certs\wildcard.pfx' ``" -ForegroundColor White
|
||||
Write-Host " -CertificatePassword `$certPass -Domain '$Domain'" -ForegroundColor White
|
||||
Write-Host ""
|
||||
Write-Host " # Or with existing certificate:" -ForegroundColor Gray
|
||||
Write-Host " .\Setup-WinRM-HTTPS.ps1 -CertificateThumbprint 'THUMBPRINT' -Domain '$Domain'" -ForegroundColor White
|
||||
Write-Host ""
|
||||
Write-Host "This will:" -ForegroundColor Yellow
|
||||
Write-Host " 1. Install/locate the wildcard certificate" -ForegroundColor White
|
||||
Write-Host " 2. Create HTTPS listener on port 5986" -ForegroundColor White
|
||||
Write-Host " 3. Configure Windows Firewall" -ForegroundColor White
|
||||
Write-Host " 4. Enable WinRM service" -ForegroundColor White
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
# Main execution
|
||||
try {
|
||||
Write-Host "=== Remote Asset Collection Script (HTTPS) ===" -ForegroundColor Cyan
|
||||
Write-Host "Starting at $(Get-Date)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
|
||||
# Initialize logging
|
||||
Initialize-Logging -LogPath $LogPath
|
||||
|
||||
# Get target computers
|
||||
$fqdns = Get-ComputerTargets -HostnameList $HostnameList -HostnameListFile $HostnameListFile -Domain $Domain
|
||||
|
||||
if ($fqdns.Count -eq 0) {
|
||||
Write-Log "No target computers specified. Use -HostnameList or -HostnameListFile parameter." $LogPath "ERROR"
|
||||
Show-SetupInstructions -Domain $Domain
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Log "Target computers (FQDNs): $($fqdns -join ', ')" $LogPath "INFO"
|
||||
|
||||
# Resolve IP addresses
|
||||
Write-Host "`nResolving IP addresses..." -ForegroundColor Yellow
|
||||
$resolvedComputers = @()
|
||||
foreach ($fqdn in $fqdns) {
|
||||
Write-Host "Resolving $fqdn..." -NoNewline
|
||||
$ip = Resolve-ComputerIP -FQDN $fqdn
|
||||
if ($ip) {
|
||||
Write-Host " [$ip]" -ForegroundColor Green
|
||||
$resolvedComputers += @{ FQDN = $fqdn; IP = $ip }
|
||||
Write-Log "Resolved $fqdn to $ip" $LogPath "INFO"
|
||||
} else {
|
||||
Write-Host " [DNS FAILED]" -ForegroundColor Red
|
||||
Write-Log "Failed to resolve $fqdn" $LogPath "WARN"
|
||||
}
|
||||
}
|
||||
|
||||
if ($resolvedComputers.Count -eq 0) {
|
||||
Write-Log "No computers could be resolved via DNS" $LogPath "ERROR"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Get credentials if not provided
|
||||
if (-not $Credential) {
|
||||
Write-Host "`nEnter 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 HTTPS connections only..." -ForegroundColor Yellow
|
||||
foreach ($comp in $resolvedComputers) {
|
||||
$fqdn = $comp.FQDN
|
||||
Write-Host "Testing $fqdn..." -NoNewline
|
||||
if (Test-WinRMHTTPSConnection -ComputerName $fqdn -Credential $Credential -Port $Port -SkipCertCheck $SkipCertificateCheck) {
|
||||
Write-Host " [OK]" -ForegroundColor Green
|
||||
Write-Log "HTTPS connection test successful for $fqdn" $LogPath "SUCCESS"
|
||||
} else {
|
||||
Write-Host " [FAIL]" -ForegroundColor Red
|
||||
Write-Log "HTTPS connection test failed for $fqdn" $LogPath "ERROR"
|
||||
}
|
||||
}
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Validate all connections and script existence before starting collection
|
||||
Write-Host "`nValidating remote HTTPS connections and script availability..." -ForegroundColor Yellow
|
||||
$validComputers = @()
|
||||
|
||||
foreach ($comp in $resolvedComputers) {
|
||||
$fqdn = $comp.FQDN
|
||||
Write-Host "Validating $fqdn..." -NoNewline
|
||||
|
||||
if (-not (Test-WinRMHTTPSConnection -ComputerName $fqdn -Credential $Credential -Port $Port -SkipCertCheck $SkipCertificateCheck)) {
|
||||
Write-Host " [CONNECTION FAILED]" -ForegroundColor Red
|
||||
Write-Log "Cannot connect to $fqdn via WinRM HTTPS" $LogPath "ERROR"
|
||||
continue
|
||||
}
|
||||
|
||||
if (-not (Test-RemoteScriptExists -ComputerName $fqdn -Credential $Credential -ScriptPath $ScriptPath -Port $Port -SkipCertCheck $SkipCertificateCheck)) {
|
||||
Write-Host " [SCRIPT NOT FOUND]" -ForegroundColor Red
|
||||
Write-Log "Script not found on $fqdn at $ScriptPath" $LogPath "ERROR"
|
||||
continue
|
||||
}
|
||||
|
||||
Write-Host " [OK]" -ForegroundColor Green
|
||||
$validComputers += $comp
|
||||
}
|
||||
|
||||
if ($validComputers.Count -eq 0) {
|
||||
Write-Log "No valid computers found for data collection" $LogPath "ERROR"
|
||||
Show-SetupInstructions -Domain $Domain
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Log "Valid computers for collection: $($validComputers.FQDN -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 "Using HTTPS on port: $Port" -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.FQDN -join ', ')" -ForegroundColor Yellow
|
||||
|
||||
# Start jobs for current batch
|
||||
foreach ($comp in $batch) {
|
||||
$fqdn = $comp.FQDN
|
||||
|
||||
$job = Start-Job -ScriptBlock {
|
||||
param($FQDN, $Credential, $ScriptPath, $ProxyURL, $DashboardURL, $SkipWarranty, $Port, $SkipCertCheck, $LogPath, $Functions)
|
||||
|
||||
# Import functions into job scope
|
||||
Invoke-Expression $Functions
|
||||
|
||||
Invoke-RemoteAssetScript -ComputerName $FQDN -Credential $Credential `
|
||||
-ScriptPath $ScriptPath -ProxyURL $ProxyURL -DashboardURL $DashboardURL `
|
||||
-SkipWarranty $SkipWarranty -Port $Port -SkipCertCheck $SkipCertCheck -LogPath $LogPath
|
||||
|
||||
} -ArgumentList $fqdn, $Credential, $ScriptPath, $ProxyURL, $DashboardURL, $SkipWarranty, $Port, $SkipCertificateCheck, $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 "[OK] $computer - Completed successfully" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "[FAIL] $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
|
||||
}
|
||||
Reference in New Issue
Block a user