CustomGPT zur automatischen Generierung von Assets Discovery Custom Patterns

Die Entwicklung großer Sprachmodelle (LLMs) und generativer KI-Technologie markiert einen entscheidenden Durchbruch im Bereich des maschinellen Lernens. Sie erleichtern ein breites Spektrum an Anwendungen – von der Erstellung von Inhalten bis hin zum Kundensupport.

Mit der Einführung von Atlassian Intelligence hat Atlassian diese Technologie in zahlreiche seiner Produkte wie Jira Service Management (JSM), Confluence und Bitbucket eingebettet. Obwohl die Integration erhebliche Vorteile bietet, etwa beim Erstellen und Editieren von Seiten in Confluence oder beim Verfassen von Commit-Nachrichten in Bitbucket, sind wir überzeugt, dass in spezifischeren Anwendungsgebieten noch Potential schlummert. Zur Prüfung der Realisierbarkeit solch maßgeschneiderter Lösungen haben wir einen speziellen Assistenten kreiert, der fähig ist, benutzerdefinierte Patterns für Jira Assets Discovery zu erzeugen.

Was ist Jira Assets Discovery?

Jira Assets Discovery ist eine von Atlassian bereitgestellte, kostenlose Marketplace-App für Jira Service Management. Mit ihr lassen sich Informationen über Hard- und Softwaresysteme in einer Organisation automatisiert erkennen und inventarisieren – und somit in Assets für JSM eine Objektdatenbank aufbauen. Wird beispielsweise eine Sicherheitslücke gefunden, von der Teile der Systeme betroffen sind, können sofort alle Geräte im Netzwerk ermittelt werden, die einen Patch benötigen.

Der Scanprozess innerhalb eines Netzwerks stützt sich auf sogenannte Scan Patterns. Ein Scan Pattern besteht immer aus einem (Kommandozeilen-) Befehl, der die zu sammelnden Daten abfragt, sowie einem kurzen C#-Skript, welches die Ausgabe des Befehls einliest und daraus für Assets verständliche Objekte erstellt.

Beispielsweise könnte es innerhalb eines Unternehmens eine neue Richtlinie geben, die es erfordert, dass für jedes Gerät der letzte angemeldete Nutzer festgehalten werden soll.

In diesem Fall würde man ein Scan Pattern mit dem last-Befehl ausführen. Eine Ausgabe des Befehls könnte wie folgend aussehen:

mark     pts/0        10.10.0.7   Fri Feb 21 21:23   still logged in
mark     pts/0        10.10.0.7   Tue Feb 18 22:34 - 00:05  (01:31)
lisa     :0           :0          Thu Feb 13 09:19   gone - no logout
reboot   system boot  4.15.0-74-g Fri Jan 24 08:03 - 08:03  (00:00)


Nun würde das C# Skript aus der Ausgabe die tatsächliche Information, dass der letzte Nutzer “mark” heißt, extrahieren und daraus ein Host-Objekt mit dem entsprechenden Wert im Feld “Last User” generieren.

Dieses System bietet durch das Erstellen von Custom Scan Patterns eine hohe Flexibilität, da somit alle Daten inventarisierbar sind, welche durch einen Kommandozeilenbefehl abgefragt werden können.

Betreibt ein Unternehmen für bestimmte Anwendungsfälle zum Beispiel eine proprietäre Datenbank, welche per Kommandozeile ein Abfragen von Datenbankversion und -größe ermöglicht, kann diese ebenfalls als Asset automatisiert inventarisiert werden.

Wie erstelle ich Custom Patterns ohne C# Kenntnisse?

Obwohl das Custom Pattern System eine große Flexibilität für benutzerdefinierte Lösungen bietet, gibt es einen Nachteil: Sobald über die Standardanforderungen hinausgehende Informationen gesammelt werden sollen, sind zum Erstellen von Custom Patterns sowohl grundsätzliche C# Kenntnisse als auch tiefgreifendes Wissen über Assets Discovery und die Assets-Discovery-C# Bibliothek notwendig.

