Add DeployUDCWebServerConfig task and rename UpdateEMxInfo to UpdateEMxAuthToken
Add new maintenance task to deploy udc_webserver_settings.json to shopfloor PCs that have UDC installed. Checks C:\Program Files\UDC before pushing the config file, skipping PCs without UDC. Rename UpdateEMxInfo to UpdateEMxAuthToken to better describe the task's purpose. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,8 @@
|
|||||||
|
|
||||||
.DESCRIPTION
|
.DESCRIPTION
|
||||||
Executes maintenance tasks on remote shopfloor PCs using WinRM.
|
Executes maintenance tasks on remote shopfloor PCs using WinRM.
|
||||||
Supports system repair, disk optimization, cleanup, and database updates.
|
Supports system repair, disk optimization, cleanup, and reboots.
|
||||||
|
Can target PCs by name, file list, PC type, business unit, or all.
|
||||||
|
|
||||||
.PARAMETER ComputerName
|
.PARAMETER ComputerName
|
||||||
Single computer name, IP address, or array of computers to target.
|
Single computer name, IP address, or array of computers to target.
|
||||||
@@ -15,6 +16,15 @@
|
|||||||
.PARAMETER All
|
.PARAMETER All
|
||||||
Target all shopfloor PCs from ShopDB database.
|
Target all shopfloor PCs from ShopDB database.
|
||||||
|
|
||||||
|
.PARAMETER PcType
|
||||||
|
Target PCs by type (e.g., Dashboard, Lobby Display, CMM, Shopfloor).
|
||||||
|
Valid values: Standard, Engineer, Shopfloor, CMM, Wax / Trace, Keyence,
|
||||||
|
Genspect, Heat Treat, Part Marker, Dashboard, Lobby Display, Uncategorized
|
||||||
|
|
||||||
|
.PARAMETER BusinessUnit
|
||||||
|
Target PCs by business unit (e.g., Blisk, HPT, Spools).
|
||||||
|
Valid values: TBD, Blisk, HPT, Spools, Inspection, Venture, Turn/Burn, DT
|
||||||
|
|
||||||
.PARAMETER Task
|
.PARAMETER Task
|
||||||
Maintenance task to execute. Available tasks:
|
Maintenance task to execute. Available tasks:
|
||||||
|
|
||||||
@@ -38,7 +48,17 @@
|
|||||||
- SyncTime : Force time sync with domain controller
|
- SyncTime : Force time sync with domain controller
|
||||||
|
|
||||||
DNC:
|
DNC:
|
||||||
- UpdateEMxInfo : Update eMxInfo.txt from network share (backs up old file first)
|
- UpdateEMxAuthToken : Update eMx auth token (eMxInfo.txt) from network share (backs up old file first)
|
||||||
|
- DeployUDCWebServerConfig : Deploy UDC web server settings to PCs with UDC installed
|
||||||
|
|
||||||
|
SYSTEM:
|
||||||
|
- Reboot : Restart the computer (30 second delay)
|
||||||
|
|
||||||
|
SOFTWARE DEPLOYMENT:
|
||||||
|
- InstallDashboard : Install GE Aerospace Dashboard kiosk app
|
||||||
|
- InstallLobbyDisplay : Install GE Aerospace Lobby Display kiosk app
|
||||||
|
- UninstallDashboard : Uninstall GE Aerospace Dashboard
|
||||||
|
- UninstallLobbyDisplay : Uninstall GE Aerospace Lobby Display
|
||||||
|
|
||||||
.PARAMETER Credential
|
.PARAMETER Credential
|
||||||
PSCredential for remote authentication. Prompts if not provided.
|
PSCredential for remote authentication. Prompts if not provided.
|
||||||
@@ -62,12 +82,32 @@
|
|||||||
.\Invoke-RemoteMaintenance.ps1 -All -Task DiskCleanup
|
.\Invoke-RemoteMaintenance.ps1 -All -Task DiskCleanup
|
||||||
|
|
||||||
.EXAMPLE
|
.EXAMPLE
|
||||||
# Update database with disk health info
|
# Reboot all Dashboard PCs
|
||||||
.\Invoke-RemoteMaintenance.ps1 -All -Task DiskHealth
|
.\Invoke-RemoteMaintenance.ps1 -PcType Dashboard -Task Reboot
|
||||||
|
|
||||||
.EXAMPLE
|
.EXAMPLE
|
||||||
# Run all database update tasks
|
# Reboot all Lobby Display PCs
|
||||||
.\Invoke-RemoteMaintenance.ps1 -ComputerName "PC01" -Task AllDatabaseUpdates
|
.\Invoke-RemoteMaintenance.ps1 -PcType "Lobby Display" -Task Reboot
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
# Flush DNS on all PCs in Blisk business unit
|
||||||
|
.\Invoke-RemoteMaintenance.ps1 -BusinessUnit Blisk -Task FlushDNS
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
# Clear browser cache on all CMM PCs
|
||||||
|
.\Invoke-RemoteMaintenance.ps1 -PcType CMM -Task ClearBrowserCache
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
# Install Dashboard on specific PCs
|
||||||
|
.\Invoke-RemoteMaintenance.ps1 -ComputerName "PC001","PC002" -Task InstallDashboard
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
# Install Lobby Display from a list file
|
||||||
|
.\Invoke-RemoteMaintenance.ps1 -ComputerListFile ".\lobby-pcs.txt" -Task InstallLobbyDisplay
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
# Uninstall Dashboard from a PC
|
||||||
|
.\Invoke-RemoteMaintenance.ps1 -ComputerName "PC001" -Task UninstallDashboard
|
||||||
|
|
||||||
.NOTES
|
.NOTES
|
||||||
Author: Shop Floor Tools
|
Author: Shop Floor Tools
|
||||||
@@ -86,11 +126,21 @@ param(
|
|||||||
[Parameter(ParameterSetName='All')]
|
[Parameter(ParameterSetName='All')]
|
||||||
[switch]$All,
|
[switch]$All,
|
||||||
|
|
||||||
|
[Parameter(ParameterSetName='ByPcType')]
|
||||||
|
[ValidateSet('Standard', 'Engineer', 'Shopfloor', 'CMM', 'Wax / Trace', 'Keyence',
|
||||||
|
'Genspect', 'Heat Treat', 'Part Marker', 'Dashboard', 'Lobby Display', 'Uncategorized')]
|
||||||
|
[string]$PcType,
|
||||||
|
|
||||||
|
[Parameter(ParameterSetName='ByBusinessUnit')]
|
||||||
|
[ValidateSet('TBD', 'Blisk', 'HPT', 'Spools', 'Inspection', 'Venture', 'Turn/Burn', 'DT')]
|
||||||
|
[string]$BusinessUnit,
|
||||||
|
|
||||||
[Parameter(Mandatory=$true)]
|
[Parameter(Mandatory=$true)]
|
||||||
[ValidateSet(
|
[ValidateSet(
|
||||||
'DISM', 'SFC', 'OptimizeDisk', 'DiskCleanup', 'ClearUpdateCache',
|
'DISM', 'SFC', 'OptimizeDisk', 'DiskCleanup', 'ClearUpdateCache',
|
||||||
'RestartSpooler', 'FlushDNS', 'ClearBrowserCache', 'RestartWinRM',
|
'RestartSpooler', 'FlushDNS', 'ClearBrowserCache', 'RestartWinRM',
|
||||||
'SetTimezone', 'SyncTime', 'UpdateEMxInfo'
|
'SetTimezone', 'SyncTime', 'UpdateEMxAuthToken', 'DeployUDCWebServerConfig', 'Reboot',
|
||||||
|
'InstallDashboard', 'InstallLobbyDisplay', 'UninstallDashboard', 'UninstallLobbyDisplay'
|
||||||
)]
|
)]
|
||||||
[string]$Task,
|
[string]$Task,
|
||||||
|
|
||||||
@@ -110,23 +160,11 @@ param(
|
|||||||
# =============================================================================
|
# =============================================================================
|
||||||
# SSL/TLS Configuration
|
# SSL/TLS Configuration
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
try {
|
# Enable all modern TLS versions
|
||||||
if (-not ([System.Management.Automation.PSTypeName]'TrustAllCertsPolicy').Type) {
|
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls
|
||||||
Add-Type @"
|
|
||||||
using System.Net;
|
# Bypass SSL certificate validation (for self-signed certs)
|
||||||
using System.Security.Cryptography.X509Certificates;
|
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { param($sender, $cert, $chain, $errors) return $true }
|
||||||
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
|
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Helper Functions
|
# Helper Functions
|
||||||
@@ -146,9 +184,30 @@ function Write-Log {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Get-ShopfloorPCsFromApi {
|
function Get-ShopfloorPCsFromApi {
|
||||||
param([string]$ApiUrl)
|
param(
|
||||||
|
[string]$ApiUrl,
|
||||||
|
[int]$PcTypeId = 0,
|
||||||
|
[int]$BusinessUnitId = 0
|
||||||
|
)
|
||||||
try {
|
try {
|
||||||
$response = Invoke-RestMethod -Uri "$ApiUrl`?action=getShopfloorPCs" -Method Get -ErrorAction Stop
|
# Force TLS 1.2 immediately before request
|
||||||
|
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||||
|
|
||||||
|
$queryParams = "action=getShopfloorPCs"
|
||||||
|
if ($PcTypeId -gt 0) {
|
||||||
|
$queryParams += "&pctypeid=$PcTypeId"
|
||||||
|
}
|
||||||
|
if ($BusinessUnitId -gt 0) {
|
||||||
|
$queryParams += "&businessunitid=$BusinessUnitId"
|
||||||
|
}
|
||||||
|
|
||||||
|
$fullUrl = "$ApiUrl`?$queryParams"
|
||||||
|
|
||||||
|
# Use WebClient - more reliable with TLS in script context
|
||||||
|
$webClient = New-Object System.Net.WebClient
|
||||||
|
$json = $webClient.DownloadString($fullUrl)
|
||||||
|
$response = $json | ConvertFrom-Json
|
||||||
|
|
||||||
if ($response.success -and $response.data) {
|
if ($response.success -and $response.data) {
|
||||||
return $response.data
|
return $response.data
|
||||||
}
|
}
|
||||||
@@ -159,6 +218,18 @@ function Get-ShopfloorPCsFromApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Lookup tables for filtering
|
||||||
|
$PcTypeLookup = @{
|
||||||
|
'Standard' = 1; 'Engineer' = 2; 'Shopfloor' = 3; 'Uncategorized' = 4;
|
||||||
|
'CMM' = 5; 'Wax / Trace' = 6; 'Keyence' = 7; 'Genspect' = 8;
|
||||||
|
'Heat Treat' = 9; 'Part Marker' = 10; 'Dashboard' = 11; 'Lobby Display' = 12
|
||||||
|
}
|
||||||
|
|
||||||
|
$BusinessUnitLookup = @{
|
||||||
|
'TBD' = 1; 'Blisk' = 2; 'HPT' = 3; 'Spools' = 4;
|
||||||
|
'Inspection' = 5; 'Venture' = 6; 'Turn/Burn' = 7; 'DT' = 8
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Maintenance Task Scriptblocks
|
# Maintenance Task Scriptblocks
|
||||||
@@ -685,15 +756,15 @@ $TaskScripts = @{
|
|||||||
}
|
}
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
# UpdateEMxInfo - Backup and prepare for file copy (runs on remote PC)
|
# UpdateEMxAuthToken - Backup and prepare for file copy (runs on remote PC)
|
||||||
# The actual file is pushed via Copy-Item -ToSession from the caller
|
# The actual file is pushed via Copy-Item -ToSession from the caller
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
'UpdateEMxInfo' = {
|
'UpdateEMxAuthToken' = {
|
||||||
param($SourceFileContent)
|
param($SourceFileContent)
|
||||||
|
|
||||||
$result = @{
|
$result = @{
|
||||||
Success = $false
|
Success = $false
|
||||||
Task = 'UpdateEMxInfo'
|
Task = 'UpdateEMxAuthToken'
|
||||||
Hostname = $env:COMPUTERNAME
|
Hostname = $env:COMPUTERNAME
|
||||||
Output = ""
|
Output = ""
|
||||||
Error = $null
|
Error = $null
|
||||||
@@ -858,6 +929,233 @@ $TaskScripts = @{
|
|||||||
|
|
||||||
return $result
|
return $result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
# DeployUDCWebServerConfig - Deploy udc_webserver_settings.json to UDC PCs
|
||||||
|
# The actual file is pushed via Copy-Item -ToSession from the caller
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
'DeployUDCWebServerConfig' = {
|
||||||
|
$result = @{
|
||||||
|
Success = $false
|
||||||
|
Task = 'DeployUDCWebServerConfig'
|
||||||
|
Hostname = $env:COMPUTERNAME
|
||||||
|
Output = ""
|
||||||
|
Error = $null
|
||||||
|
FailReason = ""
|
||||||
|
UDCInstalled = $false
|
||||||
|
BackupCreated = $false
|
||||||
|
}
|
||||||
|
|
||||||
|
$udcInstallDir = "C:\Program Files\UDC"
|
||||||
|
$destDir = "C:\ProgramData\UDC"
|
||||||
|
$destFile = "udc_webserver_settings.json"
|
||||||
|
$destPath = Join-Path $destDir $destFile
|
||||||
|
$tempPath = "C:\Windows\Temp\udc_webserver_settings.json"
|
||||||
|
|
||||||
|
try {
|
||||||
|
# Check if UDC is installed
|
||||||
|
if (-not (Test-Path $udcInstallDir)) {
|
||||||
|
$result.FailReason = "UDC not installed ($udcInstallDir not found) - skipping"
|
||||||
|
$result.Output = $result.FailReason
|
||||||
|
Write-Output $result.FailReason
|
||||||
|
return $result
|
||||||
|
}
|
||||||
|
|
||||||
|
$result.UDCInstalled = $true
|
||||||
|
Write-Output "UDC installation found at $udcInstallDir"
|
||||||
|
|
||||||
|
# Check if temp file was pushed
|
||||||
|
if (-not (Test-Path $tempPath)) {
|
||||||
|
$result.FailReason = "Source file not found at $tempPath - file push may have failed"
|
||||||
|
$result.Error = $result.FailReason
|
||||||
|
Write-Output $result.FailReason
|
||||||
|
return $result
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create destination directory if it doesn't exist
|
||||||
|
if (-not (Test-Path $destDir)) {
|
||||||
|
New-Item -Path $destDir -ItemType Directory -Force | Out-Null
|
||||||
|
Write-Output "Created directory: $destDir"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Backup existing config if present
|
||||||
|
if (Test-Path $destPath) {
|
||||||
|
$dateStamp = Get-Date -Format "yyyyMMdd"
|
||||||
|
$backupName = "udc_webserver_settings-old-$dateStamp.json"
|
||||||
|
$backupPath = Join-Path $destDir $backupName
|
||||||
|
|
||||||
|
Write-Output "Existing config found, backing up to $backupName..."
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (Test-Path $backupPath) {
|
||||||
|
Remove-Item $backupPath -Force -ErrorAction Stop
|
||||||
|
}
|
||||||
|
Rename-Item -Path $destPath -NewName $backupName -Force -ErrorAction Stop
|
||||||
|
$result.BackupCreated = $true
|
||||||
|
} catch {
|
||||||
|
Write-Output "Warning: Could not backup existing config - $($_.Exception.Message)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Copy from temp location to destination
|
||||||
|
Copy-Item -Path $tempPath -Destination $destPath -Force -ErrorAction Stop
|
||||||
|
|
||||||
|
# Verify the copy
|
||||||
|
if (Test-Path $destPath) {
|
||||||
|
$result.Success = $true
|
||||||
|
$result.Output = "Config deployed to $destPath"
|
||||||
|
if ($result.BackupCreated) {
|
||||||
|
$result.Output += " (backup created)"
|
||||||
|
}
|
||||||
|
Write-Output "SUCCESS: $($result.Output)"
|
||||||
|
} else {
|
||||||
|
$result.FailReason = "Copy succeeded but file not found at destination"
|
||||||
|
$result.Error = $result.FailReason
|
||||||
|
Write-Output "FAILED: $($result.FailReason)"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Clean up temp file
|
||||||
|
Remove-Item $tempPath -Force -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
} catch {
|
||||||
|
$result.FailReason = "Unexpected error: $($_.Exception.Message)"
|
||||||
|
$result.Error = $result.FailReason
|
||||||
|
Write-Output $result.FailReason
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result
|
||||||
|
}
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
# InstallDashboard / InstallLobbyDisplay - Install kiosk app
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
'InstallKioskApp' = {
|
||||||
|
param($InstallerPath, $AppName)
|
||||||
|
|
||||||
|
$result = @{
|
||||||
|
Success = $false
|
||||||
|
Task = 'InstallKioskApp'
|
||||||
|
Hostname = $env:COMPUTERNAME
|
||||||
|
Output = ""
|
||||||
|
Error = $null
|
||||||
|
AppName = $AppName
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (-not (Test-Path $InstallerPath)) {
|
||||||
|
$result.Error = "Installer not found at $InstallerPath"
|
||||||
|
Write-Output $result.Error
|
||||||
|
return $result
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Output "Installing $AppName..."
|
||||||
|
$proc = Start-Process -FilePath $InstallerPath -ArgumentList "/VERYSILENT /SUPPRESSMSGBOXES /NORESTART" -Wait -PassThru -WindowStyle Hidden
|
||||||
|
|
||||||
|
# Clean up installer
|
||||||
|
Remove-Item $InstallerPath -Force -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
if ($proc.ExitCode -eq 0) {
|
||||||
|
$result.Success = $true
|
||||||
|
$result.Output = "$AppName installed successfully"
|
||||||
|
} else {
|
||||||
|
$result.Error = "Installer exited with code $($proc.ExitCode)"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Output $result.Output
|
||||||
|
} catch {
|
||||||
|
$result.Error = $_.Exception.Message
|
||||||
|
Write-Output "Error: $($result.Error)"
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result
|
||||||
|
}
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
# UninstallDashboard / UninstallLobbyDisplay - Uninstall kiosk app
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
'UninstallKioskApp' = {
|
||||||
|
param($UninstallGuid, $AppName)
|
||||||
|
|
||||||
|
$result = @{
|
||||||
|
Success = $false
|
||||||
|
Task = 'UninstallKioskApp'
|
||||||
|
Hostname = $env:COMPUTERNAME
|
||||||
|
Output = ""
|
||||||
|
Error = $null
|
||||||
|
AppName = $AppName
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Write-Output "Uninstalling $AppName..."
|
||||||
|
|
||||||
|
# Find uninstaller in registry
|
||||||
|
$uninstallPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$UninstallGuid`_is1"
|
||||||
|
if (-not (Test-Path $uninstallPath)) {
|
||||||
|
$uninstallPath = "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\$UninstallGuid`_is1"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Test-Path $uninstallPath) {
|
||||||
|
$uninstallString = (Get-ItemProperty $uninstallPath).UninstallString
|
||||||
|
if ($uninstallString) {
|
||||||
|
$uninstallExe = $uninstallString -replace '"', ''
|
||||||
|
$proc = Start-Process -FilePath $uninstallExe -ArgumentList "/VERYSILENT /SUPPRESSMSGBOXES /NORESTART" -Wait -PassThru -WindowStyle Hidden
|
||||||
|
|
||||||
|
if ($proc.ExitCode -eq 0) {
|
||||||
|
$result.Success = $true
|
||||||
|
$result.Output = "$AppName uninstalled successfully"
|
||||||
|
} else {
|
||||||
|
$result.Error = "Uninstaller exited with code $($proc.ExitCode)"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$result.Error = "No uninstall string found in registry"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$result.Error = "$AppName not found in registry (may not be installed)"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Output $(if ($result.Success) { $result.Output } else { $result.Error })
|
||||||
|
} catch {
|
||||||
|
$result.Error = $_.Exception.Message
|
||||||
|
Write-Output "Error: $($result.Error)"
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result
|
||||||
|
}
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
# Reboot - Restart the computer
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
'Reboot' = {
|
||||||
|
$result = @{
|
||||||
|
Success = $false
|
||||||
|
Task = 'Reboot'
|
||||||
|
Hostname = $env:COMPUTERNAME
|
||||||
|
Output = ""
|
||||||
|
Error = $null
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Write-Output "Initiating system restart..."
|
||||||
|
|
||||||
|
# Use shutdown command with 30 second delay to allow WinRM to return
|
||||||
|
$shutdownResult = & shutdown.exe /r /t 30 /c "Remote maintenance reboot initiated" 2>&1
|
||||||
|
$exitCode = $LASTEXITCODE
|
||||||
|
|
||||||
|
if ($exitCode -eq 0) {
|
||||||
|
$result.Success = $true
|
||||||
|
$result.Output = "Reboot scheduled in 30 seconds"
|
||||||
|
Write-Output $result.Output
|
||||||
|
} else {
|
||||||
|
$result.Error = "Shutdown command failed with exit code $exitCode : $shutdownResult"
|
||||||
|
Write-Output $result.Error
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
$result.Error = $_.Exception.Message
|
||||||
|
Write-Output "Error: $($result.Error)"
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
@@ -888,6 +1186,18 @@ if ($All) {
|
|||||||
$shopfloorPCs = Get-ShopfloorPCsFromApi -ApiUrl $ApiUrl
|
$shopfloorPCs = Get-ShopfloorPCsFromApi -ApiUrl $ApiUrl
|
||||||
$computers = $shopfloorPCs | ForEach-Object { $_.hostname } | Where-Object { $_ }
|
$computers = $shopfloorPCs | ForEach-Object { $_.hostname } | Where-Object { $_ }
|
||||||
Write-Log "Found $($computers.Count) shopfloor PCs" -Level "INFO"
|
Write-Log "Found $($computers.Count) shopfloor PCs" -Level "INFO"
|
||||||
|
} elseif ($PcType) {
|
||||||
|
$pcTypeId = $PcTypeLookup[$PcType]
|
||||||
|
Write-Log "Querying ShopDB for PCs of type '$PcType' (ID: $pcTypeId)..." -Level "INFO"
|
||||||
|
$shopfloorPCs = Get-ShopfloorPCsFromApi -ApiUrl $ApiUrl -PcTypeId $pcTypeId
|
||||||
|
$computers = $shopfloorPCs | ForEach-Object { $_.hostname } | Where-Object { $_ }
|
||||||
|
Write-Log "Found $($computers.Count) PCs of type '$PcType'" -Level "INFO"
|
||||||
|
} elseif ($BusinessUnit) {
|
||||||
|
$businessUnitId = $BusinessUnitLookup[$BusinessUnit]
|
||||||
|
Write-Log "Querying ShopDB for PCs in business unit '$BusinessUnit' (ID: $businessUnitId)..." -Level "INFO"
|
||||||
|
$shopfloorPCs = Get-ShopfloorPCsFromApi -ApiUrl $ApiUrl -BusinessUnitId $businessUnitId
|
||||||
|
$computers = $shopfloorPCs | ForEach-Object { $_.hostname } | Where-Object { $_ }
|
||||||
|
Write-Log "Found $($computers.Count) PCs in business unit '$BusinessUnit'" -Level "INFO"
|
||||||
} elseif ($ComputerListFile) {
|
} elseif ($ComputerListFile) {
|
||||||
if (Test-Path $ComputerListFile) {
|
if (Test-Path $ComputerListFile) {
|
||||||
$computers = Get-Content $ComputerListFile | Where-Object { $_.Trim() -and -not $_.StartsWith("#") }
|
$computers = Get-Content $ComputerListFile | Where-Object { $_.Trim() -and -not $_.StartsWith("#") }
|
||||||
@@ -898,7 +1208,7 @@ if ($All) {
|
|||||||
} elseif ($ComputerName) {
|
} elseif ($ComputerName) {
|
||||||
$computers = $ComputerName
|
$computers = $ComputerName
|
||||||
} else {
|
} else {
|
||||||
Write-Log "No computers specified. Use -ComputerName, -ComputerListFile, or -All" -Level "ERROR"
|
Write-Log "No computers specified. Use -ComputerName, -ComputerListFile, -All, -PcType, or -BusinessUnit" -Level "ERROR"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -922,12 +1232,12 @@ $tasksToRun = @($Task)
|
|||||||
# Create session options
|
# Create session options
|
||||||
$sessionOption = New-PSSessionOption -OpenTimeout 30000 -OperationTimeout 600000 -NoMachineProfile
|
$sessionOption = New-PSSessionOption -OpenTimeout 30000 -OperationTimeout 600000 -NoMachineProfile
|
||||||
|
|
||||||
# Special handling for UpdateEMxInfo - requires pushing file first
|
# Special handling for UpdateEMxAuthToken - requires pushing file first
|
||||||
if ($Task -eq 'UpdateEMxInfo') {
|
if ($Task -eq 'UpdateEMxAuthToken') {
|
||||||
$sourcePath = "\\tsgwp00525.rd.ds.ge.com\shared\cameron\eMxInfo-2026.txt"
|
$sourcePath = "\\tsgwp00525.rd.ds.ge.com\shared\cameron\eMxInfo-2026.txt"
|
||||||
$remoteTempPath = "C:\Windows\Temp\eMxInfo-2026.txt"
|
$remoteTempPath = "C:\Windows\Temp\eMxInfo-2026.txt"
|
||||||
|
|
||||||
Write-Log "UpdateEMxInfo: Checking source file..." -Level "INFO"
|
Write-Log "UpdateEMxAuthToken: Checking source file..." -Level "INFO"
|
||||||
|
|
||||||
if (-not (Test-Path $sourcePath)) {
|
if (-not (Test-Path $sourcePath)) {
|
||||||
Write-Log "Source file not found: $sourcePath" -Level "ERROR"
|
Write-Log "Source file not found: $sourcePath" -Level "ERROR"
|
||||||
@@ -953,7 +1263,7 @@ if ($Task -eq 'UpdateEMxInfo') {
|
|||||||
|
|
||||||
# Execute the scriptblock
|
# Execute the scriptblock
|
||||||
Write-Log " Executing update task..." -Level "INFO"
|
Write-Log " Executing update task..." -Level "INFO"
|
||||||
$result = Invoke-Command -Session $session -ScriptBlock $TaskScripts['UpdateEMxInfo'] -ErrorAction Stop
|
$result = Invoke-Command -Session $session -ScriptBlock $TaskScripts['UpdateEMxAuthToken'] -ErrorAction Stop
|
||||||
|
|
||||||
# Close session
|
# Close session
|
||||||
Remove-PSSession $session -ErrorAction SilentlyContinue
|
Remove-PSSession $session -ErrorAction SilentlyContinue
|
||||||
@@ -995,6 +1305,186 @@ if ($Task -eq 'UpdateEMxInfo') {
|
|||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Special handling for DeployUDCWebServerConfig - check for UDC installation, then push config file
|
||||||
|
if ($Task -eq 'DeployUDCWebServerConfig') {
|
||||||
|
$sourcePath = Join-Path $PSScriptRoot "udc_webserver_settings.json"
|
||||||
|
$remoteTempPath = "C:\Windows\Temp\udc_webserver_settings.json"
|
||||||
|
|
||||||
|
Write-Log "DeployUDCWebServerConfig: Checking source file..." -Level "INFO"
|
||||||
|
|
||||||
|
if (-not (Test-Path $sourcePath)) {
|
||||||
|
Write-Log "Source file not found: $sourcePath" -Level "ERROR"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Log "Source file found: $sourcePath" -Level "INFO"
|
||||||
|
Write-Log "Will check each PC for UDC installation before deploying." -Level "INFO"
|
||||||
|
|
||||||
|
$successCount = 0
|
||||||
|
$failCount = 0
|
||||||
|
$skippedCount = 0
|
||||||
|
|
||||||
|
foreach ($fqdn in $targetFQDNs) {
|
||||||
|
Write-Host ""
|
||||||
|
Write-Log "Processing: $fqdn" -Level "TASK"
|
||||||
|
|
||||||
|
try {
|
||||||
|
# Create session
|
||||||
|
$session = New-PSSession -ComputerName $fqdn -Credential $Credential -SessionOption $sessionOption -Authentication Negotiate -ErrorAction Stop
|
||||||
|
|
||||||
|
# Check if UDC is installed before pushing the file
|
||||||
|
$udcInstalled = Invoke-Command -Session $session -ScriptBlock { Test-Path "C:\Program Files\UDC" } -ErrorAction Stop
|
||||||
|
|
||||||
|
if (-not $udcInstalled) {
|
||||||
|
Write-Log "[SKIP] $fqdn - UDC not installed" -Level "INFO"
|
||||||
|
Remove-PSSession $session -ErrorAction SilentlyContinue
|
||||||
|
$skippedCount++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
# Push the config file to remote temp location
|
||||||
|
Write-Log " UDC installed - pushing config file..." -Level "INFO"
|
||||||
|
Copy-Item -Path $sourcePath -Destination $remoteTempPath -ToSession $session -Force -ErrorAction Stop
|
||||||
|
|
||||||
|
# Execute the scriptblock
|
||||||
|
Write-Log " Executing deploy task..." -Level "INFO"
|
||||||
|
$result = Invoke-Command -Session $session -ScriptBlock $TaskScripts['DeployUDCWebServerConfig'] -ErrorAction Stop
|
||||||
|
|
||||||
|
# Close session
|
||||||
|
Remove-PSSession $session -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
# Process result
|
||||||
|
if ($result.Success) {
|
||||||
|
Write-Log "[OK] $($result.Hostname): $($result.Output)" -Level "SUCCESS"
|
||||||
|
$successCount++
|
||||||
|
} else {
|
||||||
|
$errorMsg = if ($result.FailReason) { $result.FailReason } else { $result.Error }
|
||||||
|
Write-Log "[FAIL] $($result.Hostname): $errorMsg" -Level "ERROR"
|
||||||
|
$failCount++
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch {
|
||||||
|
Write-Log "[FAIL] ${fqdn}: $($_.Exception.Message)" -Level "ERROR"
|
||||||
|
$failCount++
|
||||||
|
if ($session) { Remove-PSSession $session -ErrorAction SilentlyContinue }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||||
|
Write-Host " SUMMARY" -ForegroundColor Cyan
|
||||||
|
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||||
|
Write-Host " Task: $Task" -ForegroundColor White
|
||||||
|
Write-Host " Successful: $successCount" -ForegroundColor Green
|
||||||
|
Write-Host " Skipped: $skippedCount (UDC not installed)" -ForegroundColor Yellow
|
||||||
|
Write-Host " Failed: $failCount" -ForegroundColor $(if ($failCount -gt 0) { "Red" } else { "White" })
|
||||||
|
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Special handling for Install/Uninstall kiosk apps
|
||||||
|
$KioskAppConfig = @{
|
||||||
|
'InstallDashboard' = @{
|
||||||
|
Action = 'Install'
|
||||||
|
InstallerName = 'GEAerospaceDashboardSetup.exe'
|
||||||
|
AppName = 'GE Aerospace Dashboard'
|
||||||
|
UninstallGuid = '{9D9EEE25-4D24-422D-98AF-2ADEDA4745ED}'
|
||||||
|
}
|
||||||
|
'InstallLobbyDisplay' = @{
|
||||||
|
Action = 'Install'
|
||||||
|
InstallerName = 'GEAerospaceLobbyDisplaySetup.exe'
|
||||||
|
AppName = 'GE Aerospace Lobby Display'
|
||||||
|
UninstallGuid = '{42FFB952-0B72-493F-8869-D957344CA305}'
|
||||||
|
}
|
||||||
|
'UninstallDashboard' = @{
|
||||||
|
Action = 'Uninstall'
|
||||||
|
InstallerName = 'GEAerospaceDashboardSetup.exe'
|
||||||
|
AppName = 'GE Aerospace Dashboard'
|
||||||
|
UninstallGuid = '{9D9EEE25-4D24-422D-98AF-2ADEDA4745ED}'
|
||||||
|
}
|
||||||
|
'UninstallLobbyDisplay' = @{
|
||||||
|
Action = 'Uninstall'
|
||||||
|
InstallerName = 'GEAerospaceLobbyDisplaySetup.exe'
|
||||||
|
AppName = 'GE Aerospace Lobby Display'
|
||||||
|
UninstallGuid = '{42FFB952-0B72-493F-8869-D957344CA305}'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($KioskAppConfig.ContainsKey($Task)) {
|
||||||
|
$appConfig = $KioskAppConfig[$Task]
|
||||||
|
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||||
|
|
||||||
|
if ($appConfig.Action -eq 'Install') {
|
||||||
|
# Find installer
|
||||||
|
$installerPath = Join-Path $scriptDir $appConfig.InstallerName
|
||||||
|
if (-not (Test-Path $installerPath)) {
|
||||||
|
Write-Log "Installer not found: $installerPath" -Level "ERROR"
|
||||||
|
Write-Log "Place $($appConfig.InstallerName) in the script directory" -Level "ERROR"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
Write-Log "$($appConfig.Action): $($appConfig.AppName)" -Level "INFO"
|
||||||
|
Write-Log "Installer: $installerPath" -Level "INFO"
|
||||||
|
} else {
|
||||||
|
Write-Log "$($appConfig.Action): $($appConfig.AppName)" -Level "INFO"
|
||||||
|
}
|
||||||
|
|
||||||
|
$successCount = 0
|
||||||
|
$failCount = 0
|
||||||
|
|
||||||
|
foreach ($fqdn in $targetFQDNs) {
|
||||||
|
Write-Host ""
|
||||||
|
Write-Log "Processing: $fqdn" -Level "TASK"
|
||||||
|
|
||||||
|
try {
|
||||||
|
$session = New-PSSession -ComputerName $fqdn -Credential $Credential -SessionOption $sessionOption -Authentication Negotiate -ErrorAction Stop
|
||||||
|
|
||||||
|
if ($appConfig.Action -eq 'Install') {
|
||||||
|
$remoteTempPath = "C:\Windows\Temp\$($appConfig.InstallerName)"
|
||||||
|
|
||||||
|
Write-Log " Pushing installer to remote PC..." -Level "INFO"
|
||||||
|
Copy-Item -Path $installerPath -Destination $remoteTempPath -ToSession $session -Force -ErrorAction Stop
|
||||||
|
|
||||||
|
Write-Log " Running installer silently..." -Level "INFO"
|
||||||
|
$result = Invoke-Command -Session $session -ScriptBlock $TaskScripts['InstallKioskApp'] -ArgumentList $remoteTempPath, $appConfig.AppName -ErrorAction Stop
|
||||||
|
} else {
|
||||||
|
Write-Log " Running uninstaller..." -Level "INFO"
|
||||||
|
$result = Invoke-Command -Session $session -ScriptBlock $TaskScripts['UninstallKioskApp'] -ArgumentList $appConfig.UninstallGuid, $appConfig.AppName -ErrorAction Stop
|
||||||
|
}
|
||||||
|
|
||||||
|
Remove-PSSession $session -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
if ($result.Success) {
|
||||||
|
Write-Log "[OK] $($result.Hostname) - $($result.Output)" -Level "SUCCESS"
|
||||||
|
$successCount++
|
||||||
|
} else {
|
||||||
|
$errorMsg = if ($result.Error) { $result.Error } else { "Unknown error" }
|
||||||
|
Write-Log "[FAIL] $($result.Hostname): $errorMsg" -Level "ERROR"
|
||||||
|
$failCount++
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch {
|
||||||
|
Write-Log "[FAIL] ${fqdn}: $($_.Exception.Message)" -Level "ERROR"
|
||||||
|
$failCount++
|
||||||
|
if ($session) { Remove-PSSession $session -ErrorAction SilentlyContinue }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||||
|
Write-Host " SUMMARY" -ForegroundColor Cyan
|
||||||
|
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||||
|
Write-Host " Task: $Task" -ForegroundColor White
|
||||||
|
Write-Host " App: $($appConfig.AppName)" -ForegroundColor White
|
||||||
|
Write-Host " Successful: $successCount" -ForegroundColor Green
|
||||||
|
Write-Host " Failed: $failCount" -ForegroundColor $(if ($failCount -gt 0) { "Red" } else { "White" })
|
||||||
|
Write-Host ("=" * 70) -ForegroundColor Cyan
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
# Process each task
|
# Process each task
|
||||||
foreach ($currentTask in $tasksToRun) {
|
foreach ($currentTask in $tasksToRun) {
|
||||||
|
|
||||||
@@ -1053,7 +1543,7 @@ foreach ($currentTask in $tasksToRun) {
|
|||||||
'DiskCleanup' {
|
'DiskCleanup' {
|
||||||
Write-Host " Space freed: $($result.SpaceFreed) GB" -ForegroundColor Gray
|
Write-Host " Space freed: $($result.SpaceFreed) GB" -ForegroundColor Gray
|
||||||
}
|
}
|
||||||
'UpdateEMxInfo' {
|
'UpdateEMxAuthToken' {
|
||||||
Write-Host " $($result.Output)" -ForegroundColor Gray
|
Write-Host " $($result.Output)" -ForegroundColor Gray
|
||||||
if ($result.PathsFailed.Count -gt 0) {
|
if ($result.PathsFailed.Count -gt 0) {
|
||||||
foreach ($fail in $result.PathsFailed) {
|
foreach ($fail in $result.PathsFailed) {
|
||||||
|
|||||||
8
remote-execution/udc_webserver_settings.json
Normal file
8
remote-execution/udc_webserver_settings.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"ServerAddress": "10.80.92.30",
|
||||||
|
"ServerPort": 5100,
|
||||||
|
"Enabled": true,
|
||||||
|
"ReconnectDelaySeconds": 10,
|
||||||
|
"ConnectTimeoutSeconds": 10,
|
||||||
|
"MaxQueue": 1000
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user