Hello,

I have the following script which returns me the values I want when I run it manually on the server from ad administrative PS shell.

$manufacturer = Get-WmiObject Win32_Computersystem | select manufacturer
$manufacturer = $manufacturer.manufacturer
$model = Get-WmiObject Win32_Computersystem | select model
$model = $model.model
$OS = Get-WmiObject Win32_OperatingSystem | select caption
$OS = $OS.caption
$age = Get-WmiObject Win32_OperatingSystem | select InstallDate
$age = $age.Installdate

$hostname = $env:computername
$drives = get-psdrive -psprovider 'FileSystem' | select root
$drives = $drives.root

ForEach ($drive in $drives) 
    {$path = $drive + "XYZ\ZYX\Plugins\startup_plugin.xml"
     if (test-path $path)
     {$startup = $path}
    }

[xml]$XmlDocument = Get-Content  $startup 
$databases = $xmldocument.BVSManager.StartupData.DBEntries.Database | where { $_.Server -eq $hostname} 
$databases = $databases.Path
$DB1Name = (get-item $databases[0]).FullName
$DB2Name = (get-item $databases[1]).FullName
$DB1Size = (get-item $databases[0]).Length
$DB2Size = (get-item $databases[1]).Length


write-host "<prtg>"
write-host "<result>"
write-host "<channel>Make</channel>"
write-host "<value>"
write-host $manufacturer
write-host "</value>"
write-host "</result>"
write-host "<result>"
write-host "<channel>Model</channel>"
write-host "<value>"
write-host $model
write-host "</value>"
write-host "</result>"
write-host "<result>"
write-host "<channel>OS Version</channel>"
write-host "<value>"
write-host $OS
write-host "</value>"
write-host "</result>"
write-host "<result>"
write-host "<channel>Build Date</channel>"
write-host "<value>"
write-host $age
write-host "</value>"
write-host "</result>"
write-host "<result>"
write-host "<channel>DB1</channel>"
write-host "<value>"
write-host $DB1Name
write-host "</value>"
write-host "</result>"
write-host "<result>"
write-host "<channel>DB2</channel>"
write-host "<value>"
write-host $DB2Name
write-host "</value>"
write-host "</result>"
write-host "<result>"
write-host "<channel>DB1 Size</channel>"
write-host "<value>"
write-host $DB1Size
write-host "</value>"
write-host "<result>"
write-host "<channel>DB2 Size</channel>"
write-host "<value>"
write-host $DB2Size
write-host "</value>"
write-host "</result>"
write-host "</result>"
write-host "</prtg>"

However, when I add this custom sensor, what I get as a response is simply "0 #" . What is tehe problem? If the problem is not having administrative PS shell, how can I make this happen?


Article Comments

Hello mbaybarsk,
we appreciate your contact.

As for not having values, please be aware that channel values must be numerical, example result:

<prtg>
<result>
<channel>CPU Core #1</channel>
<value>34</value>
<Unit>Temperature</Unit>
</result>
<result>
<channel>CPU Core #2</channel>
<value>42</value>
<Unit>Temperature</Unit>
</result>
<result>
<channel>CPU Package</channel>
<value>42</value>
<Unit>Temperature</Unit>
</result>
</prtg>

Make sure that all values are numerical. You can check the actual result received by PRTG by enabling the Write EXE result to disk setting within the sensor, the log will be stored on the probe which runs the sensor under this folder:

C:\ProgramData\Paessler\PRTG Network Monitor\Logs (Sensors)

Best Regards,


May, 2016 - Permalink

If I'm only allowed numerical sensors with this type of sensor. Is there any way I can use WQL scripts to get string results? Or any other type?


May, 2016 - Permalink

