lordmilko / PrtgAPI

C#/PowerShell interface for PRTG Network Monitor
MIT License
301 stars 37 forks source link

TriggerChannel does not properly serialize to JSON via ConvertTo-Json #353

Closed rummens closed 1 year ago

rummens commented 1 year ago

Describe the bug

When fetching a Notification Trigger, which has a channel configured (e.g. Threshold or Volume) the response of the Channel attribute is empty or an empty dict when being cased to JSON.

A few examples:

Get-Device -Id 4900 | Get-Trigger -Inherited $false -Type Volume | ConvertTo-Json -Depth 9

{
"ObjectId": 4900, "ParentId": 4900, "Inherited": false, "Type": 2, "TypeName": "Volume Trigger", "SubId": 25, "State": null, "Latency": null, "Channel": {}, "Unit": "Byte/Hour", "UnitSize": 5, "UnitTime": null, "Period": 0, "OnNotificationAction": { "Url": "/editnotification.htm?id=301", "Postpone": true, "Comments": "*****", "Schedule": { "Url": null, "TimeTable": null, "Id": -1, "ParentId": 0, "Name": "None", "Tags": null, "DisplayType": null, "Type": null, "Active": false }, "SummaryMode": 2, "SummarySubject": "[%sitename] %summarycount Summarized Notifications", "SummaryPeriod": 1, "Email": { "UserAccount": { "Id": -1, "ParentId": 0, "Name": "None", "Tags": null, "DisplayType": null, "Type": null, "Active": false }, "UserGroup": { "Id": 201, "ParentId": 0, "Name": "PRTG Users Group", "Tags": null, "DisplayType": null, "Type": null, "Active": false }, "Address": null, "Subject": "[%sitename] %device %name %status %down (%message)", "ContentType": 0, "CustomText": null, "Priority": 0, "Enabled": true }, "Push": { "UserAccount": { "Id": -1, "ParentId": 0, "Name": "None", "Tags": null, "DisplayType": null, "Type": null, "Active": false }, "UserGroup": { "Id": -1, "ParentId": 0, "Name": "None", "Tags": null, "DisplayType": null, "Type": null, "Active": false }, "Message": "[%sitename] %device %name %status %down (%message)", "Enabled": false }, "SMS": { "UserAccount": { "Id": -1, "ParentId": 0, "Name": "None", "Tags": null, "DisplayType": null, "Type": null, "Active": false }, "UserGroup": { "Id": -1, "ParentId": 0, "Name": "None", "Tags": null, "DisplayType": null, "Type": null, "Active": false }, "Address": null, "Message": "[%sitename] %device %name %status %down (%message)", "Enabled": false }, "EventLog": { "LogName": 0, "EventSource": "PRTG Network Monitor", "EventType": null, "Message": "[%sitename] %device %name %status %down (%message)", "Enabled": false }, "Syslog": { "Host": null, "Port": 514, "Facility": 0, "Encoding": 1, "Message": "[%sitename] %device %name %status %down (%message)", "Enabled": false }, "SNMP": { "Host": null, "Port": 162, "Community": null, "TrapCode": 0, "MessageId": 0, "Message": "[%sitename] %device %name %status %down (%message)", "SenderIP": null, "Enabled": false }, "Http": { "Url": null, "SendSNI": false, "SNIName": null, "PostData": null, "Enabled": false }, "Program": { "ExeFile": null, "Parameters": "[%sitename] %device %name %status %down (%message)", "WindowsDomain": null, "WindowsUserName": null, "HasWindowsPassword": false, "Timeout": 60, "Enabled": false }, "Amazon": { "AccessKey": null, "SecretKey": null, "Region": null, "ResourceName": null, "Subject": null, "Message": "[%sitename] %device %name %status %down (%message)", "Enabled": false }, "Ticket": { "IsUserGroup": true, "UserAccount": { "Id": 100, "ParentId": 0, "Name": "PRTG System Administrator", "Tags": null, "DisplayType": null, "Type": null, "Active": false }, "UserGroup": { "Id": 200, "ParentId": 0, "Name": "PRTG Administrators", "Tags": null, "DisplayType": null, "Type": null, "Active": false }, "Subject": "%device %name %status %down (%message)", "Message": "\r\nSensor: %name\r\nStatus: %status %down\r\n\r\nDate/Time: %datetime (%timezone)\r\nLast Result: %lastvalue\r\nLast Message: %message\r\n\r\nProbe: %probe\r\nGroup: %group\r\nDevice: %device (%host)\r\n\r\nLast Scan: %lastcheck\r\nLast Up: %lastup\r\nLast Down: %lastdown\r\nUptime: %uptime\r\nDowntime: %downtime\r\nCumulated since: %cumsince\r\nLocation: %location\r\n\r\n", "AutoClose": true, "Enabled": false }, "Id": 301, "ParentId": -3, "Name": "Email to all members of group PRTG Users Group", "Tags": null, "DisplayType": "Notification Template", "Type": { "Value": 8, "StringValue": "notification" }, "Active": true }, "OffNotificationAction": null, "DisplayThreshold": "1", "Threshold": 1.0, "Condition": 2, "EscalationLatency": null, "EscalationNotificationAction": null, "RepeatInterval": null, "Name": "Email to all members of group PRTG Users Group", "Id": 25 }

