[CmdletBinding()] param( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$CollectorAccount, [switch]$Gmsa, [ValidateSet("", "ACC", "DEV", "TST", "PRD")] [string]$EnvironmentName = "", [string]$InstallDirectory = "$env:ProgramFiles\BizTalkCheckmkPulse", [string]$CheckmkLocalDirectory = "$env:ProgramData\checkmk\agent\local" ) $ErrorActionPreference = "Stop" Set-StrictMode -Version 2.0 $taskName = "BizTalk Checkmk Pulse Provider" $runtimeRoot = Join-Path $env:ProgramData "BizTalkCheckmkPulse" $dataDirectory = Join-Path $runtimeRoot "data" $logDirectory = Join-Path $runtimeRoot "logs" $sourceApplication = Join-Path $PSScriptRoot "application" $sourceWrapper = Join-Path $PSScriptRoot "biztalk_checkmk_pulse.cmd" $targetExe = Join-Path $InstallDirectory "BizTalkCheckmkPulse.exe" $targetConfig = "$targetExe.config" $targetWrapper = Join-Path $CheckmkLocalDirectory "biztalk_checkmk_pulse.cmd" function Assert-Administrator { $identity = [Security.Principal.WindowsIdentity]::GetCurrent() $principal = New-Object Security.Principal.WindowsPrincipal($identity) if (-not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { throw "Die Installation muss in einer administrativen Windows PowerShell ausgefuehrt werden." } } function Invoke-Icacls { param( [Parameter(Mandatory = $true)][string]$Path, [Parameter(Mandatory = $true)][string[]]$Arguments ) & icacls.exe $Path @Arguments | Out-Host if ($LASTEXITCODE -ne 0) { throw "icacls ist fuer '$Path' mit Exitcode $LASTEXITCODE fehlgeschlagen." } } Assert-Administrator if (-not (Test-Path -LiteralPath $sourceApplication -PathType Container)) { throw "Quellverzeichnis fehlt: $sourceApplication" } if (-not (Test-Path -LiteralPath $sourceWrapper -PathType Leaf)) { throw "Checkmk-Wrapper fehlt: $sourceWrapper" } if ($Gmsa -and -not $CollectorAccount.EndsWith('$')) { throw "Ein gMSA-Kontoname muss mit '$' enden, z.B. DOMAIN\svc_biztalk_cmk$." } Write-Host "Installiere Programmdateien nach $InstallDirectory ..." New-Item -ItemType Directory -Path $InstallDirectory -Force | Out-Null Copy-Item -Path (Join-Path $sourceApplication "*") -Destination $InstallDirectory -Force [xml]$configuration = Get-Content -LiteralPath $targetConfig $environmentSetting = $configuration.configuration.appSettings.add | Where-Object { $_.key -eq "EnvironmentName" } | Select-Object -First 1 if ($null -eq $environmentSetting) { throw "EnvironmentName fehlt in $targetConfig." } $environmentSetting.value = $EnvironmentName $configuration.Save($targetConfig) Write-Host "Erzeuge Runtime-Verzeichnisse und Least-Privilege-ACLs ..." New-Item -ItemType Directory -Path $runtimeRoot, $dataDirectory, $logDirectory -Force | Out-Null # Runtime-Root: Provider lesen, SYSTEM lesen, lokale Administratoren verwalten. Invoke-Icacls -Path $runtimeRoot -Arguments @( "/inheritance:r", "/grant:r", "*S-1-5-18:(OI)(CI)(RX)", "*S-1-5-32-544:(OI)(CI)(F)", "${CollectorAccount}:(OI)(CI)(RX)" ) # Daten: ausschliesslich Provider schreibt, LocalSystem liest den Snapshot. Invoke-Icacls -Path $dataDirectory -Arguments @( "/inheritance:r", "/grant:r", "*S-1-5-18:(OI)(CI)(RX)", "*S-1-5-32-544:(OI)(CI)(F)", "${CollectorAccount}:(OI)(CI)(M)" ) # Logs: Provider und LocalSystem-Consumer duerfen getrennte Diagnosezeilen anhaengen. Invoke-Icacls -Path $logDirectory -Arguments @( "/inheritance:r", "/grant:r", "*S-1-5-18:(OI)(CI)(M)", "*S-1-5-32-544:(OI)(CI)(F)", "${CollectorAccount}:(OI)(CI)(M)" ) Write-Host "Installiere Checkmk Local Check nach $CheckmkLocalDirectory ..." New-Item -ItemType Directory -Path $CheckmkLocalDirectory -Force | Out-Null Copy-Item -LiteralPath $sourceWrapper -Destination $targetWrapper -Force Write-Host "Registriere Scheduled Task '$taskName' ..." $action = New-ScheduledTaskAction ` -Execute $targetExe ` -Argument "--collect" ` -WorkingDirectory $InstallDirectory $trigger = New-ScheduledTaskTrigger ` -Once ` -At (Get-Date).AddMinutes(1) ` -RepetitionInterval (New-TimeSpan -Minutes 1) $settings = New-ScheduledTaskSettingsSet ` -MultipleInstances IgnoreNew ` -ExecutionTimeLimit (New-TimeSpan -Minutes 5) ` -StartWhenAvailable ` -RestartCount 2 ` -RestartInterval (New-TimeSpan -Minutes 1) if ($Gmsa) { $principal = New-ScheduledTaskPrincipal ` -UserId $CollectorAccount ` -LogonType Password ` -RunLevel Highest $task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings -Principal $principal Register-ScheduledTask -TaskName $taskName -InputObject $task -Force | Out-Null } else { $credential = Get-Credential ` -UserName $CollectorAccount ` -Message "Kennwort fuer das dedizierte BizTalk-Monitoringkonto eingeben" if ($credential.UserName -ne $CollectorAccount) { throw "Das eingegebene Konto stimmt nicht mit CollectorAccount ueberein." } $principal = New-ScheduledTaskPrincipal ` -UserId $CollectorAccount ` -LogonType Password ` -RunLevel Highest $task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings -Principal $principal Register-ScheduledTask ` -TaskName $taskName ` -InputObject $task ` -User $CollectorAccount ` -Password $credential.GetNetworkCredential().Password ` -Force | Out-Null } Write-Host "Fuehre formatseitigen Self-Test aus ..." $selfTest = & $targetExe --self-test if ($LASTEXITCODE -ne 0 -or @($selfTest).Count -ne 6) { throw "Self-Test fehlgeschlagen. Erwartet wurden sechs Checkmk-Zeilen." } Write-Host "Starte den Provider einmalig ..." Start-ScheduledTask -TaskName $taskName Write-Host "" Write-Host "Installation abgeschlossen." Write-Host "Naechste Pruefungen:" Write-Host " Get-ScheduledTaskInfo -TaskName '$taskName'" Write-Host " Get-Content '$logDirectory\biztalk-checkmk-pulse-*.log' -Tail 50" Write-Host " & '$targetExe' --consume" Write-Host " & 'C:\Program Files (x86)\checkmk\service\cmk-agent-ctl.exe' dump"