# Runbook-Anpassung

## Übersicht

Die RealmJoin-Runbook-Implementierung bietet dem Autor eines Runbooks oder dem Administrator einer Umgebung Anpassungsmöglichkeiten, sodass sie:

* kundenspezifische Parameter und Vorlagen für Kunden/Tenant hosten
* UI-Elemente wie Benutzerauswahlen oder Dropdown-Auswahlen anbieten
* menschenlesbare Erklärungen von Parametern anzeigen
* nicht benötigte UI-Elemente ausblenden

<figure><img src="/files/76b6516c2b7abccee9bfd796f014cc6fdf3455f4" alt=""><figcaption></figcaption></figure>

Die Anpassungen können im Runbook selbst enthalten sein und/oder in der RealmJoin Portal-Instanz des Kunden gespeichert werden. Standardmäßig versuchen wir, in den auf dem Portal angebotenen Runbooks sinnvolle Standardwerte anzubieten [GitHub](https://github.com/realmjoin/realmjoin-runbooks).

Einige Runbooks enthalten Beispiele dafür, wie kundenspezifische Vorlagen konfiguriert werden können, etwa die Angabe von Office-Standorten für das Onboarding von Benutzern.

### Formatieren

Die Anpassung kann definiert werden (in absteigender Priorität)

* JSON-Block in [RealmJoin Portal-Einstellungen](https://portal.realmjoin.com/settings/runbooks-customizations), der das Standardverhalten des Runbooks überschreibt
* JSON-Block im Header eines Runbooks

Zusätzlich (mit geringster Priorität)

* pro Parameter im Runbook-Header
* pro Parameter im Param-Block des Runbooks (unter Verwendung des RJRb Helper Module)

Einige Funktionen (wie Vorlagen) sind nur im JSON-Format verfügbar. Einige Funktionen (wie das Erstellen eines Benutzer-Pickers) sind nur verfügbar, wenn im Param-Block ein Datentyp angegeben wird. Sie können mehrere Arten von Anpassungen kombinieren, um die besten Ergebnisse zu erzielen.

## Runbook Param Block

Das RealmJoin Portal analysiert den PowerShell-Param-Block eines Runbooks, um zu bestimmen, welche Eingabefelder gerendert werden sollen. Wo möglich, werden die Eingaben außerdem entsprechend dem für eine Variable angegebenen .NET-Typ validiert.

Die folgenden Datentypen werden derzeit verstanden:

* `[bool]`, `[boolean]` - zeigt einen binären Schalter an
* `[string]` - zeigt ein Textfeld an, in das beliebige alphanumerische Eingaben eingegeben werden können
* `[int]` - zeigt ein Textfeld an, das nur numerische Eingaben zulässt
* `[DateTime]`, `[DateTimeOffset]` - zeigt einen Datum/Uhrzeit-Picker an

Sie können für Parameter standardmäßige PowerShell-Modifier verwenden. RealmJoin Portal versteht insbesondere, wenn Sie `[Parameter(Mandatory = $true)]` angeben, um einen Pflichtparameter zu kennzeichnen und zu erzwingen, dass diese Parameter ausgefüllt werden.

Wo möglich, liest RealmJoin Portal auch vorgegebene Standardwerte aus und zeigt sie in der UI an.

Beachten Sie, dass Standardwerte aus dem Runbook durch Anpassungen überschrieben werden können. Außerdem können Parameter durch Anpassungen vollständig ausgeblendet werden.

### Parameter anpassen

Damit Sie Parameter anpassen können, stellen Sie bitte sicher, dass das RealmJoin Runbook Helper PS Module in Ihrem Runbook enthalten ist:

`#Requires -Modules @{ModuleName = "RealmJoin.RunbookHelper"; ModuleVersion = "0.6.0" }`

Sie können dann `[ValidateScript( { Use-RJInterface ... } )]` -Anweisungen in die Parameterdefinitionen einfügen. Das folgende Beispiel erstellt etwa einen Benutzer-Picker, mit dem ein Entra ID-Benutzer ausgewählt werden kann, und übergibt dessen Objekt-ID als String an das Runbook.

```powershell
param(
    [ValidateScript( { Use-RJInterface -DisplayName "Dieses Gerät diesem Benutzer zuweisen (optional)" -Type Graph -Entity User } )]
    [string] $AssignedUserId = ""
)
```

Gehen wir das Schritt für Schritt durch. `[ValidateScript...]` ist ein Modifier für den nächsten im Param-Block definierten Parameter. In diesem Fall ist die Variable `$AssignedUserId`.

`Use-RJInterface` ist Teil unseres [RealmJoin Runbook Helper](https://github.com/realmjoin/RealmJoin.RunbookHelper) PowerShell-Moduls. Es ermöglicht Ihnen, anzugeben, welche Art von Eingabe Sie erwarten, indem Sie `-Type` und `-Entity`verwenden, sofern dies nicht bereits vollständig durch den Typ der Variable definiert ist.

`-DisplayName` ermöglicht es Ihnen, RealmJoin Portal einen menschenlesbaren Hinweis / eine Beschreibung für diesen Parameter zu übergeben.

#### Graph-Ressourcen

Im obigen Beispiel ist die Informationsquelle MS Graph, wie durch `-Type Graph`beschrieben. Für MS Graph verwenden Sie `-Entity` um anzugeben, welche Art von Ressource Sie erwarten. Verfügbare Entitäten sind `Benutzern`, `Gruppe`, `Gerät`. Dadurch wird ein Picker für Benutzer, Gruppen oder Geräte im angegebenen Entra ID erstellt.

Der Picker enthält eine Schnellsuche, um die benötigte Ressource leicht zu finden.

![Picker-Beispiel](/files/911b8089249c23b0de9115269f896d725eafcf62)

Derzeit ist mit einem Picker keine Mehrfachauswahl möglich.

Standardmäßig gibt ein MS-Graph-Picker die ID des Objekts zurück. Wenn Sie z. B. stattdessen den User Principal Name benötigen, achten Sie darauf, "name" als Suffix im Variablennamen zu verwenden. Um also die ID eines Benutzers zu erhalten, benennen Sie den Parameter `$userid`. Wenn Sie einen UPN möchten, benennen Sie ihn `$username`.

#### Graph-Filterung

Wenn Sie einen auf MS Graph basierenden Picker verwenden, können Sie auch `-Filter` angeben und einen [ODATA-Filter](https://docs.microsoft.com/en-us/graph/query-parameters?context=graph%2Fapi%2F1.0\&view=graph-rest-1.0#filter-parameter) verwenden, um die im Picker angebotenen Objekte einzuschränken.

Das folgende Beispiel listet nur Gruppen aus Entra ID auf, die mit "LIC\_" beginnen.

```powershell
param(
    [Parameter(Mandatory = $true)]
    [ValidateScript( { Use-RJInterface -Type Graph -Entity Group -Filter "startswith(DisplayName, 'LIC_')" -DisplayName "Lizenzgruppe" } )]
    [String] $GroupID_License
)
```

Sie können Filter vorbereiten und über mehrere Skripte hinweg wiederverwenden, indem Sie den [zentralen Datenspeicher](#graph-filters)verwenden. In diesem Fall verweisen Sie einfach mit `-Filter "ref:LicenseGroup"`auf den Filternamen, wobei `ref:` angibt, dass nach einem gespeicherten Filter gesucht werden soll.

```powershell
param(
    [Parameter(Mandatory = $true)]
    [ValidateScript( { Use-RJInterface -Type Graph -Entity Group -Filter "ref:LicenseGroup" } )]
    [String] $GroupID_License
)
```

Dieses spezielle Beispiel `ref:LicenseGroup` ist standardmäßig ohne weitere Konfiguration verfügbar.

![ODATA-Filter](/files/1a5c80af5aad018e8182912d822b12d1214524d4)

## Runbook-Header

Das Portal kann den [kommentarbasierten Hilfebereich](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_comment_based_help?view=powershell-5.1) eines Runbooks parsen, falls vorhanden.

Hier ist ein Beispiel:

```powershell
<#
  .SYNOPSIS
  (Zu-) oder Abweisen einer Lizenz für einen Benutzer über Gruppenmitgliedschaft.

  .DESCRIPTION
  (Zu-) oder Abweisen einer Lizenz für einen Benutzer über Gruppenmitgliedschaft. Ausführlichere Beschreibung...

  .PARAMETER DefaultGroups
  Kommagetrennte Liste von Gruppen, die zugewiesen werden sollen. z. B. "DL Sales,LIC Internal Product"

  .NOTES
  Berechtigungen:
  MS Graph (API):
  - User.Read.All
  - GroupMember.ReadWrite.All 
  - Group.ReadWrite.All

  .INPUTS
  RunbookCustomization: {
        "Parameters": {
            "UserName": {
                "Hide": true
            },
            "Remove": {
                "DisplayName": "Lizenz zuweisen oder entfernen",
                "SelectSimple": {
                    "Assign License to User": false,
                    "Remove License from User": true
                }
            }
        }
    }
#>
```

`.SYNOPSIS` - Geben Sie eine sehr kurze Beschreibung der Funktion Ihres Runbooks an. Diese wird in der Liste der verfügbaren Runbooks angezeigt.

`.DESCRIPTION` - Geben Sie eine Beschreibung der Funktion Ihres Runbooks an. Sie kann etwas detaillierter sein, da sie im Ausführungs- / Parameterdialog des Runbooks angezeigt wird.

`.PARAMETER` - Muss von einem Parameternamen gefolgt werden. Ermöglicht es Ihnen, eine detaillierte Erklärung der erwarteten Eingabe für den betreffenden Parameter anzugeben.

`.INPUTS` - Kann einen Block mit JSON-basierter Runbook-Anpassung enthalten.

`.NOTES` - Wird nicht geparst / gerendert. Bitte verwenden Sie diesen Bereich, um festzuhalten, welche Berechtigungen und Anforderungen für Ihr Runbook gelten.

`.EXAMPLE` - Wird nicht geparst / gerendert. Kann ein Beispiel für eine JSON-basierte Anpassung enthalten, die im RealmJoin-Datenspeicher in Ihrem Tenant verwendet werden soll. Dies können Beispiele dafür sein, wie Vorlagen erstellt werden, z. B. für unterschiedliche Workflows oder Benutzerklassen.

## JSON-basierte Anpassung

### Zentraler Datenspeicher

Jeder Azure Tenant kann einen Datenspeicher für "Runbook Customizations" hosten, zu finden unter <https://portal.realmjoin.com/settings/runbooks-customizations> .

Das Format ist JSON mit Kommentaren und erlaubt nachgestellte Kommas. Derzeit gibt es drei relevante Abschnitte, `Einstellungen`, `Vorlagen`, `Runbooks`.

```json
{
    "Settings": {
    },
    "Templates": {
    },
    "Runbooks": {
    }
}
```

### Runbooks-Abschnitt

`Runbooks` wird vom Portal beim Starten eines Runbooks geparst. Wenn ein Abschnitt mit dem Namen des aktuellen Azure Automation Runbooks vorhanden ist, wird dessen Inhalt verwendet, um die dem Benutzer angezeigte Oberfläche anzupassen.

Nehmen wir an, das folgende einfache Demo-Runbook heißt `rjgit-device_demo-runbook-customizing`.

```powershell
<#
  .SYNOPSIS
  Runbook-Anpassung demonstrieren

  .DESCRIPTION
  Runbook-Anpassung demonstrieren, z. B. Dropdown/Auswahl
#>

#Requires -Modules @{ModuleName = "RealmJoin.RunbookHelper"; ModuleVersion = "0.6.0" }

param(
    [string] $DeviceId,
    [bool] $ExtraWorkflow = $true,
    [int] $ExtraWorkflowTime = 15
)

"## Etwas mit Gerät '$DeviceID' tun"

# Sehr optionaler, komplizierter Workflow
if ($ExtraWorkflow) {
    "## Meditation ausführen..."
    Start-Sleep -Seconds $ExtraWorkflowTime
}
```

Wenn nicht angepasst, wird es im Frontend so angezeigt:

![Demo - vorher](/files/41e98d6189ed793f8098f7d4b7459ac73de10ea0)

Gedanken:

* Da dieses Runbook aus dem Kontext eines Geräts im Portal gestartet wird, sind die `$DeviceId` redundante Informationen für einen Benutzer. Ich weiß bereits, an welchem Gerät ich arbeite.
* Was passiert, wenn ich den "Extra Workflow" aktiviere oder deaktiviere? Muss ich an die "Extra Workflow Time" denken, wenn ich den "Extra Workflow" deaktiviere?

Lassen Sie uns das verbessern. Das folgende Beispiel-JSON im zentralen Datenspeicher wird die UI für das Runbook ändern.

```json
{
    "Runbooks": {
        "rjgit-device_demo-runbook-customizing": {
            "ParameterList": [
                {
                    "Name": "DeviceId",
                    "Hide": true
                }, 
                {
                    "Name": "ExtraWorkflow",
                    "Hide": true
                },
                {
                    "Name": "ExtraWorkflowTime",
                    "DisplayName": "Wie lange meditieren?",
                },
                {
                    "DisplayName": "Extra Workflow ausführen",
                    "DisplayBefore": "ExtraWorkflowTime",
                    "Select": {
                        "Options": [
                            {
                                "Display": "Meditation ausführen (optional)",
                                "Customization": {
                                    "Default": {
                                        "ExtraWorkflow": true
                                    }
                                }
                            },
                            {
                                "Display": "Geräte-Achtsamkeit überspringen",
                                "Customization": {
                                    "Default": {
                                        "ExtraWorkflow": false
                                    },
                                    "Hide": [
                                        "ExtraWorkflowTime"
                                    ]
                                }
                            }
                        ],
                        
                    },
                    "Default": "Geräte-Achtsamkeit überspringen"
                }
            ]
        }
    }
}
```

Sie können dieselbe Notation / dieselben Funktionen in Ihrem [Runbook-Header](#runbook-header).

#### ParameterList

Jeder Parameter hat seinen eigenen Abschnitt in `ParameterList`. [Modifier](#modifiers) ermöglichen, das Verhalten dieses Parameters zu ändern.

Das Ergebnis sieht dann so aus:

![Demo - nach dem Ausblenden](/files/a8dc28106480abe9bc7bed962462995453f861d3)

Wenn der zusätzliche Workflow ausgewählt wird, werden weitere Parameter angezeigt (eingeblendet):

![Demo - nach dem Einblenden](/files/c6482d8e58f6df72f3315529f02310ce4a047601)

Dies sorgt im Vergleich zu vorher für weniger Unübersichtlichkeit. Gleichzeitig stehen dem Benutzer mehr Informationen über die Alternativen von "Extra Workflow" zur Verfügung. Außerdem muss sich ein Benutzer nun nur dann um "Extra Workflow Time" kümmern, wenn sie relevant ist.

Die Sichtbarkeit dieses Feldes wurde über einen `"Customization"` -Block innerhalb einer der `"Select"` -Optionen geändert. Sie können derzeit höchstens einen solchen `"Customization"` -Block gleichzeitig aktiv haben.

Wie Sie sehen, ist der Parameter `$DeviceId` vollständig ausgeblendet. Dies geschieht, indem für diesen Parameter `"Hide": true` gesetzt wird.

Parameter können ein `DisplayName`haben. Wir haben eine benutzerfreundliche `DisplayName` verwendet, um `$ExtraWorkflowTime` in der UI zu ersetzen. Siehe weitere [Modifier](#modifiers) für mehr.

Sie können "unbenannte" Parameter einfügen (fehlende `Name` -Anweisung) wie den Abschnitt "Extra Workflow ausführen", wenn Sie UI-Elemente anbieten möchten, ohne direkt einen Wert zurückzugeben. Dies wird normalerweise nur in Verbindung mit `Wählen Sie`.

#### Wählen Sie

Wir verwendeten `Wählen Sie`um eine Liste von `Optionen` in einem Dropdown anzuzeigen. Jede Option kann `Anzeige` Text anzeigen oder einen `Anpassung`auslösen, z. B. das Setzen von `Hide` oder eines `Default` -Werts bei anderen Parametern. In unserem Beispiel haben wir es verwendet, um `$ExtraWorkflowTime` auszublenden bzw. einzublenden und `$ExtraWorkflow`zu überschreiben.

`$ExtraWorkflowTime` wird daher nur angezeigt, wenn es relevant ist, und der binäre Schalter `$ExtraWorkflow` wird nun aus Nutzersicht durch sinnvolle Alternativen ersetzt.

Im Fall eines `Wählen Sie` für einen benannten Parameter sollte jede Option einen `"ParameterValue": "..."` zum Übergeben an das Runbook haben. Sie können `"ShowValue: false"` innerhalb des `Wählen Sie` -Blocks platzieren, um nur das Dropdown und kein Feld für den resultierenden Parameterwert anzuzeigen.

Beispiel für benannte Parameter:

```json
{
    "Name": "ExtraWorkflow",
    "DefaultValue": true,
    "DisplayName": "Extra Workflow ausführen",
    "DisplayBefore": "ExtraWorkflowTime",
    "Select": {
        "Options": [
            {
                "Display": "Meditation ausführen (optional)",
                "ParameterValue": true
            },
            {
                "Display": "Geräte-Achtsamkeit überspringen",
                "ParameterValue": false,
                "Customization": {
                    "Hide": [
                        "ExtraWorkflowTime"
                    ]
                }
            }
        ],
        "ShowValue": false
    }
}
```

Die `Default` / `DefaultValue` -Anweisung im Parameter legt außerdem den Anfangszustand des Dropdowns fest. Verwenden Sie im Fall eines unbenannten Parameters den `DisplayName` des gewünschten Eintrags, andernfalls geben Sie einen Standard-Rückgabewert an, z. B. "true" oder "false" oder einen anderen String.

#### Parameter

Wenn Sie nur benannte Parameter haben, können Sie das etwas kürzere `Parameter` Format statt `ParameterList`.

verwenden. Ein Beispiel finden Sie unter SelectSimple

#### SelectSimple

Wenn die volle Funktionalität eines `Wählen Sie` nicht benötigt wird und Sie einfach nur eine Liste möglicher Werte in einem Dropdown anbieten möchten (ohne zusätzliche Anpassungen anzuwenden), können Sie `SelectSimple`.

`SelectSimple` ist nur für benannte Parameter verwendbar.

Beispiel:

```json
{
    "Runbooks": {
        "rjgit-device_demo-runbook-customizing": {
            "Parameters": {
                "DeviceId": {
                    "Hide": true
                }, 
                "ExtraWorkflow": {
                    "Name": "ExtraWorkflow",
                    "DisplayName": "Extra Workflow ausführen",
                    "Default": false,
                    "SelectSimple": {
                        "Execute Meditation (optional)": true,
                        "Skip Device Mindfulness": false
                    }
                },
                "ExtraWorkflowTime": {
                    "DisplayName": "Wie lange meditieren?"
                }
            }
        }
    }
}
```

Der größte Unterschied zu unserem vorherigen Beispiel (abgesehen davon, dass es viel kürzer ist) ist, dass `$ExtraWorkflowTime` immer sichtbar ist.

#### Modifier

Jeder Parameter kann einen oder mehrere der folgenden Modifier haben:

* `"DisplayName": "text"` - Zeigt "text" als Namen für den Parameter in der UI an
* `"Hide": true / false` - Diesen Parameter ausblenden
* `"Mandatory": true / false` - Erfordert, dass dieser Parameter ausgefüllt wird
* `"ReadOnly": true / false` - Schützt diesen Parameter davor, von seinem Standardwert geändert zu werden
* `"DefaultValue": "..."` - Legt einen Standardwert für diesen Parameter fest. (Sie können auch `Default` stattdessen verwenden.)
* `"GraphFilter": "startswith(DisplayName, 'LIC_')"` - siehe [Graph-Filterung](#graph-filtering)
* `"AllowEdit": true / false` - Schützt diesen Parameter davor, manuell bearbeitet zu werden. (kombinieren Sie dies mit Vorlagen)

### Einstellungen

`Einstellungen` ermöglicht es Ihnen, Konfigurationsdaten wie Azure Storage Account-Namen an einer zentralen Stelle zu speichern und sie dennoch von Ihren Runbooks getrennt zu halten.

Sie können auf einzelne Werte aus einem Runbook-Param-Block mit `Use-RJInterface`.

zugreifen. Nehmen wir diesen Beispiel-Param-Block eines Runbooks:

```powershell
param(
    [ValidateScript( { Use-RJInterface -Type Setting -Attribute "CaPoliciesExport.Container" } )]
    [string] $ContainerName,
    [ValidateScript( { Use-RJInterface -Type Setting -Attribute "CaPoliciesExport.ResourceGroup" } )]
    [string] $ResourceGroupName,
    [ValidateScript( { Use-RJInterface -Type Setting -Attribute "CaPoliciesExport.StorageAccount.Name" } )]
    [string] $StorageAccountName,
    [ValidateScript( { Use-RJInterface -Type Setting -Attribute "CaPoliciesExport.StorageAccount.Location" } )]
    [string] $StorageAccountLocation,
    [ValidateScript( { Use-RJInterface -Type Setting -Attribute "CaPoliciesExport.StorageAccount.Sku" } )]
    [string] $StorageAccountSku
)
```

Das Portal versucht, jeden Parameter mit Werten aus dem zentralen Datenspeicher vorab zu befüllen - sofern vorhanden. Das funktioniert auch, wenn der Parameter in der UI ausgeblendet wurde.

Ein mögliches JSON im Datenspeicher für dieses Runbook wäre:

```json
{
    "Settings": {
        "CaPoliciesExport": {
            "ResourceGroup": "rj-runbooks-01",
            "StorageAccount": {
                "Name": "rjrbexports01",
                "Location": "West Europe",
                "Sku": "Standard_LRS"
            }
        }
    }
}
```

Das fehlende `Container` -Element wird in der UI einfach nicht vorbefüllt.

### Vorlagen

`Vorlagen` verwenden Sie JSON-Referenzen, um Daten einzubinden - zum Beispiel eine lange Liste von Office-Standorten - wenn Sie eine `Wählen Sie` -Anweisung verwenden.

Dies ermöglicht es, eine Anpassung neutral/wiederverwendbar/getrennt von den eigentlichen Daten zu halten.

Nehmen wir das Beispiel des Onboardings neuer Benutzer. Sie haben möglicherweise mehrere vorgegebene Optionen für Abteilungen oder Office-Standorte, wobei die Zuweisung eines Office-Standorts auch eine bestimmte Straße, ein Land, ein Bundesland usw. erfordert.

Das folgende Beispiel einer Runbook-Anpassung verwendet den `$ref` innerhalb des `Runbooks` -Abschnitt, um einen Teilbaum aus dem `Vorlagen` -Abschnitt zu referenzieren/importieren. Achten Sie auf die `$id`/`$values` Schlüsselwörter. Beachten Sie, dass `$id`/`$values` vor der Referenzierung über `$ref`definiert sein müssen. Deshalb ist `Vorlagen` in diesem Beispiel vor `Runbooks` definiert.

In diesem Beispiel teilen wir dem Portal mit, dass es den Teilbaum mit dem `$id` mit dem Namen `LocationOptions` abrufen und dessen `$values`einfügen soll, wobei die `$ref` -Anweisung ersetzt wird. Das Portal rendert also einen `Wählen Sie` wie im `Runbooks` -Abschnitt beschrieben, verwendet aber die tatsächlichen Optionen aus `Vorlagen`.

Eine Vorlage kann jede Anweisung enthalten, die am referenzierenden Ort unterstützt wird. In diesem Beispiel verwenden wir eine `Anpassung` -Anweisung, um andere Parameter wie `StreetAddress`.

zu ändern. So können wir eine runbook-spezifische Anpassung in `Runbooks` wiederverwendbar über mehrere Umgebungen hinweg haben und gleichzeitig die eigentlichen Daten getrennt halten.

```json
{
    "Templates": {
        "Options": [
            {
                "$id": "LocationOptions",
                "$values": [
                    {
                        "Display": "DE-OF",
                        "Customization": {
                            "Default": {
                                "StreetAddress": "Kaiserstraße 39",
                                "PostalCode": "63065",
                                "City": "Offenbach",
                                "Country": "Deutschland"
                            }
                        }
                    },
                    {
                        "Display": "DE-DEG",
                        "Customization": {
                            "Default": {
                                "StreetAddress": "Lateinschulgassse 24-26",
                                "PostalCode": "94469",
                                "City": "Deggendorf",
                                "Country": "Deutschland"
                            }
                        }
                    },
                    {
                        "Display": "DE-HH",
                        "Customization": {
                            "Default": {
                                "StreetAddress": "Hans-Henny-Jahnn-Weg 53",
                                "PostalCode": "22085",
                                "City": "Hamburg",
                                "Country": "Deutschland"
                            }
                        }
                    },
                    {
                        "Display": "FI-HS",
                        "Customization": {
                            "Default": {
                                "StreetAddress": "Somewhere 42",
                                "PostalCode": "12345",
                                "City": "Helsinki",
                                "Country": "Finnland"
                            }
                        }
                    }
                ]
            },
            {
                "$id": "CompanyOptions",
                "$values": [
                    {
                        "Id": "gkg",
                        "Display": "glueckkanja",
                        "Value": "glueckkanja AG"
                    },
                    {
                        "Id": "pp",
                        "Display": "PRIMEPULSE",
                        "Value": "PRIMEPULSE SE"
                    }
                ]
            }
        ]
    },
    "Runbooks": {
        "rjgit-org_general_add-user": {
            "ParameterList": [
                {
                    "DisplayName": "Office-Standort",
                    "DisplayAfter": "CompanyName",
                    "Select": {
                        "Options": {
                            "$ref": "LocationOptions"
                        }
                    }
                },
                {
                    "Name": "CompanyName",
                    "Select": {
                        "Options": {
                            "$ref": "CompanyOptions"
                        },
                        "AllowEdit": false
                    }
                }
            ],
            "ReadOnly": [
                "StreetAddress",
                "PostalCode",
                "City",
                "Country"
            ]
        }
    }
}
```

Dadurch wird folgende UI erstellt:

![Demo - ref-location](/files/d253d62ecb4af9318694eb9d6c7c388f4886ccc6)

![Demo - ref-address](/files/00bdf48c5ab914011f717496d5e87fc435ada0fa)

### Graph-Filter

Sie können [ODATA Graph-Filter](https://docs.microsoft.com/en-us/graph/query-parameters?context=graph%2Fapi%2F1.0\&view=graph-rest-1.0#filter-parameter) vorbereiten, die in mehreren Runbooks verwendet werden sollen. Speichern Sie diese in einem Abschnitt namens `GraphFilters`.

Die folgenden Beispiel-Filter für ein bestimmtes Präfix im `DisplayName` einer Gruppe, um im Gruppen-Picker nur gruppenbezogene Lizenzgruppen anzuzeigen.

```json
"GraphFilters": {
    "LicenseGroup": "startswith(DisplayName, 'LIC_')" // auch im RJ-Code als Standard enthalten
  }
```

Siehe [Graph-Filterung](#graph-filtering) zur Verwendung dieses Werts in einem Runbook.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.realmjoin.com/de/automatisierung/runbooks/runbook-customization.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