Get-Device -Id 4900 | Get-Trigger -Inherited $false -Type Threshold | ConvertTo-Json -Depth 20 [
{ "ObjectId": 4900, "ParentId": 4900, "Inherited": false, "Type": 3, "TypeName": "Threshold Trigger", "SubId": 23, "State": null, "Latency": 60, "Channel": {}, "Unit": null, "UnitSize": null, "UnitTime": null, "Period": null, ... } ]

Steps to reproduce

Create any Notification Trigger with a Channel and check either the response of the Creation/Update Body or do a Get like shown above. Example command used:

Get-Device -Id 4900 | New-Trigger -Type Volume -OnNotificationAction "Email to all members of group PRTG Users Group" -Threshold 1 -Channel Primary

What is the output of 'Get-PrtgClient -Diagnostic'?

Get-PrtgClient -Diagnostic                                                                     
PSVersion      : 7.3.5
PSEdition      : Core
OS             : Linux 3.10.0-1160.59.1.el7.x86_64 #1 SMP Wed Feb 23 16:47:03 UTC 2022
PrtgAPIVersion : 0.9.18
Culture        : de-DE
CLRVersion     : .NETCoreApp,Version=v7.0
PrtgVersion    : 23.2.84.1566
PrtgLanguage   : english.lng

Additional context

The Creation and Update of Channels works without issues and the correct Channel is being shown inside the PRTG UI.

lordmilko commented 1 year ago

What is the output of

Get-Device -Id 4900 | Get-Trigger -Inherited $false -Type Volume -Verbose

Please omit personally identifiable info including the server name, username and passhash

rummens commented 1 year ago

Hi there,

Output is like this:

Get-Device -Id 4900 | Get-Trigger -Inherited $false -Type Volume -Verbose                  
VERBOSE: Get-NotificationTrigger: Synchronously executing request https://XXX/api/table.xml?id=4900&content=triggers&columns=content,objid&username=XXX&passhash=XXX
VERBOSE: Get-NotificationTrigger: Synchronously executing request https://XXX/api/table.xml?content=objects&columns=objid,name,parentid,tags,type,active,basetype&count=*&filter_objid=4900&username=XX&passhash=XX

Type      ObjectId SubId Inherited ParentId Latency Condition Threshold Unit       OnNotificationAction                 
----      -------- ----- --------- -------- ------- --------- --------- ----       --------------------                 
Volume    4900     30    False     4900             Equals    1         KByte/Hour Email to all members of group PRTG Users Group
lordmilko commented 1 year ago

Can you provide the output of

Set-PrtgClient -LogLevel Response

Get-Device -Id 4900 | Get-Trigger -Inherited $false -Type Volume -Verbose   

The response will include the details of all triggers defined on the object, so if there are any triggers with notification actions that contain personally identifiable information, please redact this info.

It can be a lot easier to check the output for identifying information by first doing a find replace on " with "

rummens commented 1 year ago

Here you go. Seems the Channel is being retrieved here.

Get-Device -Id 4900 | Get-Trigger -Inherited $false -Type Volume -Ver
VERBOSE: Get-NotificationTrigger: <?xml version="1.0" encoding="UTF-8"?>                                                
  <triggers totalcount="3" listend="1">
   <prtg-version>23.2.84.1566</prtg-version>
   <item>
    <content>{"type":"volume","channel":"Primary","threshold":"1", "unitsize":"KB", "period":"hour","typename":"Volume Trigger","onnotificationid":"301|Email to all members of group PRTG Users Group|email:Email","objectlink":"&lt;a dependency=\"4901\" deptype=\"select\" thisid=\"4900\" class=\"devicemenu isnotpaused isnotfavorite localprobe\" style=\"background-image:url(/icons/devices/A_Server_1.png?svg)\" id=\"4900\" href=\"device.htm?id=4900\"&gt;cmpXXX &lt;/a&gt;"}</content>
    <objid>30</objid>
   </item>
   <item>
    <content>{"type":"volume","channel":"Primary","threshold":"1", "unitsize":"KB", "period":"hour","typename":"Volume Trigger","onnotificationid":"301|Email to all members of group PRTG Users Group|email:Email","objectlink":"&lt;a dependency=\"4901\" deptype=\"select\" thisid=\"4900\" class=\"devicemenu isnotpaused isnotfavorite localprobe\" style=\"background-image:url(/icons/devices/A_Server_1.png?svg)\" id=\"4900\" href=\"device.htm?id=4900\"&gt;cmpXXX &lt;/a&gt;"}</content>
    <objid>31</objid>
   </item>
   <item>
    <content>{"type":"state","latency":"600","esclatency":"900","repeatival":"0","offnotificationid":"300|Email and push notification to admin|email:Email,push:Push Notification,slack:Slack","escnotificationid":"-1|None|","nodest":"Down","typename":"State Trigger","onnotificationid":"300|Email and push notification to admin|email:Email,push:Push Notification,slack:Slack","objectlink":"&lt;a dependency=\"-1000\" thisid=\"0\" class=\"rootgroupmenu isnotpaused isnotfavorite fixed\" id=\"0\" href=\"group.htm?id=0\"&gt;Root &lt;/a&gt;"}</content>
    <objid>1</objid>
   </item>
  </triggers>
