Add reboot mode, TLS fallback, kiosk app detection, and user registry scanning
- Add -Reboot/-MinUptimeDays parameter set to reboot high-uptime PCs via API - Add WebClient fallback for TLS/SSL connection errors on API calls - Add per-user registry scanning (HKU hives) for installed app detection - Add Dashboard and Lobby Display kiosk app detection (app IDs 82, 83) - Add SkipCertificateCheck support for PowerShell 7+ - Increase session timeouts (20s connect, 120s operation) - Increase default ThrottleLimit from 10 to 25 - Add Install-KioskApp.ps1 and user registry detection test scripts Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -35,6 +35,18 @@
|
||||
$cred = Get-Credential
|
||||
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "SHOPFLOOR-PC01" -Credential $cred
|
||||
|
||||
.EXAMPLE
|
||||
# Reboot all PCs with uptime >= 30 days (will prompt for confirmation)
|
||||
.\Update-ShopfloorPCs-Remote.ps1 -Reboot -MinUptimeDays 30
|
||||
|
||||
.EXAMPLE
|
||||
# Preview which PCs would be rebooted (no actual reboot)
|
||||
.\Update-ShopfloorPCs-Remote.ps1 -Reboot -MinUptimeDays 30 -WhatIf
|
||||
|
||||
.EXAMPLE
|
||||
# Reboot PCs with uptime >= 60 days without confirmation prompt
|
||||
.\Update-ShopfloorPCs-Remote.ps1 -Reboot -MinUptimeDays 60 -Force -Credential $cred
|
||||
|
||||
.NOTES
|
||||
Requires:
|
||||
- WinRM enabled on target PCs (Enable-PSRemoting)
|
||||
@@ -53,6 +65,15 @@ param(
|
||||
[Parameter(ParameterSetName='SetupTrust')]
|
||||
[switch]$SetupTrustedHosts,
|
||||
|
||||
[Parameter(ParameterSetName='Reboot', Mandatory)]
|
||||
[switch]$Reboot,
|
||||
|
||||
[Parameter(ParameterSetName='Reboot', Mandatory)]
|
||||
[int]$MinUptimeDays,
|
||||
|
||||
[Parameter(ParameterSetName='Reboot')]
|
||||
[switch]$Force,
|
||||
|
||||
[Parameter()]
|
||||
[PSCredential]$Credential,
|
||||
|
||||
@@ -69,16 +90,36 @@ param(
|
||||
[switch]$UseSSL,
|
||||
|
||||
[Parameter()]
|
||||
[int]$ThrottleLimit = 10,
|
||||
[int]$ThrottleLimit = 25,
|
||||
|
||||
[Parameter()]
|
||||
[switch]$WhatIf
|
||||
)
|
||||
|
||||
# SSL/TLS Certificate Bypass for HTTPS connections
|
||||
# SSL/TLS Configuration - MUST be set before any web requests
|
||||
# Set ALL modern TLS versions - fixes "underlying connection was closed" errors
|
||||
try {
|
||||
if (-not ([System.Management.Automation.PSTypeName]'TrustAllCertsPolicy').Type) {
|
||||
Add-Type @"
|
||||
# Enable all available TLS protocols (1.0, 1.1, 1.2, 1.3 if available)
|
||||
$protocols = [Net.SecurityProtocolType]::Tls12
|
||||
try { $protocols = $protocols -bor [Net.SecurityProtocolType]::Tls13 } catch {}
|
||||
try { $protocols = $protocols -bor [Net.SecurityProtocolType]::Tls11 } catch {}
|
||||
try { $protocols = $protocols -bor [Net.SecurityProtocolType]::Tls } catch {}
|
||||
[Net.ServicePointManager]::SecurityProtocol = $protocols
|
||||
} catch {
|
||||
# Absolute fallback
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||
}
|
||||
|
||||
# Increase connection limits and timeouts
|
||||
[Net.ServicePointManager]::DefaultConnectionLimit = 100
|
||||
[Net.ServicePointManager]::Expect100Continue = $false
|
||||
[Net.ServicePointManager]::MaxServicePointIdleTime = 10000
|
||||
|
||||
# Certificate Bypass for HTTPS connections (self-signed certs) - PowerShell 5.x
|
||||
if ($PSVersionTable.PSVersion.Major -lt 7) {
|
||||
try {
|
||||
if (-not ([System.Management.Automation.PSTypeName]'TrustAllCertsPolicy').Type) {
|
||||
Add-Type @"
|
||||
using System.Net;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
public class TrustAllCertsPolicy : ICertificatePolicy {
|
||||
@@ -89,10 +130,22 @@ public class TrustAllCertsPolicy : ICertificatePolicy {
|
||||
}
|
||||
}
|
||||
"@
|
||||
}
|
||||
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
|
||||
} catch {
|
||||
Write-Warning "Could not set certificate policy: $_"
|
||||
}
|
||||
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
|
||||
} catch { }
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||
|
||||
# Also set callback for newer .NET versions (backup method)
|
||||
try {
|
||||
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { param($sender, $cert, $chain, $errors) return $true }
|
||||
} catch {}
|
||||
}
|
||||
|
||||
# Load System.Web for URL encoding (used in WebClient fallback)
|
||||
try {
|
||||
Add-Type -AssemblyName System.Web -ErrorAction SilentlyContinue
|
||||
} catch {}
|
||||
|
||||
#region Functions
|
||||
|
||||
@@ -115,21 +168,108 @@ function Get-ShopfloorPCsFromApi {
|
||||
#>
|
||||
param([string]$ApiUrl)
|
||||
|
||||
$fullUrl = "$ApiUrl`?action=getShopfloorPCs"
|
||||
Write-Log "Querying API: $fullUrl" -Level "INFO"
|
||||
|
||||
# Try PowerShell native method first
|
||||
try {
|
||||
Write-Log "Querying API: $ApiUrl`?action=getShopfloorPCs" -Level "INFO"
|
||||
$response = Invoke-RestMethod -Uri "$ApiUrl`?action=getShopfloorPCs" -Method Get -ErrorAction Stop
|
||||
# Build params - use SkipCertificateCheck for PS7+, rely on ServicePointManager for PS5
|
||||
$restParams = @{
|
||||
Uri = $fullUrl
|
||||
Method = 'Get'
|
||||
ErrorAction = 'Stop'
|
||||
UseBasicParsing = $true
|
||||
TimeoutSec = 30
|
||||
}
|
||||
|
||||
# Add SkipCertificateCheck for PowerShell 7+
|
||||
if ($PSVersionTable.PSVersion.Major -ge 7) {
|
||||
$restParams.SkipCertificateCheck = $true
|
||||
}
|
||||
|
||||
$response = Invoke-RestMethod @restParams
|
||||
|
||||
if ($response.success -and $response.data) {
|
||||
Write-Log "API returned $($response.count) shopfloor PCs" -Level "SUCCESS"
|
||||
|
||||
# Return full PC objects, not just hostnames
|
||||
return $response.data
|
||||
} else {
|
||||
Write-Log "No shopfloor PCs returned from API" -Level "WARNING"
|
||||
return @()
|
||||
}
|
||||
} catch {
|
||||
Write-Log "Failed to query API for shopfloor PCs: $_" -Level "ERROR"
|
||||
$errMsg = $_.Exception.Message
|
||||
$innerMsg = if ($_.Exception.InnerException) { $_.Exception.InnerException.Message } else { "" }
|
||||
|
||||
# Check if it's a TLS/connection error - try WebClient as fallback
|
||||
if ($errMsg -match "underlying connection|closed|SSL|TLS|secure channel" -or $innerMsg -match "underlying connection|closed|SSL|TLS|secure channel") {
|
||||
Write-Log "TLS error detected, trying WebClient fallback..." -Level "WARNING"
|
||||
|
||||
try {
|
||||
$webClient = New-Object System.Net.WebClient
|
||||
$webClient.Headers.Add("User-Agent", "PowerShell/ShopDB-Updater")
|
||||
$jsonResponse = $webClient.DownloadString($fullUrl)
|
||||
$response = $jsonResponse | ConvertFrom-Json
|
||||
|
||||
if ($response.success -and $response.data) {
|
||||
Write-Log "API returned $($response.count) shopfloor PCs (via WebClient)" -Level "SUCCESS"
|
||||
return $response.data
|
||||
} else {
|
||||
Write-Log "No shopfloor PCs returned from API" -Level "WARNING"
|
||||
return @()
|
||||
}
|
||||
} catch {
|
||||
Write-Log "WebClient fallback also failed: $($_.Exception.Message)" -Level "ERROR"
|
||||
}
|
||||
}
|
||||
|
||||
Write-Log "Failed to query API for shopfloor PCs: $errMsg" -Level "ERROR"
|
||||
Write-Log " Exception Type: $($_.Exception.GetType().FullName)" -Level "ERROR"
|
||||
if ($innerMsg) {
|
||||
Write-Log " Inner Exception: $innerMsg" -Level "ERROR"
|
||||
}
|
||||
Write-Log " Tip: Try using HTTP instead of HTTPS, or check if the server certificate is valid" -Level "INFO"
|
||||
return @()
|
||||
}
|
||||
}
|
||||
|
||||
function Get-HighUptimePCsFromApi {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Queries ShopDB API to get PCs with uptime >= specified days.
|
||||
#>
|
||||
param(
|
||||
[string]$ApiUrl,
|
||||
[int]$MinUptimeDays
|
||||
)
|
||||
|
||||
$fullUrl = "$ApiUrl`?action=getHighUptimePCs&minUptime=$MinUptimeDays"
|
||||
Write-Log "Querying API for PCs with uptime >= $MinUptimeDays days: $fullUrl" -Level "INFO"
|
||||
|
||||
try {
|
||||
$restParams = @{
|
||||
Uri = $fullUrl
|
||||
Method = 'Get'
|
||||
ErrorAction = 'Stop'
|
||||
UseBasicParsing = $true
|
||||
TimeoutSec = 30
|
||||
}
|
||||
|
||||
if ($PSVersionTable.PSVersion.Major -ge 7) {
|
||||
$restParams.SkipCertificateCheck = $true
|
||||
}
|
||||
|
||||
$response = Invoke-RestMethod @restParams
|
||||
|
||||
if ($response.success -and $response.data) {
|
||||
Write-Log "API returned $($response.count) PCs with uptime >= $MinUptimeDays days" -Level "SUCCESS"
|
||||
return $response.data
|
||||
} else {
|
||||
Write-Log "No high-uptime PCs returned from API" -Level "WARNING"
|
||||
return @()
|
||||
}
|
||||
} catch {
|
||||
$errMsg = $_.Exception.Message
|
||||
Write-Log "Failed to query API for high-uptime PCs: $errMsg" -Level "ERROR"
|
||||
return @()
|
||||
}
|
||||
}
|
||||
@@ -461,7 +601,8 @@ function Get-RemotePCInfo {
|
||||
$hasVnc = $false
|
||||
$regPaths = @(
|
||||
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*",
|
||||
"HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*"
|
||||
"HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*",
|
||||
"HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*"
|
||||
)
|
||||
foreach ($path in $regPaths) {
|
||||
if (Test-Path $path) {
|
||||
@@ -486,6 +627,8 @@ function Get-RemotePCInfo {
|
||||
# Get all installed apps once for efficiency (with version info)
|
||||
$installedApps = @()
|
||||
$installedAppsWithVersion = @()
|
||||
|
||||
# Check machine-wide registry paths
|
||||
foreach ($path in $regPaths) {
|
||||
if (Test-Path $path) {
|
||||
$apps = Get-ItemProperty $path -ErrorAction SilentlyContinue |
|
||||
@@ -500,6 +643,29 @@ function Get-RemotePCInfo {
|
||||
}
|
||||
}
|
||||
|
||||
# Check per-user installed apps by enumerating loaded hives in HKU
|
||||
$hkuKeys = Get-ChildItem "Registry::HKU" -ErrorAction SilentlyContinue
|
||||
foreach ($key in $hkuKeys) {
|
||||
$sid = $key.PSChildName
|
||||
# Only check real user SIDs (S-1-5-21-*), skip _Classes entries
|
||||
if ($sid -match "^S-1-5-21-" -and $sid -notmatch "_Classes$") {
|
||||
$userUninstallPath = "Registry::HKU\$sid\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*"
|
||||
if (Test-Path $userUninstallPath -ErrorAction SilentlyContinue) {
|
||||
$apps = Get-ItemProperty $userUninstallPath -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.DisplayName -and $_.DisplayName.Trim() -ne "" }
|
||||
foreach ($app in $apps) {
|
||||
if ($app.DisplayName -notin $installedApps) {
|
||||
$installedApps += $app.DisplayName
|
||||
$installedAppsWithVersion += @{
|
||||
DisplayName = $app.DisplayName.Trim()
|
||||
Version = if ($app.DisplayVersion) { $app.DisplayVersion.Trim() } else { "" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ================================================================
|
||||
# Match against tracked applications (embedded from applications.csv)
|
||||
# ================================================================
|
||||
@@ -520,6 +686,8 @@ function Get-RemotePCInfo {
|
||||
@{ app_id = 74; app_name = "DODA"; patterns = @("Dovetail Digital Analysis", "DODA") }
|
||||
@{ app_id = 75; app_name = "FormStatusMonitor"; patterns = @("FormStatusMonitor") }
|
||||
@{ app_id = 77; app_name = "HeatTreat"; patterns = @("HeatTreat") }
|
||||
@{ app_id = 82; app_name = "GE Aerospace Dashboard"; patterns = @("^GE Aerospace Dashboard") }
|
||||
@{ app_id = 83; app_name = "GE Aerospace Lobby Display"; patterns = @("^GE Aerospace Lobby Display") }
|
||||
)
|
||||
|
||||
$matchedApps = @()
|
||||
@@ -678,10 +846,36 @@ function Get-RemotePCInfo {
|
||||
}
|
||||
$result.HasHeatTreat = $hasHeatTreat
|
||||
|
||||
# Dashboard Detection (GE Aerospace Dashboard kiosk installer)
|
||||
$hasDashboard = $false
|
||||
foreach ($app in $installedApps) {
|
||||
if ($app -match "^GE Aerospace Dashboard") {
|
||||
$hasDashboard = $true
|
||||
break
|
||||
}
|
||||
}
|
||||
$result.HasDashboard = $hasDashboard
|
||||
$result.IsDashboard = $hasDashboard
|
||||
|
||||
# Lobby Display Detection (GE Aerospace Lobby Display kiosk installer)
|
||||
$hasLobbyDisplay = $false
|
||||
foreach ($app in $installedApps) {
|
||||
if ($app -match "^GE Aerospace Lobby Display") {
|
||||
$hasLobbyDisplay = $true
|
||||
break
|
||||
}
|
||||
}
|
||||
$result.HasLobbyDisplay = $hasLobbyDisplay
|
||||
$result.IsLobbyDisplay = $hasLobbyDisplay
|
||||
|
||||
# Determine PC Type based on detected software
|
||||
# Priority: CMM > Wax Trace > Keyence > EAS1000 > Genspect > Heat Treat > Generic hint > Shopfloor (default)
|
||||
# Priority: Dashboard > Lobby Display > CMM > Wax Trace > Keyence > EAS1000 > Genspect > Heat Treat > Generic hint > Shopfloor (default)
|
||||
$detectedPcType = "Shopfloor" # Default for shopfloor PCs
|
||||
if ($result.IsCMM) {
|
||||
if ($hasDashboard) {
|
||||
$detectedPcType = "Dashboard"
|
||||
} elseif ($hasLobbyDisplay) {
|
||||
$detectedPcType = "Lobby Display"
|
||||
} elseif ($result.IsCMM) {
|
||||
$detectedPcType = "CMM"
|
||||
} elseif ($result.IsWaxTrace) {
|
||||
$detectedPcType = "Wax Trace"
|
||||
@@ -776,8 +970,23 @@ function Send-PCDataToApi {
|
||||
$postData.installedApps = $PCData.MatchedAppsJson
|
||||
}
|
||||
|
||||
# Build params for API call
|
||||
$restParams = @{
|
||||
Uri = $ApiUrl
|
||||
Method = 'Post'
|
||||
Body = $postData
|
||||
ErrorAction = 'Stop'
|
||||
UseBasicParsing = $true
|
||||
TimeoutSec = 30
|
||||
}
|
||||
|
||||
# Add SkipCertificateCheck for PowerShell 7+
|
||||
if ($PSVersionTable.PSVersion.Major -ge 7) {
|
||||
$restParams.SkipCertificateCheck = $true
|
||||
}
|
||||
|
||||
# Send to API
|
||||
$response = Invoke-RestMethod -Uri $ApiUrl -Method Post -Body $postData -ErrorAction Stop
|
||||
$response = Invoke-RestMethod @restParams
|
||||
|
||||
return @{
|
||||
Success = $response.success
|
||||
@@ -785,9 +994,37 @@ function Send-PCDataToApi {
|
||||
MachineId = $response.machineid
|
||||
}
|
||||
} catch {
|
||||
$errMsg = $_.Exception.Message
|
||||
$innerMsg = if ($_.Exception.InnerException) { $_.Exception.InnerException.Message } else { "" }
|
||||
|
||||
# Try WebClient fallback for TLS errors
|
||||
if ($errMsg -match "underlying connection|closed|SSL|TLS|secure channel" -or $innerMsg -match "underlying connection|closed|SSL|TLS|secure channel") {
|
||||
try {
|
||||
$webClient = New-Object System.Net.WebClient
|
||||
$webClient.Headers.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||
$webClient.Headers.Add("User-Agent", "PowerShell/ShopDB-Updater")
|
||||
|
||||
# Convert postData hashtable to form-urlencoded string
|
||||
$formData = ($postData.GetEnumerator() | ForEach-Object {
|
||||
"$([System.Web.HttpUtility]::UrlEncode($_.Key))=$([System.Web.HttpUtility]::UrlEncode($_.Value))"
|
||||
}) -join "&"
|
||||
|
||||
$jsonResponse = $webClient.UploadString($ApiUrl, $formData)
|
||||
$response = $jsonResponse | ConvertFrom-Json
|
||||
|
||||
return @{
|
||||
Success = $response.success
|
||||
Message = $response.message
|
||||
MachineId = $response.machineid
|
||||
}
|
||||
} catch {
|
||||
# WebClient also failed
|
||||
}
|
||||
}
|
||||
|
||||
return @{
|
||||
Success = $false
|
||||
Message = $_.Exception.Message
|
||||
Message = if ($innerMsg) { "$errMsg ($innerMsg)" } else { $errMsg }
|
||||
MachineId = $null
|
||||
}
|
||||
}
|
||||
@@ -815,6 +1052,121 @@ if ($SetupTrustedHosts) {
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Handle Reboot mode
|
||||
if ($Reboot) {
|
||||
Write-Log "=== Reboot Mode ===" -Level "INFO"
|
||||
Write-Log "Minimum Uptime: $MinUptimeDays days" -Level "INFO"
|
||||
Write-Log "API URL: $ApiUrl" -Level "INFO"
|
||||
|
||||
# Query API for high-uptime PCs
|
||||
$highUptimePCs = Get-HighUptimePCsFromApi -ApiUrl $ApiUrl -MinUptimeDays $MinUptimeDays
|
||||
|
||||
if ($highUptimePCs.Count -eq 0) {
|
||||
Write-Log "No PCs found with uptime >= $MinUptimeDays days" -Level "WARNING"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Display PCs to be rebooted
|
||||
Write-Host ""
|
||||
Write-Host "=" * 80 -ForegroundColor Red
|
||||
Write-Host " WARNING: The following $($highUptimePCs.Count) PCs will be REBOOTED" -ForegroundColor Red
|
||||
Write-Host "=" * 80 -ForegroundColor Red
|
||||
Write-Host ""
|
||||
Write-Host (" {0,-25} {1,-15} {2,-12} {3,-20}" -f "Hostname", "Machine #", "Uptime Days", "Last Boot") -ForegroundColor Yellow
|
||||
Write-Host " $("-" * 75)" -ForegroundColor Gray
|
||||
|
||||
foreach ($pc in $highUptimePCs) {
|
||||
$machineNo = if ($pc.machinenumber) { $pc.machinenumber } else { "-" }
|
||||
$uptimeDays = if ($pc.uptime_days) { $pc.uptime_days } else { "?" }
|
||||
$lastBoot = if ($pc.lastboottime) { $pc.lastboottime } else { "Unknown" }
|
||||
Write-Host (" {0,-25} {1,-15} {2,-12} {3,-20}" -f $pc.hostname, $machineNo, $uptimeDays, $lastBoot)
|
||||
}
|
||||
|
||||
Write-Host " $("-" * 75)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
|
||||
if ($WhatIf) {
|
||||
Write-Log "WhatIf mode - no reboots will be performed" -Level "WARNING"
|
||||
Write-Host " Would reboot $($highUptimePCs.Count) PCs" -ForegroundColor Yellow
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Confirmation
|
||||
if (-not $Force) {
|
||||
Write-Host " Are you sure you want to reboot these $($highUptimePCs.Count) PCs?" -ForegroundColor Red
|
||||
Write-Host ""
|
||||
$confirm = Read-Host " Type 'YES' to confirm"
|
||||
if ($confirm -ne "YES") {
|
||||
Write-Log "Reboot cancelled by user" -Level "WARNING"
|
||||
exit 0
|
||||
}
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
# Prompt for credentials if not provided
|
||||
if (-not $Credential) {
|
||||
Write-Log "No credentials provided. Prompting for credentials..." -Level "INFO"
|
||||
$Credential = Get-Credential -Message "Enter admin credentials for remote PCs"
|
||||
if (-not $Credential) {
|
||||
Write-Log "Credentials required. Exiting." -Level "ERROR"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
Write-Log "Starting reboot process..." -Level "INFO"
|
||||
|
||||
# Build FQDN list
|
||||
$targetPCs = @()
|
||||
foreach ($pc in $highUptimePCs) {
|
||||
$fqdn = if ($pc.hostname -like "*.*") { $pc.hostname } else { "$($pc.hostname).$DnsSuffix" }
|
||||
$targetPCs += @{
|
||||
Hostname = $pc.hostname
|
||||
FQDN = $fqdn
|
||||
UptimeDays = $pc.uptime_days
|
||||
}
|
||||
}
|
||||
|
||||
# Reboot each PC
|
||||
$rebootSuccess = 0
|
||||
$rebootFailed = 0
|
||||
|
||||
foreach ($target in $targetPCs) {
|
||||
Write-Log "Rebooting $($target.Hostname) (uptime: $($target.UptimeDays) days)..." -Level "INFO"
|
||||
|
||||
try {
|
||||
$rebootParams = @{
|
||||
ComputerName = $target.FQDN
|
||||
Force = $true
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
if ($Credential) {
|
||||
$rebootParams.Credential = $Credential
|
||||
}
|
||||
|
||||
Restart-Computer @rebootParams
|
||||
Write-Log " -> Reboot command sent successfully" -Level "SUCCESS"
|
||||
$rebootSuccess++
|
||||
} catch {
|
||||
Write-Log " -> FAILED: $($_.Exception.Message)" -Level "ERROR"
|
||||
$rebootFailed++
|
||||
}
|
||||
}
|
||||
|
||||
# Summary
|
||||
Write-Host ""
|
||||
Write-Host "=" * 60 -ForegroundColor Cyan
|
||||
Write-Host " REBOOT SUMMARY" -ForegroundColor Cyan
|
||||
Write-Host "=" * 60 -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host " Total PCs: $($targetPCs.Count)" -ForegroundColor White
|
||||
Write-Host " Successful: $rebootSuccess" -ForegroundColor Green
|
||||
Write-Host " Failed: $rebootFailed" -ForegroundColor $(if ($rebootFailed -gt 0) { "Red" } else { "White" })
|
||||
Write-Host ""
|
||||
Write-Host "=" * 60 -ForegroundColor Cyan
|
||||
|
||||
exit 0
|
||||
}
|
||||
|
||||
Write-Log "=== ShopDB Remote PC Update Script ===" -Level "INFO"
|
||||
Write-Log "API URL: $ApiUrl" -Level "INFO"
|
||||
Write-Log "DNS Suffix: $DnsSuffix" -Level "INFO"
|
||||
@@ -919,7 +1271,8 @@ if ($WhatIf) {
|
||||
$fqdnList = $targetComputers | ForEach-Object { $_.FQDN }
|
||||
|
||||
# Create session options with short timeout (15 seconds per PC)
|
||||
$sessionOption = New-PSSessionOption -OpenTimeout 15000 -OperationTimeout 30000 -NoMachineProfile
|
||||
# Timeouts: 20s to connect, 120s for operations (app detection takes time)
|
||||
$sessionOption = New-PSSessionOption -OpenTimeout 20000 -OperationTimeout 120000 -NoMachineProfile
|
||||
|
||||
$sessionParams = @{
|
||||
ComputerName = $fqdnList
|
||||
@@ -973,6 +1326,8 @@ foreach ($result in $results) {
|
||||
# Show detected PC type and software
|
||||
if ($result.DetectedPcType) {
|
||||
$detectedSoftware = @()
|
||||
if ($result.HasDashboard) { $detectedSoftware += "GE Aerospace Dashboard" }
|
||||
if ($result.HasLobbyDisplay) { $detectedSoftware += "GE Aerospace Lobby Display" }
|
||||
if ($result.HasPcDmis) { $detectedSoftware += "PC-DMIS" }
|
||||
if ($result.HasGoCMM) { $detectedSoftware += "goCMM" }
|
||||
if ($result.HasDODA) { $detectedSoftware += "DODA" }
|
||||
@@ -1011,7 +1366,18 @@ foreach ($result in $results) {
|
||||
hostname = $result.Hostname
|
||||
hasWinRM = "1"
|
||||
}
|
||||
$winrmResponse = Invoke-RestMethod -Uri $ApiUrl -Method Post -Body $winrmBody -ErrorAction Stop
|
||||
$winrmParams = @{
|
||||
Uri = $ApiUrl
|
||||
Method = 'Post'
|
||||
Body = $winrmBody
|
||||
ErrorAction = 'Stop'
|
||||
UseBasicParsing = $true
|
||||
TimeoutSec = 15
|
||||
}
|
||||
if ($PSVersionTable.PSVersion.Major -ge 7) {
|
||||
$winrmParams.SkipCertificateCheck = $true
|
||||
}
|
||||
$winrmResponse = Invoke-RestMethod @winrmParams
|
||||
if ($winrmResponse.success) {
|
||||
Write-Log " -> WinRM status updated" -Level "SUCCESS"
|
||||
}
|
||||
@@ -1071,7 +1437,18 @@ if ($connectionFailures.Count -gt 0) {
|
||||
action = "getRecordedIP"
|
||||
hostname = $hostname
|
||||
}
|
||||
$ipResponse = Invoke-RestMethod -Uri $ApiUrl -Method Post -Body $ipLookupBody -ErrorAction Stop
|
||||
$ipLookupParams = @{
|
||||
Uri = $ApiUrl
|
||||
Method = 'Post'
|
||||
Body = $ipLookupBody
|
||||
ErrorAction = 'Stop'
|
||||
UseBasicParsing = $true
|
||||
TimeoutSec = 15
|
||||
}
|
||||
if ($PSVersionTable.PSVersion.Major -ge 7) {
|
||||
$ipLookupParams.SkipCertificateCheck = $true
|
||||
}
|
||||
$ipResponse = Invoke-RestMethod @ipLookupParams
|
||||
|
||||
if ($ipResponse.success -and $ipResponse.ipaddress -and $ipResponse.ipaddress -match "^10\.134\.") {
|
||||
$fallbackIP = $ipResponse.ipaddress
|
||||
|
||||
Reference in New Issue
Block a user