You can use the <text> element to return text within a sensor, but please be aware that:

  1. The text is for the whole sensor (Sensor's message), it can't be assigned to channels. See output below for example.
  2. PRTG will not perform further evaluation upon the text, any warning/error related status processing will have to be done in the script itself, see second example.
            <prtg>
            <result>
            <channel>First channel</channel>
            <value>10</value>
            </result>
            <result>
            <channel>Second channel</channel>
            <value>20</value>
            </result>
            <text>This is the sensors text</text>
            </prtg>

Example output to set force the sensor into error (Down) :

              <prtg>
              <error>1</error>
              <text>Your error message</text>
              </prtg>
  • It's also possible to set the whole sensor to a Warning status by appending it to one of the <channel> entries (In contrast to the <error>1</error> which must be used outside of the <result>):
            <prtg>
            <result>
            <channel>First channel</channel>
            <value>10</value>
            <Warning>1</Warning>
            </result>
            <result>
            <channel>Second channel</channel>
            <value>20</value>
            </result>
            <text>This is the sensors text</text>
            </prtg>

Please check the API's documentation for further details.

Best Regards,


May, 2016 - Permalink

Hello,

I get it, I will have to use WMI for those text based values. However, the problem with other numerical values continue. Here's a better version of the same script.

Get-Content : Cannot bind argument to parameter 'Path' because it is null.
$output = "<prtg>"
$hostname = $env:computername
$drives = get-psdrive -psprovider 'FileSystem' | select root
$drives = $drives.root

ForEach ($drive in $drives) 
    {$path = $drive + "BroadView\ServerManager\Plugins\startup_plugin.xml"
     if (test-path $path)
     {$startup = $path}
    }

[xml]$XmlDocument = Get-Content  $startup 
$databases = $xmldocument.BVSManager.StartupData.DBEntries.Database | where { $_.Server -eq $hostname} 
$databases = $databases.Path
$numberofdbs = $databases.count 



for  ($i=0; $i -le $numberofdbs; $i++)
{
$size = (get-item($databases[$i])).Length
$output = $output + "<result><channel>" + $i + "</channel><value>" + $size + "</value></result>" 
}

$output += "</prtg>"
write-host $output

When I run this script manually on the destination servers, it runs perfectly fine & gives me the XML I want but the script fails when run as a sensor. Here are the error messages:

Get-Content : Cannot bind argument to parameter 'Path' because it is null.
At C:\Program Files (x86)\PRTG Network Monitor\custom 
sensors\EXEXML\BVS_Clients.ps1:12 char:34
+ [xml]$XmlDocument = Get-Content  $startup
+                                  ~~~~~~~~
    + CategoryInfo          : InvalidData: (:) [Get-Content], ParameterBinding 
   ValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,M 
   icrosoft.PowerShell.Commands.GetContentCommand
 
Cannot index into a null array.
At C:\Program Files (x86)\PRTG Network Monitor\custom 
sensors\EXEXML\BVS_Clients.ps1:21 char:1
+ $size = (get-item($databases[$i])).Length
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : NullArray
 
<prtg><result><channel>0</channel><value></value></result></prtg>

I believe the reason for that is PRTG is simply running this locally. How can I make PRTG run this script on the host that has this sensor setup?


May, 2016 - Permalink

You're absolutely correct:

PRTG will always run any script locally on the Probe that monitors the said device/sensor. This is desirable in some cases and to run the script on a remote system you need to use some sort of remoting, for instance powershell offers:

Invoke-Command -ComputerName $host [...]

Within PRTG you can pass the %host parameter to the custom-script sensor to use it within the script later. The same applies to the other parameters (%windowsdomain, %windowsuser, %windowspassword, ...)

Please note that the remote system must also be configured to accept powershell-remoting connections.

More details are available here PRTG Manual: Custom Sensors.

Please check the custom-script-exe tagged posts, they may provide examples or further details about remoting.

Best Regards,


May, 2016 - Permalink

Thanks for the response, it all works as I wanted other than having the ability to have strings as a value on powershell scripts.

Here's the final form of my script if anybody needs an example on how to make this conversion.

param(
    [string]$device = 'xxx' ,
    [string]$smdevice = 'xxx' ,
    [string]$domain = 'domain',
    [string]$username = 'user',
    [string]$password = 'password'
    )

$combination = $domain + "\" + $username
$pass = ConvertTo-SecureString -AsPlainText $password -Force
$Cred = New-Object System.Management.Automation.PSCredential -ArgumentList $combination,$pass

$result = Invoke-Command -ComputerName $smdevice -ScriptBlock {  

param(
    [string]$device
    )

$drives = get-psdrive -psprovider 'FileSystem' | select root
$drives = $drives.root

ForEach ($drive in $drives) 
    {$path = $drive + "xyz\ServerManager\Plugins\startup_plugin.xml"
     if (test-path $path)
     {$startup = $path}
    }

[xml]$XmlDocument = Get-Content  $startup 
$databases = $xmldocument.BVSManager.StartupData.DBEntries.Database | where { $_.Server -eq $device}
$databases = $databases.Path 
return $databases

} -credential $cred -ArgumentList $device


Invoke-Command -ComputerName $device -ScriptBlock { 
param(
    [array]$result
    ) 

$databases = $result
$numberofdbs = $databases.count

$output = "<prtg>"

for  ($i=0; $i -lt $numberofdbs; $i++)
{
$size = (get-item($databases[$i])).Length
if ($databases[$i]) {$channelname = $databases[$i]} else {$channelname = 'unknown'}
$output = $output + "<result><channel>" + $channelname + "</channel><value>" + $size + "</value></result>" 
}

$output += "</prtg>"
return $output


} -credential $cred -ArgumentList (,$result) 

May, 2016 - Permalink