VERBOSE: Get-NotificationTrigger: <?xml version="1.0" encoding="UTF-8"?>                                                
  <objects totalcount="1" listend="1">
   <prtg-version>23.2.84.1566</prtg-version>
   <item>
    <objid>4900</objid>
    <name>cmp205707059198</name>
    <parentid>4895</parentid>
    <type>Device</type>
    <type_raw>device</type_raw>
    <active>True</active>
    <active_raw>-1</active_raw>
    <basetype>device</basetype>
   </item>
  </objects>

Type      ObjectId SubId Inherited ParentId Latency Condition Threshold Unit       OnNotificationAction                 
----      -------- ----- --------- -------- ------- --------- --------- ----       --------------------                 
Volume    4900     30    False     4900             Equals    1         KByte/Hour Email to all members of group PRTG Users Group
Volume    4900     31    False     4900             Equals    1         KByte/Hour Email to all members of group PRTG Users Group

I ran one more on a Sensor out of curiosity, here it also seems to pick up the right Channel. I suppose this means something is going wrong during the Translation into Json?

Get-Sensor -Id 4901 | Get-Trigger -Inherited $false -Type Threshold -Verbose
VERBOSE: Get-NotificationTrigger: <?xml version="1.0" encoding="UTF-8"?>                                                
  <triggers totalcount="2" listend="1">
   <prtg-version>23.2.84.1566</prtg-version>
   <item>
    <content>{"type":"threshold","latency":"60","offnotificationid":"-1|None|","channel":"Maximum", "condition":"equal to","threshold":"1","typename":"Threshold Trigger","onnotificationid":"301|Email to all members of group PRTG Users Group|email:Email","objectlink":"&lt;a class=\"sensorid4901 sensg sensormenu isnotpaused isnotfavorite\" id=\"4901\" href=\"sensor.htm?id=4901\"&gt;Ping&lt;/a&gt;"}</content>
    <objid>1</objid>
   </item>
   <item>
    <content>{"type":"state","latency":"600","esclatency":"900","repeatival":"0","offnotificationid":"300|Email and push notification to admin|email:Email,push:Push Notification,slack:Slack","escnotificationid":"-1|None|","nodest":"Down","typename":"State Trigger","onnotificationid":"300|Email and push notification to admin|email:Email,push:Push Notification,slack:Slack","objectlink":"&lt;a dependency=\"-1000\" thisid=\"0\" class=\"rootgroupmenu isnotpaused isnotfavorite fixed\" id=\"0\" href=\"group.htm?id=0\"&gt;Root &lt;/a&gt;"}</content>
    <objid>1</objid>
   </item>
  </triggers>
VERBOSE: Get-NotificationTrigger: <?xml version="1.0" encoding="UTF-8"?>                                                
  <objects totalcount="1" listend="1">
   <prtg-version>23.2.84.1566</prtg-version>
   <item>
    <objid>4901</objid>
    <name>Ping</name>
    <parentid>4900</parentid>
    <tags>pingsensor</tags>
    <type>Ping</type>
    <type_raw>ping</type_raw>
    <active>True</active>
    <active_raw>-1</active_raw>
    <basetype>sensor</basetype>
   </item>
  </objects>
VERBOSE: Get-NotificationTrigger: <?xml version="1.0" encoding="UTF-8"?>                                                
  <channels totalcount="0" listend="1">
   <prtg-version>23.2.84.1566</prtg-version>
   <item>
    <objid>-4</objid>
    <objid_raw>*000000004</objid_raw>
    <name>Downtime</name>
   </item>
   <item>
    <objid>0</objid>
    <objid_raw>0000000000</objid_raw>
    <name>Ping Time</name>
    <lastvalue>0 msec</lastvalue>
    <lastvalue_raw>0.0000</lastvalue_raw>
   </item>
   <item>
    <objid>1</objid>
    <objid_raw>0000000001</objid_raw>
    <name>Minimum</name>
    <lastvalue>0 msec</lastvalue>
    <lastvalue_raw>0.0000</lastvalue_raw>
   </item>
   <item>
    <objid>2</objid>
    <objid_raw>0000000002</objid_raw>
    <name>Maximum</name>
    <lastvalue>0 msec</lastvalue>
    <lastvalue_raw>0.0000</lastvalue_raw>
   </item>
   <item>
    <objid>3</objid>
    <objid_raw>0000000003</objid_raw>
    <name>Packet Loss</name>
    <lastvalue>0 %</lastvalue>
    <lastvalue_raw>0.0000</lastvalue_raw>
   </item>
  </channels>
