Skip to content

Deferred Tree Values

lordmilko edited this page Sep 11, 2021 · 13 revisions

Contents

Consider the following command:

SensorNode ping

This creates a new SensorNode for any Sensor objects named ping. Or so you'd think. There of course could be many dozen ping sensors on your PRTG installation, and you might only be interested in one of them!

Now consider the following: suppose we have a device, dc-1, that we'd like to model as having a child sensor. i.e, we wish to describe the tree

Server (Device)
└──Ping (Sensor)

PrtgAPI enables you to model this hierarchy via the use of ScriptBlock objects that can be specified to PrtgAPI's node cmdlets. These ScriptBlocks literally allow you to describe the levels at which different objects should appear.

DeviceNode dc-1 {
    SensorNode ping
}

While this all sounds nice, we have a problem: logically, when we do SensorNode ping, what we really want is to retrieve only ping sensors that exist within the context of the parent dc-1 device. However, the SensorNode doesn't know anything about its parent context. How are we supposed to retrieve the right information?

It's even worse in this example:

We want to describe the following tree

Windows Infrastructure (Group)
└──dc-1 (Device)
   └──Ping (Sensor)
└──exch-1 (Device)
   └──Ping (Sensor)

So we do the following in PowerShell

$ping = SensorNode ping

GroupNode "Windows Infrastructure" {
    DeviceNode dc-1 {
        $ping
    }

    DeviceNode exch-1 {
        $ping
    }
}

Not only did we retrieve our ping sensors outside of the scope of their parent objects, but we've then attempted to apply these as the children of two completely different devices. How can PrtgAPI possibly deal with this madness? We certainly don't want to retrieve all ping sensors and then filter them down to just 1 or 2.

The answer is simple: when a node cmdlet is invoked with non-uniquely identifiable parameters (e.g. there could be several objects all over the tree with a given Name, Position or Tag), PrtgAPI simply wraps up your request and returns a deferred value that will be evaluated later, once it has been made the child of a suitable parent.

# Create a SensorNode around sensors named ping. Upon emitting the value to the pipeline,
# we see that two such sensors exist within the PRTG server
C:\> SensorNode ping

Name                 Type   Parent Children
----                 ----   ------ --------
[Maybe] Ping, Ping   Sensor        {}

If any members of the node's Value are accessed (such as its Name), PrtgAPI will execute an API request to PRTG based on what it knows so far to identify the potential candidates that may satisfy your original request. When a single matching candidate is found, you will be able to access the members of that candidate via your deferred value

# Get the Tags of the single "Uptime" candidate"
C:\> $node = SensorNode Uptime
C:\> $node.Value.Tags

wmiuptimesensor
C_OS_VMware

# Note that it's not a real sensor however!
C:\> $node.Value.GetType()

IsPublic IsSerial Name              BaseType
-------- -------- ----              --------
False    False    SensorProxy       PrtgAPI.Tree.SensorOrDeviceOrGroupO...

If zero matches were found, the PowerShell formatting system will helpfully display to you that an error occurred, however you won't be able to get more specific information until you actually try and resolve your SensorNode under a parent.

C:\> $node = SensorNode Uptime1
C:\> $node

Name Type   Parent Children
---- ----   ------ --------
#ERR Sensor        {}
Failed to evaluate expression "Name".
    + CategoryInfo          : InvalidArgument: (:PSObject) [], GetValueInvocationException
    + FullyQualifiedErrorId : mshExpressionError
C:\> DeviceNode dc-1 { $node }

format-default : The following exception occurred while retrieving members: "Failed to resolve any Sensor objects
where 'Name = Uptime1, Device = dc-1'. Could not create a SensorNode."
    + CategoryInfo          : NotSpecified: (:) [format-default], ExtendedTypeSystemException
    + FullyQualifiedErrorId : CatchFromBaseGetMembers,Microsoft.PowerShell.Commands.FormatDefaultCommand

Note that in both of these examples, since both the sensor and devices list here are deferred values, both of these errors are actually thrown while emitting these value to the pipeline

  • In the first example, accessing the Name of the sensor triggers the exception.

    Since this exception occurs inside of PowerShell's formatting engine (rather than a PrtgAPI cmdlet such as the New-SensorNode cmdlet, which has already ended) we're unable to get more detailed information about what went wrong

  • In the second example, the exception is thrown while trying to display the names of the Children under the device.

    Since the sensor is resolved under the context of the still-active New-DeviceNode cmdlet, we're able to see the error message when the sensor cannot be resolved

Ultimately, PrtgAPI will force resolution of all of the objects in your tree when you go to calculate the changes that will need to be applied to PRTG, so any errors like this will ultimately be caught one way or the other.

Clone this wiki locally