mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-02-18 00:17:39 +01:00
Refine Windows host installer logging (related to #709)
This commit is contained in:
@@ -17,22 +17,24 @@ param(
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# ANSI color codes for output
|
||||
$Red = "`e[31m"
|
||||
$Green = "`e[32m"
|
||||
$Yellow = "`e[33m"
|
||||
$Blue = "`e[34m"
|
||||
$Reset = "`e[0m"
|
||||
function Write-PulseMessage {
|
||||
param(
|
||||
[string]$Label,
|
||||
[string]$Message,
|
||||
[ConsoleColor]$Color
|
||||
)
|
||||
|
||||
function Write-Color {
|
||||
param([string]$Color, [string]$Message)
|
||||
Write-Host "${Color}${Message}${Reset}"
|
||||
if ($Label) {
|
||||
Write-Host ("[{0}] {1}" -f $Label, $Message) -ForegroundColor $Color
|
||||
} else {
|
||||
Write-Host $Message -ForegroundColor $Color
|
||||
}
|
||||
}
|
||||
|
||||
function Write-Success { param([string]$msg) Write-Color $Green "✓ $msg" }
|
||||
function Write-Error { param([string]$msg) Write-Color $Red "✗ $msg" }
|
||||
function Write-Info { param([string]$msg) Write-Color $Blue "ℹ $msg" }
|
||||
function Write-Warning { param([string]$msg) Write-Color $Yellow "⚠ $msg" }
|
||||
function PulseSuccess { param([string]$msg) Write-PulseMessage -Label 'OK' -Message $msg -Color 'Green' }
|
||||
function PulseError { param([string]$msg) Write-PulseMessage -Label 'FAIL' -Message $msg -Color 'Red' }
|
||||
function PulseInfo { param([string]$msg) Write-PulseMessage -Label 'INFO' -Message $msg -Color 'Cyan' }
|
||||
function PulseWarn { param([string]$msg) Write-PulseMessage -Label 'WARN' -Message $msg -Color 'Yellow' }
|
||||
|
||||
function Write-InstallerEvent {
|
||||
param(
|
||||
@@ -47,7 +49,7 @@ function Write-InstallerEvent {
|
||||
try {
|
||||
Write-EventLog -LogName Application -Source $SourceName -EventId $EventId -EntryType $EntryType -Message $Message
|
||||
} catch {
|
||||
Write-Warning "Unable to write installer event log entry: $_"
|
||||
PulseWarn "Unable to write installer event log entry: $_"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,16 +94,17 @@ function Test-AgentRegistration {
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Color $Blue "═══════════════════════════════════════════════════════════"
|
||||
Write-Color $Blue " Pulse Host Agent - Windows Installation"
|
||||
Write-Color $Blue "═══════════════════════════════════════════════════════════"
|
||||
$banner = "=" * 59
|
||||
Write-Host $banner -ForegroundColor Cyan
|
||||
Write-Host " Pulse Host Agent - Windows Installation" -ForegroundColor Cyan
|
||||
Write-Host $banner -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
# Check if running as Administrator
|
||||
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
if (-not $isAdmin) {
|
||||
Write-Error "This script must be run as Administrator"
|
||||
Write-Info "Right-click PowerShell and select 'Run as Administrator'"
|
||||
PulseError "This script must be run as Administrator"
|
||||
PulseInfo "Right-click PowerShell and select 'Run as Administrator'"
|
||||
exit 1
|
||||
}
|
||||
|
||||
@@ -112,7 +115,7 @@ if (-not $PulseUrl) {
|
||||
$PulseUrl = $PulseUrl.TrimEnd('/')
|
||||
|
||||
if (-not $Token) {
|
||||
Write-Warning "No API token provided - agent will attempt to connect without authentication"
|
||||
PulseWarn "No API token provided - agent will attempt to connect without authentication"
|
||||
$response = Read-Host "Continue without token? (y/N)"
|
||||
if ($response -ne 'y' -and $response -ne 'Y') {
|
||||
$Token = Read-Host "Enter API token"
|
||||
@@ -123,7 +126,7 @@ if (-not $Interval) {
|
||||
$Interval = "30s"
|
||||
}
|
||||
|
||||
Write-Info "Configuration:"
|
||||
PulseInfo "Configuration:"
|
||||
Write-Host " Pulse URL: $PulseUrl"
|
||||
Write-Host " Token: $(if ($Token) { '***' + $Token.Substring([Math]::Max(0, $Token.Length - 4)) } else { 'none' })"
|
||||
Write-Host " Interval: $Interval"
|
||||
@@ -137,13 +140,19 @@ switch ($osArch) {
|
||||
'X64' { $arch = 'amd64' }
|
||||
'X86' { $arch = '386' }
|
||||
default {
|
||||
Write-Error "Unsupported architecture: $osArch"
|
||||
PulseError "Unsupported architecture: $osArch"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
$downloadUrl = "$PulseUrl/download/pulse-host-agent?platform=windows&arch=$arch"
|
||||
|
||||
Write-Info "Downloading agent binary from $downloadUrl..."
|
||||
PulseInfo "System Information:"
|
||||
Write-Host " OS Architecture: $osArch"
|
||||
Write-Host " Download Architecture: $arch"
|
||||
Write-Host " Download URL: $downloadUrl"
|
||||
Write-Host ""
|
||||
|
||||
PulseInfo "Downloading agent binary from $downloadUrl..."
|
||||
try {
|
||||
# Create install directory
|
||||
if (-not (Test-Path $InstallPath)) {
|
||||
@@ -154,7 +163,66 @@ try {
|
||||
|
||||
# Download binary
|
||||
Invoke-WebRequest -Uri $downloadUrl -OutFile $agentPath -UseBasicParsing
|
||||
Write-Success "Downloaded agent to $agentPath"
|
||||
PulseSuccess "Downloaded agent to $agentPath"
|
||||
|
||||
# Validate PE header
|
||||
$fileBytes = [System.IO.File]::ReadAllBytes($agentPath)
|
||||
$fileSizeMB = [math]::Round($fileBytes.Length / 1MB, 2)
|
||||
PulseInfo "File size: $fileSizeMB MB ($($fileBytes.Length) bytes)"
|
||||
|
||||
if ($fileBytes.Length -lt 64) {
|
||||
throw "Downloaded file is too small ($($fileBytes.Length) bytes) - expected Windows PE executable"
|
||||
}
|
||||
|
||||
# Check for MZ signature (PE header)
|
||||
if ($fileBytes[0] -ne 0x4D -or $fileBytes[1] -ne 0x5A) {
|
||||
$firstBytes = ($fileBytes[0..15] | ForEach-Object { $_.ToString("X2") }) -join " "
|
||||
throw "Downloaded file is not a valid Windows executable (missing MZ signature). First bytes: $firstBytes"
|
||||
}
|
||||
|
||||
# Get PE header offset (at 0x3C)
|
||||
$peOffset = [BitConverter]::ToUInt32($fileBytes, 0x3C)
|
||||
if ($peOffset -ge $fileBytes.Length - 6) {
|
||||
throw "Invalid PE header offset in downloaded file"
|
||||
}
|
||||
|
||||
# Check PE signature
|
||||
if ($fileBytes[$peOffset] -ne 0x50 -or $fileBytes[$peOffset+1] -ne 0x45) {
|
||||
throw "Downloaded file has invalid PE signature"
|
||||
}
|
||||
|
||||
# Check machine type (should be 0x8664 for x64, 0xAA64 for ARM64)
|
||||
$machineType = [BitConverter]::ToUInt16($fileBytes, $peOffset + 4)
|
||||
$expectedMachine = switch ($arch) {
|
||||
'amd64' { 0x8664 }
|
||||
'arm64' { 0xAA64 }
|
||||
'386' { 0x014C }
|
||||
default { 0x0000 }
|
||||
}
|
||||
|
||||
if ($machineType -ne $expectedMachine) {
|
||||
$machineStr = "0x" + $machineType.ToString("X4")
|
||||
$expectedStr = "0x" + $expectedMachine.ToString("X4")
|
||||
throw "Downloaded binary is for wrong architecture (got $machineStr, expected $expectedStr for $arch)"
|
||||
}
|
||||
|
||||
PulseSuccess "Verified PE executable for $osArch architecture"
|
||||
|
||||
# Verify checksum
|
||||
PulseInfo "Verifying checksum..."
|
||||
$checksumUrl = "$PulseUrl/download/pulse-host-agent.sha256?platform=windows&arch=$arch"
|
||||
try {
|
||||
$expectedChecksum = (Invoke-WebRequest -Uri $checksumUrl -UseBasicParsing).Content.Trim().Split()[0]
|
||||
$actualChecksum = (Get-FileHash -Path $agentPath -Algorithm SHA256).Hash.ToLower()
|
||||
|
||||
if ($actualChecksum -ne $expectedChecksum.ToLower()) {
|
||||
throw "Checksum mismatch! Expected: $expectedChecksum, Got: $actualChecksum"
|
||||
}
|
||||
PulseSuccess "Checksum verified: $actualChecksum"
|
||||
} catch {
|
||||
PulseWarn "Could not verify checksum: $_"
|
||||
PulseInfo "Continuing anyway (PE header was validated)"
|
||||
}
|
||||
|
||||
$agentArgs = @("--url", "`"$PulseUrl`"", "--interval", $Interval)
|
||||
if ($Token) {
|
||||
@@ -163,7 +231,7 @@ try {
|
||||
$serviceBinaryPath = "`"$agentPath`" $($agentArgs -join ' ')"
|
||||
$manualCommand = "& `"$agentPath`" $($agentArgs -join ' ')"
|
||||
} catch {
|
||||
Write-Error "Failed to download agent: $_"
|
||||
PulseError "Failed to download agent: $_"
|
||||
exit 1
|
||||
}
|
||||
|
||||
@@ -178,23 +246,23 @@ if ($Token) {
|
||||
}
|
||||
|
||||
$config | ConvertTo-Json | Set-Content $configPath
|
||||
Write-Success "Created configuration at $configPath"
|
||||
PulseSuccess "Created configuration at $configPath"
|
||||
|
||||
# Stop existing service if running
|
||||
$serviceName = "PulseHostAgent"
|
||||
$existingService = Get-Service -Name $serviceName -ErrorAction SilentlyContinue
|
||||
if ($existingService) {
|
||||
Write-Info "Stopping existing service..."
|
||||
PulseInfo "Stopping existing service..."
|
||||
Stop-Service -Name $serviceName -Force
|
||||
Write-Success "Stopped existing service"
|
||||
PulseSuccess "Stopped existing service"
|
||||
}
|
||||
|
||||
if (-not $NoService) {
|
||||
Write-Info "Installing native Windows service with built-in service support..."
|
||||
PulseInfo "Installing native Windows service with built-in service support..."
|
||||
|
||||
try {
|
||||
if ($existingService) {
|
||||
Write-Info "Removing existing service..."
|
||||
PulseInfo "Removing existing service..."
|
||||
sc.exe delete $serviceName | Out-Null
|
||||
Start-Sleep -Seconds 2
|
||||
}
|
||||
@@ -206,73 +274,73 @@ if (-not $NoService) {
|
||||
-Description "Monitors system metrics and reports to Pulse monitoring server" `
|
||||
-StartupType Automatic | Out-Null
|
||||
|
||||
Write-Success "Created Windows service '$serviceName'"
|
||||
PulseSuccess "Created Windows service '$serviceName'"
|
||||
|
||||
# Register Windows Event Log source
|
||||
try {
|
||||
if (-not ([System.Diagnostics.EventLog]::SourceExists($serviceName))) {
|
||||
New-EventLog -LogName Application -Source $serviceName
|
||||
Write-Success "Registered Event Log source"
|
||||
PulseSuccess "Registered Event Log source"
|
||||
}
|
||||
} catch {
|
||||
Write-Warning "Could not register Event Log source (not critical): $_"
|
||||
PulseWarn "Could not register Event Log source (not critical): $_"
|
||||
}
|
||||
|
||||
Write-InstallerEvent -SourceName $serviceName -Message "Pulse Host Agent installer registered service version $(Get-Item $agentPath).VersionInfo.FileVersion" -EventId 1000
|
||||
|
||||
# Configure service recovery options (restart on failure)
|
||||
sc.exe failure $serviceName reset= 86400 actions= restart/60000/restart/60000/restart/60000 | Out-Null
|
||||
Write-Success "Configured automatic restart on failure"
|
||||
PulseSuccess "Configured automatic restart on failure"
|
||||
|
||||
# Start the service
|
||||
Write-Info "Starting service..."
|
||||
PulseInfo "Starting service..."
|
||||
Start-Service -Name $serviceName
|
||||
Start-Sleep -Seconds 3
|
||||
|
||||
$status = (Get-Service -Name $serviceName).Status
|
||||
if ($status -eq 'Running') {
|
||||
Write-Success "Service started successfully!"
|
||||
PulseSuccess "Service started successfully!"
|
||||
|
||||
Write-Info "Waiting 10 seconds to validate agent reporting..."
|
||||
PulseInfo "Waiting 10 seconds to validate agent reporting..."
|
||||
Start-Sleep -Seconds 10
|
||||
|
||||
$hostname = $env:COMPUTERNAME
|
||||
$lookupHost = Test-AgentRegistration -PulseUrl $PulseUrl -Hostname $hostname -Token $Token
|
||||
if ($lookupHost) {
|
||||
Write-Success "Agent successfully registered with Pulse (host '$hostname')."
|
||||
PulseSuccess "Agent successfully registered with Pulse (host '$hostname')."
|
||||
if ($lookupHost.status) {
|
||||
$lastSeen = $lookupHost.lastSeen
|
||||
if ($lastSeen -is [DateTime]) {
|
||||
$lastSeen = $lastSeen.ToString("u")
|
||||
}
|
||||
Write-Info ("Pulse reports status: {0} (last seen {1})" -f $lookupHost.status, $lastSeen)
|
||||
PulseInfo ("Pulse reports status: {0} (last seen {1})" -f $lookupHost.status, $lastSeen)
|
||||
}
|
||||
Write-Info "Check your Pulse dashboard - this host should appear shortly."
|
||||
PulseInfo "Check your Pulse dashboard - this host should appear shortly."
|
||||
$statusForLog = if ($lookupHost.status) { $lookupHost.status } else { 'unknown' }
|
||||
Write-InstallerEvent -SourceName $serviceName -Message "Installer verified host '$hostname' reporting to Pulse (status: $statusForLog)." -EventId 1010
|
||||
} elseif ($Token) {
|
||||
Write-Warning "Agent is running but the lookup endpoint has not confirmed registration yet."
|
||||
Write-Info "It may take another moment for metrics to appear in the dashboard."
|
||||
PulseWarn "Agent is running but the lookup endpoint has not confirmed registration yet."
|
||||
PulseInfo "It may take another moment for metrics to appear in the dashboard."
|
||||
Write-InstallerEvent -SourceName $serviceName -Message "Installer could not yet confirm host '$hostname' registration with Pulse." -EntryType Warning -EventId 1011
|
||||
} else {
|
||||
Write-Info "Registration check skipped (no API token available)."
|
||||
PulseInfo "Registration check skipped (no API token available)."
|
||||
Write-InstallerEvent -SourceName $serviceName -Message "Installer skipped registration lookup (no API token provided)." -EventId 1012
|
||||
}
|
||||
|
||||
$recentLogs = Get-RecentAgentEvents -ProviderName $serviceName -Max 5
|
||||
if ($recentLogs) {
|
||||
Write-Info "Recent service events:"
|
||||
PulseInfo "Recent service events:"
|
||||
$recentLogs | Select-Object -First 3 | ForEach-Object {
|
||||
$time = $_.TimeCreated
|
||||
if (-not $time) { $time = $_.TimeGenerated }
|
||||
Write-Host (" [{0}] {1}" -f $time.ToString("u"), $_.Message)
|
||||
}
|
||||
} else {
|
||||
Write-Warning "No recent Application log entries were found for $serviceName."
|
||||
PulseWarn "No recent Application log entries were found for $serviceName."
|
||||
}
|
||||
} else {
|
||||
Write-Warning "Service status: $status"
|
||||
Write-Info "Checking service logs..."
|
||||
PulseWarn "Service status: $status"
|
||||
PulseInfo "Checking service logs..."
|
||||
$recentLogs = Get-RecentAgentEvents -ProviderName $serviceName -Max 5
|
||||
if ($recentLogs) {
|
||||
$recentLogs | ForEach-Object {
|
||||
@@ -281,32 +349,33 @@ if (-not $NoService) {
|
||||
Write-Host (" [{0}] {1}" -f $time.ToString("u"), $_.Message)
|
||||
}
|
||||
} else {
|
||||
Write-Warning "No Application log entries were found for $serviceName."
|
||||
PulseWarn "No Application log entries were found for $serviceName."
|
||||
}
|
||||
}
|
||||
|
||||
} catch {
|
||||
Write-Error "Failed to create/start service: $_"
|
||||
Write-Info "You can start the agent manually with:"
|
||||
PulseError "Failed to create/start service: $_"
|
||||
PulseInfo "You can start the agent manually with:"
|
||||
Write-Host " $manualCommand"
|
||||
Write-Host ""
|
||||
Write-Info "Or check Windows Event Viewer (Application log) for error details."
|
||||
PulseInfo "Or check Windows Event Viewer (Application log) for error details."
|
||||
exit 1
|
||||
}
|
||||
} else {
|
||||
Write-Info "Skipping service installation (--NoService flag)"
|
||||
PulseInfo "Skipping service installation (--NoService flag)"
|
||||
Write-Host ""
|
||||
Write-Info "To start the agent manually:"
|
||||
PulseInfo "To start the agent manually:"
|
||||
Write-Host " $manualCommand"
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Color $Green "═══════════════════════════════════════════════════════════"
|
||||
Write-Success "Installation complete!"
|
||||
Write-Color $Green "═══════════════════════════════════════════════════════════"
|
||||
$successBanner = "=" * 59
|
||||
Write-Host $successBanner -ForegroundColor Green
|
||||
PulseSuccess "Installation complete!"
|
||||
Write-Host $successBanner -ForegroundColor Green
|
||||
Write-Host ""
|
||||
|
||||
Write-Info "Service Management Commands:"
|
||||
PulseInfo "Service Management Commands:"
|
||||
Write-Host " Start: Start-Service -Name PulseHostAgent"
|
||||
Write-Host " Stop: Stop-Service -Name PulseHostAgent"
|
||||
Write-Host " Restart: Restart-Service -Name PulseHostAgent"
|
||||
@@ -315,10 +384,10 @@ Write-Host " Remove: sc.exe delete PulseHostAgent"
|
||||
Write-Host " Logs: Get-WinEvent -FilterHashtable @{LogName='Application'; ProviderName='PulseHostAgent'} -MaxEvents 50"
|
||||
Write-Host ""
|
||||
|
||||
Write-Info "Files installed:"
|
||||
PulseInfo "Files installed:"
|
||||
Write-Host " Binary: $agentPath"
|
||||
Write-Host " Config: $configPath"
|
||||
Write-Host ""
|
||||
|
||||
Write-Info "The agent is now reporting to: $PulseUrl"
|
||||
PulseInfo "The agent is now reporting to: $PulseUrl"
|
||||
Write-Host ""
|
||||
|
||||
@@ -10,92 +10,95 @@ param(
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# ANSI color codes for output
|
||||
$Red = "`e[31m"
|
||||
$Green = "`e[32m"
|
||||
$Yellow = "`e[33m"
|
||||
$Blue = "`e[34m"
|
||||
$Reset = "`e[0m"
|
||||
function Write-PulseMessage {
|
||||
param(
|
||||
[string]$Label,
|
||||
[string]$Message,
|
||||
[ConsoleColor]$Color
|
||||
)
|
||||
|
||||
function Write-Color {
|
||||
param([string]$Color, [string]$Message)
|
||||
Write-Host "${Color}${Message}${Reset}"
|
||||
if ($Label) {
|
||||
Write-Host ("[{0}] {1}" -f $Label, $Message) -ForegroundColor $Color
|
||||
} else {
|
||||
Write-Host $Message -ForegroundColor $Color
|
||||
}
|
||||
}
|
||||
|
||||
function Write-Success { param([string]$msg) Write-Color $Green "✓ $msg" }
|
||||
function Write-Error { param([string]$msg) Write-Color $Red "✗ $msg" }
|
||||
function Write-Info { param([string]$msg) Write-Color $Blue "ℹ $msg" }
|
||||
function Write-Warning { param([string]$msg) Write-Color $Yellow "⚠ $msg" }
|
||||
function PulseSuccess { param([string]$msg) Write-PulseMessage -Label 'OK' -Message $msg -Color 'Green' }
|
||||
function PulseError { param([string]$msg) Write-PulseMessage -Label 'FAIL' -Message $msg -Color 'Red' }
|
||||
function PulseInfo { param([string]$msg) Write-PulseMessage -Label 'INFO' -Message $msg -Color 'Cyan' }
|
||||
function PulseWarn { param([string]$msg) Write-PulseMessage -Label 'WARN' -Message $msg -Color 'Yellow' }
|
||||
|
||||
Write-Host ""
|
||||
Write-Color $Blue "═══════════════════════════════════════════════════════════"
|
||||
Write-Color $Blue " Pulse Host Agent - Windows Uninstallation"
|
||||
Write-Color $Blue "═══════════════════════════════════════════════════════════"
|
||||
$banner = "=" * 59
|
||||
Write-Host $banner -ForegroundColor Cyan
|
||||
Write-Host " Pulse Host Agent - Windows Uninstallation" -ForegroundColor Cyan
|
||||
Write-Host $banner -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
# Check if running as Administrator
|
||||
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
if (-not $isAdmin) {
|
||||
Write-Error "This script must be run as Administrator"
|
||||
Write-Info "Right-click PowerShell and select 'Run as Administrator'"
|
||||
PulseError "This script must be run as Administrator"
|
||||
PulseInfo "Right-click PowerShell and select 'Run as Administrator'"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$serviceName = "PulseHostAgent"
|
||||
|
||||
# Stop and remove service
|
||||
Write-Info "Checking for Pulse Host Agent service..."
|
||||
PulseInfo "Checking for Pulse Host Agent service..."
|
||||
$service = Get-Service -Name $serviceName -ErrorAction SilentlyContinue
|
||||
|
||||
if ($service) {
|
||||
if ($service.Status -eq 'Running') {
|
||||
Write-Info "Stopping service..."
|
||||
PulseInfo "Stopping service..."
|
||||
try {
|
||||
Stop-Service -Name $serviceName -Force
|
||||
Write-Success "Service stopped"
|
||||
PulseSuccess "Service stopped"
|
||||
} catch {
|
||||
Write-Warning "Could not stop service: $_"
|
||||
PulseWarn "Could not stop service: $_"
|
||||
}
|
||||
}
|
||||
|
||||
Write-Info "Removing service..."
|
||||
PulseInfo "Removing service..."
|
||||
try {
|
||||
sc.exe delete $serviceName | Out-Null
|
||||
Write-Success "Service removed"
|
||||
PulseSuccess "Service removed"
|
||||
} catch {
|
||||
Write-Warning "Could not remove service: $_"
|
||||
PulseWarn "Could not remove service: $_"
|
||||
}
|
||||
} else {
|
||||
Write-Info "Service not found (already removed or never installed)"
|
||||
PulseInfo "Service not found (already removed or never installed)"
|
||||
}
|
||||
|
||||
# Ensure all processes are terminated
|
||||
Write-Info "Ensuring all processes are terminated..."
|
||||
PulseInfo "Ensuring all processes are terminated..."
|
||||
$processes = Get-Process -Name "pulse-host-agent" -ErrorAction SilentlyContinue
|
||||
if ($processes) {
|
||||
$processes | Stop-Process -Force
|
||||
Start-Sleep -Seconds 2
|
||||
Write-Success "Processes terminated"
|
||||
PulseSuccess "Processes terminated"
|
||||
} else {
|
||||
Write-Info "No running processes found"
|
||||
PulseInfo "No running processes found"
|
||||
}
|
||||
|
||||
# Remove Event Log source
|
||||
Write-Info "Removing Event Log source..."
|
||||
PulseInfo "Removing Event Log source..."
|
||||
try {
|
||||
if ([System.Diagnostics.EventLog]::SourceExists($serviceName)) {
|
||||
Remove-EventLog -Source $serviceName
|
||||
Write-Success "Event Log source removed"
|
||||
PulseSuccess "Event Log source removed"
|
||||
} else {
|
||||
Write-Info "Event Log source not found"
|
||||
PulseInfo "Event Log source not found"
|
||||
}
|
||||
} catch {
|
||||
Write-Warning "Could not remove Event Log source: $_"
|
||||
PulseWarn "Could not remove Event Log source: $_"
|
||||
}
|
||||
|
||||
# Remove installation directory with retry logic (Windows file locking)
|
||||
if (Test-Path $InstallPath) {
|
||||
Write-Info "Removing installation directory..."
|
||||
PulseInfo "Removing installation directory..."
|
||||
|
||||
$retries = 3
|
||||
$success = $false
|
||||
@@ -106,30 +109,31 @@ if (Test-Path $InstallPath) {
|
||||
Start-Sleep -Seconds 2
|
||||
|
||||
Remove-Item -Path $InstallPath -Recurse -Force -ErrorAction Stop
|
||||
Write-Success "Installation directory removed: $InstallPath"
|
||||
PulseSuccess "Installation directory removed: $InstallPath"
|
||||
$success = $true
|
||||
} catch {
|
||||
$retries--
|
||||
if ($retries -gt 0) {
|
||||
Write-Warning "File still locked, retrying... ($retries attempts remaining)"
|
||||
PulseWarn "File still locked, retrying... ($retries attempts remaining)"
|
||||
} else {
|
||||
Write-Error "Could not remove installation directory after multiple attempts: $_"
|
||||
Write-Warning "The service may still have file handles open."
|
||||
Write-Warning "Please wait a few seconds and manually delete: $InstallPath"
|
||||
Write-Info "Or reboot and run the uninstall script again."
|
||||
PulseError "Could not remove installation directory after multiple attempts: $_"
|
||||
PulseWarn "The service may still have file handles open."
|
||||
PulseWarn "Please wait a few seconds and manually delete: $InstallPath"
|
||||
PulseInfo "Or reboot and run the uninstall script again."
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Write-Info "Installation directory not found: $InstallPath"
|
||||
PulseInfo "Installation directory not found: $InstallPath"
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Color $Green "═══════════════════════════════════════════════════════════"
|
||||
Write-Success "Uninstallation complete!"
|
||||
Write-Color $Green "═══════════════════════════════════════════════════════════"
|
||||
$successBanner = "=" * 59
|
||||
Write-Host $successBanner -ForegroundColor Green
|
||||
PulseSuccess "Uninstallation complete!"
|
||||
Write-Host $successBanner -ForegroundColor Green
|
||||
Write-Host ""
|
||||
|
||||
Write-Info "The Pulse Host Agent has been removed from this system."
|
||||
Write-Info "This host will no longer appear in your Pulse dashboard."
|
||||
PulseInfo "The Pulse Host Agent has been removed from this system."
|
||||
PulseInfo "This host will no longer appear in your Pulse dashboard."
|
||||
Write-Host ""
|
||||
|
||||
@@ -17,22 +17,24 @@ param(
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# ANSI color codes for output
|
||||
$Red = "`e[31m"
|
||||
$Green = "`e[32m"
|
||||
$Yellow = "`e[33m"
|
||||
$Blue = "`e[34m"
|
||||
$Reset = "`e[0m"
|
||||
function Write-PulseMessage {
|
||||
param(
|
||||
[string]$Label,
|
||||
[string]$Message,
|
||||
[ConsoleColor]$Color
|
||||
)
|
||||
|
||||
function Write-Color {
|
||||
param([string]$Color, [string]$Message)
|
||||
Write-Host "${Color}${Message}${Reset}"
|
||||
if ($Label) {
|
||||
Write-Host ("[{0}] {1}" -f $Label, $Message) -ForegroundColor $Color
|
||||
} else {
|
||||
Write-Host $Message -ForegroundColor $Color
|
||||
}
|
||||
}
|
||||
|
||||
function Write-Success { param([string]$msg) Write-Color $Green "✓ $msg" }
|
||||
function Write-Error { param([string]$msg) Write-Color $Red "✗ $msg" }
|
||||
function Write-Info { param([string]$msg) Write-Color $Blue "ℹ $msg" }
|
||||
function Write-Warning { param([string]$msg) Write-Color $Yellow "⚠ $msg" }
|
||||
function PulseSuccess { param([string]$msg) Write-PulseMessage -Label 'OK' -Message $msg -Color 'Green' }
|
||||
function PulseError { param([string]$msg) Write-PulseMessage -Label 'FAIL' -Message $msg -Color 'Red' }
|
||||
function PulseInfo { param([string]$msg) Write-PulseMessage -Label 'INFO' -Message $msg -Color 'Cyan' }
|
||||
function PulseWarn { param([string]$msg) Write-PulseMessage -Label 'WARN' -Message $msg -Color 'Yellow' }
|
||||
|
||||
function Write-InstallerEvent {
|
||||
param(
|
||||
@@ -47,7 +49,7 @@ function Write-InstallerEvent {
|
||||
try {
|
||||
Write-EventLog -LogName Application -Source $SourceName -EventId $EventId -EntryType $EntryType -Message $Message
|
||||
} catch {
|
||||
Write-Warning "Unable to write installer event log entry: $_"
|
||||
PulseWarn "Unable to write installer event log entry: $_"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,16 +94,17 @@ function Test-AgentRegistration {
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Color $Blue "═══════════════════════════════════════════════════════════"
|
||||
Write-Color $Blue " Pulse Host Agent - Windows Installation"
|
||||
Write-Color $Blue "═══════════════════════════════════════════════════════════"
|
||||
$banner = "=" * 59
|
||||
Write-Host $banner -ForegroundColor Cyan
|
||||
Write-Host " Pulse Host Agent - Windows Installation" -ForegroundColor Cyan
|
||||
Write-Host $banner -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
# Check if running as Administrator
|
||||
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
if (-not $isAdmin) {
|
||||
Write-Error "This script must be run as Administrator"
|
||||
Write-Info "Right-click PowerShell and select 'Run as Administrator'"
|
||||
PulseError "This script must be run as Administrator"
|
||||
PulseInfo "Right-click PowerShell and select 'Run as Administrator'"
|
||||
exit 1
|
||||
}
|
||||
|
||||
@@ -112,7 +115,7 @@ if (-not $PulseUrl) {
|
||||
$PulseUrl = $PulseUrl.TrimEnd('/')
|
||||
|
||||
if (-not $Token) {
|
||||
Write-Warning "No API token provided - agent will attempt to connect without authentication"
|
||||
PulseWarn "No API token provided - agent will attempt to connect without authentication"
|
||||
$response = Read-Host "Continue without token? (y/N)"
|
||||
if ($response -ne 'y' -and $response -ne 'Y') {
|
||||
$Token = Read-Host "Enter API token"
|
||||
@@ -123,7 +126,7 @@ if (-not $Interval) {
|
||||
$Interval = "30s"
|
||||
}
|
||||
|
||||
Write-Info "Configuration:"
|
||||
PulseInfo "Configuration:"
|
||||
Write-Host " Pulse URL: $PulseUrl"
|
||||
Write-Host " Token: $(if ($Token) { '***' + $Token.Substring([Math]::Max(0, $Token.Length - 4)) } else { 'none' })"
|
||||
Write-Host " Interval: $Interval"
|
||||
@@ -137,19 +140,19 @@ switch ($osArch) {
|
||||
'X64' { $arch = 'amd64' }
|
||||
'X86' { $arch = '386' }
|
||||
default {
|
||||
Write-Error "Unsupported architecture: $osArch"
|
||||
PulseError "Unsupported architecture: $osArch"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
$downloadUrl = "$PulseUrl/download/pulse-host-agent?platform=windows&arch=$arch"
|
||||
|
||||
Write-Info "System Information:"
|
||||
PulseInfo "System Information:"
|
||||
Write-Host " OS Architecture: $osArch"
|
||||
Write-Host " Download Architecture: $arch"
|
||||
Write-Host " Download URL: $downloadUrl"
|
||||
Write-Host ""
|
||||
|
||||
Write-Info "Downloading agent binary from $downloadUrl..."
|
||||
PulseInfo "Downloading agent binary from $downloadUrl..."
|
||||
try {
|
||||
# Create install directory
|
||||
if (-not (Test-Path $InstallPath)) {
|
||||
@@ -160,12 +163,12 @@ try {
|
||||
|
||||
# Download binary
|
||||
Invoke-WebRequest -Uri $downloadUrl -OutFile $agentPath -UseBasicParsing
|
||||
Write-Success "Downloaded agent to $agentPath"
|
||||
PulseSuccess "Downloaded agent to $agentPath"
|
||||
|
||||
# Validate PE header
|
||||
$fileBytes = [System.IO.File]::ReadAllBytes($agentPath)
|
||||
$fileSizeMB = [math]::Round($fileBytes.Length / 1MB, 2)
|
||||
Write-Info "File size: $fileSizeMB MB ($($fileBytes.Length) bytes)"
|
||||
PulseInfo "File size: $fileSizeMB MB ($($fileBytes.Length) bytes)"
|
||||
|
||||
if ($fileBytes.Length -lt 64) {
|
||||
throw "Downloaded file is too small ($($fileBytes.Length) bytes) - expected Windows PE executable"
|
||||
@@ -203,10 +206,10 @@ try {
|
||||
throw "Downloaded binary is for wrong architecture (got $machineStr, expected $expectedStr for $arch)"
|
||||
}
|
||||
|
||||
Write-Success "Verified PE executable for $osArch architecture"
|
||||
PulseSuccess "Verified PE executable for $osArch architecture"
|
||||
|
||||
# Verify checksum
|
||||
Write-Info "Verifying checksum..."
|
||||
PulseInfo "Verifying checksum..."
|
||||
$checksumUrl = "$PulseUrl/download/pulse-host-agent.sha256?platform=windows&arch=$arch"
|
||||
try {
|
||||
$expectedChecksum = (Invoke-WebRequest -Uri $checksumUrl -UseBasicParsing).Content.Trim().Split()[0]
|
||||
@@ -215,10 +218,10 @@ try {
|
||||
if ($actualChecksum -ne $expectedChecksum.ToLower()) {
|
||||
throw "Checksum mismatch! Expected: $expectedChecksum, Got: $actualChecksum"
|
||||
}
|
||||
Write-Success "Checksum verified: $actualChecksum"
|
||||
PulseSuccess "Checksum verified: $actualChecksum"
|
||||
} catch {
|
||||
Write-Warning "Could not verify checksum: $_"
|
||||
Write-Info "Continuing anyway (PE header was validated)"
|
||||
PulseWarn "Could not verify checksum: $_"
|
||||
PulseInfo "Continuing anyway (PE header was validated)"
|
||||
}
|
||||
|
||||
$agentArgs = @("--url", "`"$PulseUrl`"", "--interval", $Interval)
|
||||
@@ -228,7 +231,7 @@ try {
|
||||
$serviceBinaryPath = "`"$agentPath`" $($agentArgs -join ' ')"
|
||||
$manualCommand = "& `"$agentPath`" $($agentArgs -join ' ')"
|
||||
} catch {
|
||||
Write-Error "Failed to download agent: $_"
|
||||
PulseError "Failed to download agent: $_"
|
||||
exit 1
|
||||
}
|
||||
|
||||
@@ -243,23 +246,23 @@ if ($Token) {
|
||||
}
|
||||
|
||||
$config | ConvertTo-Json | Set-Content $configPath
|
||||
Write-Success "Created configuration at $configPath"
|
||||
PulseSuccess "Created configuration at $configPath"
|
||||
|
||||
# Stop existing service if running
|
||||
$serviceName = "PulseHostAgent"
|
||||
$existingService = Get-Service -Name $serviceName -ErrorAction SilentlyContinue
|
||||
if ($existingService) {
|
||||
Write-Info "Stopping existing service..."
|
||||
PulseInfo "Stopping existing service..."
|
||||
Stop-Service -Name $serviceName -Force
|
||||
Write-Success "Stopped existing service"
|
||||
PulseSuccess "Stopped existing service"
|
||||
}
|
||||
|
||||
if (-not $NoService) {
|
||||
Write-Info "Installing native Windows service with built-in service support..."
|
||||
PulseInfo "Installing native Windows service with built-in service support..."
|
||||
|
||||
try {
|
||||
if ($existingService) {
|
||||
Write-Info "Removing existing service..."
|
||||
PulseInfo "Removing existing service..."
|
||||
sc.exe delete $serviceName | Out-Null
|
||||
Start-Sleep -Seconds 2
|
||||
}
|
||||
@@ -271,73 +274,73 @@ if (-not $NoService) {
|
||||
-Description "Monitors system metrics and reports to Pulse monitoring server" `
|
||||
-StartupType Automatic | Out-Null
|
||||
|
||||
Write-Success "Created Windows service '$serviceName'"
|
||||
PulseSuccess "Created Windows service '$serviceName'"
|
||||
|
||||
# Register Windows Event Log source
|
||||
try {
|
||||
if (-not ([System.Diagnostics.EventLog]::SourceExists($serviceName))) {
|
||||
New-EventLog -LogName Application -Source $serviceName
|
||||
Write-Success "Registered Event Log source"
|
||||
PulseSuccess "Registered Event Log source"
|
||||
}
|
||||
} catch {
|
||||
Write-Warning "Could not register Event Log source (not critical): $_"
|
||||
PulseWarn "Could not register Event Log source (not critical): $_"
|
||||
}
|
||||
|
||||
Write-InstallerEvent -SourceName $serviceName -Message "Pulse Host Agent installer registered service version $(Get-Item $agentPath).VersionInfo.FileVersion" -EventId 1000
|
||||
|
||||
# Configure service recovery options (restart on failure)
|
||||
sc.exe failure $serviceName reset= 86400 actions= restart/60000/restart/60000/restart/60000 | Out-Null
|
||||
Write-Success "Configured automatic restart on failure"
|
||||
PulseSuccess "Configured automatic restart on failure"
|
||||
|
||||
# Start the service
|
||||
Write-Info "Starting service..."
|
||||
PulseInfo "Starting service..."
|
||||
Start-Service -Name $serviceName
|
||||
Start-Sleep -Seconds 3
|
||||
|
||||
$status = (Get-Service -Name $serviceName).Status
|
||||
if ($status -eq 'Running') {
|
||||
Write-Success "Service started successfully!"
|
||||
PulseSuccess "Service started successfully!"
|
||||
|
||||
Write-Info "Waiting 10 seconds to validate agent reporting..."
|
||||
PulseInfo "Waiting 10 seconds to validate agent reporting..."
|
||||
Start-Sleep -Seconds 10
|
||||
|
||||
$hostname = $env:COMPUTERNAME
|
||||
$lookupHost = Test-AgentRegistration -PulseUrl $PulseUrl -Hostname $hostname -Token $Token
|
||||
if ($lookupHost) {
|
||||
Write-Success "Agent successfully registered with Pulse (host '$hostname')."
|
||||
PulseSuccess "Agent successfully registered with Pulse (host '$hostname')."
|
||||
if ($lookupHost.status) {
|
||||
$lastSeen = $lookupHost.lastSeen
|
||||
if ($lastSeen -is [DateTime]) {
|
||||
$lastSeen = $lastSeen.ToString("u")
|
||||
}
|
||||
Write-Info ("Pulse reports status: {0} (last seen {1})" -f $lookupHost.status, $lastSeen)
|
||||
PulseInfo ("Pulse reports status: {0} (last seen {1})" -f $lookupHost.status, $lastSeen)
|
||||
}
|
||||
Write-Info "Check your Pulse dashboard - this host should appear shortly."
|
||||
PulseInfo "Check your Pulse dashboard - this host should appear shortly."
|
||||
$statusForLog = if ($lookupHost.status) { $lookupHost.status } else { 'unknown' }
|
||||
Write-InstallerEvent -SourceName $serviceName -Message "Installer verified host '$hostname' reporting to Pulse (status: $statusForLog)." -EventId 1010
|
||||
} elseif ($Token) {
|
||||
Write-Warning "Agent is running but the lookup endpoint has not confirmed registration yet."
|
||||
Write-Info "It may take another moment for metrics to appear in the dashboard."
|
||||
PulseWarn "Agent is running but the lookup endpoint has not confirmed registration yet."
|
||||
PulseInfo "It may take another moment for metrics to appear in the dashboard."
|
||||
Write-InstallerEvent -SourceName $serviceName -Message "Installer could not yet confirm host '$hostname' registration with Pulse." -EntryType Warning -EventId 1011
|
||||
} else {
|
||||
Write-Info "Registration check skipped (no API token available)."
|
||||
PulseInfo "Registration check skipped (no API token available)."
|
||||
Write-InstallerEvent -SourceName $serviceName -Message "Installer skipped registration lookup (no API token provided)." -EventId 1012
|
||||
}
|
||||
|
||||
$recentLogs = Get-RecentAgentEvents -ProviderName $serviceName -Max 5
|
||||
if ($recentLogs) {
|
||||
Write-Info "Recent service events:"
|
||||
PulseInfo "Recent service events:"
|
||||
$recentLogs | Select-Object -First 3 | ForEach-Object {
|
||||
$time = $_.TimeCreated
|
||||
if (-not $time) { $time = $_.TimeGenerated }
|
||||
Write-Host (" [{0}] {1}" -f $time.ToString("u"), $_.Message)
|
||||
}
|
||||
} else {
|
||||
Write-Warning "No recent Application log entries were found for $serviceName."
|
||||
PulseWarn "No recent Application log entries were found for $serviceName."
|
||||
}
|
||||
} else {
|
||||
Write-Warning "Service status: $status"
|
||||
Write-Info "Checking service logs..."
|
||||
PulseWarn "Service status: $status"
|
||||
PulseInfo "Checking service logs..."
|
||||
$recentLogs = Get-RecentAgentEvents -ProviderName $serviceName -Max 5
|
||||
if ($recentLogs) {
|
||||
$recentLogs | ForEach-Object {
|
||||
@@ -346,32 +349,33 @@ if (-not $NoService) {
|
||||
Write-Host (" [{0}] {1}" -f $time.ToString("u"), $_.Message)
|
||||
}
|
||||
} else {
|
||||
Write-Warning "No Application log entries were found for $serviceName."
|
||||
PulseWarn "No Application log entries were found for $serviceName."
|
||||
}
|
||||
}
|
||||
|
||||
} catch {
|
||||
Write-Error "Failed to create/start service: $_"
|
||||
Write-Info "You can start the agent manually with:"
|
||||
PulseError "Failed to create/start service: $_"
|
||||
PulseInfo "You can start the agent manually with:"
|
||||
Write-Host " $manualCommand"
|
||||
Write-Host ""
|
||||
Write-Info "Or check Windows Event Viewer (Application log) for error details."
|
||||
PulseInfo "Or check Windows Event Viewer (Application log) for error details."
|
||||
exit 1
|
||||
}
|
||||
} else {
|
||||
Write-Info "Skipping service installation (--NoService flag)"
|
||||
PulseInfo "Skipping service installation (--NoService flag)"
|
||||
Write-Host ""
|
||||
Write-Info "To start the agent manually:"
|
||||
PulseInfo "To start the agent manually:"
|
||||
Write-Host " $manualCommand"
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Color $Green "═══════════════════════════════════════════════════════════"
|
||||
Write-Success "Installation complete!"
|
||||
Write-Color $Green "═══════════════════════════════════════════════════════════"
|
||||
$successBanner = "=" * 59
|
||||
Write-Host $successBanner -ForegroundColor Green
|
||||
PulseSuccess "Installation complete!"
|
||||
Write-Host $successBanner -ForegroundColor Green
|
||||
Write-Host ""
|
||||
|
||||
Write-Info "Service Management Commands:"
|
||||
PulseInfo "Service Management Commands:"
|
||||
Write-Host " Start: Start-Service -Name PulseHostAgent"
|
||||
Write-Host " Stop: Stop-Service -Name PulseHostAgent"
|
||||
Write-Host " Restart: Restart-Service -Name PulseHostAgent"
|
||||
@@ -380,10 +384,10 @@ Write-Host " Remove: sc.exe delete PulseHostAgent"
|
||||
Write-Host " Logs: Get-WinEvent -FilterHashtable @{LogName='Application'; ProviderName='PulseHostAgent'} -MaxEvents 50"
|
||||
Write-Host ""
|
||||
|
||||
Write-Info "Files installed:"
|
||||
PulseInfo "Files installed:"
|
||||
Write-Host " Binary: $agentPath"
|
||||
Write-Host " Config: $configPath"
|
||||
Write-Host ""
|
||||
|
||||
Write-Info "The agent is now reporting to: $PulseUrl"
|
||||
PulseInfo "The agent is now reporting to: $PulseUrl"
|
||||
Write-Host ""
|
||||
|
||||
@@ -10,92 +10,95 @@ param(
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# ANSI color codes for output
|
||||
$Red = "`e[31m"
|
||||
$Green = "`e[32m"
|
||||
$Yellow = "`e[33m"
|
||||
$Blue = "`e[34m"
|
||||
$Reset = "`e[0m"
|
||||
function Write-PulseMessage {
|
||||
param(
|
||||
[string]$Label,
|
||||
[string]$Message,
|
||||
[ConsoleColor]$Color
|
||||
)
|
||||
|
||||
function Write-Color {
|
||||
param([string]$Color, [string]$Message)
|
||||
Write-Host "${Color}${Message}${Reset}"
|
||||
if ($Label) {
|
||||
Write-Host ("[{0}] {1}" -f $Label, $Message) -ForegroundColor $Color
|
||||
} else {
|
||||
Write-Host $Message -ForegroundColor $Color
|
||||
}
|
||||
}
|
||||
|
||||
function Write-Success { param([string]$msg) Write-Color $Green "✓ $msg" }
|
||||
function Write-Error { param([string]$msg) Write-Color $Red "✗ $msg" }
|
||||
function Write-Info { param([string]$msg) Write-Color $Blue "ℹ $msg" }
|
||||
function Write-Warning { param([string]$msg) Write-Color $Yellow "⚠ $msg" }
|
||||
function PulseSuccess { param([string]$msg) Write-PulseMessage -Label 'OK' -Message $msg -Color 'Green' }
|
||||
function PulseError { param([string]$msg) Write-PulseMessage -Label 'FAIL' -Message $msg -Color 'Red' }
|
||||
function PulseInfo { param([string]$msg) Write-PulseMessage -Label 'INFO' -Message $msg -Color 'Cyan' }
|
||||
function PulseWarn { param([string]$msg) Write-PulseMessage -Label 'WARN' -Message $msg -Color 'Yellow' }
|
||||
|
||||
Write-Host ""
|
||||
Write-Color $Blue "═══════════════════════════════════════════════════════════"
|
||||
Write-Color $Blue " Pulse Host Agent - Windows Uninstallation"
|
||||
Write-Color $Blue "═══════════════════════════════════════════════════════════"
|
||||
$banner = "=" * 59
|
||||
Write-Host $banner -ForegroundColor Cyan
|
||||
Write-Host " Pulse Host Agent - Windows Uninstallation" -ForegroundColor Cyan
|
||||
Write-Host $banner -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
# Check if running as Administrator
|
||||
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
if (-not $isAdmin) {
|
||||
Write-Error "This script must be run as Administrator"
|
||||
Write-Info "Right-click PowerShell and select 'Run as Administrator'"
|
||||
PulseError "This script must be run as Administrator"
|
||||
PulseInfo "Right-click PowerShell and select 'Run as Administrator'"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$serviceName = "PulseHostAgent"
|
||||
|
||||
# Stop and remove service
|
||||
Write-Info "Checking for Pulse Host Agent service..."
|
||||
PulseInfo "Checking for Pulse Host Agent service..."
|
||||
$service = Get-Service -Name $serviceName -ErrorAction SilentlyContinue
|
||||
|
||||
if ($service) {
|
||||
if ($service.Status -eq 'Running') {
|
||||
Write-Info "Stopping service..."
|
||||
PulseInfo "Stopping service..."
|
||||
try {
|
||||
Stop-Service -Name $serviceName -Force
|
||||
Write-Success "Service stopped"
|
||||
PulseSuccess "Service stopped"
|
||||
} catch {
|
||||
Write-Warning "Could not stop service: $_"
|
||||
PulseWarn "Could not stop service: $_"
|
||||
}
|
||||
}
|
||||
|
||||
Write-Info "Removing service..."
|
||||
PulseInfo "Removing service..."
|
||||
try {
|
||||
sc.exe delete $serviceName | Out-Null
|
||||
Write-Success "Service removed"
|
||||
PulseSuccess "Service removed"
|
||||
} catch {
|
||||
Write-Warning "Could not remove service: $_"
|
||||
PulseWarn "Could not remove service: $_"
|
||||
}
|
||||
} else {
|
||||
Write-Info "Service not found (already removed or never installed)"
|
||||
PulseInfo "Service not found (already removed or never installed)"
|
||||
}
|
||||
|
||||
# Ensure all processes are terminated
|
||||
Write-Info "Ensuring all processes are terminated..."
|
||||
PulseInfo "Ensuring all processes are terminated..."
|
||||
$processes = Get-Process -Name "pulse-host-agent" -ErrorAction SilentlyContinue
|
||||
if ($processes) {
|
||||
$processes | Stop-Process -Force
|
||||
Start-Sleep -Seconds 2
|
||||
Write-Success "Processes terminated"
|
||||
PulseSuccess "Processes terminated"
|
||||
} else {
|
||||
Write-Info "No running processes found"
|
||||
PulseInfo "No running processes found"
|
||||
}
|
||||
|
||||
# Remove Event Log source
|
||||
Write-Info "Removing Event Log source..."
|
||||
PulseInfo "Removing Event Log source..."
|
||||
try {
|
||||
if ([System.Diagnostics.EventLog]::SourceExists($serviceName)) {
|
||||
Remove-EventLog -Source $serviceName
|
||||
Write-Success "Event Log source removed"
|
||||
PulseSuccess "Event Log source removed"
|
||||
} else {
|
||||
Write-Info "Event Log source not found"
|
||||
PulseInfo "Event Log source not found"
|
||||
}
|
||||
} catch {
|
||||
Write-Warning "Could not remove Event Log source: $_"
|
||||
PulseWarn "Could not remove Event Log source: $_"
|
||||
}
|
||||
|
||||
# Remove installation directory with retry logic (Windows file locking)
|
||||
if (Test-Path $InstallPath) {
|
||||
Write-Info "Removing installation directory..."
|
||||
PulseInfo "Removing installation directory..."
|
||||
|
||||
$retries = 3
|
||||
$success = $false
|
||||
@@ -106,30 +109,31 @@ if (Test-Path $InstallPath) {
|
||||
Start-Sleep -Seconds 2
|
||||
|
||||
Remove-Item -Path $InstallPath -Recurse -Force -ErrorAction Stop
|
||||
Write-Success "Installation directory removed: $InstallPath"
|
||||
PulseSuccess "Installation directory removed: $InstallPath"
|
||||
$success = $true
|
||||
} catch {
|
||||
$retries--
|
||||
if ($retries -gt 0) {
|
||||
Write-Warning "File still locked, retrying... ($retries attempts remaining)"
|
||||
PulseWarn "File still locked, retrying... ($retries attempts remaining)"
|
||||
} else {
|
||||
Write-Error "Could not remove installation directory after multiple attempts: $_"
|
||||
Write-Warning "The service may still have file handles open."
|
||||
Write-Warning "Please wait a few seconds and manually delete: $InstallPath"
|
||||
Write-Info "Or reboot and run the uninstall script again."
|
||||
PulseError "Could not remove installation directory after multiple attempts: $_"
|
||||
PulseWarn "The service may still have file handles open."
|
||||
PulseWarn "Please wait a few seconds and manually delete: $InstallPath"
|
||||
PulseInfo "Or reboot and run the uninstall script again."
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Write-Info "Installation directory not found: $InstallPath"
|
||||
PulseInfo "Installation directory not found: $InstallPath"
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Color $Green "═══════════════════════════════════════════════════════════"
|
||||
Write-Success "Uninstallation complete!"
|
||||
Write-Color $Green "═══════════════════════════════════════════════════════════"
|
||||
$successBanner = "=" * 59
|
||||
Write-Host $successBanner -ForegroundColor Green
|
||||
PulseSuccess "Uninstallation complete!"
|
||||
Write-Host $successBanner -ForegroundColor Green
|
||||
Write-Host ""
|
||||
|
||||
Write-Info "The Pulse Host Agent has been removed from this system."
|
||||
Write-Info "This host will no longer appear in your Pulse dashboard."
|
||||
PulseInfo "The Pulse Host Agent has been removed from this system."
|
||||
PulseInfo "This host will no longer appear in your Pulse dashboard."
|
||||
Write-Host ""
|
||||
|
||||
Reference in New Issue
Block a user