VERBOSE: Get-NotificationTrigger: <div>                                                                                 
  <div class="pseudoform prtg-form prtg-plugin" data-plugin="channels" data-template="channels.htm" data-singleedit="true" data-channelid="2" data-objectid="4901" data-container=".channelsloadingform">
    <h1 style="display: none">
      Edit Channel
    </h1>
    <select name="channel" id="channelsdropdown" style="width: 100%">
      <option value="-4" data-channel-kind="5">Downtime (ID -4)</option><option value="0" data-channel-kind="6">Ping Time (ID 0)</option><option value="1" data-channel-kind="6">Minimum (ID 1)</option><option value="2" data-channel-kind="6">Maximum (ID 2)</option><option value="3" data-channel-kind="5">Packet Loss (ID 3)</option>
    </select>
    <div class="channelsloadingform">

<form id="channelsform" action="/editsettings" method="post" class="prtg-form prtg-plugin" data-ajaxsubmit="true" data-redirect="false" data-plugin="multiedit">
    <fieldset>
        <legend class="prtg-header inline-hidden">Edit Channel "Maximum"</legend>
        <div class="control-group">
            <div class="checkboxbuttonset"><label class="control-label has_help " for="name_2">Name</label>
<div class="controls " data-placement="top" data-helptext="Enter a name to identify the channel in data graphs and tables.">
<input class="text"  data-rule-required="true" type="text" name="name_2" id="name_2" autocomplete="off" value="Maximum" ></div>

<label class="control-label has_help " for="id_2">ID</label>
<div class="controls " data-placement="top" data-helptext="Shows the ID of this channel. You cannot edit this ID. It is shown for your information only.">
<div class="readonlyproperty" >2</div></div>

<label class="control-label has_help " for="limitmode_2">Limits</label>
<div class="controls " data-placement="top" data-helptext="Define if you want to use thresholds for the channel. With limits, you can set a sensor in the <b>Warning</b> or the <b>Down</b> status depending on the current value of a channel.">
<div class="radio-control">
<input type="radio" class="hidden radio  GroupShowHide" name="limitmode_2" value="0" checked  id="limitmode0" >

<label for="limitmode0" class="radio-control-label">
<i class="icon-gray icon-radio-on"></i>
Disable limits
</label>
<input type="radio" class="hidden radio  GroupShowHide" name="limitmode_2" value="1" id="limitmode1" >

<label for="limitmode1" class="radio-control-label">
<i class="icon-gray icon-radio-on"></i>
Enable alerting based on limits
</label>
</div>
</div>

<label class="control-label has_help  Showlimitmode1  Hidelimitmode0  InitialDisplayNone  Hidelimitmode2  groupshowhideelement" for="limitmaxerror_2">Upper Error Limit (msec)</label>
<div class="controls  Showlimitmode1  Hidelimitmode0  InitialDisplayNone  Hidelimitmode2  groupshowhideelement" data-placement="top" data-helptext="Specify an upper limit. Values above this limit set the sensor to the <b>Down</b> status.<br><br> <b>Note:</b> The value that you enter here must match the type of value that the device returns, either an integer or a float. For example, if the device returns float values, then you must enter a float value.">
<input type="text" class="text"  data-rule-number="true" autocomplete="off" name="limitmaxerror_2" id="limitmaxerror_2" value="" data-rule-validgroup="limitsalert"><input type="hidden" name="limitmaxerror_2_factor" id="limitmaxerror_2_factor" value="1" data-rule-validgroup="limitsalert"></div>

<label class="control-label has_help  Showlimitmode1  Hidelimitmode0  InitialDisplayNone  Hidelimitmode2  groupshowhideelement" for="limitmaxwarning_2">Upper Warning Limit (msec)</label>
<div class="controls  Showlimitmode1  Hidelimitmode0  InitialDisplayNone  Hidelimitmode2  groupshowhideelement" data-placement="top" data-helptext="Specify an upper limit. Values above this limit set the sensor to the <b>Warning</b> status.<br><br> <b>Note:</b> The value that you enter here must match the type of value that the device returns, either an integer or a float. For example, if the device returns float values, then you must enter a float value.">
<input type="text" class="text"  data-rule-number="true" autocomplete="off" name="limitmaxwarning_2" id="limitmaxwarning_2" value="" data-rule-validgroup="limitsalert"><input type="hidden" name="limitmaxwarning_2_factor" id="limitmaxwarning_2_factor" value="1" data-rule-validgroup="limitsalert"></div>