Unsere Beobachtung zeigt, dass Kunden zwar häufig über Skripterfahrung verfügen – in der Regel in anderen Sprachen als C# – dass ihnen aber, selbst wenn sie über C#-Kenntnisse verfügen, die Zeit fehlt, sich mit der von Atlassian bereitgestellten Bibliothek auseinanderzusetzen. Nichts desto trotz besitzen sie meist immer ein festes Verständnis der Anforderungen, also dem, was inventarisiert werden sollte.

Was benötigt wird, ist ein Werkzeug, um diese Anforderungen in konkrete Scan-Patterns zu übersetzen, ohne C# oder Discovery-API Kenntnisse vorrauszusetzen.

Custom Patterns mit ChatGPT schreiben lassen

Da die in den meisten Anwendungsfällen ein kurzes C#-Skript benötigt wird, um die Daten aus dem Shell-Output einzulesen, bietet sich grundsätzlich die Nutzung generativer KI an.

Als ersten Versuch beauftragten wir ChatGPT-4 mit der Implementation des eingangs beschriebene Pattern zum Inventarisieren des letzten Nutzers.

User: I need a custom pattern to get the last logged in user on MacOS devices
CustonPatternGPT: Creating a custom pattern for Jira Assets Discovery on macOS to retrieve the last logged in user involves using the Jira Assets Discovery's pattern definition language to specify how to find and report this information. Here's a step-by-step guide to achieve this:

1. Understand the Data Source
First, you need to know where macOS stores the information about the last logged-in user. macOS logs user login and logout events in the system log files, and the last logged-in user information can be retrieved from the command line using various commands like last, who, or by inspecting specific log files.

2. Determine the Command to Use
For simplicity, let's use the last command, which displays the most recent login sessions. By default, last will show a list of all logins and logouts. The command last | grep -m1 "^.*still logged in$" | awk '{print $1}' can be used to extract the name of the last logged-in user who is still logged in. Adjust the command if you need the last logged-in user regardless of their current status

3. Define the Custom Pattern
Jira Assets Discovery patterns are defined in XML. You will need to create a pattern that runs the chosen command and captures its output. Note that the exact syntax for defining a custom pattern can depend on the specific capabilities and requirements of your version of Jira Assets Discovery. Below is a hypothetical example of what the pattern definition might look like:
<DiscoveryPattern>
    <Name>Find Last Logged-In User on macOS</Name>
    <Description>This pattern retrieves the last logged-in user on a macOS system.</Description>
    <CompatibleOperatingSystems>macOS</CompatibleOperatingSystems>
    <Script language="bash">                                      
        <![CDATA[
        last | grep -m1 "^.*still logged in$" | awk '{print $1}'
        ]]>
    </Script>
    <Result>
        <Mapping>
            <Field name="LastLoggedInUser" dataType="String">
                <ScriptOutput />
            </Field>
        </Mapping>
    </Result>
</DiscoveryPattern>

1 Testing and Deployment

2. Testing: Before deploying this pattern, test it in a controlled environment. You need to ensure that the script executes correctly on macOS systems and that it accurately captures the last logged-in user.

3. Deployment: After testing, follow the Jira Assets Discovery documentation for deploying custom patterns. This typically involves importing the pattern into your Jira Assets Discovery configuration and then running discovery tasks to apply the pattern.

4. Note: this example assumes familiarity with XML and basic scripting on macOS. The actual implementation could vary based on the specific version of Jira Assets Discovery you're using and its support for custom patterns. Always refer to the official documentation for the most accurate guidance on creating and deploying custom patterns.

If the process or capabilities of Jira Assets Discovery have changed since my last update, please consult the latest documentation or support resources for updated information.
User: A pattern should contain some C# code to parse the command output. This is the core functionalty of a custom pattern
CustonPatternGPT: If you're looking to incorporate C# code into a Jira Assets Discovery pattern for parsing command output, specifically to identify the last logged-in user on a macOS system, you would typically be working with a system that allows you to execute shell commands from C# and then process the output within the same script. Given this scenario, your custom pattern might need to execute a shell command, capture its output, and then parse that output to extract the desired information.

