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 }