<label class="control-label has_help  Showlimitmode1  Hidelimitmode0  InitialDisplayNone  Hidelimitmode2  groupshowhideelement" for="limitminwarning_2">Lower Warning Limit (msec)</label>
<div class="controls  Showlimitmode1  Hidelimitmode0  InitialDisplayNone  Hidelimitmode2  groupshowhideelement" data-placement="top" data-helptext="Specify a lower limit. Values below this limit set the sensor to the <b>Warning</b> status.<br><br> <b>Note:</b> The value that you enter here must match the type of value that the device returns, either an integer or a float. For example, if the device returns float values, then you must enter a float value.">
<input type="text" class="text"  data-rule-number="true" autocomplete="off" name="limitminwarning_2" id="limitminwarning_2" value="" data-rule-validgroup="limitsalert"><input type="hidden" name="limitminwarning_2_factor" id="limitminwarning_2_factor" value="1" data-rule-validgroup="limitsalert"></div>

<label class="control-label has_help  Showlimitmode1  Hidelimitmode0  InitialDisplayNone  Hidelimitmode2  groupshowhideelement" for="limitminerror_2">Lower Error Limit (msec)</label>
<div class="controls  Showlimitmode1  Hidelimitmode0  InitialDisplayNone  Hidelimitmode2  groupshowhideelement" data-placement="top" data-helptext="Specify a lower limit. Values below this limit set the sensor to the <b>Down</b> status.<br><br> <b>Note:</b> The value that you enter here must match the type of value that the device returns, either an integer or a float. For example, if the device returns float values, then you must enter a float value.">
<input type="text" class="text"  data-rule-number="true" autocomplete="off" name="limitminerror_2" id="limitminerror_2" value="" data-rule-validgroup="limitsalert"><input type="hidden" name="limitminerror_2_factor" id="limitminerror_2_factor" value="1" data-rule-validgroup="limitsalert"></div>

<label class="control-label has_help  Showlimitmode1  Hidelimitmode0  InitialDisplayNone  Hidelimitmode2  groupshowhideelement" for="limiterrormsg_2">Error Limit Message</label>
<div class="controls  Showlimitmode1  Hidelimitmode0  InitialDisplayNone  Hidelimitmode2  groupshowhideelement" data-placement="top" data-helptext="Enter a message that you want to add to the sensor message when the sensor is in the <b>Down</b> status.">
<input class="text"  type="text" name="limiterrormsg_2" id="limiterrormsg_2" autocomplete="off" value="" ></div>

<label class="control-label has_help  Showlimitmode1  Hidelimitmode0  InitialDisplayNone  Hidelimitmode2  groupshowhideelement" for="limitwarningmsg_2">Warning Limit Message</label>
<div class="controls  Showlimitmode1  Hidelimitmode0  InitialDisplayNone  Hidelimitmode2  groupshowhideelement" data-placement="top" data-helptext="Enter a message that you want to add to the sensor message when the sensor is in the <b>Warning</b> status.">
<input class="text"  type="text" name="limitwarningmsg_2" id="limitwarningmsg_2" autocomplete="off" value="" ></div>

<label class="control-label has_help " for="showchart_2">Graph Rendering</label>
<div class="controls " data-placement="top" data-helptext="Define if you want to show this channel in data graphs.">
<div class="radio-control">
<input type="radio" class="hidden radio " name="showchart_2" value="1" checked  id="showchart1" >

<label for="showchart1" class="radio-control-label">
<i class="icon-gray icon-radio-on"></i>
Show in graphs
</label>
<input type="radio" class="hidden radio " name="showchart_2" value="0" id="showchart0" >

<label for="showchart0" class="radio-control-label">
<i class="icon-gray icon-radio-on"></i>
Hide in graphs
</label>
</div>
</div>

<label class="control-label has_help " for="show_2">Table Rendering</label>
<div class="controls " data-placement="top" data-helptext="Define if you want to show this channel in data tables. <br/><br/><b>Important:</b> Only if you show this channel in data tables, PRTG uses it for the calculation of the <b>Total</b> channel of this sensor. Channels that you only show in graphs and not in tables do not contribute to the <b>Total</b> channel of this sensor.">
<div class="radio-control">
<input type="radio" class="hidden radio " name="show_2" value="1" checked  id="show1" >

<label for="show1" class="radio-control-label">
<i class="icon-gray icon-radio-on"></i>
Show in tables
</label>
<input type="radio" class="hidden radio " name="show_2" value="0" id="show0" >

<label for="show0" class="radio-control-label">
<i class="icon-gray icon-radio-on"></i>
Hide in tables
</label>
</div>
</div>

