<# .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