About patterns

For collecting data from remote Systems or Devices the Patterns are used to describe how to get information and transforming that to Discovery-Objects. The best way to see which Objects are possible is to generate Host and Device Examples with "Discovery.exe -e".


Pattern Structure

A Pattern is a XML File wich can contain the following Nodes:

NodeMandatoryDescription
<Version>
A version string for the pattern
<PatternID>(tick)A unique string for each pattern
<AlternativePattern>(tick)A pattern that will be used instead of that one (e.g. used for PowerShell)
<ProcessType>(tick)

Describes which type of execution will be proceed by the Discovery-Tool to collect information.

All possible Process Types are listed under 1.1.

<PatternType>(tick)

Describes for which type of Discovery-Object the pattern is responsible.

All possible Pattern Types are listed under 1.2.

<OrderNr>(tick)

It is possible to have multiple Pattern for one Discovery-Object,

the order number is used to set in which order the Pattern are executed.

(For example you can see in the pattern folder 3 Pattern for Linux Network Interface)

<Command>(error)

Contains the Command that will be executed on the Remote-System.

The command depends on the Process Type examples are listed under 1.1:

<Processing>(tick)

Contains the C# SourceCode to processing result data to Discovery-Objects.

For more details see Creating Custom Pattern

<IgnoreCommandCache>(error)

If set to true, the CommandProvider will not observe the cache.

Per default a command result will be stored in the cache and the result of the same command will be read from the cache.

The cache is just persistent for a scan session.

<RegValue>(error)The Registry Variable that would be read in combination with the Command used by WMIRegValue.
<ApplicationName>(error)The name of the application that is used to collect extended information for
<ContextName>(error)Optional SNMP Walk context name
<WMINamespace>(error)define an alternative WMI Namespace for the initial command

Process Types

TypeExample CommandCommand Result TypeDescription
SSHExecuteifconfig -aStringExecutes a SSH Command on a connected Remote Unix System
WMIQuerySELECT * FROM Win32_OperatingSystemManagementObjectCollectionExecutes a WMI Query on a connected Remote Windows System
WMIExecutenetstat -anString

Executes a Command on a connected Remote Windows System

WMIRegValue

<![CDATA[
SOFTWARE\MySoftware\
]]>

object

The result object can any type of a registry value

By WMIRegValue the Command contains the Registry Path and reads the Value described in the <RegValue> Node of the Pattern.

The "Root" is set by default to "HKEY_LOCAL_MACHINE\" and should not included in the command.

The Result is an object containing all Variations of an Registry Variable.

WMIRegValueList

<![CDATA[
SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\
]]>

List<string>

By WMIRegValueList the Command contains the Registry Path and returning the "subKeys" of the Registry Path.

The "Root" is set by default to "HKEY_LOCAL_MACHINE\" and should not included in the command.

PowerShellExecuteGet-WmiObject win32_computersystemStringExecutes a PowerShell-Command on a connected Remote Windows System

SNMP_GET

1.3.6.1.4.1.2021.4.5.0;1.3.6.1.4.1.2021.4.6.0

List<ExtendedInformation>

ExtendedInformation is an object with two attributes:


Executes a SNMP GET Command for the given MIB's.

Returning a List of ExtendedInformation, a ExtendedInformation containing the Name (the MIB) and the Value of the MIB.

SNMP_WALK1.3.6.1.2.1.2.2.1.2;1.3.6.1.2.1.4.20.1.2

List<ExtendedInformation>

ExtendedInformation is an object with two attributes:

Executes a SNMP WALK Command for the given MIB's.

Returning a List of ExtendedInformation, a ExtendedInformation containing the Name (the MIB) and the Value of the MIB.

Command Result Types

In Discovery 3 version every Pattern Process Type has a Command Result implementation.

Process Type

Command Result Type

WMIQueryWMIQueryResult
WMIRegValue

WMIRegValueResult

WMIRegValueList

WMIRegValueListResult

WMIExecuteWMIExecuteResult
PowerShellExecutePowerShellExecuteResult
SSHExecuteSSHExecuteResult
SNMP_GETSNMPExecuteResult
SNMP_WALKSNMPExecuteResult
VIMObject