Here's a simplified example of how you might structure such a pattern in C#, keeping in mind the specifics of implementation could vary based on the exact framework or application environment you're working within Jira Assets Discovery:
using System;
using System.Diagnostics;
using System.IO;
class LastLoggedInUserDiscovery
{
    static void Main()
    {
        try
        {
            // Command to get the last logged-in user.
            string command = "last | grep -m1 \"^.*still logged in$\" | awk '{print $1}'";
            // Execute the command and get the output.
            var processStartInfo = new ProcessStartInfo
            {
                FileName = "/bin/bash",
                Arguments = $"-c \"{command}\"",
                RedirectStandardOutput = true,
                UseShellExecute = false,
                CreateNoWindow = true,
            };
            var process = new Process { StartInfo = processStartInfo };
            process.Start();
            string output = process.StandardOutput.ReadToEnd();
            process.WaitForExit();
            // Process the output to extract the user name.
            var lastLoggedInUser = output.Trim();
            if (!string.IsNullOrEmpty(lastLoggedInUser))
            {
                Console.WriteLine($"Last Logged-In User: {lastLoggedInUser}");
                // Here, instead of just writing to the console,
                // you would typically pass this data to Jira Assets Discovery.
            }
            else
            {
                Console.WriteLine("No user currently logged in or unable to determine.");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"An error occurred: {ex.Message}");
        }
    }
}


Leider waren die Ergebnisse nicht zufriedenstellend: Trotz der grundsätzlichen Fähigkeit von ChatGPT, validen C#-Code zu generieren, wird deutlich, dass weder Hintergrundinformationen zu Jira Assets Discovery noch zur Discovery-C#-Anbindung bestehen.

Um bei unseren Beispiel zu bleiben: GPT war zwar in der Lage, unsere Anforderungen zu verstehen und den richtigen Kommandozeilenbefehl zu wählen. Die Generierung des Patterns schlägt jedoch fehl, da ChatGPT nicht weiß, dass ein Custom Pattern C#-Code enthalten sollte.

Auch nach der direkten Aufforderung, C# Code für Assets Discovery zu generieren, da dies die Kernfunktionalität eines Patterns sei, war die KI nicht in der Lage, dies umzusetzen.

Discovery Custom Pattern Assistent

Um dieses Problem zu lösen, haben wir ChatGPT mit der notwendigen Dokumentation ausgestattet. Glücklicherweise führte OpenAI zu dieser Zeit CustomGPTs ein, die das Hinzufügen von benutzerdefinierten Wissensdateien und die Ausführung von "Aktionen" ermöglichen.

Eigene Wissensdatenbank

Wenn ein Benutzer eine Frage stellt, führt ChatGPT zunächst eine Textähnlichkeitssuche in der bereitgestellten Wissensdatenbank durch. Anschließend fügt die KI die Suchergebnisse stillschweigend an die Frage des Benutzers an. Auf diese Weise kann der Chatbot Informationen nutzen, auf die er nicht speziell trainiert wurde, um Fragen zu beantworten.

Da ChatGPT das Hochladen mehrerer Wissensdateien unterstützt, haben wir uns entschieden, unsere Daten in drei Dateien aufzuteilen:

  1. Allgemeine Dokumentation über Assets Discovery und Custom Patterns aus der Dokumentation von Atlassian
  2. Unsere umfassende Dokumentation zu den eigentlichen C#-Klassen der Bibliothek
  3. Eine Liste von Compiler-Fehlern und deren Lösungen für häufige Fehler, die durch ChatGPT verursacht werden

Nach der Bereitstellung dieses relevanten Wissens war eine deutliche Verbesserung zu verzeichnen: Wo die KI zuvor nicht wusste, wie sie die Bibliothek verwenden sollte, nutzte sie nun die Klassen korrekt und erstellte akkurate Objekte.

Im Vergleich zu vorher waren diese Ergebnisse vielversprechend; daher fügten wir nach dem "Trust but verify"-Ansatz für die KI die generierten Patterns in Assets Discovery ein. Die Ergebnisse waren zwar deutlich besser als zuvor, aber immer noch uneinheitlich. Die meisten Fehler bei den Patterns waren auf (meist triviale) Compiler-Fehler zurückzuführen. Ein Compiler wird verwendet, um C#-Quellcode in maschinenlesbaren Code zu übersetzen und während der Kompilierung auf Codefehler zu prüfen.

