Files
powershell-scripts/remote-execution/Install-KioskApp.ps1
cproudlock f40b79c087 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>
2026-02-03 10:44:42 -05:00

274 lines
9.2 KiB
PowerShell

<#
.SYNOPSIS
Remote installer for Dashboard and Lobby Display kiosk applications.
.DESCRIPTION
Deploys GE Aerospace Dashboard or Lobby Display kiosk installers to remote PCs via WinRM.
Pushes the installer file and runs it silently.
.PARAMETER ComputerName
Single computer name, IP address, or array of computers to target.
.PARAMETER ComputerListFile
Path to text file containing computer names/IPs (one per line).
.PARAMETER App
Which application to install: Dashboard or LobbyDisplay
.PARAMETER InstallerPath
Path to the installer .exe file. If not specified, looks in the script directory.
.PARAMETER Credential
PSCredential for remote authentication. Prompts if not provided.
.PARAMETER Uninstall
Uninstall the application instead of installing.
.EXAMPLE
# Install Dashboard on a single PC
.\Install-KioskApp.ps1 -ComputerName "PC001" -App Dashboard
.EXAMPLE
# Install Lobby Display on multiple PCs from file
.\Install-KioskApp.ps1 -ComputerListFile ".\lobby-pcs.txt" -App LobbyDisplay
.EXAMPLE
# Uninstall Dashboard from a PC
.\Install-KioskApp.ps1 -ComputerName "PC001" -App Dashboard -Uninstall
.NOTES
Author: Shop Floor Tools
Requires: PowerShell 5.1+, WinRM enabled on targets, Admin credentials
#>
[CmdletBinding()]
param(
[Parameter(Position=0)]
[string[]]$ComputerName,
[Parameter()]
[string]$ComputerListFile,
[Parameter(Mandatory=$true)]
[ValidateSet('Dashboard', 'LobbyDisplay')]
[string]$App,
[Parameter()]
[string]$InstallerPath,
[Parameter()]
[PSCredential]$Credential,
[Parameter()]
[string]$DnsSuffix = "logon.ds.ge.com",
[Parameter()]
[switch]$Uninstall
)
# =============================================================================
# Configuration
# =============================================================================
$AppConfig = @{
'Dashboard' = @{
InstallerName = 'GEAerospaceDashboardSetup.exe'
AppName = 'GE Aerospace Dashboard'
UninstallGuid = '{9D9EEE25-4D24-422D-98AF-2ADEDA4745ED}'
}
'LobbyDisplay' = @{
InstallerName = 'GEAerospaceLobbyDisplaySetup.exe'
AppName = 'GE Aerospace Lobby Display'
UninstallGuid = '{42FFB952-0B72-493F-8869-D957344CA305}'
}
}
$config = $AppConfig[$App]
# =============================================================================
# Helper Functions
# =============================================================================
function Write-Log {
param([string]$Message, [string]$Level = "INFO")
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$color = switch ($Level) {
"ERROR" { "Red" }
"WARNING" { "Yellow" }
"SUCCESS" { "Green" }
"TASK" { "Cyan" }
default { "White" }
}
Write-Host "[$timestamp] [$Level] $Message" -ForegroundColor $color
}
# =============================================================================
# Main Execution
# =============================================================================
Write-Host ""
Write-Host ("=" * 70) -ForegroundColor Cyan
Write-Host " Kiosk App Installer - $($config.AppName)" -ForegroundColor Cyan
Write-Host ("=" * 70) -ForegroundColor Cyan
Write-Host ""
# Get credentials
if (-not $Credential) {
Write-Log "Enter credentials for remote PCs:" -Level "INFO"
$Credential = Get-Credential -Message "Enter admin credentials for remote PCs"
if (-not $Credential) {
Write-Log "Credentials required. Exiting." -Level "ERROR"
exit 1
}
}
# Build computer list
$computers = @()
if ($ComputerListFile) {
if (Test-Path $ComputerListFile) {
$computers = Get-Content $ComputerListFile | Where-Object { $_.Trim() -and -not $_.StartsWith("#") }
} else {
Write-Log "Computer list file not found: $ComputerListFile" -Level "ERROR"
exit 1
}
} elseif ($ComputerName) {
$computers = $ComputerName
} else {
Write-Log "No computers specified. Use -ComputerName or -ComputerListFile" -Level "ERROR"
exit 1
}
if ($computers.Count -eq 0) {
Write-Log "No computers to process." -Level "ERROR"
exit 1
}
Write-Log "Target computers: $($computers.Count)" -Level "INFO"
Write-Log "Action: $(if ($Uninstall) { 'Uninstall' } else { 'Install' })" -Level "TASK"
Write-Host ""
# Find installer if not specified (for install only)
if (-not $Uninstall) {
if (-not $InstallerPath) {
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$InstallerPath = Join-Path $scriptDir $config.InstallerName
}
if (-not (Test-Path $InstallerPath)) {
Write-Log "Installer not found: $InstallerPath" -Level "ERROR"
Write-Log "Please specify -InstallerPath or place $($config.InstallerName) in the script directory" -Level "ERROR"
exit 1
}
Write-Log "Installer: $InstallerPath" -Level "INFO"
}
# Build FQDNs
$targetFQDNs = $computers | ForEach-Object {
if ($_ -like "*.*") { $_ } else { "$_.$DnsSuffix" }
}
# Create session options
$sessionOption = New-PSSessionOption -OpenTimeout 30000 -OperationTimeout 300000 -NoMachineProfile
$successCount = 0
$failCount = 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
if ($Uninstall) {
# Uninstall
Write-Log " Uninstalling $($config.AppName)..." -Level "INFO"
$result = Invoke-Command -Session $session -ScriptBlock {
param($guid, $appName)
$result = @{ Success = $false; Output = ""; Error = $null }
# Find uninstaller
$uninstallPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$guid`_is1"
if (-not (Test-Path $uninstallPath)) {
$uninstallPath = "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\$guid`_is1"
}
if (Test-Path $uninstallPath) {
$uninstallString = (Get-ItemProperty $uninstallPath).UninstallString
if ($uninstallString) {
# Run uninstaller silently
$uninstallExe = $uninstallString -replace '"', ''
$proc = Start-Process -FilePath $uninstallExe -ArgumentList "/VERYSILENT /SUPPRESSMSGBOXES /NORESTART" -Wait -PassThru -WindowStyle Hidden
$result.Success = ($proc.ExitCode -eq 0)
$result.Output = "Exit code: $($proc.ExitCode)"
} else {
$result.Error = "No uninstall string found"
}
} else {
$result.Error = "$appName not found in registry"
}
return $result
} -ArgumentList $config.UninstallGuid, $config.AppName
} else {
# Install
$remoteTempPath = "C:\Windows\Temp\$($config.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 {
param($installerPath)
$result = @{ Success = $false; Output = ""; Error = $null }
try {
$proc = Start-Process -FilePath $installerPath -ArgumentList "/VERYSILENT /SUPPRESSMSGBOXES /NORESTART" -Wait -PassThru -WindowStyle Hidden
$result.Success = ($proc.ExitCode -eq 0)
$result.Output = "Exit code: $($proc.ExitCode)"
# Clean up installer
Remove-Item $installerPath -Force -ErrorAction SilentlyContinue
} catch {
$result.Error = $_.Exception.Message
}
return $result
} -ArgumentList $remoteTempPath
}
# Close session
Remove-PSSession $session -ErrorAction SilentlyContinue
# Process result
if ($result.Success) {
Write-Log "[OK] $fqdn - $($result.Output)" -Level "SUCCESS"
$successCount++
} else {
$errorMsg = if ($result.Error) { $result.Error } else { $result.Output }
Write-Log "[FAIL] $fqdn - $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 " App: $($config.AppName)" -ForegroundColor White
Write-Host " Action: $(if ($Uninstall) { 'Uninstall' } else { 'Install' })" -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