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
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:
- The text is for the whole sensor (Sensor's message), it can't be assigned to channels. See output below for example.
- 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
Hello mbaybarsk,
we appreciate your contact.
As for not having values, please be aware that channel values must be numerical, example result:
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:
Best Regards,
May, 2016 - Permalink