Initial commit: Organized PowerShell scripts for ShopDB asset collection

Structure:
- asset-collection/: Local PC data collection scripts
- remote-execution/: WinRM remote execution scripts
- setup-utilities/: Configuration and testing utilities
- registry-backup/: GE registry backup scripts
- winrm-https/: WinRM HTTPS certificate setup
- docs/: Complete documentation

Each folder includes a README with detailed documentation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
cproudlock
2025-12-10 10:57:54 -05:00
commit 62c0c7bb06
102 changed files with 28017 additions and 0 deletions

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

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

171
remote-execution/README.md Normal file
View File

@@ -0,0 +1,171 @@
# Remote Execution Scripts
Scripts for remotely executing asset collection on multiple shopfloor PCs via WinRM.
## Scripts
### Invoke-RemoteAssetCollection.ps1
**Remote collection via WinRM HTTP** - Execute asset collection on multiple PCs using WinRM over HTTP (port 5985).
**What it does:**
1. Establishes WinRM connections to target PCs
2. Executes `Update-PC-CompleteAsset.ps1` remotely
3. Collects and logs results from each PC
4. Supports parallel execution for efficiency
**Usage:**
```powershell
# From file with prompted credentials
.\Invoke-RemoteAssetCollection.ps1 -ComputerListFile ".\shopfloor-pcs.txt"
# Specific computers with stored credentials
$cred = Get-Credential
.\Invoke-RemoteAssetCollection.ps1 -ComputerList @("PC001","PC002") -Credential $cred
# Test connections only
.\Invoke-RemoteAssetCollection.ps1 -ComputerList @("PC001") -TestConnections
```
**Parameters:**
| Parameter | Default | Description |
|-----------|---------|-------------|
| `-ComputerList` | - | Array of computer names/IPs |
| `-ComputerListFile` | - | Path to text file with computer list |
| `-Credential` | - | PSCredential for authentication |
| `-MaxConcurrent` | `5` | Maximum parallel sessions |
| `-TestConnections` | `$false` | Test connectivity only |
| `-ScriptPath` | `C:\Scripts\Update-PC-CompleteAsset.ps1` | Path to script on remote PCs |
**Prerequisites:**
- WinRM enabled on target PCs (`Enable-PSRemoting -Force`)
- Admin credentials for remote PCs
- Port 5985 (HTTP) open in firewall
---
### Invoke-RemoteAssetCollection-HTTPS.ps1
**Secure remote collection via WinRM HTTPS** - Same as above but uses encrypted HTTPS connections (port 5986).
**What it does:**
- Uses HTTPS/TLS encryption for secure communication
- Supports wildcard certificates for domain-wide deployment
- Automatic FQDN construction from hostnames
**Usage:**
```powershell
# With domain suffix
.\Invoke-RemoteAssetCollection-HTTPS.ps1 -HostnameList @("PC001","PC002") -Domain "logon.ds.ge.com"
# From file
.\Invoke-RemoteAssetCollection-HTTPS.ps1 -HostnameListFile ".\hostnames.txt" -Domain "logon.ds.ge.com"
# Test HTTPS connections
.\Invoke-RemoteAssetCollection-HTTPS.ps1 -HostnameList @("PC001") -Domain "logon.ds.ge.com" -TestConnections
```
**Parameters:**
| Parameter | Default | Description |
|-----------|---------|-------------|
| `-HostnameList` | - | Array of hostnames (without domain) |
| `-HostnameListFile` | - | Path to text file with hostnames |
| `-Domain` | - | Domain suffix (e.g., "logon.ds.ge.com") |
| `-Port` | `5986` | HTTPS port |
| `-SkipCertificateCheck` | `$false` | Skip SSL validation |
**Prerequisites:**
- WinRM HTTPS configured on targets (see `winrm-https/` folder)
- Valid SSL certificates installed
- Port 5986 open in firewall
---
### Update-ShopfloorPCs-Remote.ps1
**Query and update all shopfloor PCs** - Queries ShopDB for PC list and updates them remotely.
**What it does:**
1. Queries ShopDB API for list of all shopfloor PCs
2. Establishes WinRM connections to each PC
3. Collects system info remotely and POSTs to API
4. Logs success/failure for each PC
**Usage:**
```powershell
# Update all shopfloor PCs from ShopDB database
.\Update-ShopfloorPCs-Remote.ps1 -All
# Update specific PCs
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "PC001","PC002"
# Setup WinRM trusted hosts first
.\Update-ShopfloorPCs-Remote.ps1 -SetupTrustedHosts
```
**Parameters:**
| Parameter | Default | Description |
|-----------|---------|-------------|
| `-ComputerName` | - | Specific PC(s) to update |
| `-All` | `$false` | Update all shopfloor PCs from ShopDB |
| `-SetupTrustedHosts` | `$false` | Configure WinRM trusted hosts |
| `-Credential` | - | PSCredential for authentication |
| `-ApiUrl` | Production URL | ShopDB API URL |
---
## Batch File Launchers
| File | Purpose |
|------|---------|
| `Run-RemoteCollection.bat` | Launcher for remote collection script |
---
## Requirements
- PowerShell 5.1 or later
- **Administrator privileges** (required)
- WinRM enabled on management server and target PCs
- Network access to target PCs (ports 5985 or 5986)
- Admin credentials for target PCs
## Architecture
```
┌─────────────────────────────────────┐
│ Management Server │
│ ┌───────────────────────────────┐ │
│ │ Invoke-RemoteAssetCollection │ │
│ │ Update-ShopfloorPCs-Remote │ │
│ └──────────────┬────────────────┘ │
└─────────────────┼───────────────────┘
│ WinRM (5985/5986)
┌─────────────────────────────────────┐
│ Shopfloor PC 1 │
│ ┌───────────────────────────────┐ │
│ │ Update-PC-CompleteAsset.ps1 │ │
│ └───────────────────────────────┘ │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ Shopfloor PC 2 │
│ ┌───────────────────────────────┐ │
│ │ Update-PC-CompleteAsset.ps1 │ │
│ └───────────────────────────────┘ │
└─────────────────────────────────────┘
... (parallel execution)
```
## WinRM Setup
### On Management Server:
```powershell
Enable-PSRemoting -Force
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "*" -Force
```
### On Target PCs:
```powershell
Enable-PSRemoting -Force
Set-NetFirewallRule -DisplayName "Windows Remote Management (HTTP-In)" -Enabled True
```
For HTTPS setup, see the `winrm-https/` folder documentation.

View File

@@ -0,0 +1,25 @@
@echo off
REM Batch file to run remote asset collection
REM Requires administrator privileges
echo === Remote Asset Collection ===
echo.
REM Check for admin privileges
net session >nul 2>&1
if %errorLevel% neq 0 (
echo This script requires administrator privileges.
echo Please run as administrator.
pause
exit /b 1
)
echo Starting PowerShell script...
echo.
REM Run the PowerShell script with execution policy bypass
powershell.exe -ExecutionPolicy Bypass -File "%~dp0Invoke-RemoteAssetCollection.ps1" -ComputerListFile "%~dp0shopfloor-pcs.txt"
echo.
echo Collection completed. Check logs folder for details.
pause

File diff suppressed because it is too large Load Diff