VIMCommandResult


Pattern Types

The pattern type defines which type of Discovery-Object are returning as result from the processing.

The result of Discovery-Objects will be merged. For example in the Discovery/pattern folder you can see multiple HostInfo pattern, they are all collecting partial results of a host and the Discovery-Tool merging the Attributes together.

Typeexample Pattern (inlcuded)Description
Host

Linux_Hostinfo_Hostname.pat

Windows_Hostinfo_Hostname_Model.pat

Processing collected data for a Host.

The pattern function (PerformAction) processing a HostInfo-Object.

DeviceinfoSNMP_Deviceinfo_Default.pat

Processing collected data for a Host or a Device.

The pattern function (PerformAction) processing a DeviceInfo-Object.

Network

Linux_NetworkInterfaces.pat

Windows_NetworkInterfaces.pat

Processing collected data for NetworkInterfaces.

The pattern function (PerformAction) processing the NetworkInterface-Objects of the parent system.

CPU

Linux_CPUs.pat

Windows_CPUs.pat

Processing collected data for CPUs.

The pattern function (PerformAction) processing the CPUInfo-Objects of the parent system.

OS

Linux_OS.pat

Windows_OS.pat

Processing collected data for OS.

The pattern function (PerformAction) processing the OSInfo-Objects of the parent system.

FileSystem

Linux_FileSystem.pat

Windows_FileSystem.pat

Processing collected data for FileSystems.

The pattern function (PerformAction) processing the FileSystemInfo-Objects of the parent system.

Application

Linux_Application_RPM.pat

Windows_Application_Product.pat

Processing collected data for Applications.

The pattern function (PerformAction) returning a list of ApplicationInfo-Objectsof the parent system.

Patch

Windows_Patches.pat

Processing collected data for Patches.

The pattern function (PerformAction) processing the PatchInfo-Objects of the parent system.

ApplicationServiceWindows_ApplicationServices.pat

Processing collected data for ApplicationServices.

The pattern function (PerformAction) processing the ApplicationServiceInfo-Objects of the parent system.

OSProductKeyWindows_ProductKey.pat

Processing collected data for License.

The pattern function (PerformAction) processing the License for the Operating-System

ApplicationProductKeyExample: Application Product Key

Processing collected data for License.

The pattern function (PerformAction) processing the License for the Applications of the parent system.

UserLinux_User.pat
Windows_User.pat

Processing collected data for User.

The pattern function (PerformAction) processing the User of the parent system.

GroupLinux_Group.pat
Windows_Group.pat

Processing collected data for Groups.

The pattern function (PerformAction) processing the Groups of the parent system.

ConnectedPeripherieWindows_Peripherie_USB_Storage.pat

Processing collected data for Extended Informations.

The pattern function (PerformAction) processing the ExtendedInformation-Objects of the parent system.

SNMPExtendedValues

SNMP_Deviceinfo_ExtExampleRAM.pat

Example: SNMP Extended Values

Processing collected data for Extended Informations.

The pattern function (PerformAction) processing the ExtendedInformation-Objects of the parent system.

ConnectedPeripherieWindows_Peripherie_USB_Storage.patProcessing collected data for Connected Devices of the parent system.
HostinfoList

Windows_VBox_VMs.pat

Linux_VBox_VMs.pat

Processing collected data for a lis of Virtual Guests

The patten function (PerformAction) processing the Host-Objects (like virtual guest machines) of the parent system.

PostProcessing

Post Processing pattern will be executed after all the pattern types and can be used to add or modify host/device information

The pattern function (PerformAction) returning a HostInfo- or a DeviceInfo-Object.


Creating custom patterns

For creating a custom pattern navigate to the Discovery/pattern folder. Here you can create a new file (UTF-8) with the ending .pat or you copy and modifying an existing pattern of the Pattern-Type you want. The best practice to develop and test a new pattern is to extract a separate Discover-Tool Instance and setting up a connection to the Host or Device that returning the result data you want to handle with.

