From b50aafa06af82a539f0a124892d0372f6debc5d4 Mon Sep 17 00:00:00 2001 From: code-commit Date: Thu, 18 Sep 2025 03:03:12 +0000 Subject: [PATCH] first commit --- .gitignore | 1 + Generate-AllInOneInstaller.ps1 | 57 +++ Public/Add-ZabbixFirewallRules.ps1 | 52 +++ Public/Expand-ZabbixAgentPackage.ps1 | 25 ++ Public/Generate-ZabbixAgentHostname.ps1 | 9 + Public/Get-ComputerDomainMembership.ps1 | 42 +++ Public/Get-ZabbixAgentPackage.ps1 | 103 ++++++ Public/Install-ZabbixAgent2.ps1 | 385 ++++++++++++++++++++ Public/Remove-ZabbixAgent.ps1 | 115 ++++++ Public/Set-FileSystemPermission.ps1 | 146 ++++++++ Public/Set-ServiceRecoveryAction.ps1 | 50 +++ Templates/Install-ZabbixAgent2.Template.ps1 | 26 ++ 12 files changed, 1011 insertions(+) create mode 100644 .gitignore create mode 100644 Generate-AllInOneInstaller.ps1 create mode 100644 Public/Add-ZabbixFirewallRules.ps1 create mode 100644 Public/Expand-ZabbixAgentPackage.ps1 create mode 100644 Public/Generate-ZabbixAgentHostname.ps1 create mode 100644 Public/Get-ComputerDomainMembership.ps1 create mode 100644 Public/Get-ZabbixAgentPackage.ps1 create mode 100644 Public/Install-ZabbixAgent2.ps1 create mode 100644 Public/Remove-ZabbixAgent.ps1 create mode 100644 Public/Set-FileSystemPermission.ps1 create mode 100644 Public/Set-ServiceRecoveryAction.ps1 create mode 100644 Templates/Install-ZabbixAgent2.Template.ps1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bfa11e7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +aio-installer/* \ No newline at end of file diff --git a/Generate-AllInOneInstaller.ps1 b/Generate-AllInOneInstaller.ps1 new file mode 100644 index 0000000..f7eec7b --- /dev/null +++ b/Generate-AllInOneInstaller.ps1 @@ -0,0 +1,57 @@ +# generate all-in-one install script, more suitable for running on the endpoints + +$cmdMagic = @' +# 2> nul & powershell.exe -ExecutionPolicy Bypass -NoProfile -Command "[scriptblock]::Create((Get-Content -LiteralPath '%~f0' -Raw)).Invoke()" #& EXIT /B +'@ + + +pushd $PSScriptRoot + +$sourcefile = 'Install-ZabbixAgent2.Template.ps1' + + +#Join-Path aio-installer + +if (Test-path (Join-Path aio-installer $sourcefile)) { + $gi = Get-Item (Join-Path aio-installer $sourcefile) + Write-Verbose ('Template exists at {0}' -f $sourcefile) + + } +else { + + if (Test-Path (Join-Path Templates $sourcefile)) { + + try { + Copy-Item -Path (Join-Path Templates $sourcefile) -Destination (Join-Path . aio-installer) -ErrorAction Stop + $gi = Get-Item (Join-Path aio-installer $sourcefile) + } + catch { + throw ("Couldn't copy the template {0} to current dir, aborting" -f (Join-Path Templates $sourcefile)) + } + + } + + + } + +$c = Get-Content $gi.FullName + +$n = @() + +$regex = '^\s*#include#\.\s+?(?.+)$' + +foreach ($l in $c) { + if ($l -match $regex) { + Get-Content $Matches['includePath'] | % { $n += $_ } + } + else { + $n += $l + } + } + +$n | Set-Content (Join-Path aio-installer ($sourcefile -replace '\.Template\.ps1','.AllInOne.ps1')) + + +@($cmdMagic) + $n | Set-Content (Join-Path aio-installer ($sourcefile -replace '\.Template\.ps1','.AllInOne.cmd')) + +popd diff --git a/Public/Add-ZabbixFirewallRules.ps1 b/Public/Add-ZabbixFirewallRules.ps1 new file mode 100644 index 0000000..3ca3b0f --- /dev/null +++ b/Public/Add-ZabbixFirewallRules.ps1 @@ -0,0 +1,52 @@ +function Add-ZabbixFirewallRules { + param ( + [Parameter(Mandatory=$true)] + [string]$FilePath, + + $RuleName = "Zabbix Agent 2" + ) + + begin { + # Ensure the required module is available + if (-not (Get-Module -Name NetSecurity)) { + Import-Module NetSecurity -ErrorAction Stop + } + + $splat = @{ + DisplayName = $ruleName + Program = $FilePath + Action = 'Allow' + ErrorAction = 'Stop' + } + + $directionList = 'Outbound', 'Inbound' + } + + process { + try { + + foreach ($direction in $directionList) { + + # Check if the rule already exists + $existingRule = Get-NetFirewallRule -DisplayName $ruleName -ErrorAction SilentlyContinue | ? {$_.Direction -eq $direction} + + if ($null -eq $existingRule) { + Write-Verbose "Creating new firewall rule..." + + New-NetFirewallRule @splat -Direction $direction + + Write-Verbose "Firewall rule created successfully." + } else { + Write-Verbose "Firewall rule already exists. No changes made." + } + } + } catch { + Write-Error "An error occurred while setting the firewall rule: $_" + throw + } + } + + end { + # Optionally, you can add any cleanup or finalization logic here if needed. + } +} diff --git a/Public/Expand-ZabbixAgentPackage.ps1 b/Public/Expand-ZabbixAgentPackage.ps1 new file mode 100644 index 0000000..9dcfd1f --- /dev/null +++ b/Public/Expand-ZabbixAgentPackage.ps1 @@ -0,0 +1,25 @@ +function Expand-ZabbixAgentPackage { + param ( + # Path to the .zip of the agent + [string] + $PackagePath = 'ZabbixAgent2.zip' + + + ) + + + $tempExtractPath = Join-Path $env:TEMP ZabbixAgent2 + + 'Extracted package path: {0}'-f $tempExtractPath | Write-Verbose + try { + New-Item -ItemType Directory -Path $tempExtractPath + Expand-Archive -Path $PackagePath -DestinationPath $tempExtractPath -Force + gi $tempExtractPath + } + catch { + $_ + } + + + } + diff --git a/Public/Generate-ZabbixAgentHostname.ps1 b/Public/Generate-ZabbixAgentHostname.ps1 new file mode 100644 index 0000000..f9a6b55 --- /dev/null +++ b/Public/Generate-ZabbixAgentHostname.ps1 @@ -0,0 +1,9 @@ +function Generate-ZabbixAgentHostname { + + $w32cs = Get-CimInstance 'Win32_ComputerSystem' + $w32os = Get-CimInstance 'Win32_OperatingSystem' + + # generate unique identifier for Zabbix Server + '__{0}-__{1}__-{2}' -f $w32cs.Domain, $w32cs.Name, $w32os.SerialNumber + + } # end function Generate-Hostname diff --git a/Public/Get-ComputerDomainMembership.ps1 b/Public/Get-ComputerDomainMembership.ps1 new file mode 100644 index 0000000..290a3c0 --- /dev/null +++ b/Public/Get-ComputerDomainMembership.ps1 @@ -0,0 +1,42 @@ +function Get-ComputerDomainMembership { + + # https://learn.microsoft.com/en-us/windows/win32/api/dsrole/ne-dsrole-dsrole_machine_role + # https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-computersystem + + enum MACHINE_ROLE { + StandaloneWorkstation = 0 + MemberWorkstation = 1 + StandaloneServer = 2 + MemberServer = 3 + BackupDomainController = 4 + PrimaryDomainController = 5 + } + + $Win32CS = Get-CimInstance -ClassName Win32_ComputerSystem -Property Domain, DomainRole + + $obj = [PSCustomObject][ordered]@{ + Domain = $Win32CS.Domain + DomainRole = [MACHINE_ROLE]$Win32CS.DomainRole + IsDomainMember = $false + IsWorkstation = $false + IsServer = $true + IsDomainController = $false + + } + + if ($obj.DomainRole -in 1,3,4,5) { + $obj.IsDomainMember = $true + } + + if ($obj.DomainRole -in 4,5) { + $obj.IsDomainController = $true + } + + if ($obj.DomainRole -in 0,1) { + $obj.IsWorkstation = $true + $obj.IsServer = $false + } + + $obj + +} \ No newline at end of file diff --git a/Public/Get-ZabbixAgentPackage.ps1 b/Public/Get-ZabbixAgentPackage.ps1 new file mode 100644 index 0000000..dec92f1 --- /dev/null +++ b/Public/Get-ZabbixAgentPackage.ps1 @@ -0,0 +1,103 @@ +function Get-ZabbixAgentPackage { +<# +.Synopsis + Downloads Zabbix Agent Package +.DESCRIPTION + Downloads Zabbix Agent Package from a predefined URI for the Agent 2 from Zabbix CDN or your custom URI + + The file is saved to the $env:TEMP because it's always writeable + + Use Get-Help Get-ZabbixAgentPackage -Full to see the current hardcoded CDN URI + +.EXAMPLE +# Just run with defaults and get a file object + +$file = Get-ZabbixAgentPackage +$file + + + Directory: C:\Users\dalek5439587\AppData\Local\Temp + + +Mode LastWriteTime Length Name +---- ------------- ------ ---- +-a---- 07.07.2023 13:34 13561856 ZabbixAgent2.msi + + + + +.EXAMPLE +# Specify some other URI and the resulting filename + +$file = Get-ZabbixAgentPackage -SourceURI https://contoso.tld/zabbix_agent2.msi -FileName zabbixagent2-latest.msi +$file + + + Directory: C:\Users\dalek5439587\AppData\Local\Temp + + +Mode LastWriteTime Length Name +---- ------------- ------ ---- +-a---- 07.07.2023 13:34 13561856 zabbixagent2-latest.msi + +#> +[CmdletBinding()] + +param ( + + # Source URI, so you can override it with a later version or your custom distribution point + $SourceURI = 'https://cdn.zabbix.com/zabbix/binaries/stable/7.0/latest/zabbix_agent2-7.0-latest-windows-amd64-openssl-static.zip', + + # File name for the downloaded file + $FileName = 'ZabbixAgent2.zip' + + ) + + function Enable-TransportLayerSecurity { + param ( + $SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + ) + + # Get current one + $currentProtocol = [Net.ServicePointManager]::SecurityProtocol + + # Stupid string comparison + if ($currentProtocol -notcontains $SecurityProtocol) { + + # ADD the requested protocol to the current list + Write-Verbose "Enabling Tls12" + [Net.ServicePointManager]::SecurityProtocol = $currentProtocol -bor $SecurityProtocol + + } + } # end Enable-TransportLayerSecurity + + +if ($SourceURI) { + + Enable-TransportLayerSecurity + + $outFile = Join-Path $env:TEMP $FileName + + 'Downloading agent from {0} to {1}' -f $SourceURI, $outFile | Write-Verbose + + try { + + $file = Invoke-WebRequest -Uri $SourceURI -OutFile $outFile + $file = Get-Item $outFile -ErrorAction Stop + $file + } + + catch { + + $err = @{ + Exception = 'ZabbixAgentPackageDownloadFailed' + Message = 'Agent download failed, aborting: {0}' -f $Error[0].Exception + } + Write-Error @err + break + + } + + } + +} \ No newline at end of file diff --git a/Public/Install-ZabbixAgent2.ps1 b/Public/Install-ZabbixAgent2.ps1 new file mode 100644 index 0000000..e9a4af9 --- /dev/null +++ b/Public/Install-ZabbixAgent2.ps1 @@ -0,0 +1,385 @@ +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 +} diff --git a/Public/Remove-ZabbixAgent.ps1 b/Public/Remove-ZabbixAgent.ps1 new file mode 100644 index 0000000..cee97cc --- /dev/null +++ b/Public/Remove-ZabbixAgent.ps1 @@ -0,0 +1,115 @@ +function Remove-ZabbixAgent { + + Write-Verbose 'Running Remove-ZabbixAgent' + + $state = [ordered]@{ + Service = @() + UninstallString = @() + EventLogRegistration = $null + } + + # Services + $filter = "name like 'zabbix agent%'" + $Service = @( gcim -ClassName Win32_Service -Filter $filter ) + + Write-Verbose -Message ('Found {0} services with the filter {1}' -f $service.Count, $filter) + + Foreach ($thisService in $Service) { + # Default service strings: + # "C:\Program Files\Zabbix Agent\zabbix_agentd.exe" --config "C:\Program Files\Zabbix Agent\zabbix_agentd.conf" + # "C:\Program Files\Zabbix Agent 2\zabbix_agent2.exe" -c "C:\Program Files\Zabbix Agent 2\zabbix_agent2.conf" -f=false + + $regex = '^"?(?\w\:\\.+(?zabbix_agent.?\.exe))"?' + '.+?' + '"?(?\w:\\.+\.conf)"?' + + if ($thisService.PathName -match $regex) { + $state.Service += [pscustomobject][ordered]@{ + ServiceName = $thisService.Name + ExecutablePath = $Matches.exepath + ConfigurationPath = $Matches.confpath + ExecutableDir = Split-Path -Parent -Path $Matches.exepath + } + } + + } + + + # System uninstall list + + $regUninstall = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall' + $UninstallList = @( Get-ChildItem -Path $regUninstall | Get-ItemProperty | ? DisplayName -match 'Zabbix\s+?Agent' ) + + Write-Verbose -Message ('Found {0} uninstall strings' -f $UninstallList.Count) + + foreach ($thisItem in $UninstallList) { + + # why, why?! + $UninstallString = ('{0} {1}' -f $thisItem.UninstallString, '/passive /norestart') -replace '\s?/I{',' /x{' + + $state.UninstallString += $UninstallString + } + + # EventLog registration + + if ($gi = Get-Item 'HKLM:\SYSTEM\CurrentControlSet\Services\EventLog\Application\Zabbix Agent 2' -ErrorAction SilentlyContinue) { + $State.EventLogRegistration = $gi + } + + # stop services and call builtin service removal + + foreach ($thisService in $state.Service) { + Stop-Service -Force -Name $thisService.ServiceName -Confirm:$false -Verbose + + # call builtin agent uninstall routine + $splat = @{ + FilePath = $thisService.ExecutablePath + ArgumentList = '-c "{0}" -d' -f $thisService.ConfigurationPath + } + + Write-Verbose ('Running built-in uninstall: {0} {1}' -f $splat.Filepath, $splat.ArgumentList) + + Start-Process -Wait @splat + Start-Sleep -Seconds 1 + + # for some unknown reason (again) Z doesn't remove it's Service registration, so just in case: + + try { + sc.exe delete $($thisService.ServiceName) + } + catch { + # nothing, actually + } + } + + # call msiexec uninstaller + + foreach ($thisUninstallString in $state.UninstallString) { + + Write-Verbose ('Runing MSI uninstaller: {0}' -f $thisUninstallString) + + & (Get-command cmd.exe).Source -ArgumentList ('/c', $thisUninstallString) + + } + + # remove eventlog registration because sometimes it's left there and it blocks install + + if ($state.EventLogRegistration) { + if (test-path $state.EventLogRegistration.PSPath -ErrorAction SilentlyContinue) { + + Write-Verbose ('Removing EventLogRegistration {0}' -f $state.EventLogRegistration.PSPath) + + Remove-Item $state.EventLogRegistration.PSPath -Force + } + } + + # remove the directory because... the installer sometimes refuse to install if it's not empty + + foreach ($thisService in $state.Service) { + if (Test-Path $thisService.ExecutableDir) { + + Write-Verbose ('Removing Executable directory {0}' -f $thisService.ExecutableDir) + + Remove-Item -Path $thisService.ExecutableDir -Force -Recurse + } + } + + } # End Remove-ZabbixAgent \ No newline at end of file diff --git a/Public/Set-FileSystemPermission.ps1 b/Public/Set-FileSystemPermission.ps1 new file mode 100644 index 0000000..f6186ca --- /dev/null +++ b/Public/Set-FileSystemPermission.ps1 @@ -0,0 +1,146 @@ + +function Set-FileSystemPermission { + # This function sets permissions to Administrators and SYSTEM as full control on a specified path + + param( + [Parameter(Mandatory=$true)] + [string]$Path, + + [Parameter(Mandatory=$true)] + [string] + $Identity, + + [Parameter(Mandatory=$true)] + [ValidateSet("FullControl", "ListDirectory", "ReadAndExecute")] + [string] + $Permission, + + [ValidateSet('ContainerInherit, ObjectInherit', 'ContainerInherit','ObjectInherit','None')] + $Inheritance = 'ContainerInherit, ObjectInherit', + + [switch] + $BreakInheritance + ) + + try { + Get-item $Path | ForEach-Object { + $acl = Get-Acl $_ + + + + if ($Permission -eq 'ListDirectory') { + $inheritance = 'ContainerInherit' + } + + $aclRule = New-Object System.Security.AccessControl.FileSystemAccessRule($Identity, $Permission, $inheritance, 'None', 'Allow') + # The first argument is the identity that needs permissions (in this case, administrators) + # The second argument specifies the permissions (FullControl means give full control to the file/folder) + # The third argument forces the permission to be inherited on the child objects + # The fourth argument determines whether the rules should be applied to new files or directories when copying ACLs (it's None, meaning don't change existing permissions) + # The fifth argument is the type of permission ("Allow" means give access) + # Remove all inherited permissions + + if ($BreakInheritance){ + $acl.SetAccessRuleProtection($true, $false) + } + + + + $acl.AddAccessRule($aclRule) + try { + Set-Acl -Path $_ -AclObject $acl + } catch { + Write-Error "Failed to set permissions for file '$_' with error: $_" + } + } + } catch { + Write-Error "Failed to traverse the path '$Path' with error: $_" + } +} + + +function Translate-SidToNTAccount { + param ( + # SID + [Parameter(Mandatory=$true, + ValueFromPipelineByPropertyName=$true, + Position=0)] + [string] + $SID + ) + # list of the Well-known SIDs https://learn.microsoft.com/en-us/windows/win32/secauthz/well-known-sids + + $pSID = [System.Security.Principal.SecurityIdentifier]$SID + + $pSID.Translate([System.Security.Principal.NTAccount]).Value + + } + + +<# + +#region folders + + + +$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' + } + + +Remove-Item -Recurse $fOrg -Force -ErrorAction SilentlyContinue + + + + 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 + + } + } + +#endregion + + + + # This is the well-known SID for the administrators group + $admins = (New-Object System.Security.Principal.SecurityIdentifier 'S-1-5-32-544').Translate([System.Security.Principal.NTAccount]).Value + # This is a hard-coded string representing the SYSTEM account name + $system = "NT AUTHORITY\SYSTEM" + + #users + $users = ([System.Security.Principal.SecurityIdentifier]'S-1-5-32-545').Translate([System.Security.Principal.NTAccount]).Value + + +$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 $admins -Permission FullControl -BreakInheritance +Set-FileSystemPermission -Path $fOrg -Identity $system -Permission FullControl +Set-FileSystemPermission -Path $fOrg -Identity $users -Permission ListDirectory +Set-FileSystemPermission -Path ($folder['bin']) -Identity $users -Permission ReadAndExecute + + +#> diff --git a/Public/Set-ServiceRecoveryAction.ps1 b/Public/Set-ServiceRecoveryAction.ps1 new file mode 100644 index 0000000..03533dc --- /dev/null +++ b/Public/Set-ServiceRecoveryAction.ps1 @@ -0,0 +1,50 @@ +function Set-ServiceRecoveryAction { +<# +.Synopsis + Set Windows service recovery actions +.DESCRIPTION + Set Windows service recovery actions + Reference: + https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-R2-and-2012/cc742019(v=ws.11)?redirectedfrom=MSDN +.EXAMPLE + Set-ServiceRecoveryAction -Service AppIDSvc + +#> + param + ( + # Service name (not display name) + [Parameter(Mandatory=$true)] + [string] + $Service, + + # Action delay time in seconds + [ValidateSet("run", "restart", "reboot")] + $Action1 = "restart", + + [int] + $Time1 = 60, + + # Action delay time in seconds + [ValidateSet("run", "restart", "reboot")] + $Action2 = "restart", + + [int] + $Time2 = 60, + + # Action delay time in seconds + [ValidateSet("run", "restart", "reboot")] + $Action3 = "restart", + + [int] + $Time3 = 60, + + + # Specifies the length of the period (in seconds) with no failures after which the failure count should be reset to 0 (zero) + [int] + $Reset = 600 + ) + + $actions = '{0}/{1}/{2}/{3}/{4}/{5}' -f $Action1, ($Time1 * 1000), $Action2, ($Time2 * 1000), $Action3, ($Time3 * 1000) + + sc.exe failure "$service" actions= $actions reset= $Reset +} diff --git a/Templates/Install-ZabbixAgent2.Template.ps1 b/Templates/Install-ZabbixAgent2.Template.ps1 new file mode 100644 index 0000000..0caeae8 --- /dev/null +++ b/Templates/Install-ZabbixAgent2.Template.ps1 @@ -0,0 +1,26 @@ + +#include#. ./Public/Get-ComputerDomainMembership.ps1 + +#include#. ./Public/Get-ZabbixAgentPackage.ps1 + +#include#. ./Public/Expand-ZabbixAgentPackage.ps1 + +#include#. ./Public/Remove-ZabbixAgent.ps1 + +#include#. ./Public/Generate-ZabbixAgentHostname.ps1 + +#include#. ./Public/Add-ZabbixFirewallRules.ps1 + +#include#. ./Public/Set-FileSystemPermission.ps1 + +#include#. ./Public/Install-ZabbixAgent2.ps1 + +#include#. ./Public/Set-ServiceRecoveryAction.ps1 + +<# +If you generated an all-in-one install script - this is the great place to put your +call to Install-ZabbixAgent2 with the parameters you wish! + +Run 'Get-Help Install-ZabbixAgent2 -Examples' to see an example. +#> +