Introduction

When issuing an instruction you can define a filter that's applied to the results. When issuing a follow up instruction, you can define a filter to apply to the results of the previous instruction in the follow up chain.

On this page:

Use case for filters

Results filters allow you to create a filter that will be evaluated by the client before sending the data back to Tachyon server.

This help cut the "noise" that an instruction may generate by removing responses that you know you are not interested in. They are best used in a situation where you are interested in a subset of data that the instruction would normally returned and that subset can be identified (and the filter specificed) before the instruction is issued. So this feature is useful when you know that you are only interested in a subset of information returned and you want to the agents not to send data you know is irrelevant to what you're looking for.

Filters can be applied to any instruction that returns data and work on the data returned by the instruction.

If a response produced by an agent is filtered down to 0 rows (so there is no data the matches the filter) the agent will return "Success no content". This means that Tachyon server will only get filtered data so this feature should not be used when you want to examine the data set using different filters. In that situation it is best to issue an instruction without the filter and apply filtering when retrieving responses, or you can issue multiple copies of the instruction, each with a different results filter.

Example use case

Let's say you want to check if any of the devices in your estate have a specific drived with an identified vulnerability installed.

You could simply issue the "1E-Explorer-TachyonCore-DeviceDrivers" instruction, but that would return all drivers and in this instance you know exactly what driver you're insterested in.

Results filters allow you to issue an instruction which will returns the rows you want.

How filters work

Results filter

A "results filter" is executed at the end of an instruction and filters the results much like a SQL "WHERE" clause would.

This filter can use any column that exist in the instruction's schema.

The instruction is executes as normal and produced a return data set. Then the agent applies the filter to the dataset and sends back the matching rows. If no matching rows were found, it sends back "Success no content".

Example

The flow here is simple:

  • Execute the instruction are prepare return dataset
  • Apply filter to the return dataset
  • Return filtered dataset

Previous results filter

A "previous results filter" can only be used in a follow-up scenario. It work on the result set returned by the previous instruction, so the instruction that you are issuing a follow up to.

As a quick refresher, a follow-up instruction forms a chain of two or more instructions. When a follow-up instruction is executes, each element in chain is executed if the previous one returned data, so if its final select statement produced a dataset that wasn't empty. This means that only the dataset from the last link in the chain, so the follow-up instruction itself is returned. Dataset from the internediate instructions in the chain are there for the agent to make a decision if it should continue executing instruction in the chain and are not returned to the Tachyon server.

This means that this filter uses the columns from the schema of the previous instruction and not the one you are issuing.

This means that "previous results filter" is executed at the end of the previous instruction and before the follow up instruction. It filters the results of the previous instruction much like a SQL "WHERE" clause would.

If there is any data left in the dataset after it was filtered, the follow up instruction is executed.

Simple example

Let's assume you have issed an instruction called "Search-For-Stuff" and now you are issuing a follow-up to that called "Fix-Stuff", but you want to fix only certain things identified by "Search-For-Stuff" instruction, so when issuing "Fix-Stuff" you apply a previous results filter to it. The flow here would be:

  • Execute "Search-For-Stuff" instruction and prepare its return dataset
  • Apply the Previous Results Filter to the return dataset
  • If filtered dataset has no rows, return "Success no content" immediatelly. If it does have rows, continue the execution
  • Execute "Fix-Stuff" instruction and prepare its dataset
  • Return the dataset from the "Fix-Stuff" instruction

Complex example

Let's assume you have a slightly more complex chain of events. You issue an instruction called "Asset-Inventory", then you issue "Software-Inventory" instruction as a follow up to "Asset-Inventory" and lastly you issue "Update-Software" instruction as a follow up to "Software-Inventory" but you specify a previous results filter so that only specific software from a specific manufacturer gets updated. The flow here would be:

  • Execute "Asset-Inventory" instruction and prepare its return dataset
  • If the return dataset has no rows, return "Success no content" immediatelly. If it does have rows, continue the execution
  • Execute "Software-Inventory" instruction and prepare its return dataset
  • Apply the Previous Results Filter to the return dataset of "Software-Inventory" instruction.
  • If filtered dataset has no rows, return "Success no content" immediatelly. If it does have rows, continue the execution
  • Execute "Update-Software" instruction and prepare its dataset
  • Return the dataset from the "Update-Software" instruction

Combining filter types

Both filter types can be combined and they execute in a specific sequence:

  • 1st instruction executes producing Dataset A
  • Results filter of the 1st instruction executes on Dataset A producting Dataset B
  • Previous results filter of the 2nd instruction executes on the Dataset B producing dataset C
  • 2nd instruction executes producing Dataset D
  • Results filter of the 2nd instruction executes on the Dataset D producing Dataset E
  • Dataset E is returned

Of course, if any of the datasets A through D were empty, a "success no content" would be returned immediately.

As you can see each filter, be that Results filter or Previous results filter, is executed against the last dataset created. This is why 2nd instruction's Previous Results Filter is executed against the dataset that was the result of he 1st instruction's Results Filter.