<label class="control-label has_help " for="colmode_2">Line Color</label>
<div class="controls " data-placement="top" data-helptext="Choose if you want an automatic line color for this channel in graphs or define the color manually.">
<div class="radio-control">
<input type="radio" class="hidden radio  GroupShowHide" name="colmode_2" value="0" checked  id="colmode0" >

<label for="colmode0" class="radio-control-label">
<i class="icon-gray icon-radio-on"></i>
Automatic
</label>
<input type="radio" class="hidden radio  GroupShowHide" name="colmode_2" value="1" id="colmode1" >

<label for="colmode1" class="radio-control-label">
<i class="icon-gray icon-radio-on"></i>
Manual
</label>
</div>
</div>

<label class="control-label has_help  Showcolmode1  Hidecolmode0  InitialDisplayNone  groupshowhideelement" for="color_2">Color (#rrggbb)</label>
<div class="controls  Showcolmode1  Hidecolmode0  InitialDisplayNone  groupshowhideelement" data-placement="top" data-helptext="Enter the color in hexadecimal RGB notation with a leading # (as in HTML/CSS, for example, <i>#ff0000</i> for red, <i>#0000ff</i> for blue) or directly choose a color.">
<input class="text colorselector"  data-rule-required="true" data-rule-hexcolor="true" autocomplete="off" type="text" name="color_2" id="color_2" value="" ></div>

<label class="control-label has_help " for="linewidth_2">Line Width</label>
<div class="controls " data-placement="top" data-helptext="Enter the line width for large graphs.">
<input class="text"  data-rule-number="true" data-rule-max="25" data-rule-required="true" type="text" name="linewidth_2" id="linewidth_2" autocomplete="off" value="1" ></div>

<label class="control-label has_help " for="percent_2">Data</label>
<div class="controls " data-placement="top" data-helptext="Choose if you want to show actual values with the given unit or to calculate and show a percentage based on the maximum value as defined below.">
<div class="radio-control">
<input type="radio" class="hidden radio  GroupShowHide" name="percent_2" value="0" checked  id="percent0" >

<label for="percent0" class="radio-control-label">
<i class="icon-gray icon-radio-on"></i>
Display actual values in msec
</label>
<input type="radio" class="hidden radio  GroupShowHide" name="percent_2" value="1" id="percent1" >

<label for="percent1" class="radio-control-label">
<i class="icon-gray icon-radio-on"></i>
Display in percent of maximum
</label>
</div>
</div>

<label class="control-label has_help  Showpercent1  Hidepercent0  InitialDisplayNone  groupshowhideelement" for="ref100percent_2">Maximum (msec)</label>
<div class="controls  Showpercent1  Hidepercent0  InitialDisplayNone  groupshowhideelement" data-placement="top" data-helptext="Enter a maximum value on which the percentage calculation is based.">
<input type="text" class="text"  data-rule-number="true" data-rule-required="true" autocomplete="off" name="ref100percent_2" id="ref100percent_2" value="" ><input type="hidden" name="ref100percent_2_factor" id="ref100percent_2_factor" value="1" ></div>

<label class="control-label has_help " for="avgmode_2">Value Mode</label>
<div class="controls " data-placement="top" data-helptext="Choose the value that you want to use to display as historic data for this channel. Instead of averages, you can show the maximum or the minimum values of a time span.">
<div class="radio-control">
<input type="radio" class="hidden radio " name="avgmode_2" value="0" checked  id="avgmode0" >

<label for="avgmode0" class="radio-control-label">
<i class="icon-gray icon-radio-on"></i>
Average
</label>
<input type="radio" class="hidden radio " name="avgmode_2" value="1" id="avgmode1" >

<label for="avgmode1" class="radio-control-label">
<i class="icon-gray icon-radio-on"></i>
Minimum
</label>
<input type="radio" class="hidden radio " name="avgmode_2" value="2" id="avgmode2" >

<label for="avgmode2" class="radio-control-label">
<i class="icon-gray icon-radio-on"></i>
Maximum
</label>
</div>
</div>

<label class="control-label has_help " for="decimalmode_2">Decimal Places</label>
<div class="controls " data-placement="top" data-helptext="Define the number of decimal places you want to display in this channel. You can enter a custom number below.">
<div class="radio-control">
<input type="radio" class="hidden radio  GroupShowHide" name="decimalmode_2" value="0" checked  id="decimalmode0" >

<label for="decimalmode0" class="radio-control-label">
<i class="icon-gray icon-radio-on"></i>
Automatic
</label>
<input type="radio" class="hidden radio  GroupShowHide" name="decimalmode_2" value="1" id="decimalmode1" >

<label for="decimalmode1" class="radio-control-label">
<i class="icon-gray icon-radio-on"></i>
All
</label>
<input type="radio" class="hidden radio  GroupShowHide" name="decimalmode_2" value="2" id="decimalmode2" >

<label for="decimalmode2" class="radio-control-label">
<i class="icon-gray icon-radio-on"></i>
Custom
</label>
</div>
</div>

<label class="control-label no_help  Showdecimalmode2  Hidedecimalmode0  InitialDisplayNone  Hidedecimalmode1  groupshowhideelement" for="decimaldigits_2"></label>
<div class="controls  Showdecimalmode2  Hidedecimalmode0  InitialDisplayNone  Hidedecimalmode1  groupshowhideelement" data-placement="top" >
<input class="text"  data-rule-number="true" data-rule-required="true" data-rule-min="0" data-rule-max="15" type="text" name="decimaldigits_2" id="decimaldigits_2" autocomplete="off" value="2" ></div>

<label class="control-label has_help " for="spikemode_2">Spike Filter</label>
<div class="controls " data-placement="top" data-helptext="Choose if you want to filter out incorrect values from data graphs and tables that are too high or too low. The filter applies to existing data. This can take a few minutes.">
<div class="radio-control">
<input type="radio" class="hidden radio  GroupShowHide" name="spikemode_2" value="0" checked  id="spikemode0" >

<label for="spikemode0" class="radio-control-label">
<i class="icon-gray icon-radio-on"></i>
Disable filtering
</label>
<input type="radio" class="hidden radio  GroupShowHide" name="spikemode_2" value="1" id="spikemode1" >

<label for="spikemode1" class="radio-control-label">
<i class="icon-gray icon-radio-on"></i>
Enable filtering
</label>
</div>
</div>

<label class="control-label has_help  Showspikemode1  Hidespikemode0  InitialDisplayNone  groupshowhideelement" for="spikemax_2">Spike Filter Max. Value (msec)</label>
<div class="controls  Showspikemode1  Hidespikemode0  InitialDisplayNone  groupshowhideelement" data-placement="top" data-helptext="Define the upper spike filter. PRTG disregards all data above this value.">
<input type="text" class="text"  data-rule-number="true" autocomplete="off" name="spikemax_2" id="spikemax_2" value="" ><input type="hidden" name="spikemax_2_factor" id="spikemax_2_factor" value="1" ></div>

<label class="control-label has_help  Showspikemode1  Hidespikemode0  InitialDisplayNone  groupshowhideelement" for="spikemin_2">Spike Filter Min. Value (msec)</label>
<div class="controls  Showspikemode1  Hidespikemode0  InitialDisplayNone  groupshowhideelement" data-placement="top" data-helptext="Define the lower spike filter. PRTG disregards all data below this value.">
<input type="text" class="text"  data-rule-number="true" autocomplete="off" name="spikemin_2" id="spikemin_2" value="" ><input type="hidden" name="spikemin_2_factor" id="spikemin_2_factor" value="1" ></div>

<label class="control-label has_help " for="axismode_2">Vertical Axis Scaling</label>
<div class="controls " data-placement="top" data-helptext="Define the vertical axis scaling of graphs for this channel. Choose if you want to automatically set the vertical axis scaling or to manually set the minimum and maximum for the vertical axis. <br/><br/><b>Note:</b> PRTG ignores this setting if you set the <b>Graph Type</b> to <b>Stack channels on top of each other</b> in the sensor settings.">
<div class="radio-control">
<input type="radio" class="hidden radio  GroupShowHide" name="axismode_2" value="0" checked  id="axismode0" >

<label for="axismode0" class="radio-control-label">
<i class="icon-gray icon-radio-on"></i>
Automatic scaling
</label>
<input type="radio" class="hidden radio  GroupShowHide" name="axismode_2" value="1" id="axismode1" >

<label for="axismode1" class="radio-control-label">
<i class="icon-gray icon-radio-on"></i>
Manual scaling
</label>
</div>
</div>

<label class="control-label no_help  Showaxismode1  Hideaxismode0  InitialDisplayNone  groupshowhideelement" for="axismax_2">Vertical Axis Maximum (msec)</label>
<div class="controls  Showaxismode1  Hideaxismode0  InitialDisplayNone  groupshowhideelement" data-placement="top" >
<input type="text" class="text"  data-rule-number="true" data-rule-required="true" autocomplete="off" name="axismax_2" id="axismax_2" value="" ><input type="hidden" name="axismax_2_factor" id="axismax_2_factor" value="1" ></div>

<label class="control-label no_help  Showaxismode1  Hideaxismode0  InitialDisplayNone  groupshowhideelement" for="axismin_2">Vertical Axis Minimum (msec)</label>
<div class="controls  Showaxismode1  Hideaxismode0  InitialDisplayNone  groupshowhideelement" data-placement="top" >
<input type="text" class="text"  data-rule-number="true" data-rule-required="true" autocomplete="off" name="axismin_2" id="axismin_2" value="" ><input type="hidden" name="axismin_2_factor" id="axismin_2_factor" value="1" ></div>

</div>
            <input type="hidden" name="id" value="4901">
            <input type="hidden" name="anti-csrf-token" value="YzIzM2FlOTYzZGY0ZDVjNWE2YjMyZjM2OTkyMDJmNjg0YjlkZmM1NzlmNDIxNGY4ZjE1NzVhMjgxZjA3OTM2NA==">
            <!-- <input type="hidden" name="targeturl" value="/sensor.htm?id=4901&tabid=11"> -->
        </div>
    </fieldset>
    <div class="submitbuttonboxanchor">
        <div class="submitbuttonbox">
            <input style="" id="mysubmit" class="submit button btngrey" type="submit" value="Save">
            <input style="" onclick="history.back();return(false)" class="cancel btngrey button hideinwingui" type="reset" value="Cancel">
        </div>
    </div>
</form>

    </div>
  </div>
</div>

Type      ObjectId SubId Inherited ParentId Latency Condition Threshold Unit       OnNotificationAction                 
----      -------- ----- --------- -------- ------- --------- --------- ----       --------------------                 
Threshold 4901     1     False     4901     60      Equals    1                    Email to all members of group PRTG Users Group
lordmilko commented 1 year ago

This is very bizzare. Can you do

$a = Get-Device -Id 4900 | Get-Trigger -Inherited $false -Type Volume | select -first 1

$a.gettype().getfield("channel", [System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::NonPublic).getvalue($a)

$a.gettype().getfield("channelName", [System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::NonPublic).getvalue($a)

$a.gettype().getfield("translatedChannelName", [System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::NonPublic).getvalue($a)

and provide the output of each command

rummens commented 1 year ago

Here you go (first and last command didn't output anything):

$a = Get-Device -Id 4900 | Get-Trigger -Inherited $false -Type Volume | select -first 1
$a.gettype().getfield("channel", [System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::NonPublic).getvalue($a)
Primary
$a.gettype().getfield("channelName", [System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::NonPublic).getvalue($a)
Primary
$a.gettype().getfield("translatedChannelName", [System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::NonPublic).getvalue($a)
lordmilko commented 1 year ago
$a.gettype().getfield("channel", [System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::NonPublic).getvalue($a)
Primary

The fact this returned Primary seems to indicate to me there is a channel in there

What do you get when you do

$a = Get-Device -Id 4900 | Get-Trigger -Inherited $false -Type Volume | select -first 1

$a.gettype().getfield("channel", [System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::NonPublic).getvalue($a).gettype()

$a.Channel

Set-StrictMode -Version 5

$a.Channel

$a.gettype().getproperty("Channel").getvalue($a)
rummens commented 1 year ago

Getting this, first command again empty:

$a = Get-Device -Id 4900 | Get-Trigger -Inherited $false -Type Volume | select -first 1          
$a.gettype().getfield("channel", [System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::NonPublic).getvalue($a).gettype()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     False    TriggerChannel                           System.Object

$a.Channel
Primary

Set-StrictMode -Version 5

$a.Channel
Primary

$a.gettype().getproperty("Channel").getvalue($a)
Primary
lordmilko commented 1 year ago

I think I've realized what the issue is.

If you do

Get-Device -Id 4900 | Get-Trigger -Inherited $false -Type Volume | fl

you will see the channel. Your issue is only that when you do ConvertTo-Json you don't see the channel

When I test this on my computer I get the following

PS C:\> get-device ci*|get-trigger -type volume | fl

ObjectId                     : 2055
...
Channel                      : Total
Unit                         : KByte/Day
PS C:\> get-device ci*|get-trigger -type Volume | convertto-json
{
    "ObjectId":  2055,
    "ParentId":  2055,
    "Inherited":  false,
    "Type":  2,
    "TypeName":  "Volume Trigger",
    "SubId":  3,
    "State":  null,
    "Latency":  null,
    "Channel":  {

                },
    "Unit":  "KByte/Day",

The issue is purely regarding the serialization of the Channel property to JSON. The Channel property contains a value of type TriggerChannel which is a special type of "class enum". I don't know why you're converting this data to JSON, but you can bypass this issue by creating a new PSObject containing all of the properties of the NotificationTrigger, replacing the Channel property with a string representation of the TriggerChannel and then calling ConvertTo-Json

$a = Get-Device -Id 4900 | Get-Trigger -Inherited $false -Type Volume
$a|select *|foreach { $_.Channel = $_.Channel.ToString(); $_ }|convertto-json

I'm not sure to what extent TriggerChannel could even be modified to natively serialize properly via ConvertTo-Json. As such I would recommend using the workaround listed above

rummens commented 1 year ago

Wow you are right, this works. Thanks so much for the quick answers and fix! And cudos to the great work you have done with this API, we are using it very heavily and this is the first "issue" we came about.