# Runbook-Anpassung

## Übersicht

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

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

<figure><img src="https://2298793958-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MkrcM7cKOpXKri1kVrh%2Fuploads%2FmVmZrDFgG1ShkZlo1Fbe%2Fimage.png?alt=media&#x26;token=39876732-3578-41d2-acf1-8571bb941e68" alt=""><figcaption></figcaption></figure>

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

Einige Runbooks werden mit Beispielen dafür geliefert, wie kundenspezifische Vorlagen konfiguriert werden, z. B. die Angabe von Bürostandorten für das Onboarding von Benutzern.

### Formatieren

Die Anpassungen können definiert werden (in absteigender Prioritätsreihenfolge)

* 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 der niedrigsten Priorität)

* pro Parameter im Header des Runbooks
* 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 einer Benutzerauswahl) 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, validiert es die Eingaben außerdem anhand des für eine Variable angegebenen .NET-Typs.

Die folgenden Datentypen werden derzeit verstanden:

* `[bool]`, `[boolean]` - zeigt einen binären Umschalter 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-Auswahldialog an

Sie können Standard-PowerShell-Modifier auf Parameter anwenden. Das RealmJoin-Portal wird insbesondere verstehen, wenn Sie angeben `[Parameter(Mandatory = $true)]` um einen Pflichtparameter anzuzeigen und zu erzwingen, dass diese Parameter ausgefüllt werden.

Wo möglich, liest das RealmJoin-Portal auch angegebene 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 Runbook Helper PS Module von RealmJoin in Ihrem Runbook enthalten ist:

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

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

```powershell
param(
    [ValidateScript( { Use-RJInterface -DisplayName "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 als Nächstes im Param-Block definerten Parameter. In diesem Fall 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, falls dies nicht bereits vollständig durch den Variablentyp definiert ist.

`-DisplayName` ermöglicht es Ihnen, einen menschenlesbaren Prompt / eine Beschreibung für diesen Parameter an das RealmJoin-Portal 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 eine Auswahl für Benutzer, Gruppen oder Geräte im angegebenen Entra ID erstellt.

Die Auswahl enthält eine Schnellsuche, um die benötigte Ressource einfach zu finden.

![Auswahlbeispiel](https://2298793958-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MkrcM7cKOpXKri1kVrh%2Fuploads%2Fgit-blob-0c393c4ea73a77b34da2c678b0712a6556ed3bc2%2Frunbook-customization-img2.png?alt=media)

Derzeit ist mit einer Auswahl keine Mehrfachauswahl möglich.

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

#### Graph-Filterung

Wenn Sie eine auf MS Graph basierende Auswahl 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 in der Auswahl angebotenen Objekte einzugrenzen.

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 sie über mehrere Skripte hinweg wiederverwenden, indem Sie den [zentralen Datenspeicher](#graph-filters)verwenden. Verweisen Sie in diesem Fall 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](https://2298793958-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MkrcM7cKOpXKri1kVrh%2Fuploads%2Fgit-blob-4913ddfbc3324fc7a3522de2bc6887e8d2745e35%2Frunbook-customization-img3.png?alt=media)

## 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 analysieren, falls vorhanden.

Hier ist ein Beispiel:

```powershell
<#
  .SYNOPSIS
  (Un-)Zuweisen einer Lizenz an einen Benutzer über Gruppenmitgliedschaft.

  .DESCRIPTION
  (Un-)Zuweisen einer Lizenz an 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. Kann etwas mehr Details enthalten, da dies innerhalb des Runbook-Ausführungs-/Parameterdialogs angezeigt wird.

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

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

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

`.EXAMPLE` - Wird nicht analysiert / gerendert. Kann ein Beispiel für eine JSON-basierte Anpassung enthalten, die im RealmJoin-Datenspeicher Ihres Tenants 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 Kommata. Derzeit gibt es drei relevante Abschnitte, `Einstellungen`, `Vorlagen`, `Runbooks`.

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

### Runbooks-Abschnitt