If 1st instruction had no Results Filter defined, 2nd instruction's Previous results filter would still execute against the latest dataset - the dataset returned by the 1st instruction (in the example above that's Dataset A).

Using results filter

Results filter will be applied to any data that would normally be returned after the instruction was run. Because of that, it can only use the columns returned by the instruction, so columns from instruction's schema.

You can define a filter on any and all of those columns, but only on those columns. If you define a filter, only results matching the filter will be returned by the client. If a client evaluates a filter and discovers it has no data that matches it, it returns "Success no content" message.

This filter is useful when the instruction you want to issue does not have a parameter that would allow you to narrow down the results.

Example

For example, for an instruction returning general information about each computer and normally, when unfiltered, gives the following results:

CaptionFree Physical MemoryLocaleNumber of usersRegistered User
Server18192en-us7Administrator
Server28192en-us4Administrator
Desktop11024en-us1JohnDoe
Desktop28192en-us1JaneDoe

The instruction itself does not allow any parameters, but to see computers for example, with less than 2GB of RAM the results can be defined with this filter:

Filter
{
    "Attribute": "Free Physical Memory",
    "Operator": "<=",
    "Value": "2048"
}

This filters the results to show computers with less than 2GB of RAM:

CaptionFree Physical MemoryLocaleNumber of usersRegistered User
Desktop11024en-us1JohnDoe

Using previous results filter

The previous results filter is applied to the results of the previous instruction in the follow up chain, and before the actual instruction being issued is run.

This filter is useful if you want to issue a follow up instruction that will be executed only by agents that would send results that fulfill a given condition.

It is worth noting that unlike scope, a filter will not limit the number of agents that receive the instruction, but will limit the results being sent back.

Example

These results are for an instruction that returns network adapters installed on each computer.

The results contain the columns: Description, MAC Address, Manufacturer and Physical Adapter.

Device NameDescriptionMAC AddressManufacturerPhysical Adapter
machine1.localIntel(R) 82579LM Gigabit Network Connection18:03:73:34:25:93Intel Corporationtrue
machine1.localHyper-V Virtual Ethernet Adapter12:12:22:12:11:11Microsoftfalse
machine2.localIntel(R) 82579LM Gigabit Network Connection18:03:73:35:22:98Intel Corporationtrue
server1.localX710-DA422:21:95:34:33:53DELLtrue
server2.localNC1000TX-G54:56:32:77:34:45Dynamodetrue

To find out what driver version each computer uses for the Intel 82579LM you can issue an instruction that returns the driver version and defines the following filter for the previous results:

Previous Results Filter
{
	"Operator": "AND",
	"Operands": [{
 		    "Attribute": "Description",
		    "Operator": "like",
		    "Value": "%82579LM%"
		},
		{
			"Attribute": "Manufacturer",
			"Operator": "like",
			"Value": "Intel%",
		}
}

The previous results filter only cause the agents that would return a matching result to execute the follow-up instruction. This removes any unwanted results from other NICs.

Device NameDescriptionDriver Version
machine1.localIntel(R) 82579LM Gigabit Network Connection1.0.0.1
machine2.localIntel(R) 82579LM Gigabit Network Connection1.0.0.5

Putting it all together

You can combine a previous results filter with the results filter on the same instruction.

For example, to make sure network drivers on all computers on your estate are up to date:

  1. Issue an instruction to return network adapters.
  2. Only return physical adapters.
  3. Set the results filter to filter out virtual adapters.
First instruction's results filter
{
    "Attribute": "Physical Adapter",
    "Operator": "==",
    "Value": "true",
}

This returns a list of results of physical network adapters on all computers:

Device NameDescriptionMAC AddressManufacturerPhysical Adapter
machine1.localIntel(R) 82579LM Gigabit Network Connection18:03:73:34:25:93Intel Corporationtrue
machine2.localIntel(R) 82579LM Gigabit Network Connection18:03:73:35:22:98Intel Corporationtrue
server1.localX710-DA422:21:95:34:33:53DELLtrue
server2.localNC1000TX-G54:56:32:77:34:45Dynamodetrue
server3.localX710-DA423:89:82:34:22:00DELLtrue

On this list there's a number of DELL adapters which have had recent driver updates because of stability issues. Because drivers older than version 11 can be problematic, you'd need see which computers require a driver update.

You issue an instruction returning network driver details.

Because you only want DELL adapters returned, you apply a previous result filter to filter out everything else:

Follow up instruction's previous resoults filter
{
	"Operator": "AND",
	"Operands": [{
 		    "Attribute": "Description",
		    "Operator": "==",
		    "Value": "X710-DA4"
		},
		{
			"Attribute": "Manufacturer",
			"Operator": "==",
			"Value": "DELL",
		}
}

To find versions older than 11, apply a results filter onto the same instruction:

Follow up instruction's results filter
{
    "Attribute": "Driver version",
    "Operator": "<",
    "Value": "11",
}

It returns these results:

Device NameDescriptionDriver Version
server1.local
X710-DA4
9

You could use these results to update the drivers on those specific computers.