Then remove all Pattern excluding a "main" HostInfo Pattern (Linux_Hostinfo_Hostname.pat, Windows_Hostinfo_Hostname_Model.pat, SNMP_Deviceinfo_Default.pat) it is mandatory to have a "main" HostInfo Object with the including Hostname. With this Setup it is possible to fast testing a new pattern without waiting of the response of all other Pattern.

Be sure that your new Pattern are containing all required XML-Nodes, the <Processing>-Node containing the C# class to process the result data from the command to a Discovery-Object. The functionality is that the Discovery-Tool reading the C# Source Code that is including the <Processing>-Node and invoking the PerformAction-Method of the PatternExec-Class.

The PerformAction Method is mandatory and the Discovery-Tool invoking it with an object array that are including the following 4 objects:

parameterobject typedescription
parameters[0]Command ResultContaining the result of the initial pattern command
parameters[1]

IProvider

Containing the executing Provider-Class that is connected to the discovering system.

This provider will be used in the pattern to execute other commands if required.

parameters[2]object

Containing the HostInfo-/Device-Object that is initial created on the start of the scan.

For connecting to Host or Devices there are 4 Types of Providers used by the Discovery-Tool, the following described Providers handling the connection and execution of commands to collecting data.

Inside of a Pattern you have the availability to use the actual connected Provider to execute additional commands if more informations from the System are needed.

SSH-Provider

The SSH-Provider-Class is connected to a Linux System and can be used insight of a Pattern:

using Insight.Discovery.ProviderClasses; // Include the ProviderClasses Namespace at the Head of the PatternCode
using Insight.Discovery.InfoClasses; // Include the InfoClasses Namespace at the Head of the PatternCode

// Casting the connected Provider out of the parameters from the PerformAction-Method
SSHProvider ssh = (SSHProvider)parameters[1];
 
// using the SSH-Provider to execute a command and receiving the result.
var result = (SSHExecuteResult)ssh.ExecuteCommand("hostname"); // returning the hostname of a Linux System

For example a cast SSHProvider is used in the "Linux_Hostinfo_Hostname.pat" Pattern.

WMI-Provider

The WMI-Provider-Class is connected to a Windows System and can be used insight of a Pattern:

using Insight.Discovery.ProviderClasses; // Include the ProviderClasses Namespace at the Head of the PatternCode
using Insight.Discovery.InfoClasses; // Include the InfoClasses Namespace at the Head of the PatternCode

// Casting the connected Provider out of the parameters from the PerformAction-Method
WMIProvider wmiProvider = (WMIProvider)parameters[1];
 
// using the WMI-Provider to read a Registry Value.
var result = (WMIRegValueResult)wmiProvider.GetRegistryValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\<Key>", "DisplayName");
 
