[CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$ConfigurationTemplate, [string]$PipelineCollector = "$PSScriptRoot\Get-NdcMissionCorePipelineTelemetry.ps1" ) $ErrorActionPreference = "Stop" $serviceName = "telegraf" $installRoot = "C:\Program Files\NDC\Mission Core\Telegraf" $configurationRoot = "C:\ProgramData\NDC\MissionCore\telemetry-agent" $configurationPath = Join-Path $configurationRoot "telegraf.conf" $collectorPath = Join-Path $configurationRoot "Get-NdcMissionCorePipelineTelemetry.ps1" $executable = Join-Path $installRoot "telegraf.exe" $serviceRegistryPath = "HKLM:\SYSTEM\CurrentControlSet\Services\$serviceName" $service = Get-Service -Name $serviceName -ErrorAction Stop if (-not (Test-Path -LiteralPath $executable -PathType Leaf)) { throw "NDC Mission Core Telegraf executable is missing" } if (-not (Test-Path -LiteralPath $ConfigurationTemplate -PathType Leaf)) { throw "Configuration template not found: $ConfigurationTemplate" } if (-not (Test-Path -LiteralPath $PipelineCollector -PathType Leaf)) { throw "Pipeline collector not found: $PipelineCollector" } $serviceEnvironmentBefore = @((Get-ItemProperty -Path $serviceRegistryPath).Environment) foreach ($entry in $serviceEnvironmentBefore) { $name, $value = $entry -split "=", 2 if ($name -and $value) { Set-Item -Path "Env:$name" -Value $value } } if (-not $env:MISSIONCORE_TELEMETRY_INTERVAL) { $env:MISSIONCORE_TELEMETRY_INTERVAL = "2s" } $serviceEnvironmentCandidate = @($serviceEnvironmentBefore) if (-not ($serviceEnvironmentCandidate | Where-Object { $_ -like "MISSIONCORE_TELEMETRY_INTERVAL=*" })) { $serviceEnvironmentCandidate += ( "MISSIONCORE_TELEMETRY_INTERVAL=$($env:MISSIONCORE_TELEMETRY_INTERVAL)" ) } $temporaryRoot = Join-Path $env:TEMP "ndc-mission-core-telegraf-update-$([Guid]::NewGuid().ToString('N'))" $validationOutput = Join-Path $temporaryRoot "validation.out.log" $validationError = Join-Path $temporaryRoot "validation.error.log" $backupRoot = Join-Path $configurationRoot "backups" $backupPath = Join-Path $backupRoot "telegraf-$([DateTime]::UtcNow.ToString('yyyyMMddTHHmmssZ')).conf" $backupCollectorPath = Join-Path $backupRoot ` "pipeline-collector-$([DateTime]::UtcNow.ToString('yyyyMMddTHHmmssZ')).ps1" $hadCollector = Test-Path -LiteralPath $collectorPath -PathType Leaf try { New-Item -ItemType Directory -Path $temporaryRoot, $backupRoot -Force | Out-Null $collectorProbe = & powershell.exe -NoLogo -NoProfile -NonInteractive ` -ExecutionPolicy Bypass -File $PipelineCollector if ($LASTEXITCODE -ne 0) { throw "Pipeline collector validation failed" } $collectorDocument = $collectorProbe | ConvertFrom-Json if (@($collectorDocument).Count -ne 9) { throw "Pipeline collector must publish exactly nine stage samples" } if ($hadCollector) { Copy-Item -LiteralPath $collectorPath -Destination $backupCollectorPath } Copy-Item -LiteralPath $PipelineCollector -Destination $collectorPath $validation = Start-Process -FilePath $executable ` -ArgumentList @("--config", $ConfigurationTemplate, "--test") ` -NoNewWindow -Wait -PassThru ` -RedirectStandardOutput $validationOutput ` -RedirectStandardError $validationError if ($validation.ExitCode -ne 0) { $validationDetail = Get-Content -LiteralPath $validationError -Tail 8 | Out-String throw "Telegraf configuration validation failed: $validationDetail" } Copy-Item -LiteralPath $configurationPath -Destination $backupPath Set-ItemProperty -Path $serviceRegistryPath -Name Environment ` -Type MultiString -Value $serviceEnvironmentCandidate Stop-Service -Name $serviceName $service = Get-Service -Name $serviceName $service.WaitForStatus( [ServiceProcess.ServiceControllerStatus]::Stopped, [TimeSpan]::FromSeconds(20) ) try { Copy-Item -LiteralPath $ConfigurationTemplate -Destination $configurationPath Start-Service -Name $serviceName $service = Get-Service -Name $serviceName $service.WaitForStatus( [ServiceProcess.ServiceControllerStatus]::Running, [TimeSpan]::FromSeconds(20) ) } catch { Copy-Item -LiteralPath $backupPath -Destination $configurationPath if ($hadCollector) { Copy-Item -LiteralPath $backupCollectorPath -Destination $collectorPath } else { Remove-Item -LiteralPath $collectorPath -Force -ErrorAction SilentlyContinue } Start-Service -Name $serviceName throw } [ordered]@{ SchemaVersion = "missioncore.telemetry-agent-config-result/v1" ServiceName = $serviceName Status = (Get-Service -Name $serviceName).Status.ToString() Configuration = $configurationPath Backup = $backupPath PipelineCollector = $collectorPath PipelineCollectorBackup = if ($hadCollector) { $backupCollectorPath } else { $null } } | ConvertTo-Json -Compress } catch { Set-ItemProperty -Path $serviceRegistryPath -Name Environment ` -Type MultiString -Value $serviceEnvironmentBefore if ($hadCollector -and (Test-Path -LiteralPath $backupCollectorPath -PathType Leaf)) { Copy-Item -LiteralPath $backupCollectorPath -Destination $collectorPath } elseif (-not $hadCollector) { Remove-Item -LiteralPath $collectorPath -Force -ErrorAction SilentlyContinue } throw } finally { Remove-Item -LiteralPath $temporaryRoot -Recurse -Force -ErrorAction SilentlyContinue }