Inputs Exec Powershell

Hi,

I’ve a powershell script for dhcp scopes. It’ll return output like below:

scope id, free, reserved, inuse

It’ll return 1 row for each scope id and scope id will be a tag and there are 3 measurements.
How should I configure telegraf and edit script accordingly?

Thanks,

I had a similar need few weeks ago and solved it with the following approach:

  • Powershell will return objects
  • Add/rename some properties
  • Using the Influx Powershell Module you can serialize the data in Influx format
  • feed the data to Telegraf

Here is the script and the corresponding conf (I will put them on Github someday
Configuration:

# Read metrics from one or more commands that can output to stdout
[[inputs.exec]]

  ## Override default gathering interval
  interval = "3h"

  ## Commands array
  commands = [
     'powershell "C:\Monitoring\telegraf\Configuration\telegraf.d\custom_input_scripts\Get_DiskSpace.ps1 -HostList SQLCSRV04"'
  ]
  
  ## Timeout for each command to complete.
  timeout = "2m"

  ## data format options:
  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md
  data_format = "influx"

Powershell script:

# ===================================================
# Script Requirements
# ===================================================
# 1. Powershell remoting enabled, even on local machine. run as admin -> Enable-PSRemoting
# 2. Influx Powershell Module, run as admin -> Install-Module Influx

param(
    [String[]] $HostList = [Environment]::MachineName
)

# only DriveType = 3 → Local hard disk
$VolumeData = Get-CimInstance CIM_LogicalDisk -ComputerName $HostList | Where-Object {$_.DriveType -eq 3}

# ===================================================
# Set calculated/renamed Fields
# ===================================================

$Server = @{label="Server";expression={$_.SystemName}}
$Volume = @{label="VolumeId";expression={$_.DeviceID}}

$TotalSize = @{label="TotalSpace(MB)";expression={[math]::Round($_.Size/1MB, 2)}}
$FreeSpace = @{label="FreeSpace(MB)";expression={[math]::Round($_.FreeSpace/1MB, 2)}}
$FreeSpacePerc = @{label="FreeSpace(%)";expression={[math]::Round(1-($_.Size - $_.FreeSpace)/$_.Size , 4)}}

# $_.Description may contain the same value
$VolumeTypeC = @{label="VolumeType";expression={
    switch ($_.DriveType) {
        1 {"No root directory"; break}
        2 {"Removable drive"; break}
        3 {"Local hard disk"; break}
        4 {"Network disk"; break}
        5 {"Compact disk"; break}
        6 {"RAM disk"; break}
        default {"Unknown"; break}
    }
}}

# ===================================================
# Define Tags and Metrics property mapping
# ===================================================
$Measurement = "ServerDisk"
$TagList = "Server","VolumeId","VolumeName"
$MetricList = "TotalSpace(MB)","FreeSpace(MB)","FreeSpace(%)"

# ===================================================
# Output
# ===================================================
# Warnings can't be sent to the output therefore "-WarningAction SilentlyContinue" is used
$VolumeData | Select-Object $Server,$Volume,VolumeName,$VolumeTypeC,$TotalSize,$FreeSpace,$FreeSpacePerc | ConvertTo-Metric -Measure $Measurement -MetricProperty $MetricList -TagProperty $TagList | ConvertTo-InfluxLineString -WarningAction SilentlyContinue

Notes:

  • that the Input server list is passed manually, you may want to fetch it from somewhere else (ie a file, or some other Powershell command that returns a list of server)
  • The influx ps module can post the data directly to influxdc
1 Like

@Giovanni_Luisotto I didn’t the get your approach quite well. Do I really need powershell-influx module? Will this not work?

 Write-Host $Measurement,tag1=xyz,tag2=abc field1=32,field2=34

Without any timestamp.

The simple answer is no, you don’t need the powershell module and write host will work.

You can serialize the data yourself but I wanted a more structured, safe and flexible approach.

One of my main problem was the mapping, in every “manual/custom” input plugin (ie. exec, file) you have to map the input data to the influxdb structure, I wanted all that logic in powershell, using powershell objects and that module does the trick.
You also want to manage null/empty values since influx won’t accept them.

In the end It’s all up to the complexity and usability of the powershell objects/output you have, if you have an object with safe and well formatted fields the you can simply write it directly to stdout and telegraf will get the data.

1 Like

Thanks, but telegraf didn’t get the data. I also tried it with the simple example script from here telegraf/plugins/inputs/exec at master · influxdata/telegraf · GitHub (echo ‘static influx line protocol example’).

  • Telegraf running in a windows server as local admin.
  • It doesn’t write any log files even though it’s specified in the config file logfile = “.\telegraf.log”

Where should I look into?

That’s another problem.
If you are executing a file and it gives an error it won’t be logged because the exit code if not specified will be 0… which means ok… (i opened an issue on github on this)

The easiest way to check what’s wrong is to execute the script form powershell as the same user that runs the service and see what happens.

Can you share the exec config you are using?

1 Like

@Giovanni_Luisotto;

Exec Config:

[[inputs.exec]]
  interval = "10s"
  commands = [
'powershell "C:\Program Files\telegraf\telegraf.d\dhcp.ps1"',
'cmd "C:\Program Files\telegraf\telegraf.d\test.bat"']
  timeout = "2m"
  data_format = "influx"

PowerShell Script:

$scopes = Get-DHCPServerv4Scope | Select-Object "Name", "StartRange","EndRange","ScopeID","State"

foreach ($scope in $scopes)
{
    $dhcpstats = Get-DhcpServerv4ScopeStatistics -ScopeId $scope.ScopeID | Select-Object "ScopeId", "Reserved", "InUse", "Free"
    Write-Host "dhcp,scopeID=$($scope.ScopeId),scopeName=$($scope.Name) InUse=$($dhcpstats.InUse),Reserved=$($dhcpstats.Reserved),Free=$($dhcpstats.Free)"
}

Script works manually as expected and returns the expected output in influx line protocol.

The script looks fine (I can’t test it), I would just add the arg -File in the Powershell call

  commands = [
    'powershell -File "C:\Program Files\telegraf\telegraf.d\dhcp.ps1"',
    'cmd "C:\Program Files\telegraf\telegraf.d\test.bat"'
  ]

Does the config work when you test it with your user?
I would try to create a test conf with the following agent settings (to print all the output to stdout) and the minimum input

[agent]
  ## Log at debug level.
  # debug = true
  ## Log only error level messages.
  # quiet = false

  ## Log file name, the empty string means to log to stderr.
  logfile = ""

and test it using powershell/cmd:

_path_\telegraf.exe --config _file.conf_ --test

Run it with your user, if the data are printed then it works and the problem is related to the user permissions, if you get nothing or an error then something else is wrong.

1 Like

@Giovanni_Luisotto

Powershell runned as administrator with “–test” parameter. Here is the error I get:

 D! [inputs.exec] Error in plugin: exec: exec: "powershell": executable file not found in %PATH% for command 'powershell -File "C:\Program Files\telegraf\telegraf.d\dhcp.ps1"':
 E! [telegraf] Error running agent: One or more input plugins had an error

I’ve added powershell path to environment variables.
Tried to give exact location of powershell.exe instead of just “powershell” or “powershell.exe” in the config file.

Just to know, on which system is telegraf running? I’ve never had an issue like this before

It’s Windows Server 2016 Datacenter.

I’ve fixed the issue by the way. Thanks, for your help.

Here is the solution:

  1. Powershell path should be added in environment variables > system variables > ‘Path’
    C:\Windows\System32\WindowsPowerShell\v1.0 C:\Windows\SysWOW64\WindowsPowerShell\v1.0
    At first I added only system32 but the error remained, I think it’s because telegraf binaries for windows is 64bit. Also the OS was 64bit.
  2. I edited the script to add escape characters for spaces in tags. https://docs.influxdata.com/influxdb/v0.9/write_protocols/write_syntax/
1 Like

Glad to hear that, just remember to escape all the special chars, also in tags, fields and measurements. (which probably is not completely done by the influx ps module… I will have a look into that)

If you haven’t yet figured this out, you need to use \\ in the path because that’s what TOML expects.

Thanks, but it actually works with a \ single one.

Huh, thanks for that! I tried that and it wasn’t working. Might have been something else. Again, many thanks!!

This topic was automatically closed 60 minutes after the last reply. New replies are no longer allowed.