// using the WMI-Provider to get a List of all Registry-Sub-Keys.
var result = (WMIRegValueListResult)wmiProvider.GetSubKeysFromRegistry("SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\");

//using the WMI-Provider to execute a WMI query receiving the result.
var result = (WMIQueryResult)wmiProvider.ExecuteWMIQuery("netstat -an");

//using the WMI-Provider to execute a command and receiving the result.
var result = (WMIExecuteResult)wmiProvider.ExecuteWMICommand("netstat -an");

SNMP-Provider

The SNMP-Provider-Class is connected to a SNMP Device and can be used insight of a Pattern:

using Insight.Discovery.ProviderClasses; // Include the ProviderClasses Namespace at the Head of the PatternCode
using Insight.Discovery.InfoClasses; // Include the InfoClasses Namespace at the Head of the PatternCode
 
// Casting the connected Provider out of the parameters from the PerformAction-Method
SNMPProvider snmp = (SNMPProvider)parameters[1];
 
// using the SNMP-Provider to execute a SNMPGet command and receiving the results
var result = (SNMPExecuteResult)snmp.ExecuteCommand("1.3.6.1.2.1.1.6.0", ScanProcessType.SNMP_GET, true);
 
// using the SNMP-Provider to execute a SNMPWalk command and receiving the results
var result = (SNMPExecuteResult)snmp.ExecuteCommand("1.3.6.1.2.1.2.2.1.2", ScanProcessType.SNMP_WALK, true);

// using the SNMP-Provider to execute a SNMPWalk command with contextName and receiving the results
var result = (SNMPExecuteResult)snmp.ExecuteCommand("1.3.6.1.2.1.2.2.1.2", ScanProcessType.SNMP_WALK, "myContext",true);

VIM-Provider

The SNMP-Provider-Class is connected to a VMWare ESXi System and can be used insight of a Pattern:

using Insight.Discovery.ProviderClasses; // Include the ProviderClasses Namespace at the Head of the PatternCode
using Insight.Discovery.InfoClasses; // Include the InfoClasses Namespace at the Head of the PatternCode
 
// Casting the connected Provider out of the parameters from the PerformAction-Method
VIMProvider snmp = (SNMPProvider)parameters[1];
 
// using the VIM-Provider to execute a command and receiving the results
var result = (VIMCommandResult)snmp.ExecuteCommand("HostSystem");

Additional Functions

ImportService

If you want to set a Date Attribute for a Discovery-Object like the InstallDate for an Application it must be in a specific Format ("MM/dd/yyyy").

You can use the delivered ImportService.ImportDate Method that will do the transformation for you:

using Insight.Discovery.Tools; // Include the Discovery Tools Namespace at the Head of the PatternCode
 
// using the ImportDate Method to transform the Date string of a result Object
discoveryObject.InstallDate = ImportService.Instance.ImportDate("resultDateString");
 
// The following input formats will be transformed:
// "MM/dd/yy", "M/dd/yy", "MM/dd/yyyy", "M/dd/yyyy", "MM/dd/yy", "M/d/yy", "MM/d/yyyy", "M/d/yyyy", "yyyyMMdd", "yyMMdd", "dd.MM.yy", "dd.MM.yyyy", "MMM-dd-yy", "MMM-dd-yyyy", "yyyy-MM-dd"

LogService

If you want to write entrys into the Discovery Logfile you can use the delivered LogService Class.

using Insight.Discovery.Tools; // Include the Discovery Tools Namespace at the Head of the PatternCode
 
// creating a "normal" log entry
LogService.Instance.LogNormal("My normal log entry");
 
// creating a "debug" log entry with additional Exception object
try
{
	LogService.Instance.LogDebug("a debug log entry");
	// Code that could raise an exception
}
catch (Exception ex)
{
	LogService.Instance.LogError("Log of an exception", ex);
}


Custom Pattern examples

Example: SNMP Extended Values

It is possible to extend the Information of a SNMP Device.

You must know which OID-Number returning the Value that should be discovered. In the processing script the return value of the OID will be mapped to a ExtendedInformation.

The following example is sending 3 OID's to discover different RAM Information.

<?xml version="1.0" encoding="utf-8"?>
<ScanPattern xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Version>3.0.1</Version>
<PatternID>RIADA-Cust-SNMP-1</PatternID>
<OrderNr>0</OrderNr>
<ProcessType>SNMP_GET</ProcessType>
<PatternType>SNMPExtendedValues</PatternType>
<Command>
    <![CDATA[
    1.3.6.1.4.1.2021.4.5.0;1.3.6.1.4.1.2021.4.6.0;1.3.6.1.4.1.2021.4.11.0
    ]]>
</Command>
<Processing>
    <![CDATA[
    using System;
    using System.Collections.Generic;
    using Insight.Discovery.InfoClasses.CommandResult.ResultTypes;
    using Insight.Discovery.Tools;
    using Insight.Discovery.InfoClasses;
    using Insight.Discovery.InfoClasses.CommandResult;
    
    namespace Insight.Discovery {
      public class PatternExec {
        public void PerformAction(object[] parameters)
        {
            DeviceInfo deviceInfo = (DeviceInfo)parameters[2];
            
            if (deviceInfo.ExtendedInformations.IsNullOrEmpty())
                    deviceInfo.ExtendedInformations = new List<ExtendedInformation>();

            try
            {
                var commandResult = (SNMPExecuteResult)parameters[0];
                commandResult.LogResult();

                foreach (KeyValuePair<string, object> item in commandResult)
                {
                    switch (item.Key)
                    {
                        case "1.3.6.1.4.1.2021.4.5.0": // OID to get available RAM
                            if (item.Value != null)
                            {
                                try
                                {
                                    long t = 0;
                                    long.TryParse(item.Value.ToString().Replace("\n", "").Trim(), out t);

                                    if (t > 0)
                                    {
                                        deviceInfo.ExtendedInformations.Add(new ExtendedInformation() { Name = "RAM Total", Value = (t / 1024).ToString() });
                                    }
                                }
                                catch
                                {
                                    //
                                }
                            }

                            break;
                        case "1.3.6.1.4.1.2021.4.6.0": // OID to get used RAM
                            if (item.Value != null)
                            {
                                try
                                {
                                    long t = 0;
                                    long.TryParse(item.Value.ToString().Replace("\n", "").Trim(), out t);

                                    if (t > 0)
                                    {
                                        deviceInfo.ExtendedInformations.Add(new ExtendedInformation()
                                        { Name = "RAM Used", Value = (t / 1024).ToString() });
                                    }
                                }
                                catch
                                {
                                    //
                                }
                            }
                            break;
                        case "1.3.6.1.4.1.2021.4.11.0": // OID to get free RAM
                            if (item.Value != null)
                            {
                                try
                                {
                                    long t = 0;
                                    long.TryParse(item.Value.ToString().Replace("\n", "").Trim(), out t);

                                    if (t > 0)
                                    {
                                        deviceInfo.ExtendedInformations.Add(new ExtendedInformation() { Name = "RAM Free", Value = (t / 1024).ToString() });
                                    }
                                }
                                catch
                                {
                                    //
                                }
                            }
                            break;
                    }
                }
            }
            catch (Exception ex)
            { LogService.Instance.LogDebug("Error getting Extended SNMP RAM Information.", ex); }
        }
  
      }
    }  
    ]]>
  </Processing>
</ScanPattern>

Example: Application Product Key

It is possible to add a discovered Licence-Information to an Application. For example if you know that a Licence File exists you can add a Pattern that read this file.

In the following example the pattern is reading a file "lic" that contains the Licence-Key for the Linux-Application "apt".

<?xml version="1.0" encoding="utf-8"?>
<!-- © Mindville -->
<ScanPattern xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Version>1.0.1</Version>
<PatternID>Mindville-Cust-Linux-AppPK-1</PatternID>
<OrderNr>0</OrderNr>
<ProcessType>SSHExecute</ProcessType>
<PatternType>ApplicationProductKey</PatternType>
<ApplicationName>apt</ApplicationName>
<Command>
    <![CDATA[
    cat /etc/apt/lic
    ]]>
</Command>
<Processing>
    <![CDATA[
    using System;
    using Insight.Discovery.InfoClasses;
    using Insight.Discovery.Tools;
    using Insight.Discovery.InfoClasses.CommandResult.ResultTypes;
    using System.Collections.Generic;
    
    namespace Insight.Discovery {
      public class PatternExec {        
          public void PerformAction(object[] parameters)
        {
            HostInfo hostInfo = (HostInfo) parameters[2];

            try
            {
                SSHExecuteResult sshExecuteResult = (SSHExecuteResult)parameters[0];
                sshExecuteResult.LogResult();

                string input = sshExecuteResult;

                if (input != string.Empty)
                {
                    if(hostInfo.OS.License == null)hostInfo.OS.License = new LicenseInfo();

                    hostInfo.OS.License.LicenseKey = input.Trim();
                }
            }
            catch (Exception ex)
            { LogService.Instance.LogDebug("Error getting apt product key Information", ex); }
            
        }
      }
    }
    ]]>
  </Processing>
</ScanPattern>

Example: Application Extended Information

It is possible to extend the Information of any object type.

IN the following example, we exten the host info with some extended informations.

<?xml version="1.0" encoding="utf-8"?>
<ScanPattern xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Version>1.0.1</Version>
<PatternID>Mindville-Cust-Linux-OpenPorts-1</PatternID>
<OrderNr>700</OrderNr>
<ProcessType>SSHExecute</ProcessType>
<PatternType>Host</PatternType>
<Command>
    <![CDATA[
    netstat -an
    ]]>
</Command>
<Processing>
    <![CDATA[
    using System;
    using System.Collections.Generic;
    using Insight.Discovery.Tools;
    using Insight.Discovery.InfoClasses;
    using Insight.Discovery.InfoClasses.CommandResult.ResultTypes;
    using Insight.Discovery.Tools.Networking;
    
    namespace Insight.Discovery {
      public class PatternExec {
        public void PerformAction(object[] parameters)
        {
            HostInfo hostInfo = (HostInfo)parameters[2];
            try
            {
                SSHExecuteResult sshExecuteResult = (SSHExecuteResult)parameters[0];
                sshExecuteResult.LogResult();

                string input = sshExecuteResult;

                if (input != string.Empty)
                {
                    if (hostInfo != null)
                    {
                        string[] lines = input.Split('\n');
                        ExtendedInformation tcpPortInfo = new ExtendedInformation() { Name = "TCP Ports", Value = string.Empty };
                        ExtendedInformation udpPortInfo = new ExtendedInformation() { Name = "UDP Ports", Value = string.Empty };

                        for (int i = 0; i < lines.Length; i++)
                        {
                            if (!string.IsNullOrEmpty(lines[i]) && lines[i].Contains(":")
                                && (lines[i].ToLower().StartsWith("tcp") || lines[i].ToLower().StartsWith("udp")))
                            {
                                string[] parts = lines[i].TrimReduce().Split(' ');

                                try
                                {
                                    for (int x = 0; x < parts.Length; x++)
                                    {
                                        if (parts[x].Contains("]"))
                                        {
                                            parts[x] = parts[1].Substring(parts[x].IndexOf("]"));
                                        }

                                        if (parts[0].ToLower().StartsWith("tcp") && !string.IsNullOrEmpty(parts[x]) &&
                                            parts[x].Contains(":"))
                                        {
                                            if (!tcpPortInfo.Value.Contains(parts[x].Split(':')[1]))
                                            {
                                                tcpPortInfo.Value += parts[x].Split(':')[1] + ",";
                                                break;
                                            }
                                        }

                                        if (parts[0].ToLower().StartsWith("udp") && !string.IsNullOrEmpty(parts[x]) &&
                                            parts[x].Contains(":"))
                                        {
                                            if (!udpPortInfo.Value.Contains(parts[x].Split(':')[1]))
                                            {
                                                udpPortInfo.Value += parts[x].Split(':')[1] + ",";
                                                break;
                                            }
                                        }
                                    }
                                }
                                catch
                                {
                                    //
                                }
                            }
                        }

                        if (hostInfo.ExtendedInformations.IsNullOrEmpty())
                            hostInfo.ExtendedInformations = new List<ExtendedInformation>();

                        if (!string.IsNullOrEmpty(tcpPortInfo.Value) && tcpPortInfo.Value.EndsWith(","))
                        {
                            tcpPortInfo.Value = tcpPortInfo.Value.Substring(0, tcpPortInfo.Value.Length - 1);
                            hostInfo.ExtendedInformations.Add(tcpPortInfo);
                        }
                        if (!string.IsNullOrEmpty(udpPortInfo.Value) && udpPortInfo.Value.EndsWith(","))
                        {
                            udpPortInfo.Value = udpPortInfo.Value.Substring(0, udpPortInfo.Value.Length - 1);
                            hostInfo.ExtendedInformations.Add(udpPortInfo);
                        }
                    }
                }
            }
            catch (Exception ex)
            { LogService.Instance.LogDebug("Error getting ReferencedHosts Information", ex); }

          }
        }
    }
    ]]>
  </Processing>
</ScanPattern>

Modifying patterns

It is possible but not recommend to modify delivered Pattern. If there are any missing Information the best practice is to add a new pattern, the missing Information will be merged to the Discovery-Object. If you are modified a delivered Pattern, you should save that Pattern external to pretend the lose of your change by updating the Discovery-Tool.

When you updating the Discovery-Tool with the updater, the updater will ask you before overwriting the modified Pattern.

Removing patterns

You can disable a pattern file in general:

  • go to the Pattern Tab and uncheck the unwanted pattern

You can disable a pattern file for a specific scan range

  • got to the Scan Setting an select the pattern files that you don't want to use
  • No labels