Dies bedeutet, dass es sich um einen automatisierbaren Prozess handelt, der entweder ein kompiliertes, ausführbares Programm oder eine Reihe von Fehlern zusammen mit ihren Positionen im Code liefern kann.

Wenn wir unserem benutzerdefinierten GPT die Fähigkeit verleihen, seinen eigenen Code zu kompilieren, kann es seine Ergebnisse automatisch überprüfen. Im Falle eines Fehlers kann es im Anschluss seinen Code anhand der identifizierten Fehler entsprechend anpassen.

Custom Actions

Mit Hilfe von “Actions” können CustomGPTs Webanfragen an ein benutzerdefiniertes Backend stellen. Dadurch erhalten sie Flexibilität bei der Verwendung benutzerdefinierter Tools, wie zum Beispiel der Bereitstellung aktueller Wetterdaten oder der Durchführung komplexer Physiksimulationen.

Um den generierten Code automatisch auf Compiler-Fehler zu überprüfen, haben wir unser eigenes Backend implementiert. Dieses stellt einen Endpunkt bereit, der ein C#-Snippet empfängt und die Kompilierung versucht. Die Antwort enthält entweder eine Erfolgsbestätigung oder die Feststellung von Fehlern.

Innerhalb der ChatGPT-Schnittstelle selbst haben wir zwei Aktionen erstellt, die die Interaktion mit unserem benutzerdefinierten Backend ermöglicht: Eine zum Kompilieren des C#-Codes und eine weitere zum Überprüfen der um den C#-Code generierten XML-Datei.

Nachdem wir unserem ChatGPT die Fähigkeit gegeben haben, seinen eigenen Code zu kompilieren und selbst zu überprüfen, haben wir die KI erneut evaluiert und schließlich Ergebnisse erzielt, die unsere Erwartungen übertrafen.

Leistungsbewertung des virtuellen Assistenten

In der verlinkten Chatsitzung übernahmen wir die Rolle eines sachkundigen Jira-/JSM-Benutzers ohne weitere Hintergrundkenntnisse in C# oder dem Schreiben von Custom Patterns:

Wir begannen eine Konversation und baten um die Erstellung eines benutzerdefinierten Patterns anhand einer Reihe von Anforderungen:

User: I need a custom pattern to get the last logged in user on MacOS devices
CustonPatternGPT: To create a custom pattern for fetching the last logged-in user on MacOS devices, you can leverage the SSH protocol, as MacOS is Unix-based and supports SSH for remote command execution. The command to get the last logged-in user on a MacOS device is last -1 -t console. This command fetches the most recent login on the device, specifically on the console, which typically indicates a physical login.

Below is a template for creating such a pattern, including all necessary using directives and adhering to the specifications for .NET Framework 4.7 or below, as well as the requirements you've provided:
<?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</Version>
  <PatternID>MacOS-LastUserLogin</PatternID>
  <OrderNr>0</OrderNr>
  <ProcessType>SSHExecute</ProcessType>
  <PatternType>Custom</PatternType>
  <Command>
    <![CDATA[
    last -1 -t console
    ]]>
  </Command>
  <Processing>
    <![CDATA[
    using System;
    using Insight.Discovery.InfoClasses;
    using Insight.Discovery.ProviderClasses; // Include the ProviderClasses Namespace
    using Insight.Discovery.InfoClasses.CommandResult.ResultTypes; // For handling SSH command results
    namespace Insight.Discovery {
      public class PatternExec {
        public void PerformAction(object[] parameters) {
          HostInfo hostInfo = (HostInfo)parameters[2]; // Cast the third parameter to HostInfo
          // Cast the first parameter to SSHExecuteResult and implicitly assign to string
          string sshOutput = ((SSHExecuteResult)parameters[0]);
          // Processing the SSH output to extract the last logged-in user
          if (!string.IsNullOrEmpty(sshOutput)) {
            var lines = sshOutput.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
            if (lines.Length > 0) {
              var lastLoginInfo = lines[0].Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
              if (lastLoginInfo.Length > 0) {
                string lastUser = lastLoginInfo[0];
                // Setting the LastUser property of the HostInfo object
                hostInfo.LastUser = lastUser;
              }
            }
          }
        }
      }
    } 
    ]]>
  </Processing>
</ScanPattern>

