From b1bd830b0cd3be630e8a0b2f4cba472f3ab7f3c3 Mon Sep 17 00:00:00 2001 From: DistractADD Date: Thu, 10 Sep 2026 14:59:32 +1000 Subject: [PATCH] Update Deploy-ZabbixAgent2.ps1 Update SMB/HTTPS Failover --- Deploy-ZabbixAgent2.ps1 | 340 +++++++++++++++++++++++----------------- 1 file changed, 192 insertions(+), 148 deletions(-) diff --git a/Deploy-ZabbixAgent2.ps1 b/Deploy-ZabbixAgent2.ps1 index 0ad2ee2..974aa5c 100644 --- a/Deploy-ZabbixAgent2.ps1 +++ b/Deploy-ZabbixAgent2.ps1 @@ -1,149 +1,193 @@ -<# -.SYNOPSIS - Standardized Zabbix Agent 2 Enterprise Deployer (V2 Fleet Reconciliation) -#> -$ErrorActionPreference = "Stop" - -# --- 1. Versioned Idempotency Check --- -$markerDir = "C:\ProgramData\Zabbix" -$marker = "$markerDir\installed_v2.flag" -$service = Get-Service -Name "Zabbix Agent 2" -ErrorAction SilentlyContinue - -if ((Test-Path $marker) -and ($service -and $service.Status -eq "Running")) { - exit 0 -} - -if (-not (Test-Path $markerDir)) { - New-Item -ItemType Directory -Path $markerDir -Force | Out-Null -} - -# --- 2. Complete Network Subnet Resolution --- -$localIPs = (Get-NetIPAddress -AddressFamily IPv4 | Where-Object { $_.IPAddress -notmatch '^(127\.|169\.254\.)' }).IPAddress - -# Node 1: 192.168.100.0/24 through 192.168.105.255 -if ($localIPs -match '^192\.168\.(10[0-5])\.') { - $Location = "Node1" - $ZabbixServer = "192.168.101.30" - $ShareSource = "\\EHI-DC4\Zabbix" -} -# Node 2: 192.168.130.0-135.255 AND 192.168.141.0-145.255 -elseif ($localIPs -match '^192\.168\.(13[0-5]|14[1-5])\.') { - $Location = "Node2" - $ZabbixServer = "192.168.130.80" - $ShareSource = "\\E2HI-DC5\Zabbix" -} -# Brisbane: 192.168.3.0/24 AND 192.168.200.0/24 -elseif ($localIPs -match '^192\.168\.(3|200)\.') { - $Location = "Brisbane" - $ZabbixServer = "192.168.3.43" - $ShareSource = "\\BI-DC1\Zabbix" -} -# Fallback Default to Node 1 -else { - $Location = "Node1" - $ZabbixServer = "192.168.101.30" - $ShareSource = "\\EHI-DC4\Zabbix" -} - -# --- 3. Dynamic Hardware and Role Detection --- -$osInfo = Get-CimInstance -ClassName Win32_OperatingSystem -$Hostname = $env:COMPUTERNAME - -# Workstations -if ($osInfo.ProductType -eq 1) { - $Role = "Workstation" -} -# Primary: Hostname matches SQL naming convention (e.g., EHTS-SS01, BI-SS02) -elseif ($Hostname -match '-ss\d*') { - $Role = "SQL" -} -# Primary: Hostname matches Application naming convention (e.g., EHTS-APP38) -elseif ($Hostname -match '-app\d*') { - $Role = "Application" -} -# Secondary Fallback: Active MSSQLSERVER service on unstandardized server names -elseif (Get-Service -Name "MSSQLSERVER" -ErrorAction SilentlyContinue | Where-Object { $_.Status -eq "Running" }) { - $Role = "SQL" -} -# Default fallback for DCs, utilities, and general servers -else { - $Role = "Application" -} - -$HardwareType = if ((Get-CimInstance -ClassName Win32_ComputerSystem).Model -match "Virtual|VMware|KVM|Hyper-V") { - "VM" -} else { - "Physical" -} - -$MetadataVal = "Windows:$($HardwareType):$($Location):$($Role)" - -# --- 4. File Pull from Local DC Share --- -$SourceZip = "$ShareSource\zabbix_agent2.zip" -$InstallDir = "C:\Program Files\Zabbix Agent 2" -$TempZip = "C:\Temp\zabbix_agent2.zip" - -if (-not (Test-Path "C:\Temp")) { New-Item -ItemType Directory -Path "C:\Temp" -Force | Out-Null } - -# Stop running instances safely before touching binaries -Get-Service "Zabbix Agent*" -ErrorAction SilentlyContinue | Stop-Service -Force -ErrorAction SilentlyContinue -Get-Process "zabbix_agent*" -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue - -Copy-Item -Path $SourceZip -Destination $TempZip -Force - -if (Test-Path $InstallDir) { - Remove-Item $InstallDir -Recurse -Force -ErrorAction SilentlyContinue -} -New-Item -Path $InstallDir -ItemType Directory -Force | Out-Null - -Expand-Archive -Path $TempZip -DestinationPath $InstallDir -Force - -$BinDir = Get-ChildItem -Path $InstallDir -Recurse | Where-Object { $_.Name -eq "zabbix_agent2.exe" } | Select-Object -ExpandProperty DirectoryName -if ($BinDir -ne $InstallDir) { - Copy-Item -Path "$BinDir\*" -Destination $InstallDir -Recurse -Force -} - -# --- 5. Generate Standardized Configuration --- -$ConfigContent = @" -LogType=file -LogFile=$InstallDir\zabbix_agent2.log -Server=$ZabbixServer -ServerActive=$ZabbixServer -Hostname=$Hostname -HostMetadata=$MetadataVal -AllowKey=system.run[*] -Timeout=30 -ControlSocket=\\.\pipe\agent.sock -"@ -Set-Content -Path "$InstallDir\zabbix_agent2.conf" -Value $ConfigContent - -# --- 6. Service Installation & Startup --- -$ExePath = "$InstallDir\zabbix_agent2.exe" -$ConfPath = "$InstallDir\zabbix_agent2.conf" - -$existingService = Get-Service -Name "Zabbix Agent 2" -ErrorAction SilentlyContinue - -if (-not $existingService) { - # Remove orphan Event Log key if left behind by prior uninstalls or sc delete - Remove-Item -Path "HKLM:\SYSTEM\CurrentControlSet\Services\EventLog\Application\Zabbix Agent 2" -Recurse -Force -ErrorAction SilentlyContinue - - # Register the service for the first time - & $ExePath --config "$ConfPath" --install - Start-Sleep -Seconds 2 -} - -# Ensure service is started and set to automatic -Start-Service "Zabbix Agent 2" -ErrorAction SilentlyContinue -Set-Service -Name "Zabbix Agent 2" -StartupType Automatic - -# --- 7. Firewall Rules --- -if (-not (Get-NetFirewallRule -DisplayName "Zabbix Agent Inbound" -ErrorAction SilentlyContinue)) { - New-NetFirewallRule -DisplayName "Zabbix Agent Inbound" -Direction Inbound -LocalPort 10050 -Protocol TCP -Action Allow -Profile Any | Out-Null -} -if (-not (Get-NetFirewallRule -DisplayName "Zabbix Agent Outbound" -ErrorAction SilentlyContinue)) { - New-NetFirewallRule -DisplayName "Zabbix Agent Outbound" -Direction Outbound -RemotePort 10051 -Protocol TCP -Action Allow -Profile Any | Out-Null -} - -# --- 8. Finalize V2 State --- -New-Item -ItemType File -Path $marker -Force | Out-Null +<# +.SYNOPSIS + Standardized Zabbix Agent 2 Enterprise Deployer (V2 Fleet Reconciliation) +#> +$ErrorActionPreference = "Stop" + +# --- 1. Versioned Idempotency Check --- +$markerDir = "C:\ProgramData\Zabbix" +$marker = "$markerDir\installed_v2.flag" +$service = Get-Service -Name "Zabbix Agent 2" -ErrorAction SilentlyContinue + +if ((Test-Path $marker) -and ($service -and $service.Status -eq "Running")) { + exit 0 +} + +if (-not (Test-Path $markerDir)) { + New-Item -ItemType Directory -Path $markerDir -Force | Out-Null +} + +# --- 2. Complete Network Subnet Resolution --- +$localIPs = (Get-NetIPAddress -AddressFamily IPv4 | Where-Object { $_.IPAddress -notmatch '^(127\.|169\.254\.)' }).IPAddress + +# Node 1: 192.168.100.0/24 through 192.168.105.255 +if ($localIPs -match '^192\.168\.(10[0-5])\.') { + $Location = "Node1" + $ZabbixServer = "192.168.101.30" + $ShareSource = "\\EHI-DC4\Zabbix" +} +# Node 2: 192.168.130.0-135.255 AND 192.168.141.0-145.255 +elseif ($localIPs -match '^192\.168\.(13[0-5]|14[1-5])\.') { + $Location = "Node2" + $ZabbixServer = "192.168.130.80" + $ShareSource = "\\E2HI-DC5\Zabbix" +} +# Brisbane: 192.168.3.0/24 AND 192.168.200.0/24 +elseif ($localIPs -match '^192\.168\.(3|200)\.') { + $Location = "Brisbane" + $ZabbixServer = "192.168.3.43" + $ShareSource = "\\BI-DC1\Zabbix" +} +# Fallback Default to Node 1 +else { + $Location = "Node1" + $ZabbixServer = "192.168.101.30" + $ShareSource = "\\EHI-DC4\Zabbix" +} + +# --- 3. Dynamic Hardware and Role Detection --- +$osInfo = Get-CimInstance -ClassName Win32_OperatingSystem +$Hostname = $env:COMPUTERNAME + +# Workstations +if ($osInfo.ProductType -eq 1) { + $Role = "Workstation" +} +# Primary: Hostname matches SQL naming convention (e.g., EHTS-SS01, BI-SS02) +elseif ($Hostname -match '-ss\d*') { + $Role = "SQL" +} +# Primary: Hostname matches Application naming convention (e.g., EHTS-APP38) +elseif ($Hostname -match '-app\d*') { + $Role = "Application" +} +# Secondary Fallback: Active MSSQLSERVER service on unstandardized server names +elseif (Get-Service -Name "MSSQLSERVER" -ErrorAction SilentlyContinue | Where-Object { $_.Status -eq "Running" }) { + $Role = "SQL" +} +# Default fallback for DCs, utilities, and general servers +else { + $Role = "Application" +} + +$HardwareType = if ((Get-CimInstance -ClassName Win32_ComputerSystem).Model -match "Virtual|VMware|KVM|Hyper-V") { + "VM" +} else { + "Physical" +} + +$MetadataVal = "Windows:$($HardwareType):$($Location):$($Role)" + +# --- 4. File Acquisition with Multi-Tier Fallback (SMB -> Git -> CDN) --- +$SourceZip = "$ShareSource\zabbix_agent2.zip" +$GitZipUrl = "https://git.mkau.au/DistractADD/zabbix/raw/branch/main/zabbix_agent2.zip" +$CdnZipUrl = "https://cdn.zabbix.com/zabbix/binaries/stable/7.4/7.4.11/zabbix_agent2-7.4.11-windows-amd64-openssl-static.zip"[cite: 1, 3, 4, 5] +$InstallDir = "C:\Program Files\Zabbix Agent 2"[cite: 1, 3, 4, 5] +$TempZip = "C:\Temp\zabbix_agent2.zip"[cite: 1, 3, 4, 5] + +if (-not (Test-Path "C:\Temp")) { New-Item -ItemType Directory -Path "C:\Temp" -Force | Out-Null }[cite: 1, 3, 4, 5] + +# Stop running instances safely before replacing binaries +Get-Service "Zabbix Agent*" -ErrorAction SilentlyContinue | Stop-Service -Force -ErrorAction SilentlyContinue[cite: 1, 3, 4, 5] +Get-Process "zabbix_agent*" -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue[cite: 1, 3, 4, 5] + +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12[cite: 1, 3, 4, 5] +$acquired = $false + +# Attempt 1: Local DC SMB Share +try { + if (Test-Path $SourceZip -ErrorAction Stop) { + Copy-Item -Path $SourceZip -Destination $TempZip -Force -ErrorAction Stop + if ((Test-Path $TempZip) -and ((Get-Item $TempZip).Length -gt 1000000)) { + $acquired = $true + } + } +} +catch { + # SMB failed or blocked +} + +# Attempt 2: Internal Git Server (Ideal for firewalled/isolated subnets) +if (-not $acquired) { + try { + Write-Host "SMB inaccessible. Downloading agent archive from internal Git..." -ForegroundColor Yellow + Invoke-WebRequest -Uri $GitZipUrl -OutFile $TempZip -UseBasicParsing -TimeoutSec 30 -ErrorAction Stop + if ((Test-Path $TempZip) -and ((Get-Item $TempZip).Length -gt 1000000)) { + $acquired = $true + } + } + catch { + # Git raw zip not present or timed out + } +} + +# Attempt 3: Official Zabbix CDN Fallback +if (-not $acquired) { + try { + Write-Host "Git archive download failed. Falling back to official Zabbix CDN..." -ForegroundColor Yellow + Invoke-WebRequest -Uri $CdnZipUrl -OutFile $TempZip -UseBasicParsing -TimeoutSec 60 -ErrorAction Stop[cite: 1, 3, 4, 5] + if ((Test-Path $TempZip) -and ((Get-Item $TempZip).Length -gt 1000000)) { + $acquired = $true + } + } + catch { + throw "Critical: Failed to acquire Zabbix Agent archive via SMB, internal Git, or external CDN." + } +} + +if (Test-Path $InstallDir) { + Remove-Item $InstallDir -Recurse -Force -ErrorAction SilentlyContinue[cite: 1, 3, 4, 5] +} +New-Item -Path $InstallDir -ItemType Directory -Force | Out-Null[cite: 1, 3, 4, 5] + +Expand-Archive -Path $TempZip -DestinationPath $InstallDir -Force[cite: 1, 3, 4, 5] + +$BinDir = Get-ChildItem -Path $InstallDir -Recurse | Where-Object { $_.Name -eq "zabbix_agent2.exe" } | Select-Object -ExpandProperty DirectoryName[cite: 1, 3, 4, 5] +if ($BinDir -ne $InstallDir) { + Copy-Item -Path "$BinDir\*" -Destination $InstallDir -Recurse -Force[cite: 1, 3, 4, 5] +} + +# --- 5. Generate Standardized Configuration --- +$ConfigContent = @" +LogType=file +LogFile=$InstallDir\zabbix_agent2.log +Server=$ZabbixServer +ServerActive=$ZabbixServer +Hostname=$Hostname +HostMetadata=$MetadataVal +AllowKey=system.run[*] +Timeout=30 +ControlSocket=\\.\pipe\agent.sock +"@ +Set-Content -Path "$InstallDir\zabbix_agent2.conf" -Value $ConfigContent + +# --- 6. Service Installation & Startup --- +$ExePath = "$InstallDir\zabbix_agent2.exe" +$ConfPath = "$InstallDir\zabbix_agent2.conf" + +$existingService = Get-Service -Name "Zabbix Agent 2" -ErrorAction SilentlyContinue + +if (-not $existingService) { + # Remove orphan Event Log key if left behind by prior uninstalls or sc delete + Remove-Item -Path "HKLM:\SYSTEM\CurrentControlSet\Services\EventLog\Application\Zabbix Agent 2" -Recurse -Force -ErrorAction SilentlyContinue + + # Register the service for the first time + & $ExePath --config "$ConfPath" --install + Start-Sleep -Seconds 2 +} + +# Ensure service is started and set to automatic +Start-Service "Zabbix Agent 2" -ErrorAction SilentlyContinue +Set-Service -Name "Zabbix Agent 2" -StartupType Automatic + +# --- 7. Firewall Rules --- +if (-not (Get-NetFirewallRule -DisplayName "Zabbix Agent Inbound" -ErrorAction SilentlyContinue)) { + New-NetFirewallRule -DisplayName "Zabbix Agent Inbound" -Direction Inbound -LocalPort 10050 -Protocol TCP -Action Allow -Profile Any | Out-Null +} +if (-not (Get-NetFirewallRule -DisplayName "Zabbix Agent Outbound" -ErrorAction SilentlyContinue)) { + New-NetFirewallRule -DisplayName "Zabbix Agent Outbound" -Direction Outbound -RemotePort 10051 -Protocol TCP -Action Allow -Profile Any | Out-Null +} + +# --- 8. Finalize V2 State --- +New-Item -ItemType File -Path $marker -Force | Out-Null Remove-Item -Path $TempZip -Force -ErrorAction SilentlyContinue \ No newline at end of file