# Runbook のカスタマイズ

## 概要

RealmJoin の runbook 実装は、runbook の作成者または環境の管理者にカスタマイズ機能を提供し、次のことを可能にします。

* 顧客/Tenant 固有のパラメーターとテンプレートをホストする
* ユーザーピッカーやドロップダウン選択などの UI 要素を提供する
* パラメーターの人間が読める説明を表示する
* 不要な UI 要素を非表示にする

<figure><img src="/files/fd4bf11feaa74f1b5e62c680eee97424a0fcb682" alt=""><figcaption></figcaption></figure>

カスタマイズは runbook 自体に含めることも、顧客の RealmJoin Portal インスタンスに保存することもできます。既定では、提供される runbook では妥当な既定値を提供しようとします。 [GitHub](https://github.com/realmjoin/realmjoin-runbooks).

いくつかの runbook には、ユーザーのオンボーディング時にオフィス所在地を指定するなど、顧客固有のテンプレートをどのように構成するかの例が付属します。

### 書式設定

カスタマイズは（優先度の高い順に）次のように定義できます

* JSON のブロックを [RealmJoin Portal の設定に](https://portal.realmjoin.com/settings/runbooks-customizations)記述し、既定の runbook の動作を上書きする
* runbook のヘッダー内の JSON ブロック

さらに（最も優先度が低いものとして）

* runbook ヘッダー内の各パラメーターごとに
* runbook の param ブロック内の各パラメーターごとに（RJRb Helper Module を使用）

一部の機能（テンプレートなど）は JSON 形式でのみ利用できます。一部の機能（ユーザーピッカーの作成など）は、param ブロックでデータ型を指定した場合にのみ利用できます。最良の結果を得るために、複数のカスタマイズを組み合わせることができます。

## Runbook Param Block

RealmJoin Portal は、runbook の PowerShell param ブロックを解析して、どの入力フィールドを表示するかを判断します。可能な場合は、変数に対して指定された .NET 型に従って入力の検証も行います。

現在、次のデータ型が理解されます。

* `[bool]`, `[boolean]` - 二値のトグルを表示します
* `[string]` - 任意の英数字入力を入力できるテキストボックスを表示します
* `[int]` - 数値のみを許可するテキストボックスを表示します
* `[DateTime]`, `[DateTimeOffset]` - 日時ピッカーを表示します

標準の PowerShell 修飾子をパラメーターに適用できます。RealmJoin Portal は、特に次のように指定した場合、それを理解します `[Parameter(Mandatory = $true)]` 必須パラメーターであることを示し、これらのパラメーターが入力されることを強制します。

可能な場合、RealmJoin Portal は UI に指定された既定値も読み取り、表示します。

runbook の既定値はカスタマイズによって上書きできることに注意してください。さらに、パラメーターはカスタマイズによって完全に非表示にすることもできます。

### パラメーターのカスタマイズ

パラメーターをカスタマイズできるようにするには、runbook に RealmJoin の Runbook Helper PS Module を含めてください。

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

その後、 `[ValidateScript( { Use-RJInterface ... } )]` をパラメーター定義に含めることができます。たとえば、次の記述はユーザーピッカーを作成し、Entra ID ユーザーを選択できるようにし、そのオブジェクト ID を文字列として runbook に渡します。

```powershell
param(
    [ValidateScript( { Use-RJInterface -DisplayName "このユーザーにデバイスを割り当てる（任意）" -Type Graph -Entity User } )]
    [string] $AssignedUserId = ""
)
```

これを少しずつ見ていきましょう。 `[ValidateScript...]` は、param ブロックで定義された次のパラメーターに対する修飾子です。この場合、変数 `$AssignedUserId`.

`Use-RJInterface` は私たちの [RealmJoin Runbook Helper](https://github.com/realmjoin/RealmJoin.RunbookHelper) PowerShell Module の一部です。これにより、 `-Type` と `-Entity`を使用して、変数の型だけでは完全に定義されていない場合でも、どのような入力を期待しているかを指定できます。

`-DisplayName` を使うと、このパラメーターに対する人間が読めるプロンプト/説明を RealmJoin Portal に渡せます。

#### Graph Resources

上の例では、情報のソースは MS Graph であり、 `-Type Graph`によって示されています。MS Graph では、 `-Entity` を使用して、どの種類のリソースを期待しているかを指定します。利用可能なエンティティは `ユーザー`, `グループ`, `デバイス`です。これにより、指定された Entra ID 内のユーザー、グループ、またはデバイスのいずれかに対するピッカーが生成されます。

ピッカーにはクイック検索が含まれており、必要なリソースを簡単に絞り込めます。

![ピッカーの例](/files/c7a0b1960df07c234e128f77ade256e76c925717)

現在、ピッカーを使用して複数選択することはできません。

既定では、MS Graph のピッカーはオブジェクトの ID を返します。たとえばユーザー プリンシパル名が必要な場合は、変数名の接尾辞として "name" を含めてください。つまり、ユーザーの id を取得したい場合は、パラメーターを `$userid`と名付けます。UPN が必要な場合は、 `$username`.

#### Graph フィルタリング

MS Graph ベースのピッカーを使用している場合、 `-Filter` を指定し、 [ODATA-Filter](https://docs.microsoft.com/en-us/graph/query-parameters?context=graph%2Fapi%2F1.0\&view=graph-rest-1.0#filter-parameter) を使って、ピッカーで提供されるオブジェクトを制限することもできます。

次の例では、Entra ID から "LIC\_" で始まるグループのみを一覧表示します。

```powershell
param(
    [Parameter(Mandatory = $true)]
    [ValidateScript( { Use-RJInterface -Type Graph -Entity Group -Filter "startswith(DisplayName, 'LIC_')" -DisplayName "ライセンス グループ" } )]
    [String] $GroupID_License
)
```

フィルターを準備し、 [中央データストア](#graph-filters)を使って複数のスクリプト間で再利用できます。この場合は、 `-Filter "ref:LicenseGroup"`を使用して名前でフィルターを参照するだけです。ここで `ref:` は、保存されたフィルターを探すことを示します。

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

この特定の例 `ref:LicenseGroup` は、追加の設定なしで既定で利用できます。

![ODATA フィルター](/files/b644d59d447d6154b03ad38703e9c1a6429301a5)

## Runbook Header

Portal は runbook の [comment based help](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_comment_based_help?view=powershell-5.1) セクションがあれば、それを解析できます。

例を示します。

```powershell
<#
  .SYNOPSIS
  グループ メンバーシップ経由でユーザーにライセンスを（解除）割り当てます。

  .DESCRIPTION
  グループ メンバーシップ経由でユーザーにライセンスを（解除）割り当てます。より詳細な説明...

  .PARAMETER DefaultGroups
  割り当てるグループのカンマ区切りリスト。例: "DL Sales,LIC Internal Product"

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

  .INPUTS
  RunbookCustomization: {
        "Parameters": {
            "UserName": {
                "Hide": true
            },
            "Remove": {
                "DisplayName": "ライセンスの割り当てまたは削除",
                "SelectSimple": {
                    "Assign License to User": false,
                    "Remove License from User": true
                }
            }
        }
    }
#>
```

`.SYNOPSIS` - runbook の機能について、非常に簡潔な説明を記入してください。これは利用可能な runbook の一覧に表示されます。

`.DESCRIPTION` - runbook の機能について説明を記入してください。少し詳しく書いても構いません。これは runbook の実行/パラメーター ダイアログ内に表示されます。

`.PARAMETER` - パラメーター名の後に続ける必要があります。対象パラメーターに対して期待される入力を詳しく説明できます。

`.INPUTS` - JSON ベースの Runbook Customization ブロックを含めることができます。

`.NOTES` - 解析/描画されません。この領域には、runbook に存在する権限や要件を記述してください。

`.EXAMPLE` - 解析/描画されません。Tenant の RealmJoin Datastore で使用する JSON ベースのカスタマイズ例を含めることができます。これらは、たとえば異なるワークフローやユーザー クラス向けのテンプレートの作成例です。

## JSON ベースのカスタマイズ

### 中央データストア

各 Azure Tenant は、"Runbook Customizations" データストアをホストでき、場所は <https://portal.realmjoin.com/settings/runbooks-customizations> .

形式はコメント付き JSON で、末尾のカンマも許可されます。現在、関連するセクションは 3 つあります。 `Settings`, `テンプレート`, `Runbooks`.

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

### Runbooks セクション

`Runbooks` は、runbook の開始時に portal によって解析されます。現在の Azure Automation Runbook と同名のセクションが存在する場合、その内容がユーザーに表示されるフロントエンドのカスタマイズに使用されます。

次のシンプルなデモ用 runbook を想定してください。名前は `rjgit-device_demo-runbook-customizing`.

```powershell
<#
  .SYNOPSIS
  Runbook Customizing のデモ

  .DESCRIPTION
  Runbook Customizing のデモ、ドロップダウン/選択など
#>

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

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

"## Device '$DeviceID' に対して処理を実行中"

# 非常に任意の複雑なワークフロー
if ($ExtraWorkflow) {
    "## Meditation を実行中..."
    Start-Sleep -Seconds $ExtraWorkflowTime
}
```

カスタマイズされていない場合、フロントエンドでは次のように表示されます。

![デモ - 変更前](/files/f20309d04dea3b091cbf1b31b43724ed522f151c)

考察:

* この runbook は portal のデバイス コンテキストから開始されるため、 `$DeviceId` はユーザーにとって冗長な情報です。どのデバイスを作業中かはすでに分かっています。
* 「Extra Workflow」を有効または無効にするとどうなりますか？「Extra Workflow」を無効にした場合でも「Extra Workflow Time」について考える必要がありますか？

それを改善しましょう。中央データストアにある次の例の JSON により、この runbook の UI が変更されます。

```json
{
    "Runbooks": {
        "rjgit-device_demo-runbook-customizing": {
            "ParameterList": [
                {
                    "Name": "DeviceId",
                    "Hide": true
                }, 
                {
                    "Name": "ExtraWorkflow",
                    "Hide": true
                },
                {
                    "Name": "ExtraWorkflowTime",
                    "DisplayName": "どれくらい長く瞑想しますか?",
                },
                {
                    "DisplayName": "追加ワークフローを実行",
                    "DisplayBefore": "ExtraWorkflowTime",
                    "Select": {
                        "Options": [
                            {
                                "Display": "Meditation を実行（任意）",
                                "Customization": {
                                    "Default": {
                                        "ExtraWorkflow": true
                                    }
                                }
                            },
                            {
                                "Display": "デバイスのマインドフルネスをスキップ",
                                "Customization": {
                                    "Default": {
                                        "ExtraWorkflow": false
                                    },
                                    "Hide": [
                                        "ExtraWorkflowTime"
                                    ]
                                }
                            }
                        ],
                        
                    },
                    "Default": "デバイスのマインドフルネスをスキップ"
                }
            ]
        }
    }
}
```

同じ表記/機能を [runbook ヘッダー](#runbook-header).

#### ParameterList

各パラメーターには `ParameterList`. [修飾子](#modifiers) 内に独自のセクションがあります。これにより、そのパラメーターの動作を変更できます。

結果は次のようになります。

![デモ - 非表示後](/files/ab6a238996984ced1f9ca2bf3418ed62773c8e92)

追加ワークフローを選択すると、さらに多くのパラメーターが表示（再表示）されます。

![デモ - 再表示後](/files/2537ec2ad7d7d404fc5f8d3ea03feb95e3426213)

これは、カスタマイズを適用する前と比べて見た目がすっきりしていることを示します。同時に、「Extra Workflow」の代替について、より多くの情報がユーザーに提供されます。また、ユーザーは「Extra Workflow Time」が関連する場合にのみ気にすればよくなります。

このフィールドの表示/非表示の変更は、次のものを使って行いました。 `"Customization"` のいずれかの中にある `"Select"` ブロックです。現在、同時に有効にできるこのような `"Customization"` ブロックは 1 つまでです。

ご覧のとおり、パラメーター `$DeviceId` は完全に非表示になっています。これは、 `"Hide": true` をこのパラメーターに設定することで実現されています。

パラメーターには `DisplayName`を持たせることができます。わかりやすい `DisplayName` を用意して `$ExtraWorkflowTime` を UI 上で置き換えました。詳細は他の [修飾子](#modifiers) を参照してください。

値を直接返さずに UI 要素を提供したい場合は、（ `名前` statement が欠けている）"Execute Extra Workflow" セクションのように、"名前なし" のパラメーターを挿入できます。これは通常、 `選択します`.

#### 選択します

を併用する場合にのみ使用されます `選択します`を使用して、 `Options` の一覧をドロップダウンに表示しました。各オプションは `表示` テキスト、または `カスタマイズ`の設定のような `Hide` や `Default` 値を他のパラメーターに対してトリガーできます。今回の例では、これを使って `$ExtraWorkflowTime` を（再）表示し、 `$ExtraWorkflow`の値を上書きしました。

`$ExtraWorkflowTime` は、そのため関連する場合にのみ表示され、二値スイッチ `$ExtraWorkflow` は、ユーザー視点では意味のある代替 विकल्पに置き換えられます。

名前付きパラメーターの `選択します` 場合、各オプションには `"ParameterValue": "..."` を runbook に渡すために含める必要があります。 `"ShowValue: false"` を `選択します` ブロック内に置くと、ドロップダウンのみを表示し、結果のパラメーター値用のフィールドは表示しません。

名前付きパラメーターの例:

```json
{
    "Name": "ExtraWorkflow",
    "DefaultValue": true,
    "DisplayName": "追加ワークフローを実行",
    "DisplayBefore": "ExtraWorkflowTime",
    "Select": {
        "Options": [
            {
                "Display": "Meditation を実行（任意）",
                "ParameterValue": true
            },
            {
                "Display": "デバイスのマインドフルネスをスキップ",
                "ParameterValue": false,
                "Customization": {
                    "Hide": [
                        "ExtraWorkflowTime"
                    ]
                }
            }
        ],
        "ShowValue": false
    }
}
```

この `Default` / `DefaultValue` パラメーター内の statement も、ドロップダウンの初期状態を指定します。名前なしパラメーターの場合は、目的のオプションの `DisplayName` を使用し、そうでない場合は "true" や "false" など、あるいは文字列などの既定の戻り値を指定してください。

#### パラメーター

名前付きパラメーターのみの場合は、 `パラメーター` の代わりに少し短い `ParameterList`.

形式を使用できます。例は SelectSimple を参照してください

#### SelectSimple

の完全な機能が不要で、ドロップダウンで候補値の一覧を提供したいだけなら（追加のカスタマイズを適用せずに）、 `選択します` を使用できます `SelectSimple`.

`SelectSimple` は名前付きパラメーターにのみ使用できます。

例:

```json
{
    "Runbooks": {
        "rjgit-device_demo-runbook-customizing": {
            "Parameters": {
                "DeviceId": {
                    "Hide": true
                }, 
                "ExtraWorkflow": {
                    "Name": "ExtraWorkflow",
                    "DisplayName": "追加ワークフローを実行",
                    "Default": false,
                    "SelectSimple": {
                        "Execute Meditation (optional)": true,
                        "Skip Device Mindfulness": false
                    }
                },
                "ExtraWorkflowTime": {
                    "DisplayName": "どれくらい長く瞑想しますか?"
                }
            }
        }
    }
}
```

この例に対する最大の違い（かなり短いこと以外）は、 `$ExtraWorkflowTime` が常に表示されることです。

#### 修飾子

各パラメーターには、次の修飾子の 1 つ以上を持たせることができます。

* `"DisplayName": "text"` - UI でパラメーター名として "text" を表示します
* `"Hide": true / false` - このパラメーターを非表示にします
* `"Mandatory": true / false` - このパラメーターの入力を必須にします
* `"ReadOnly": true / false` - このパラメーターが既定値から変更されるのを防ぎます
* `"DefaultValue": "..."` - このパラメーターの既定値を設定します。（代わりに `Default` を使用することもできます。）
* `"GraphFilter": "startswith(DisplayName, 'LIC_')"` - [Graph フィルタリング](#graph-filtering)
* `"AllowEdit": true / false` - このパラメーターが手動で編集されるのを防ぎます。（これをテンプレートと組み合わせます）

### Settings

`Settings` Azure Storage Account 名などの設定データを中央に保存しつつ、runbook とは分離しておくことができます。

runbooks の param-Block から個々の値にアクセスするには `Use-RJInterface`.

runbook の次の param-block の例を見てみましょう。

```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
)
```

Portal は、存在する場合、中央データストアの値で各パラメーターを事前入力しようとします。これは、パラメーターが UI で非表示になっている場合でも機能します。

この runbook 用にデータストアに入れることができる JSON の例は次のとおりです。

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

不足している `Container` 要素は、単に UI では事前入力されません。

### テンプレート

`テンプレート` JSON 参照を使用してデータを取り込みます。たとえば、オフィス所在地の長い一覧を、 `選択します` statement を使用する際に取り込めます。

これにより、カスタマイズを実データから分離し、ニュートラル/再利用可能/分割された状態に保てます。

新規ユーザーのオンボーディングの例を考えてみましょう。部門やオフィス所在地に複数の候補があり、オフィス所在地を割り当てると、特定の番地、国、州なども必須になる場合があります。

次の runbook customization の例では、 `$ref` を `Runbooks` セクションを使って、 `テンプレート` セクションからサブツリーを参照/インポートしています。 `$id`/`$values` キーワードに注意してください。また、 `$id`/`$values` は、 `$ref`を使って参照する前に定義しておく必要があることに注意してください。だからこそ、 `テンプレート` は `Runbooks` より前に定義されています。この例では。

この例では、portal に対して、 `$id` を持つサブツリーを取得するように指示しています。 `LocationOptions` を含め、その `$values`を取り込み、 `$ref` statement を置き換えます。つまり portal は、 `選択します` セクションで説明されているように `Runbooks` を描画しますが、実際のオプションは `テンプレート`.

から含めます。テンプレートには、参照先の場所でサポートされている任意の statement を含めることができます。この例では、 `カスタマイズ` statement を使って `StreetAddress`.

のような他のパラメーターを変更します。 `Runbooks` これにより、実データを分離したまま、複数の環境で再利用可能な runbook 固有の customziation を

```json
{
    "Templates": {
        "Options": [
            {
                "$id": "LocationOptions",
                "$values": [
                    {
                        "Display": "DE-OF",
                        "Customization": {
                            "Default": {
                                "StreetAddress": "Kaiserstraße 39",
                                "PostalCode": "63065",
                                "City": "Offenbach",
                                "Country": "Germany"
                            }
                        }
                    },
                    {
                        "Display": "DE-DEG",
                        "Customization": {
                            "Default": {
                                "StreetAddress": "Lateinschulgassse 24-26",
                                "PostalCode": "94469",
                                "City": "Deggendorf",
                                "Country": "Germany"
                            }
                        }
                    },
                    {
                        "Display": "DE-HH",
                        "Customization": {
                            "Default": {
                                "StreetAddress": "Hans-Henny-Jahnn-Weg 53",
                                "PostalCode": "22085",
                                "City": "Hamburg",
                                "Country": "Germany"
                            }
                        }
                    },
                    {
                        "Display": "FI-HS",
                        "Customization": {
                            "Default": {
                                "StreetAddress": "Somewhere 42",
                                "PostalCode": "12345",
                                "City": "Helsinki",
                                "Country": "Finland"
                            }
                        }
                    }
                ]
            },
            {
                "$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": "オフィス所在地",
                    "DisplayAfter": "CompanyName",
                    "Select": {
                        "Options": {
                            "$ref": "LocationOptions"
                        }
                    }
                },
                {
                    "Name": "CompanyName",
                    "Select": {
                        "Options": {
                            "$ref": "CompanyOptions"
                        },
                        "AllowEdit": false
                    }
                }
            ],
            "ReadOnly": [
                "StreetAddress",
                "PostalCode",
                "City",
                "Country"
            ]
        }
    }
}
```

これにより、次の UI が作成されます。

![デモ - ref-location](/files/8b22afda3009aabf7abf17f20e4e7431c8e441d3)

![デモ - ref-address](/files/217a892822135024213e34d2487caef22e38a751)

### Graph フィルター

複数の runbook で使用するために [ODATA Graph-Filters](https://docs.microsoft.com/en-us/graph/query-parameters?context=graph%2Fapi%2F1.0\&view=graph-rest-1.0#filter-parameter) を準備できます。これらは `GraphFilters`.

というセクションに保存します。 `DisplayName` 次の例では、グループの

```json
"GraphFilters": {
    "LicenseGroup": "startswith(DisplayName, 'LIC_')" // also contained in RJ code as default
  }
```

参照 [Graph フィルタリング](#graph-filtering) 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/ja/zi-dong-hua/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.