This custom pattern XML defines a pattern for executing an SSH command on a MacOS device to retrieve the last logged-in user. The <Command> section contains the actual SSH command to be executed, and the <Processing> section contains C# code to parse the command's output and extract the last logged-in user's username, which is then assigned to the LastUser property of the HostInfo object. This pattern relies on the assumption that the device supports SSH access and that the executing account has the necessary permissions to execute the last command.

Remember to test this pattern in a controlled environment before deploying it in a production setting to ensure it meets your specific requirements and works as expected across different MacOS versions.

Das Sprachmodell verstand seine Aufgabe und erklärte zunächst, welcher Shell-Befehl verwendet werden kann, um die Informationen vom Zielcomputer abzurufen, und gab einige Hintergrundinformationen über die zu verwendende C#-Version und die Sprachfunktionen.

Im nächsten Schritt haben wir unser GPT gebeten, den C#-Code zu kompilieren, um ihn auf Syntax- und Compilerfehler zu prüfen, und dann die Pattern-XML-Datei zu validieren, um sicherzustellen, dass alle erforderlichen Konfigurationselemente vorhanden sind.

User: Cool. Now, can you compile the pattern and then validate the xml to check if there aren't any issues?
CustonPatternGPT:
✅ Talked to custompatterngpt.hostname.com [compiling for errors]
❌ Taked to custompatterngpt.hostname.com [validating the pattern]

The pattern's C# code successfully compiled without any issues, indicating the code itself is syntactically correct and should work as intended.

However, when validating the XML pattern, an error occurred: Invalid PatternType: Custom. The validation process indicates that "Custom" is not a recognized PatternType. Valid pattern types include Host, Deviceinfo, Network, CPU, OS, FileSystem, Application, Patch, ApplicationService, OSProductKey, ApplicationProductKey, User, Group, ConnectedPeripherie, SNMPExtendedValues, HostInfoList, and PostProcessing.

To align with the recognized pattern types, you might consider categorizing this custom pattern under a valid type that closely matches the data it's designed to fetch. Since this pattern retrieves information about the last logged user, which is closely related to user information, a suitable PatternType might be User. If a more specific categorization is preferred and none of the listed types fit perfectly, consider using a general type like HostInfoList or PostProcessing, depending on the broader context of how you plan to use this data.

Would you like to proceed with adjusting the PatternType, or do you need further assistance with another aspect of your pattern?

Die Kompilierung war erfolgreich, allerdings wurde in der XML-Datei der Fehler gemacht, den Patterntyp auf "Custom" zu setzen. Dies ergibt auf den ersten Blick Sinn, da wir ein benutzerdefiniertes Pattern schreiben. "Custom" ist jedoch kein gültiger Pattern-Typ. Nach der automatisierten Validierung wurde das Problem schnell erkannt und eine Reihe von Optionen für einen gültigen Pattern-Typ angezeigt, der zum aktuellen Pattern passen könnte.

Um unserer Rolle als nicht-technischer Benutzer gerecht zu werden, haben wir lediglich darum gebeten, den Pattern-Typ auszuwählen, den das GPT für am geeignetsten hält.

User: Just pick the one you see fit most and please validate the pattern again
CustonPatternGPT:
Talked to custompatterngpt.hostname.com [pattern validation]

