275 lines
9.9 KiB
PowerShell
275 lines
9.9 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Downloads and silently installs Zabbix Agent 2 for Windows, configured for a
|
|
Zabbix Proxy/Server, and opens the firewall for passive checks.
|
|
|
|
.DESCRIPTION
|
|
Downloads the Zabbix Agent 2 Windows MSI from cdn.zabbix.com and installs it silently via msiexec.
|
|
Hostname is set to the local computer name; both Server and ServerActive are set to the Zabbix Proxy/Server IP
|
|
address supplied by the caller (interactively, via -ZabbixProxyIPAddress, or via
|
|
$env:ZabbixProxyIPAddress). After a successful install it creates a Windows
|
|
Firewall rule allowing inbound TCP 10050 (Zabbix Agent passive checks) from that
|
|
same IP address only. Must be run elevated (Administrator).
|
|
|
|
.PARAMETER ZabbixProxyIPAddress
|
|
IP address of the Zabbix Proxy or Zabbix Server. Used for both the agent's Server
|
|
and ServerActive settings, and as the only allowed remote address for the TCP
|
|
10050 firewall rule. Omit this parameter to be prompted interactively (or to fall
|
|
back to $env:ZabbixProxyIPAddress if that is set).
|
|
|
|
.PARAMETER ZabbixAgentMsiUri
|
|
URI of the Zabbix Agent 2 Windows MSI to download and install. Defaults to version
|
|
7.2.13. Override this to install a different version/build, e.g. one of the other
|
|
files listed under https://cdn.zabbix.com/zabbix/binaries/stable/<major.minor>/<version>/.
|
|
|
|
.EXAMPLE
|
|
PS> .\Install-ZBXAgentManual.ps1
|
|
Downloads and installs Zabbix Agent 2, prompting for the Zabbix Proxy/Server IP
|
|
address.
|
|
|
|
.EXAMPLE
|
|
PS> .\Install-ZBXAgentManual.ps1 -ZabbixProxyIPAddress '192.168.10.50'
|
|
Downloads and installs Zabbix Agent 2 non-interactively.
|
|
|
|
.EXAMPLE
|
|
PS> .\Install-ZBXAgentManual.ps1 -ZabbixProxyIPAddress '192.168.10.50' -ZabbixAgentMsiUri 'https://cdn.zabbix.com/zabbix/binaries/stable/7.0/7.0.14/zabbix_agent2-7.0.14-windows-amd64-openssl.msi'
|
|
Installs a different Zabbix Agent 2 version instead of the default 7.2.13.
|
|
|
|
.EXAMPLE
|
|
PS> irm https://s.tslab.cz/ZBXAgent | iex
|
|
Shortest way to run this directly from the repo without saving it locally first;
|
|
prompts interactively for the Zabbix Proxy/Server IP address and installs the
|
|
default MSI version.
|
|
|
|
.NOTES
|
|
Author: Petr Stepan
|
|
Created: 2026-07-21
|
|
Version: 1.1.0
|
|
Changelog:
|
|
1.0.0 - Initial version
|
|
1.1.0 - Made ZabbixAgentMsiUri a parameter (was hardcoded) so a different
|
|
agent version can be installed without editing the script
|
|
#>
|
|
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory = $false, HelpMessage = 'IP address of the Zabbix Proxy or Server. Used for Server, ServerActive and the TCP 10050 firewall rule.')]
|
|
[string]
|
|
$ZabbixProxyIPAddress,
|
|
|
|
[Parameter(Mandatory = $false, HelpMessage = 'URI of the Zabbix Agent 2 Windows MSI to download and install.')]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$ZabbixAgentMsiUri = 'https://cdn.zabbix.com/zabbix/binaries/stable/7.2/7.2.13/zabbix_agent2-7.2.13-windows-amd64-openssl.msi'
|
|
)
|
|
|
|
# --- Safety preamble -------------------------------------------------------
|
|
Set-StrictMode -Version Latest
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
# Older Windows Server releases don't enable TLS 1.2 by default, which would make the
|
|
# download below fail silently against a TLS-1.2-only server.
|
|
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
|
|
|
|
$MsiPath = Join-Path -Path $env:TEMP -ChildPath (Split-Path -Path $ZabbixAgentMsiUri -Leaf)
|
|
$MsiLogPath = Join-Path -Path $env:TEMP -ChildPath 'zabbix_agent2_install.log'
|
|
$FirewallRuleName = 'Zabbix Agent (TCP-In)'
|
|
$FirewallPort = 10050
|
|
|
|
# --- Functions ---------------------------------------------------------
|
|
|
|
function Test-CurrentUserIsAdministrator {
|
|
<#
|
|
.SYNOPSIS
|
|
Returns whether the current process is running elevated (Administrator).
|
|
#>
|
|
[CmdletBinding()]
|
|
param()
|
|
|
|
$identity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
|
|
$principal = New-Object -TypeName System.Security.Principal.WindowsPrincipal -ArgumentList $identity
|
|
return $principal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)
|
|
}
|
|
|
|
function Invoke-RemoteFileDownload {
|
|
<#
|
|
.SYNOPSIS
|
|
Downloads a single file from a URI to a local path.
|
|
.PARAMETER Uri
|
|
Source URI to download from.
|
|
.PARAMETER OutFile
|
|
Local destination file path.
|
|
#>
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$Uri,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$OutFile
|
|
)
|
|
|
|
try {
|
|
Invoke-WebRequest -Uri $Uri -OutFile $OutFile -UseBasicParsing
|
|
Write-Host "Downloaded '$Uri' to '$OutFile'."
|
|
}
|
|
catch {
|
|
Write-Error "Failed to download '$Uri' to '$OutFile': $_"
|
|
throw
|
|
}
|
|
}
|
|
|
|
function Install-ZabbixAgentMsi {
|
|
<#
|
|
.SYNOPSIS
|
|
Silently installs the Zabbix Agent 2 MSI with the given Hostname/Server settings.
|
|
.PARAMETER MsiPath
|
|
Path to the downloaded zabbix_agent2 MSI file.
|
|
.PARAMETER HostName
|
|
Value for the agent's Hostname setting.
|
|
.PARAMETER ServerAddress
|
|
Value used for both the Server and ServerActive settings.
|
|
.PARAMETER LogPath
|
|
Path for the msiexec verbose install log.
|
|
#>
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateScript({ Test-Path -Path $_ -PathType Leaf })]
|
|
[string]
|
|
$MsiPath,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$HostName,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$ServerAddress,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$LogPath
|
|
)
|
|
|
|
# Passed as an array, not one concatenated string, so Start-Process quotes each
|
|
# argument correctly even if $MsiPath/$LogPath contain spaces.
|
|
$msiArgs = @(
|
|
'/i', $MsiPath
|
|
'/qn'
|
|
"HOSTNAME=$HostName"
|
|
"SERVER=$ServerAddress"
|
|
"SERVERACTIVE=$ServerAddress"
|
|
'/l*v', $LogPath
|
|
)
|
|
|
|
Write-Host "Installing Zabbix Agent 2 (Hostname=$HostName, Server/ServerActive=$ServerAddress)..."
|
|
$process = Start-Process -FilePath 'msiexec.exe' -ArgumentList $msiArgs -Wait -PassThru -NoNewWindow
|
|
|
|
# 3010 = success, reboot required - still a successful install.
|
|
if ($process.ExitCode -notin @(0, 3010)) {
|
|
throw "msiexec failed with exit code $($process.ExitCode). See log: $LogPath"
|
|
}
|
|
|
|
Write-Host "Zabbix Agent 2 installed successfully (msiexec exit code $($process.ExitCode))."
|
|
}
|
|
|
|
function New-ZabbixAgentFirewallRule {
|
|
<#
|
|
.SYNOPSIS
|
|
Creates an inbound firewall rule for the Zabbix Agent listener, restricted to
|
|
a single remote address. Does nothing if a rule with the same name already
|
|
exists.
|
|
.PARAMETER Name
|
|
Display name of the firewall rule.
|
|
.PARAMETER Port
|
|
TCP port to allow.
|
|
.PARAMETER RemoteAddress
|
|
Only remote address allowed to reach that port.
|
|
#>
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$Name,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[int]
|
|
$Port,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$RemoteAddress
|
|
)
|
|
|
|
if (Get-NetFirewallRule -DisplayName $Name -ErrorAction SilentlyContinue) {
|
|
Write-Host "Firewall rule '$Name' already exists - skipping."
|
|
return
|
|
}
|
|
|
|
New-NetFirewallRule -DisplayName $Name -Direction Inbound -Action Allow -Protocol TCP `
|
|
-LocalPort $Port -RemoteAddress $RemoteAddress -Group 'Zabbix Agent' `
|
|
-Description "Allow the Zabbix Proxy/Server ($RemoteAddress) to reach the Zabbix Agent passive check listener." | Out-Null
|
|
|
|
Write-Host "Firewall rule '$Name' created (TCP $Port, remote address $RemoteAddress)."
|
|
}
|
|
|
|
# --- Main --------------------------------------------------------------
|
|
try {
|
|
if (-not (Test-CurrentUserIsAdministrator)) {
|
|
throw 'This script must be run elevated (as Administrator).'
|
|
}
|
|
|
|
# Only fall back to the environment variable / prompt when the caller did not pass
|
|
# the parameter at all. $env:ZabbixProxyIPAddress lets a plain "irm <url> | iex"
|
|
# one-liner supply a value without needing "& { ... } -Param" - piping into iex
|
|
# runs the downloaded param() block as a plain statement with no bound arguments,
|
|
# so -ZabbixProxyIPAddress itself can only be set that way when the script is
|
|
# invoked as a real command (locally or via "& { ... }").
|
|
if (-not $PSBoundParameters.ContainsKey('ZabbixProxyIPAddress')) {
|
|
if ($env:ZabbixProxyIPAddress) {
|
|
$ZabbixProxyIPAddress = $env:ZabbixProxyIPAddress
|
|
}
|
|
else {
|
|
$ZabbixProxyIPAddress = Read-Host -Prompt 'Enter Zabbix Proxy/Server IP address'
|
|
}
|
|
}
|
|
|
|
$parsedIp = $null
|
|
if (-not [System.Net.IPAddress]::TryParse($ZabbixProxyIPAddress, [ref] $parsedIp)) {
|
|
throw "'$ZabbixProxyIPAddress' is not a valid IP address."
|
|
}
|
|
|
|
Invoke-RemoteFileDownload -Uri $ZabbixAgentMsiUri -OutFile $MsiPath
|
|
|
|
Install-ZabbixAgentMsi -MsiPath $MsiPath -HostName $env:COMPUTERNAME -ServerAddress $ZabbixProxyIPAddress -LogPath $MsiLogPath
|
|
|
|
New-ZabbixAgentFirewallRule -Name $FirewallRuleName -Port $FirewallPort -RemoteAddress $ZabbixProxyIPAddress
|
|
|
|
Remove-Item -Path $MsiPath -Force -ErrorAction SilentlyContinue
|
|
}
|
|
catch {
|
|
Write-Error "Script failed: $_"
|
|
# $PSCommandPath is only set when this runs as an actual .ps1 file. When run via
|
|
# "irm <url> | iex" there is no backing file - the code executes in the caller's
|
|
# own session, so calling exit here would close their whole PowerShell window
|
|
# instead of just ending this script.
|
|
if ($PSCommandPath) {
|
|
exit 1
|
|
}
|
|
return
|
|
}
|
|
|
|
if ($PSCommandPath) {
|
|
exit 0
|
|
}
|