`Runbooks` wird vom Portal beim Starten eines Runbooks analysiert. Wenn ein Abschnitt mit dem Namen des aktuellen Azure Automation Runbooks existiert, wird dessen Inhalt verwendet, um das dem Benutzer angezeigte Frontend anzupassen.

Nehmen Sie folgendes einfaches Demonstrations-Runbook an, genannt `rjgit-device_demo-runbook-customizing`.

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

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

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

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

"## Aktionen für Gerät '$DeviceID' durchführen"

# Stark optionaler, komplizierter Workflow
if ($ExtraWorkflow) {
    "## Meditation wird ausgeführt..."
    Start-Sleep -Seconds $ExtraWorkflowTime
}
```

Wenn nicht angepasst, wird es im Frontend so dargestellt:

![Demo - vorher](https://2298793958-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MkrcM7cKOpXKri1kVrh%2Fuploads%2Fgit-blob-931b958f4b949268736f6ff3f174913cf56adcf7%2Frunbook-customization-img4.png?alt=media)

Gedanken:

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

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

```json
{
    "Runbooks": {
        "rjgit-device_demo-runbook-customizing": {
            "ParameterList": [
                {
                    "Name": "DeviceId",
                    "Hide": true
                }, 
                {
                    "Name": "ExtraWorkflow",
                    "Hide": true
                },
                {
                    "Name": "ExtraWorkflowTime",
                    "DisplayName": "Wie lange meditieren?",
                },
                {
                    "DisplayName": "Zusätzlichen 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 es, das Verhalten dieses Parameters zu ändern.

Das Ergebnis sieht dann so aus:

![Demo - nach dem Ausblenden](https://2298793958-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MkrcM7cKOpXKri1kVrh%2Fuploads%2Fgit-blob-4ae4e681371ad29f076063c5f1925a0cb8113872%2Frunbook-customization-img5.png?alt=media)

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

![Demo - nach dem Einblenden](https://2298793958-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MkrcM7cKOpXKri1kVrh%2Fuploads%2Fgit-blob-7960cf8309d8bbdf12ab1539c073714211715411%2Frunbook-customization-img6.png?alt=media)

Dies zeigt weniger Unordnung im Vergleich zu vorher der Anwendung der Anpassung. Gleichzeitig erhält der Benutzer mehr Informationen über die Alternativen von "Extra Workflow". Außerdem muss sich ein Benutzer nun nur dann Gedanken über "Extra Workflow Time" machen, wenn sie relevant ist.

Das Ändern der Sichtbarkeit dieses Feldes wurde mit einem `"Customization"` -Block innerhalb einer der `"Select"` -Optionen vorgenommen. 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 durch das Setzen des `"Hide": true` für diesen Parameter.

Parameter können eine `DisplayName`haben. Wir haben einen benutzerfreundlichen `DisplayName` angeboten, um `$ExtraWorkflowTime` in der UI zu ersetzen. Siehe andere [Modifier](#modifiers) für mehr.

Sie können "unnamed"-Parameter einfügen (ohne die `Name` Anweisung) wie den Abschnitt "Zusätzlichen 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 haben `Wählen Sie`verwendet, um eine Liste von `Optionen` in einem Dropdown anzuzeigen. Jede Option kann `Anzeige` Text ausgeben oder einen `Anpassung`auslösen, etwa indem `Hide` oder einen `Default` Wert für andere Parameter gesetzt wird. In unserem Beispiel haben wir es verwendet, um `$ExtraWorkflowTime` ein-/auszublenden und `$ExtraWorkflow`Wert zu überschreiben.

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

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

Beispiel für einen benannten Parameter:

```json
{
    "Name": "ExtraWorkflow",
    "DefaultValue": true,
    "DisplayName": "Zusätzlichen 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 auch den Anfangszustand des Dropdowns fest. Im Falle eines unbenannten Parameters verwenden Sie den `DisplayName` der gewünschten Option, andernfalls geben Sie einen Standard-Rückgabewert an, wie "true" oder "false" oder einen beliebigen String.

#### Parameter

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

verwenden. Ein Beispiel finden Sie unter SelectSimple

#### SelectSimple

Wenn die volle Leistungsfähigkeit 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": "Zusätzlichen Workflow ausführen",
                    "Default": false,
                    "SelectSimple": {
                        "Execute Meditation (optional)": true,
                        "Skip Device Mindfulness": false
                    }
                },
                "ExtraWorkflowTime": {
                    "DisplayName": "Wie lange meditieren?"
                }
            }
        }
    }
}
```

Der größte Unterschied (abgesehen davon, dass es viel kürzer ist) zu unserem Beispiel zuvor 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` - Verbirgt diesen Parameter
* `"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 vor manueller Bearbeitung. (kombinieren Sie dies mit Vorlagen)

### Einstellungen

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

Sie können einzelne Werte aus dem Param-Block eines Runbooks mit `Use-RJInterface`.

darauf 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 füllen – sofern vorhanden. Dies 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": "Westeuropa",
                "Sku": "Standard_LRS"
            }
        }
    }
}
```

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

### Vorlagen

`Vorlagen` verwenden Sie JSON-Referenzen, um Daten einzubinden – zum Beispiel eine umfangreiche Liste von Bürostandorten – wenn Sie eine `Wählen Sie` Anweisung verwenden.

Dadurch kann eine Anpassung neutral/wiederverwendbar/getrennt von den eigentlichen Daten bleiben.

Nehmen wir das Beispiel des Onboardings neuer Benutzer. Sie könnten mehrere vorgegebene Optionen für Abteilungen oder Bürostandorte haben, wobei die Zuweisung eines Bürostandorts auch eine bestimmte Straßenadresse, 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 mit `$ref`definiert werden müssen. Deshalb ist `Vorlagen` vor `Runbooks` in diesem Beispiel definiert.

In diesem Beispiel weisen wir das Portal an, den Teilbaum mit dem `$id` genannt `LocationOptions` zu nehmen und dessen `$values`einzuschließen, wobei die `$ref` Anweisung ersetzt wird. Das Portal rendert also eine `Wählen Sie` wie im `Runbooks` Abschnitt beschrieben, aber mit den 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 `Straßenadresse`.

zu ändern. So können wir eine runbook-spezifische Anpassung in `Runbooks` haben, die über mehrere Umgebungen hinweg wiederverwendbar ist, während die tatsächlichen Daten getrennt bleiben.

```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": "Bürostandort",
                    "DisplayAfter": "CompanyName",
                    "Select": {
                        "Options": {
                            "$ref": "LocationOptions"
                        }
                    }
                },
                {
                    "Name": "CompanyName",
                    "Select": {
                        "Options": {
                            "$ref": "CompanyOptions"
                        },
                        "AllowEdit": false
                    }
                }
            ],
            "ReadOnly": [
                "StreetAddress",
                "PostalCode",
                "City",
                "Country"
            ]
        }
    }
}
```

Dadurch wird die folgende UI erstellt:

![Demo - ref-location](https://2298793958-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MkrcM7cKOpXKri1kVrh%2Fuploads%2Fgit-blob-93295541748dcc12dbc72208851138efd0808d51%2Frunbook-customization-img7.png?alt=media)

![Demo - ref-address](https://2298793958-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MkrcM7cKOpXKri1kVrh%2Fuploads%2Fgit-blob-11e2812670e56cf10bb03fe7588059d232a8addf%2Frunbook-customization-img8.png?alt=media)

### 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 können. Speichern Sie diese in einem Abschnitt namens `GraphFilters`.

Das folgende Beispiel filtert nach einem bestimmten Präfix im `DisplayName` einer Gruppe, um im Gruppen-Auswahlfeld nur Lizenz-bezogene Gruppen anzuzeigen.

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

Siehe [Graph-Filterung](#graph-filtering) darüber, wie dies aus einem Runbook verwendet wird.