The pattern has been successfully adjusted to use the PatternType "User", which is more appropriate for the data it's designed to fetch. The validation process did not return any errors this time, indicating that the XML structure and the pattern type are now correctly defined according to the system's expectations.
<?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</Version>" <PatternID>MacOS-LastUserLogin</PatternID>
     <OrderNr>0</OrderNr> 
     <ProcessType>SSHExecute</ProcessType> 
     <PatternType>User</PatternType>
     <Command> 
        <![CDATA[ last -1 -t console ]]> 
    </Command> 
    <Processing> 
        <![CDATA[ 
            using System;
            using Insight.Discovery.InfoClasses;
            using Insight.Discovery.ProviderClasses; // Include the ProviderClasses Namespace
            using Insight.Discovery.InfoClasses.CommandResult.ResultTypes; // For handling SSH command results
            namespace Insight.Discovery {
            public class PatternExec {
                public void PerformAction(object[] parameters) {
                HostInfo hostInfo = (HostInfo)parameters[2]; // Cast the third parameter to HostInfo
                // Cast the first parameter to SSHExecuteResult and implicitly assign to string
                string sshOutput = ((SSHExecuteResult)parameters[0]);
                // Processing the SSH output to extract the last logged-in user
                if (!string.IsNullOrEmpty(sshOutput)) {
                    var lines = sshOutput.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
                    if (lines.Length > 0) {
                    var lastLoginInfo = lines[0].Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                    if (lastLoginInfo.Length > 0) {
                        string lastUser = lastLoginInfo[0];
                        // Setting the LastUser property of the HostInfo object
                        hostInfo.LastUser = lastUser;
                    }
                    }
                }
            }
        }
        ]]> 
    </Processing>
</ScanPattern>

You should now be able to use this pattern for discovering the last logged-in user on MacOS devices via SSH commands. If you need further assistance or have any more requirements, feel free to ask!

Das Pattern hat einen Pattern-Typ ausgewählt und das generierte Pattern erfolgreich erneut validiert. Und die Ausführung des Patterns auf einem MacBook bestätigt, dass das Pattern den zuletzt angemeldeten Benutzer korrekt erkennt und in der resultierenden HostInfo setzt.

Ein Blick auf die Daten zeigteallerdings, dass der letzte Benutzer auf "jiradiscovery" gesetzt war – der ssh-Benutzer, der zur Ausführung der Pattern verwendet wurde. Das ist genau das, wonach wir gefragt hatten (der zuletzt angemeldete Benutzer), aber offensichtlich nicht das, was wir wollten.

User: Great! I just tried the pattern and it's getting the last user, however because the pattern itself is executing with ssh, the last user is jiradiscovery. Can you instead get the last user that's not the jiradiscovery SSH user? Once you're done, please re-compile to see if it's still valid
CustonPatternGPT:
Talked to custompatterngpt.hostname.com [pattern compilation]
✅ Talked to custompatterngpt.hostname.com [pattern validation]

The updated pattern, which now filters out the "jiradiscovery" user and targets the last logged-in user that's not associated with the SSH session, has been successfully re-compiled without any issues. This means the code is syntactically correct and aligns with the desired functionality.

Additionally, I've validated the pattern against the expected XML structure and pattern requirements. The process did not return any errors, indicating that the pattern is correctly defined and should work as intended for discovering the last logged-in user on MacOS devices, excluding the "jiradiscovery" SSH user.

Nachdem wir ChatGPT das Problem erklärt hatte, verstand es den Fehler und schlug eine Lösung vor, kompilierte und validierte sie. Die Verwendung des neuen, verfeinerten Patterns in Discovery bestätigt, dass die Daten nun korrekt erfasst werden.

In einem letzten Schritt baten wir den Assistenten, eine Protokollierung für Debugging-Zwecke und eine Dokumentation hinzuzufügen, die sich an unerfahrene Programmierer richtet. Auf diese Weise kann jeder, der in Zukunft mit der Wartung des Patterns betraut wird, besser verstehen, was es tut:

User: Perfect, now it's working flawlessly. Finally, can you add some documentation and logging to the pattern, especially with focus on making the code understandable to a maintainer that might not know c# well?
CustonPatternGPT: To enhance the custom pattern with documentation and logging, aimed at making the code more understandable for maintainers with varying levels of C# knowledge, I've incorporated comments throughout the pattern's processing section. These comments explain the purpose of each code block and the logic behind it, along with adding logging statements to help with debugging and understanding the flow of execution:
<?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</Version>
  <PatternID>MacOS-LastUserLogin</PatternID>
  <OrderNr>0</OrderNr>
  <ProcessType>SSHExecute</ProcessType>
  <PatternType>User</PatternType>
  <Command>
    <![CDATA[
    last -1 -t console
    ]]>
  </Command>
  <Processing>
    <![CDATA[
    using System;
    using Insight.Discovery.InfoClasses;
    using Insight.Discovery.ProviderClasses; // Needed for executing commands on the host
    using Insight.Discovery.InfoClasses.CommandResult.ResultTypes; // To handle the results from SSH commands
    using Insight.Discovery.Tools; // To use logging services
    namespace Insight.Discovery {
      public class PatternExec {
        public void PerformAction(object[] parameters) {
          // Obtain the HostInfo object from the parameters array. This object represents the host we are currently scanning.
          HostInfo hostInfo = (HostInfo)parameters[2];
          // The SSH command's output is obtained from the parameters array and implicitly converted to a string.
          string sshOutput = ((SSHExecuteResult)parameters[0]);
          // Log the obtained SSH output for debugging purposes.
          LogService.Instance.LogDebug($"SSH Output: {sshOutput}");
          // Check if the SSH output is not empty or null.
          if (!string.IsNullOrEmpty(sshOutput)) {
            // Split the output into lines for processing.
            var lines = sshOutput.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
            // Iterate through each line in the SSH output.
            foreach (var line in lines) {
              // Split each line into parts to analyze the login information.
              var loginInfo = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
              // Check if the line has content and the user is not 'jiradiscovery'.
              if (loginInfo.Length > 0 && loginInfo[0] != "jiradiscovery") {
                string lastUser = loginInfo[0]; // The first part is assumed to be the username.
                // Log the found user for verification.
                LogService.Instance.LogDebug($"Last logged-in user found: {lastUser}");
                // Assign the found username to the LastUser property of the HostInfo object.
                hostInfo.LastUser = lastUser;
                // Stop processing after the first matching user is found.
                break;
              }
            }
          } else {
            // Log a warning if the SSH command did not return any output.
            LogService.Instance.LogWarning("SSH command did not return any output.");
          }
        }
      }
    }
    ]]>
  </Processing>
</ScanPattern>

This updated version of the pattern now includes detailed comments explaining the functionality of each segment of the code, making it easier for someone who may not be familiar with C# to understand the pattern's purpose and how it works. Logging statements have been added to aid in debugging and to provide insight into the pattern's operation during execution.

This documentation and logging strategy is designed to make the code more accessible and maintainable, helping future maintainers to quickly grasp the logic and purpose behind each operation.
User: Thank you, you're awesome!
CustonPatternGPT: You're welcome! I'm glad I could help. If you have any more questions or need further assistance in the future, feel free to reach out. Have a great day!

Verbesserungspotential des virtuellen Assistenten

Die erste Iteration hat sehr von der Möglichkeit profitiert, den Code zu kompilieren und so Fehler zu identifizieren. Jedoch können nicht alle Fehler auf diese Weise entdeckt werden. Diese Arten von Fehlern sind als "Laufzeitfehler" bekannt, da sie erst während der Laufzeit auftauchen.

Glücklicherweise gibt es eine Lösung für die Erfassung solcher Fehler: Automatisiertes Testen. In Zukunft wird das CustomGPT in der Lage sein, zu überprüfen, ob ein Muster korrekte Ergebnisse liefert, ohne dass es auf einem Zielrechner eingesetzt und getestet werden muss.

Nach erfolgreicher Kompilierung eines Patterns stellt das CustomGPT einen Shell-Befehl zur Verfügung, der auf einem der Zielrechner ausgeführt werden kann. Nach der Ausführung muss die von diesem Rechner erzeugte Ausgabe wieder in das Chat-Fenster eingefügt werden. Anschließend führt das GPT automatische Tests durch, um sicherzustellen, dass der generierte Code die bereitgestellte Ausgabe korrekt verarbeitet. Im Falle eines Fehlers nimmt es dann die erforderlichen Änderungen vor.

Dieses Vorgehen ermöglicht es dem GPT, die erzeugten Patterns mit Daten aus dem echten Firmennetzwerk zu prüfen, ohne GPT direkt Zugriff auf das Zielsystem geben zu müssen. Dadurch, dass der Nutzer die Kommandozeilen-Ausgabe selbstständig in das Chatfenster kopiert, gibt es an dieser Stelle ebenfalls die Möglichkeit, etwaige sensible Daten zu zensieren, bevor diese an OpenAI übertragen werden.

Sobald diese Möglichkeit zum automatisierten Testen gegeben ist, stehen dem GPT alle Möglichkeiten zum Testen und Debuggen, die auch einem menschlichen Entwickler zur Verfügung stehen, bereit.

Am beliebtesten