ZabbixAgent2Installer/Public/Install-ZabbixAgent2.ps1
2025-09-18 03:03:12 +00:00

385 lines
9.5 KiB
PowerShell

function Install-ZabbixAgent2 {
<#
.Synopsis
Install Zabbix Agent 2
.DESCRIPTION
Download and install Zabbix Agent 2 with autoconfiguration for Active Directory domains.
Configuration and log files are moved to $env:APPDATA as it is a preffered place to store application
data and also avoids access to them for unpriviliged users
.EXAMPLE
Install-ZabbixAgent2 -ForceRemove -ProxyFQDN mycoolproxy.contoso.local -EnableAllowKeySystemRun
Remove any installed Agent, explicitly configure proxy name
#>
[CmdletBinding()]
param (
# FQDN of Zabbix proxy (or Server)
$ProxyFQDN,
# Prefix for domain name to use, include the dot at the end plz
$ProxyPrefix = 'proxy01.zabbix.',
# Remove any installed Agent on the machine (otherwise execution will be aborted)
[switch]
$ForceRemove,
# URI of Agent installer, if not set the hardcoded path set in Get-ZabbixAgentInstaller would be used
$PackageSourceURI,
# Force download the installer even if there is a local one found
[switch]
$ForceDownload,
# Enable AllowKey=system.run[*] in the configuration of the Agent
[switch]
$EnableAllowKeySystemRun,
# Installer name
$InstallerName = 'ZabbixAgent2.zip'
)
$VerbosePreference=2
#region preinit
#Start-Transcript -Append -Path C:\ProgramData\Zabbix\installer\Install-ZabbixAgent2.AllInOne.ps1.txt
$Transcript = Start-Transcript
$flagShouldRunRemoveAgent = $false
$flagShouldDownloadInstaller = $false
#endregion
#region preinstall
# check parameters
if ($ProxyFQDN) {
# Proxy FQDN is set
}
else {
$cdm = Get-ComputerDomainMembership
if ($cdm.IsDomainMember) {
$ProxyFQDN = '{0}{1}' -f $ProxyPrefix, $cdm.Domain
}
else {
$msg = 'No Proxy FQDN defined and computer is not a domain member! Aborting, transcript path: {0}' -f $Transcript.Path
Stop-Transcript
throw $msg
}
}
# check if Agent is already installed
if ($ForceRemove -eq $true) {
# flag what the removal should be called
$flagShouldRunRemoveAgent = $true
}
elseif ($checkService = Get-Service -name 'Zabbix*' -ErrorAction SilentlyContinue | ? Name -match 'Zabbix\s+Agent.+?') {
if ($ForceRemove -eq $true) {
# flag what the removal should be called
$flagShouldRunRemoveAgent = $true
Write-Verbose 'Installed agent detected, would be removed per ForceRemove parameter'
}
else {
$msg = 'There is an installed Agent, but ForceRemove is not set. Aborting, transcript path: {0}' -f $Transcript.Path
Stop-Transcript
throw $msg
}
} #end if checkservice
#endregion
#region folders
<#
FolderStructure:
$env:ProgramData
$orgName
installer
$productName
conf
conf/zabbix_agent2.d
tls
log
#>
$nameOrg = 'Zabbix'
$nameProduct = 'Agent2'
$fOrg = Join-Path $env:ProgramData $nameOrg
$fProduct = Join-Path $fOrg $nameProduct
$fInstaller = Join-Path $fOrg installer
$folder = [ordered]@{
Org = $fOrg
Installer = $fInstaller
Product = $fProduct
Bin = Join-Path $fProduct 'bin'
Conf = Join-Path $fProduct 'conf'
ConfD = Join-Path (Join-Path $fProduct 'conf') 'zabbix_agent2.d'
Tls = Join-Path $fProduct 'tls'
Log = Join-Path $fProduct 'log'
}
try {
foreach ($thisFolder in $folder.Values) {
if (Test-Path $thisFolder) {
Write-Verbose ('Path {0} already exists' -f $thisFolder)
}
else {
New-Item -Path $thisFolder -ItemType Directory -ErrorAction Stop
}
}
}
catch {
$msg = "Can't create folder {0}. Aborting, transcript path: {1}" -f $thisFolder, $Transcript.Path
Stop-Transcript
throw $msg
}
#endregion
#region download
$splat = @{
FileName = $InstallerName
}
if ($PackageSourceURI) {
$splat.add('SourceURI',$PackageSourceURI)
}
$installerPath = Join-Path $folder['installer'] $InstallerName
if (Test-Path $installerPath) {
Write-Verbose ('Checking installer at {0}' -f $installerPath)
if ($ForceDownload) {
Write-Verbose ("Local installer found at {0}, but ForceDownload is set" -f $installerPath)
$flagShouldDownloadInstaller = $true
}
else {
Write-Verbose ("Local installer found at {0}" -f $installerPath)
$installer = Get-Item $installerPath
}
}
else {
$flagShouldDownloadInstaller = $true
}
if ($flagShouldDownloadInstaller) {
if ($VerbosePreference -eq 'Continue') {
Write-Verbose 'splat for get package:'
$splat
}
try {
$installer = Get-ZabbixAgentPackage @splat -ErrorAction Stop
$installer = Move-Item -LiteralPath $installer.FullName -Destination $folder['installer'] -PassThru -Force
}
catch {
$msg = 'Downloading Agent installer failed. Aborting, transcript path: {0}' -f $Transcript.Path
Stop-Transcript
throw $msg
}
}
#endregion
#region unpack
try {
$Unpacked = Expand-ZabbixAgentPackage $installer.FullName
Gci -Filter *.exe -Path $Unpacked.fullname -Recurse -Verbose | % {
Move-Item -Path $_.FullName -Destination $folder['bin'] -Verbose
}
}
catch {
$msg = 'Failed to unpack the package. Aborting, transcript path: {0}' -f $Transcript.Path
Stop-Transcript
throw $msg
}
#endregion
#region remove installed
if ($flagShouldRunRemoveAgent) {
Write-Verbose 'Removing the installed Agent'
Remove-ZabbixAgent
}
#endregion
#region generate config
$mainConfigPath = (Join-Path $folder['conf'] zabbix_agent2.conf)
$mainConfigPathContent = 'Include={0}' -f ((Join-Path $folder['confd'] '*.conf'))
# write out the default configuration file
Set-Content -Value $mainConfigPathContent -Path $mainConfigPath
# shorthand to write the configuration settings to a separate files
filter WriteConf {
param (
$filename
)
if ($filename -notmatch '\.conf') {
$filename = $filename + '.conf'
}
$_ | Set-Content (Join-Path $folder['confd'] $filename)
}
function ConfigFileParameter {
[CmdletBinding()]
[Alias('ap')]
[OutputType([string])]
Param (
[string]
$Name,
[string]
$Value
)
'{0}={1}' -f $Name, $Value
}
$ZabbixAgentHostname = Generate-ZabbixAgentHostname
ap Hostname $ZabbixAgentHostname | WriteConf 10-hostname
ap Server $ProxyFQDN | WriteConf 11-server
ap ServerActive $ProxyFQDN | WriteConf 12-serveractive
$logFilePath = Join-Path $folder['log'] zabbix_agent2.log
ap LogFile $logFilePath | WriteConf 21-logfile
ap LogFileSize 32 | WriteConf 22-logfilesize
ap ForceActiveChecksOnStart 1 | WriteConf 31-forceactivechecksonstart
if ($EnableAllowKeySystemRun) {
'AllowKey=system.run[*]' | WriteConf 69-allowkeysystemrun
}
# default built-in
'ControlSocket=\\.\pipe\agent.sock' | WriteConf 99-controlsocket
# configure tls
'Include={0}' -f ((Join-Path $folder['tls'] '*.conf')) | WriteConf 99-tls
ap TLSAccept 'unencrypted,psk' | Set-Content (Join-Path $folder['tls'] 70-tlsaccept.conf)
ap TLSConnect unencrypted | Set-Content (Join-Path $folder['tls'] 71-tlsconnect.conf)
ap TLSPSKIdentity $ZabbixAgentHostname | Set-Content (Join-Path $folder['tls'] 72-tlspskidentity.conf)
ap TLSPSKFile (Join-Path $folder['tls'] psk.key) | Set-Content (Join-Path $folder['tls'] 73-tlspskfile.conf)
# simple psk key
(new-guid) -replace '\W' | Set-Content (Join-Path $folder['tls'] psk.key)
#endregion
Write-Verbose "Adding firewall rules"
Add-ZabbixFirewallRules -FilePath (Join-Path $folder['bin'] zabbix_agent2.exe)
#region installstartservice
try {
Write-Verbose 'Registering Service'
$AgentExecutable = Join-Path $folder['bin'] zabbix_agent2.exe
$AgentArguments = '-i', '-c', $mainConfigPath
Start-Process -Wait -FilePath $AgentExecutable -ArgumentList $AgentArguments
}
catch {
$msg = 'Tried to install the service with binary {0} and arguments {1}' -f $AgentExecutable, $AgentArguments
Stop-Transcript
throw $msg
}
try {
$Service = Get-Service -Name 'Zabbix Agent 2'
Set-ServiceRecoveryAction 'Zabbix Agent 2'
Start-Service -Name $service.Name
}
catch {
$msg = "Couldn't start the service"
Stop-Transcript
throw $msg
}
#endregion
#region security
try {
Write-Verbose "Setting the security permissions"
$admins = Translate-SidToNTAccount S-1-5-32-544
$users = Translate-SidToNTAccount S-1-5-32-545
$system = Translate-SidToNTAccount S-1-5-18
Set-FileSystemPermission -Path $fOrg -Identity $system -Permission FullControl
Set-FileSystemPermission -Path $fOrg -Identity $users -Permission ReadAndExecute -Inheritance ContainerInherit
Set-FileSystemPermission -Path ($folder['bin']) -Identity $users -Permission ReadAndExecute
Set-FileSystemPermission -Path $fOrg -Identity $admins -Permission FullControl -BreakInheritance
}
catch {
$_
}
#endregion
Write-Verbose "Finished succesfully"
Stop-Transcript
Move-Item $Transcript.Path -Destination (Join-Path $folder['log'] $MyInvocation.MyCommand) -Force -PassThru
}