Skip to content

Instantly share code, notes, and snippets.

@michaellwest
Created December 21, 2025 01:55
Show Gist options
  • Select an option

  • Save michaellwest/d3ab4841c0e7488f7f98c1c104ed48ee to your computer and use it in GitHub Desktop.

Select an option

Save michaellwest/d3ab4841c0e7488f7f98c1c104ed48ee to your computer and use it in GitHub Desktop.
Sitecore PowerShell Extensions dialog helper library. Simplifies the use of Read-Variable.
description
Helper functions to simplify and optimize Read-Variable dialog creation.

Dialog Builder Functions

Overview

The Read-Variable cmdlet is powerful but requires verbose hashtable construction and manual variable initialization. These helper functions provide a fluent, intuitive API for building dialogs while handling the nuances of variable management automatically.

Key Features

  • Automatic variable initialization - Handles Item objects and other types that require pre-initialization
  • Type inference - Automatically selects appropriate editors based on variable types
  • Fluent API - Chainable methods for building complex dialogs
  • Reduced boilerplate - Eliminates repetitive hashtable construction
  • Validation support - Built-in mandatory field handling and custom validators
  • Enhanced error messages - Clear, actionable error messages help catch common mistakes early
  • Debug capabilities - Inspect dialog configuration before execution with Debug-DialogBuilder
  • Helper utilities - Copy, test, validate, and export dialog configurations
  • Extended controls - TreeList, MultiList, NameValueList, and IconSelector support
  • Dynamic building - Add or remove fields conditionally at runtime

Core Functions

New-DialogBuilder

Creates a new dialog builder instance for constructing Read-Variable dialogs.

Syntax:

New-DialogBuilder [-Title <string>] [-Description <string>] [-Width <int>] [-Height <int>]
    [-OkButtonName <string>] [-CancelButtonName <string>] [-ShowHints] [-Icon <string>]

Example:

$dialog = New-DialogBuilder -Title "My Dialog" -Width 500 -Height 400 -ShowHints

Add-DialogField

Adds a field to the dialog builder with automatic type handling.

Syntax:

Add-DialogField -DialogBuilder <hashtable> -Name <string> [-Title <string>] [-Value <object>]
    [-Tooltip <string>] [-Placeholder <string>] [-Editor <string>] [-Mandatory] [-Tab <string>]
    [-Columns <int>] [-Lines <int>] [-Root <string>] [-Source <string>] [-Domain <string>]
    [-Options <hashtable>] [-OptionTooltips <hashtable>] [-GroupId <int>] [-ParentGroupId <int>]
    [-HideOnValue <string>] [-ShowOnValue <string>]

Returns: The dialog builder (for chaining)

Show-Dialog

Executes the dialog and returns the result. All dialog field variables become available in the calling scope after the dialog is shown.

Syntax:

Show-Dialog -DialogBuilder <hashtable> [-Validator <scriptblock>] [-ValidatorParameters <hashtable>]

Parameters:

  • Validator - Optional scriptblock for custom validation logic. Access field values via $variables.<fieldName>.Value and set errors via $variables.<fieldName>.Error
  • ValidatorParameters - Optional hashtable of parameters to pass to the validator scriptblock

Returns: "ok" if user clicked OK, "cancel" if cancelled

Important: Variables defined with -Name in field functions (e.g., $rootItem, $userName) are automatically created in your script scope when Show-Dialog is called, and their values are updated based on user input when the dialog is closed with OK.

Validation Example:

$minLength = 8
$validator = {
    param($minLen)
    if ($variables.password.Value.Length -lt $minLen) {
        $variables.password.Error = "Password must be at least $minLen characters"
    }
}
$result = Show-Dialog -DialogBuilder $dialog -Validator $validator -ValidatorParameters @{ minLen = $minLength }

Debug-DialogBuilder

Displays debug information about a dialog builder instance. Useful for troubleshooting dialog configuration issues before calling Show-Dialog.

Syntax:

Debug-DialogBuilder -DialogBuilder <hashtable> [-ShowValues] [-ShowFullParameters]

Parameters:

  • ShowValues - Include current field values in the output
  • ShowFullParameters - Display all parameter details for each field (verbose)

Example:

$dialog = New-DialogBuilder -Title "Test Dialog" |
    Add-TextField -Name "userName" -Mandatory |
    Add-Checkbox -Name "isActive" -Value $true

# Inspect the dialog structure
Debug-DialogBuilder -DialogBuilder $dialog

# Show with values
Debug-DialogBuilder -DialogBuilder $dialog -ShowValues -ShowFullParameters

Test-DialogBuilder

Validates a dialog builder configuration without displaying it. Checks for common issues such as duplicate field names, orphaned ParentGroupIds, and performance concerns.

Syntax:

Test-DialogBuilder -DialogBuilder <hashtable> [-WarningsOnly]

Returns: $true if validation passes, $false otherwise

Example:

$dialog = New-DialogBuilder -Title "My Dialog" |
    Add-TextField -Name "field1" -Mandatory

$isValid = Test-DialogBuilder -DialogBuilder $dialog
if ($isValid) {
    Show-Dialog -DialogBuilder $dialog
}

Copy-DialogBuilder

Creates a deep copy of a dialog builder instance, useful for creating variations without modifying the original.

Syntax:

Copy-DialogBuilder -DialogBuilder <hashtable>

Returns: New dialog builder instance

Example:

$baseDialog = New-DialogBuilder -Title "Base" | Add-TextField -Name "name"
$dialog2 = Copy-DialogBuilder -DialogBuilder $baseDialog
$dialog2.Title = "Modified Copy"

Remove-DialogField

Removes a field from the dialog builder by name. Useful for dynamic dialog construction.

Syntax:

Remove-DialogField -DialogBuilder <hashtable> -Name <string>

Returns: The dialog builder (for chaining)

Example:

$dialog = $dialog | Remove-DialogField -Name "optionalField"

Export-DialogBuilderConfig

Exports dialog configuration to JSON format for documentation, debugging, or sharing.

Syntax:

Export-DialogBuilderConfig -DialogBuilder <hashtable> [-FilePath <string>]

Returns: JSON string (and optionally writes to file)

Example:

$json = Export-DialogBuilderConfig -DialogBuilder $dialog
Export-DialogBuilderConfig -DialogBuilder $dialog -FilePath "C:\temp\dialog.json"

Complete Function Library

<#
.SYNOPSIS
    Helper functions for building Read-Variable dialogs with less boilerplate.

.DESCRIPTION
    Provides a fluent API for constructing SPE dialogs that automatically handles:
    - Variable initialization (especially for Item types)
    - Type inference for editor selection
    - Parameter hashtable construction
    - Validation and mandatory fields
    - Enhanced error messages and debugging capabilities

.NOTES
    Version: 2.1.0
    Date: 2025-12-16
    Author: SPE Community

    Changelog:
    - v2.1.0: Refactored Add-TextField with parameter sets (-IsPassword, -IsEmail, -IsNumber)
              Added Add-LinkField, Add-TristateCheckbox, Add-RuleField, Add-RuleActionField
              Removed redundant Add-NumberField and Add-EmailField functions
    - v2.0.0: Major update with new convenience functions, validation improvements, helper utilities
    - v1.1.0: Added Debug-DialogBuilder function, validation, and better error messages
    - v1.0.0: Initial release
#>

function New-DialogBuilder {
    <#
    .SYNOPSIS
        Creates a new dialog builder instance.

    .PARAMETER Title
        The dialog title shown in the title bar.

    .PARAMETER Description
        Descriptive text shown below the title.

    .PARAMETER Width
        Dialog width in pixels (default: 500).

    .PARAMETER Height
        Dialog height in pixels (default: 400).

    .PARAMETER OkButtonName
        Custom text for the OK button (default: "OK").

    .PARAMETER CancelButtonName
        Custom text for the Cancel button (default: "Cancel").

    .PARAMETER ShowHints
        Display tooltips for fields.

    .PARAMETER Icon
        Sitecore icon path (e.g., "Office/32x32/document.png").

    .EXAMPLE
        $dialog = New-DialogBuilder -Title "Content Editor" -ShowHints
    #>
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]$Title,

        [string]$Description = "",

        [int]$Width = 500,

        [int]$Height = 400,

        [string]$OkButtonName = "OK",

        [string]$CancelButtonName = "Cancel",

        [switch]$ShowHints,

        [string]$Icon = ""
    )

    # Validate dimensions
    if ($Width -lt 200 -or $Width -gt 2000) {
        Write-Warning "Dialog width $Width is outside recommended range (200-2000 pixels). Dialog may not display properly."
    }
    if ($Height -lt 150 -or $Height -gt 1500) {
        Write-Warning "Dialog height $Height is outside recommended range (150-1500 pixels). Dialog may not display properly."
    }

    $builder = @{
        Title = $Title
        Description = $Description
        Width = $Width
        Height = $Height
        OkButtonName = $OkButtonName
        CancelButtonName = $CancelButtonName
        ShowHints = $ShowHints.IsPresent
        Icon = $Icon
        Parameters = @()
        _Variables = @{}  # Internal tracking of variables
    }

    return $builder
}

function Add-DialogField {
    <#
    .SYNOPSIS
        Adds a field to the dialog builder.

    .DESCRIPTION
        Automatically handles variable initialization and type inference.
        Supports all Read-Variable parameter types with intelligent defaults.

    .PARAMETER DialogBuilder
        The dialog builder instance from New-DialogBuilder.

    .PARAMETER Name
        Variable name (without $). This becomes the PowerShell variable name.

    .PARAMETER Title
        Field label shown to the user.

    .PARAMETER Value
        Initial/default value. For Item types, will auto-initialize if null.

    .PARAMETER Tooltip
        Help text shown when ShowHints is enabled.

    .PARAMETER Placeholder
        Placeholder text for empty text fields.

    .PARAMETER Editor
        Explicit editor type. Auto-detected if not specified.

    .PARAMETER DateOnly
        When specified with DateTime values, shows date picker without time selection.

    .PARAMETER Mandatory
        Makes this field required.

    .PARAMETER Tab
        Tab name for organizing fields.

    .PARAMETER Columns
        Column width in 12-column grid (default: 12).

    .PARAMETER Lines
        Number of lines for multi-line text fields.

    .PARAMETER Root
        Root path for item picker controls.

    .PARAMETER Source
        Data source configuration for complex controls.

    .PARAMETER Domain
        Domain filter for user/role pickers.

    .PARAMETER Options
        Options hashtable for combo/radio/checklist controls.

    .PARAMETER OptionTooltips
        Tooltips for dropdown options.

    .PARAMETER GroupId
        ID for conditional visibility grouping.

    .PARAMETER ParentGroupId
        Parent group ID for conditional visibility.

    .PARAMETER HideOnValue
        Values that hide this field when parent has them.

    .PARAMETER ShowOnValue
        Values that show this field when parent has them.

    .EXAMPLE
        $dialog | Add-DialogField -Name "userName" -Title "User Name" -Mandatory

    .EXAMPLE
        $dialog | Add-DialogField -Name "startItem" -Title "Root" -Value (Get-Item "master:/content") -Root "/sitecore/content"

    .EXAMPLE
        $dialog | Add-DialogField -Name "publishDate" -Title "Publish Date" -Value [DateTime]::Now -DateOnly
    #>
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder,

        [Parameter(Mandatory = $true)]
        [string]$Name,

        [string]$Title = "",

        [object]$Value = $null,

        [string]$Tooltip = "",

        [string]$Placeholder = "",

        [string]$Editor = "",

        [switch]$DateOnly,

        [switch]$Mandatory,

        [string]$Tab = "",

        [int]$Columns = 0,

        [int]$Lines = 0,

        [string]$Root = "",

        [string]$Source = "",

        [string]$Domain = "",

        [System.Collections.IDictionary]$Options = $null,

        [System.Collections.IDictionary]$OptionTooltips = $null,

        [int]$GroupId = 0,

        [int]$ParentGroupId = 0,

        [string]$HideOnValue = "",

        [string]$ShowOnValue = ""
    )

    # Validate DialogBuilder structure
    if (-not $DialogBuilder.ContainsKey('Parameters') -or -not $DialogBuilder.ContainsKey('_Variables')) {
        throw "Invalid DialogBuilder object. Did you create it with New-DialogBuilder?"
    }

    # Validate field name
    if ($Name -match '[^a-zA-Z0-9_]') {
        throw "Field name '$Name' contains invalid characters. Use only letters, numbers, and underscores."
    }

    # Check for duplicate field names
    if ($DialogBuilder._Variables.ContainsKey($Name)) {
        Write-Warning "Field '$Name' already exists in the dialog. Previous field will be overwritten."
    }

    # Validate Columns parameter
    if ($Columns -lt 0 -or $Columns -gt 12) {
        throw "Columns value must be between 0 and 12 (0 = auto, 12 = full width). Got: $Columns"
    }

    # Validate conditional visibility configuration
    if ($ParentGroupId -gt 0 -and ([string]::IsNullOrEmpty($HideOnValue) -and [string]::IsNullOrEmpty($ShowOnValue))) {
        Write-Warning "Field '$Name' has ParentGroupId but no HideOnValue or ShowOnValue. Field visibility will not be conditional."
    }

    if ((-not [string]::IsNullOrEmpty($HideOnValue) -or -not [string]::IsNullOrEmpty($ShowOnValue)) -and $ParentGroupId -eq 0) {
        throw "Field '$Name' has HideOnValue/ShowOnValue but no ParentGroupId. You must specify which field controls visibility."
    }

    # Use Name as Title if Title not provided
    if ([string]::IsNullOrEmpty($Title)) {
        $Title = $Name
    }

    # Auto-initialize Item variables if needed
    if ($Value -is [Sitecore.Data.Items.Item] -or
        ($Editor -match "^(item|droplist|droptree|groupeddroplink|groupeddroplist)" -and $null -eq $Value)) {

        # Initialize with a default item if null
        if ($null -eq $Value) {
            $Value = Get-Item -Path "master:/sitecore" -ErrorAction SilentlyContinue
        }

        # Store in caller's scope
        Set-Variable -Name $Name -Value $Value -Scope 1
    }

    # Auto-detect editor type based on value type
    if ([string]::IsNullOrEmpty($Editor)) {
        if ($Value -is [bool]) {
            $Editor = "checkbox"
        }
        elseif ($Value -is [DateTime]) {
            $Editor = if ($DateOnly) { "date" } else { "date time" }
        }
        elseif ($Value -is [int] -or $Value -is [double]) {
            # Number type will be inferred by Read-Variable
        }
        elseif ($Value -is [Sitecore.Data.Items.Item]) {
            # Item picker will be inferred
        }
        elseif ($Lines -gt 0) {
            # Multi-line text
        }
    }
    elseif ($DateOnly -and [string]::IsNullOrEmpty($Editor)) {
        # DateOnly was specified but no editor set and value isn't DateTime
        $Editor = "date"
    }

    # Build parameter hashtable
    $param = @{
        Name = $Name
        Title = $Title
    }

    # Always add Value to the parameter hashtable
    # Value is required for proper variable initialization in Read-Variable
    $param.Value = $Value

    # Track variable for Show-Dialog to initialize in caller scope
    $DialogBuilder._Variables[$Name] = $Value

    # Add optional parameters only if specified
    if (-not [string]::IsNullOrEmpty($Tooltip)) { $param.Tooltip = $Tooltip }
    if (-not [string]::IsNullOrEmpty($Placeholder)) { $param.Placeholder = $Placeholder }
    if (-not [string]::IsNullOrEmpty($Editor)) { $param.Editor = $Editor }
    if ($Mandatory.IsPresent) { $param.Mandatory = $true }
    if (-not [string]::IsNullOrEmpty($Tab)) { $param.Tab = $Tab }
    if ($Columns -gt 0) { $param.Columns = $Columns }
    if ($Lines -gt 0) { $param.Lines = $Lines }
    if (-not [string]::IsNullOrEmpty($Root)) { $param.Root = $Root }
    if (-not [string]::IsNullOrEmpty($Source)) { $param.Source = $Source }
    if (-not [string]::IsNullOrEmpty($Domain)) { $param.Domain = $Domain }
    if ($null -ne $Options) { $param.Options = $Options }
    if ($null -ne $OptionTooltips) { $param.OptionTooltips = $OptionTooltips }
    if ($GroupId -gt 0) { $param.GroupId = $GroupId }
    if ($ParentGroupId -gt 0) { $param.ParentGroupId = $ParentGroupId }
    if (-not [string]::IsNullOrEmpty($HideOnValue)) { $param.HideOnValue = $HideOnValue }
    if (-not [string]::IsNullOrEmpty($ShowOnValue)) { $param.ShowOnValue = $ShowOnValue }

    # Add parameter to builder
    $DialogBuilder.Parameters += $param

    # Return builder for chaining
    return $DialogBuilder
}

function Show-Dialog {
    <#
    .SYNOPSIS
        Displays the dialog and returns the result.

    .PARAMETER DialogBuilder
        The dialog builder instance.

    .PARAMETER Validator
        Optional validation scriptblock that validates field values.

    .PARAMETER ValidatorParameters
        Optional hashtable of parameters to pass to the validator scriptblock.

    .RETURNS
        "ok" if user clicked OK, "cancel" if cancelled.

    .EXAMPLE
        $result = Show-Dialog -DialogBuilder $dialog
        if ($result -eq "ok") {
            Write-Host "Accepted"
        }

    .EXAMPLE
        # With validator and parameters
        $minLen = 8
        $validator = { param($minLength)
            if ($variables.password.Value.Length -lt $minLength) {
                $variables.password.Error = "Too short"
            }
        }
        $result = Show-Dialog -DialogBuilder $dialog -Validator $validator -ValidatorParameters @{ minLength = $minLen }
    #>
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder,

        [scriptblock]$Validator = $null,

        [hashtable]$ValidatorParameters = $null
    )

    # Validate DialogBuilder structure
    if (-not $DialogBuilder.ContainsKey('Parameters') -or -not $DialogBuilder.ContainsKey('_Variables')) {
        throw "Invalid DialogBuilder object. Did you create it with New-DialogBuilder?"
    }

    # Warn if no fields were added
    if ($DialogBuilder.Parameters.Count -eq 0) {
        Write-Warning "Dialog has no fields. Did you forget to add fields with Add-DialogField or convenience functions?"
    }

    # Initialize variables in caller's scope
    foreach ($varName in $DialogBuilder._Variables.Keys) {
        try {
            Set-Variable -Name $varName -Value $DialogBuilder._Variables[$varName] -Scope 1 -ErrorAction Stop
        }
        catch {
            throw "Failed to initialize variable '$varName' in caller scope. Error: $($_.Exception.Message)"
        }
    }

    # Build Read-Variable parameters
    $readVarParams = @{
        Title = $DialogBuilder.Title
        Description = $DialogBuilder.Description
        Width = $DialogBuilder.Width
        Height = $DialogBuilder.Height
        OkButtonName = $DialogBuilder.OkButtonName
        CancelButtonName = $DialogBuilder.CancelButtonName
        Parameters = $DialogBuilder.Parameters
    }

    if ($DialogBuilder.ShowHints) {
        $readVarParams.ShowHints = $true
    }

    if (-not [string]::IsNullOrEmpty($DialogBuilder.Icon)) {
        $readVarParams.Icon = $DialogBuilder.Icon
    }

    if ($null -ne $Validator) {
        $readVarParams.Validator = $Validator
    }

    if ($null -ne $ValidatorParameters) {
        $readVarParams.ValidatorParameters = $ValidatorParameters
    }

    # Call Read-Variable
    try {
        $result = Read-Variable @readVarParams
    }
    catch {
        throw "Failed to display dialog '$($DialogBuilder.Title)'. Error: $($_.Exception.Message)"
    }

    # Update variable values in caller scope
    foreach ($varName in $DialogBuilder._Variables.Keys) {
        try {
            Set-Variable -Name $varName -Value (Get-Variable -Name $varName -ValueOnly) -Scope 1 -ErrorAction Stop
        }
        catch {
            Write-Warning "Failed to update variable '$varName' after dialog closed. Variable may not be available in your script."
        }
    }

    return $result
}

function Debug-DialogBuilder {
    <#
    .SYNOPSIS
        Displays debug information about a dialog builder instance.

    .DESCRIPTION
        Outputs a formatted summary of the dialog configuration including all fields,
        their types, and configuration details. Useful for troubleshooting dialog issues
        before calling Show-Dialog.

    .PARAMETER DialogBuilder
        The dialog builder instance to inspect.

    .PARAMETER ShowValues
        Include the current values of variables in the output.

    .PARAMETER ShowFullParameters
        Display all parameter details for each field (verbose output).

    .EXAMPLE
        $dialog = New-DialogBuilder -Title "Test"
        $dialog | Add-TextField -Name "userName"
        Debug-DialogBuilder -DialogBuilder $dialog

    .EXAMPLE
        # Inspect with values
        Debug-DialogBuilder -DialogBuilder $dialog -ShowValues

    .EXAMPLE
        # Full detailed output
        Debug-DialogBuilder -DialogBuilder $dialog -ShowFullParameters
    #>
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder,

        [switch]$ShowValues,

        [switch]$ShowFullParameters
    )

    # Validate DialogBuilder structure
    if (-not $DialogBuilder.ContainsKey('Parameters') -or -not $DialogBuilder.ContainsKey('_Variables')) {
        Write-Error "Invalid DialogBuilder object. Did you create it with New-DialogBuilder?"
        return
    }

    Write-Host ("=" * 80) -ForegroundColor Cyan
    Write-Host "DIALOG BUILDER DEBUG INFO" -ForegroundColor Cyan
    Write-Host ("=" * 80) -ForegroundColor Cyan
    Write-Host ""

    # Dialog Properties
    Write-Host "Dialog Properties:" -ForegroundColor Green
    Write-Host "  Title       : $($DialogBuilder.Title)"
    Write-Host "  Description : $($DialogBuilder.Description)"
    Write-Host "  Dimensions  : $($DialogBuilder.Width) x $($DialogBuilder.Height)"
    Write-Host "  OK Button   : $($DialogBuilder.OkButtonName)"
    Write-Host "  Cancel Button: $($DialogBuilder.CancelButtonName)"
    Write-Host "  Show Hints  : $($DialogBuilder.ShowHints)"
    if (-not [string]::IsNullOrEmpty($DialogBuilder.Icon)) {
        Write-Host "  Icon        : $($DialogBuilder.Icon)"
    }
    Write-Host ""

    # Field Summary
    $fieldCount = $DialogBuilder.Parameters.Count
    Write-Host "Fields: $fieldCount" -ForegroundColor Green

    if ($fieldCount -eq 0) {
        Write-Host "  WARNING: No fields defined!" -ForegroundColor Yellow
        Write-Host ""
        return
    }

    # Group fields by tab
    $fieldsByTab = @{}
    $noTabFields = @()

    foreach ($param in $DialogBuilder.Parameters) {
        if ([string]::IsNullOrEmpty($param.Tab)) {
            $noTabFields += $param
        }
        else {
            if (-not $fieldsByTab.ContainsKey($param.Tab)) {
                $fieldsByTab[$param.Tab] = @()
            }
            $fieldsByTab[$param.Tab] += $param
        }
    }

    # Display fields without tabs
    if ($noTabFields.Count -gt 0) {
        Write-Host ""
        Write-Host "  [No Tab]" -ForegroundColor Magenta
        foreach ($param in $noTabFields) {
            Show-FieldDebugInfo -Param $param -ShowValues:$ShowValues -ShowFullParameters:$ShowFullParameters
        }
    }

    # Display fields grouped by tab
    foreach ($tab in ($fieldsByTab.Keys | Sort-Object)) {
        Write-Host ""
        Write-Host "  [Tab: $tab]" -ForegroundColor Magenta
        foreach ($param in $fieldsByTab[$tab]) {
            Show-FieldDebugInfo -Param $param -ShowValues:$ShowValues -ShowFullParameters:$ShowFullParameters
        }
    }

    Write-Host ""
    Write-Host ("=" * 80) -ForegroundColor Cyan
}

function Show-FieldDebugInfo {
    <#
    .SYNOPSIS
        Internal helper function to display field information.
    #>
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [hashtable]$Param,

        [switch]$ShowValues,

        [switch]$ShowFullParameters
    )

    $fieldName = $Param.Name
    $editor = if ($Param.ContainsKey('Editor') -and -not [string]::IsNullOrEmpty($Param.Editor)) { $Param.Editor } else { "auto" }
    $mandatory = if ($Param.ContainsKey('Mandatory') -and $Param.Mandatory) { " [REQUIRED]" } else { "" }
    $columns = if ($Param.ContainsKey('Columns') -and $Param.Columns -gt 0) { " cols:$($Param.Columns)" } else { "" }

    Write-Host "    - $fieldName" -ForegroundColor White -NoNewline
    Write-Host " [$editor]" -ForegroundColor Gray -NoNewline
    if ($mandatory) {
        Write-Host $mandatory -ForegroundColor Red -NoNewline
    }
    if ($columns) {
        Write-Host $columns -ForegroundColor DarkGray -NoNewline
    }
    Write-Host ""

    if ($ShowValues -and $Param.ContainsKey('Value')) {
        $valueDisplay = if ($null -eq $Param.Value) {
            "(null)"
        }
        elseif ($Param.Value -is [Sitecore.Data.Items.Item]) {
            "Item: $($Param.Value.ItemPath)"
        }
        elseif ($Param.Value -is [array]) {
            "Array: $($Param.Value.Count) items"
        }
        else {
            "$($Param.Value)"
        }
        Write-Host "      Value: $valueDisplay" -ForegroundColor DarkCyan
    }

    if ($ShowFullParameters) {
        Write-Host "      Full Parameters:" -ForegroundColor DarkGray
        foreach ($key in ($Param.Keys | Sort-Object)) {
            if ($key -notin @('Name', 'Editor', 'Mandatory', 'Value')) {
                $value = $Param[$key]
                if ($null -ne $value -and $value -ne "" -and $value -ne 0 -and $value -ne $false) {
                    Write-Host "        $key = $value" -ForegroundColor DarkGray
                }
            }
        }
    }

    # Show conditional visibility info
    if ($Param.ContainsKey('GroupId') -and $Param.GroupId -gt 0) {
        Write-Host "      Controls Group: $($Param.GroupId)" -ForegroundColor DarkYellow
    }
    if ($Param.ContainsKey('ParentGroupId') -and $Param.ParentGroupId -gt 0) {
        $condition = ""
        if ($Param.ContainsKey('ShowOnValue') -and -not [string]::IsNullOrEmpty($Param.ShowOnValue)) {
            $condition = "Show when parent = '$($Param.ShowOnValue)'"
        }
        elseif ($Param.ContainsKey('HideOnValue') -and -not [string]::IsNullOrEmpty($Param.HideOnValue)) {
            $condition = "Hide when parent = '$($Param.HideOnValue)'"
        }
        Write-Host "      Controlled by Group: $($Param.ParentGroupId) - $condition" -ForegroundColor DarkYellow
    }
}

# Convenience functions for common field types

function Add-TextField {
    <#
    .SYNOPSIS
        Adds a single-line text input field with support for different input types.

    .DESCRIPTION
        Provides text input fields with optional type validation and formatting:
        - Default: Standard single-line text
        - Password: Masked password input
        - Email: Email validation
        - Number: Numeric input (integer or decimal)

    .PARAMETER IsPassword
        When specified, masks the input as a password field.

    .PARAMETER IsEmail
        When specified, provides email validation.

    .PARAMETER IsNumber
        When specified, restricts input to numeric values (integer or decimal).

    .EXAMPLE
        Add-TextField -Name "username" -Title "Username"

    .EXAMPLE
        Add-TextField -Name "password" -Title "Password" -IsPassword

    .EXAMPLE
        Add-TextField -Name "email" -Title "Email" -IsEmail -Placeholder "[email protected]"

    .EXAMPLE
        Add-TextField -Name "age" -Title "Age" -IsNumber -Value 0
    #>
    [CmdletBinding(DefaultParameterSetName = "Text")]
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder,

        [Parameter(Mandatory = $true)]
        [string]$Name,

        [string]$Title = "",

        [object]$Value = "",

        [string]$Tooltip = "",

        [string]$Placeholder = "",

        [Parameter(ParameterSetName = "Password")]
        [switch]$IsPassword,

        [Parameter(ParameterSetName = "Email")]
        [switch]$IsEmail,

        [Parameter(ParameterSetName = "Number")]
        [switch]$IsNumber,

        [switch]$Mandatory,

        [string]$Tab = "",

        [int]$Columns = 0,

        [int]$GroupId = 0,

        [int]$ParentGroupId = 0,

        [string]$HideOnValue = "",

        [string]$ShowOnValue = ""
    )

    # Remove type switches from bound parameters
    $PSBoundParameters.Remove("IsPassword") > $null
    $PSBoundParameters.Remove("IsEmail") > $null
    $PSBoundParameters.Remove("IsNumber") > $null

    # Determine editor type based on parameter set
    $editor = switch ($PSCmdlet.ParameterSetName) {
        "Password" { "password" }
        "Email"    { "email" }
        "Number"   { "number" }
        default    { $null }  # Let Add-DialogField infer
    }

    if ($editor) {
        $PSBoundParameters.Add("Editor", $editor) > $null
    }

    return Add-DialogField @PSBoundParameters
}

function Add-MultiLineTextField {
    <#
    .SYNOPSIS
        Adds a multi-line text field.
    #>
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder,
        [Parameter(Mandatory = $true)]
        [string]$Name,
        [string]$Title = "",
        [string]$Value = "",
        [int]$Lines = 3,
        [string]$Tooltip = "",
        [string]$Placeholder = "",
        [switch]$Mandatory,
        [string]$Tab = "",
        [int]$Columns = 0,
        [int]$GroupId = 0,
        [int]$ParentGroupId = 0,
        [string]$HideOnValue = "",
        [string]$ShowOnValue = ""
    )

    return Add-DialogField @PSBoundParameters
}

function Add-Checkbox {
    <#
    .SYNOPSIS
        Adds a checkbox field.
    #>
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder,
        [Parameter(Mandatory = $true)]
        [string]$Name,
        [string]$Title = "",
        [bool]$Value = $false,
        [string]$Tooltip = "",
        [string]$Tab = "",
        [int]$Columns = 0,
        [int]$GroupId = 0,
        [int]$ParentGroupId = 0,
        [string]$HideOnValue = "",
        [string]$ShowOnValue = ""
    )

    if(!$PSBoundParameters.ContainsKey("Value")) {
        $PSBoundParameters.Add("Value", $Value) > $null
    }
    return Add-DialogField @PSBoundParameters -Editor "checkbox"
}

function Add-DateTimePicker {
    <#
    .SYNOPSIS
        Adds a date/time picker field.
    #>
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder,
        [Parameter(Mandatory = $true)]
        [string]$Name,
        [string]$Title = "",
        [DateTime]$Value = [DateTime]::Now,
        [string]$Tooltip = "",
        [switch]$DateOnly,
        [switch]$Mandatory,
        [string]$Tab = "",
        [int]$Columns = 0,
        [int]$GroupId = 0,
        [int]$ParentGroupId = 0,
        [string]$HideOnValue = "",
        [string]$ShowOnValue = ""
    )

    $editor = if ($DateOnly) { "date" } else { "date time" }

    return Add-DialogField @PSBoundParameters -Editor $editor
}

function Add-ItemPicker {
    <#
    .SYNOPSIS
        Adds an item picker field.
    #>
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder,
        [Parameter(Mandatory = $true)]
        [string]$Name,
        [string]$Title = "",
        [Sitecore.Data.Items.Item]$Value = $null,
        [string]$Root = "/sitecore/content/",
        [string]$Tooltip = "",
        [switch]$Mandatory,
        [string]$Tab = "",
        [int]$Columns = 0,
        [int]$GroupId = 0,
        [int]$ParentGroupId = 0,
        [string]$HideOnValue = "",
        [string]$ShowOnValue = ""
    )

    # Initialize Value if not provided
    if (!$PSBoundParameters.ContainsKey("Value") -and $null -eq $Value) {
        $Value = Get-Item -Path $Root -ErrorAction SilentlyContinue
        if ($Value) {
            $PSBoundParameters["Value"] = $Value
        }
    }

    return Add-DialogField @PSBoundParameters
}

function Add-Droplink {
    <#
    .SYNOPSIS
        Adds a droplink field for single item selection from a flat dropdown list.

    .DESCRIPTION
        Returns the selected Sitecore Item object. Items are displayed in a flat dropdown list.
        This is a simpler alternative to the tree-based item picker for scenarios where you
        want a compact dropdown interface.
    #>
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder,
        [Parameter(Mandatory = $true)]
        [string]$Name,
        [string]$Title = "",
        [Sitecore.Data.Items.Item]$Value = $null,
        [Parameter(Mandatory = $true)]
        [string]$Source,
        [string]$Tooltip = "",
        [switch]$Mandatory,
        [string]$Tab = "",
        [int]$Columns = 0,
        [int]$GroupId = 0,
        [int]$ParentGroupId = 0,
        [string]$HideOnValue = "",
        [string]$ShowOnValue = ""
    )

    # Initialize Value if not provided
    if (!$PSBoundParameters.ContainsKey("Value") -and $null -eq $Value) {
        $Value = Get-Item -Path "master:/sitecore" -ErrorAction SilentlyContinue
        if ($Value) {
            $PSBoundParameters["Value"] = $Value
        }
    }

    return Add-DialogField @PSBoundParameters -Editor "droplink"
}

function Add-Droptree {
    <#
    .SYNOPSIS
        Adds a droptree field for single item selection with tree navigation in a dropdown.

    .DESCRIPTION
        Returns the selected Sitecore Item object. Displays a tree structure within a dropdown
        control, allowing navigation through the content hierarchy in a compact interface.
    #>
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder,
        [Parameter(Mandatory = $true)]
        [string]$Name,
        [string]$Title = "",
        [Sitecore.Data.Items.Item]$Value = $null,
        [Parameter(Mandatory = $true)]
        [string]$Source,
        [string]$Tooltip = "",
        [switch]$Mandatory,
        [string]$Tab = "",
        [int]$Columns = 0,
        [int]$GroupId = 0,
        [int]$ParentGroupId = 0,
        [string]$HideOnValue = "",
        [string]$ShowOnValue = ""
    )

    return Add-DialogField @PSBoundParameters -Editor "droptree"
}

function Add-Droplist {
    <#
    .SYNOPSIS
        Adds a droplist field for single item selection from a flat dropdown list.

    .DESCRIPTION
        Returns a string representation (path or ID) of the selected item. Items are displayed
        in a flat dropdown list. Use this when you only need the item path/ID rather than the
        full Item object.
    #>
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder,
        [Parameter(Mandatory = $true)]
        [string]$Name,
        [string]$Title = "",
        [string]$Value = "",
        [Parameter(Mandatory = $true)]
        [string]$Source,
        [string]$Tooltip = "",
        [switch]$Mandatory,
        [string]$Tab = "",
        [int]$Columns = 0,
        [int]$GroupId = 0,
        [int]$ParentGroupId = 0,
        [string]$HideOnValue = "",
        [string]$ShowOnValue = ""
    )

    return Add-DialogField @PSBoundParameters -Editor "droplist"
}

function Add-GroupedDroplink {
    <#
    .SYNOPSIS
        Adds a grouped droplink field that displays items organized by parent folders.

    .DESCRIPTION
        Returns the selected Sitecore Item object. Items are grouped by their parent folders
        making it easier to navigate large item sets.

        This is the grouped UI variant of droplink - same functionality but items are
        organized hierarchically in the dropdown instead of a flat list.
    #>
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder,
        [Parameter(Mandatory = $true)]
        [string]$Name,
        [string]$Title = "",
        [Sitecore.Data.Items.Item]$Value = $null,
        [Parameter(Mandatory = $true)]
        [string]$Source,
        [string]$Tooltip = "",
        [switch]$Mandatory,
        [string]$Tab = "",
        [int]$Columns = 0,
        [int]$GroupId = 0,
        [int]$ParentGroupId = 0,
        [string]$HideOnValue = "",
        [string]$ShowOnValue = ""
    )

    return Add-DialogField @PSBoundParameters -Editor "groupeddroplink"
}

function Add-GroupedDroplist {
    <#
    .SYNOPSIS
        Adds a grouped droplist field that displays items organized by parent folders.

    .DESCRIPTION
        Returns a string representation (path or ID) of the selected item. Items are grouped
        by their parent folders making it easier to navigate large item sets.

        This is the grouped UI variant of droplist - same functionality but items are
        organized hierarchically in the dropdown instead of a flat list.
    #>
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder,
        [Parameter(Mandatory = $true)]
        [string]$Name,
        [string]$Title = "",
        [string]$Value = "",
        [Parameter(Mandatory = $true)]
        [string]$Source,
        [string]$Tooltip = "",
        [switch]$Mandatory,
        [string]$Tab = "",
        [int]$Columns = 0,
        [int]$GroupId = 0,
        [int]$ParentGroupId = 0,
        [string]$HideOnValue = "",
        [string]$ShowOnValue = ""
    )

    return Add-DialogField @PSBoundParameters -Editor "groupeddroplist"
}

function Add-Dropdown {
    <#
    .SYNOPSIS
        Adds a dropdown/combo field.
    #>
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder,
        [Parameter(Mandatory = $true)]
        [string]$Name,
        [string]$Title = "",
        [string]$Value = "",
        [Parameter(Mandatory = $true)]
        [System.Collections.IDictionary]$Options,
        [System.Collections.IDictionary]$OptionTooltips = $null,
        [string]$Tooltip = "",
        [switch]$Mandatory,
        [string]$Tab = "",
        [int]$Columns = 0,
        [int]$GroupId = 0,
        [int]$ParentGroupId = 0,
        [string]$HideOnValue = "",
        [string]$ShowOnValue = ""
    )

    return Add-DialogField @PSBoundParameters -Editor "combo"
}

function Add-RadioButtons {
    <#
    .SYNOPSIS
        Adds radio button field.
    #>
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder,
        [Parameter(Mandatory = $true)]
        [string]$Name,
        [string]$Title = "",
        [object]$Value = $null,
        [Parameter(Mandatory = $true)]
        [System.Collections.IDictionary]$Options,
        [string]$Tooltip = "",
        [string]$Tab = "",
        [int]$GroupId = 0,
        [int]$ParentGroupId = 0,
        [string]$HideOnValue = "",
        [string]$ShowOnValue = ""
    )

    return Add-DialogField @PSBoundParameters -Editor "radio"
}

function Add-Checklist {
    <#
    .SYNOPSIS
        Adds a checklist field for multiple selections.
    #>
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder,
        [Parameter(Mandatory = $true)]
        [string]$Name,
        [string]$Title = "",
        [array]$Value = @(),
        [Parameter(Mandatory = $true)]
        [System.Collections.IDictionary]$Options,
        [string]$Tooltip = "",
        [string]$Tab = "",
        [int]$Columns = 0,
        [int]$GroupId = 0,
        [int]$ParentGroupId = 0,
        [string]$HideOnValue = "",
        [string]$ShowOnValue = ""
    )

    return Add-DialogField @PSBoundParameters -Editor "checklist"
}

function Add-UserPicker {
    <#
    .SYNOPSIS
        Adds a user picker field.
    #>
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder,
        [Parameter(Mandatory = $true)]
        [string]$Name,
        [string]$Title = "",
        [string]$Value = "",
        [string]$Tooltip = "",
        [switch]$Multiple,
        [string]$Tab = "",
        [int]$Columns = 0,
        [int]$GroupId = 0,
        [int]$ParentGroupId = 0,
        [string]$HideOnValue = "",
        [string]$ShowOnValue = ""
    )

    $editor = if ($Multiple) { "user multiple" } else { "user" }

    # Remove Multiple from bound parameters
    $PSBoundParameters.Remove("Multiple") > $null

    return Add-DialogField @PSBoundParameters -Editor $editor
}

function Add-RolePicker {
    <#
    .SYNOPSIS
        Adds a role picker field.
    #>
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder,
        [Parameter(Mandatory = $true)]
        [string]$Name,
        [string]$Title = "",
        [string]$Value = "",
        [string]$Domain = "sitecore",
        [string]$Tooltip = "",
        [switch]$Multiple,
        [string]$Tab = "",
        [int]$Columns = 0,
        [int]$GroupId = 0,
        [int]$ParentGroupId = 0,
        [string]$HideOnValue = "",
        [string]$ShowOnValue = ""
    )

    $editor = if ($Multiple) { "role multiple" } else { "role" }

    # Remove Multiple from bound parameters
    $PSBoundParameters.Remove("Multiple") > $null

    return Add-DialogField @PSBoundParameters -Editor $editor
}

function Add-UserRolePicker {
    <#
    .SYNOPSIS
        Adds a combined user and role picker field.
    #>
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder,
        [Parameter(Mandatory = $true)]
        [string]$Name,
        [string]$Title = "",
        [string]$Value = "",
        [string]$Domain = "sitecore",
        [string]$Tooltip = "",
        [switch]$Multiple,
        [string]$Tab = "",
        [int]$Columns = 0,
        [int]$GroupId = 0,
        [int]$ParentGroupId = 0,
        [string]$HideOnValue = "",
        [string]$ShowOnValue = ""
    )

    $editor = if ($Multiple) { "user role multiple" } else { "user role" }

    # Remove Multiple from bound parameters
    $PSBoundParameters.Remove("Multiple") > $null

    return Add-DialogField @PSBoundParameters -Editor $editor
}

function Add-InfoText {
    <#
    .SYNOPSIS
        Adds read-only informational text.
    #>
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder,
        [Parameter(Mandatory = $true)]
        [string]$Name,
        [string]$Title = "",
        [string]$Value = "",
        [string]$Tab = "",
        [int]$Columns = 0,
        [int]$GroupId = 0,
        [int]$ParentGroupId = 0,
        [string]$HideOnValue = "",
        [string]$ShowOnValue = ""
    )

    return Add-DialogField @PSBoundParameters -Editor "info"
}

function Add-Marquee {
    <#
    .SYNOPSIS
        Adds a scrolling marquee text display.
    #>
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder,
        [Parameter(Mandatory = $true)]
        [string]$Name,
        [string]$Title = "",
        [string]$Value = "",
        [string]$Tab = "",
        [int]$Columns = 0,
        [int]$GroupId = 0,
        [int]$ParentGroupId = 0,
        [string]$HideOnValue = "",
        [string]$ShowOnValue = ""
    )

    return Add-DialogField @PSBoundParameters -Editor "marquee"
}

function Add-TreeList {
    <#
    .SYNOPSIS
        Adds a tree list control for multi-item selection with tree view.

    .DESCRIPTION
        The TreeList control allows users to select multiple items from a hierarchical tree structure.
        Selected items are returned as an array of Sitecore items.

    .PARAMETER WithSearch
        When specified, uses "treelist search" editor which includes a search box for filtering items.
        Best for large datasets (100+ items).
    #>
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder,
        [Parameter(Mandatory = $true)]
        [string]$Name,
        [string]$Title = "",
        [array]$Value = @(),
        [string]$Root = "/sitecore/content/",
        [string]$Source = "",
        [string]$Tooltip = "",
        [switch]$Mandatory,
        [switch]$WithSearch,
        [string]$Tab = "",
        [int]$Columns = 0,
        [int]$GroupId = 0,
        [int]$ParentGroupId = 0,
        [string]$HideOnValue = "",
        [string]$ShowOnValue = ""
    )

    $editor = if ($WithSearch.IsPresent) { "treelist search" } else { "treelist" }

    # Remove WithSearch from parameters before passing to Add-DialogField
    $params = $PSBoundParameters
    $params.Remove('WithSearch') | Out-Null

    return Add-DialogField @params -Editor $editor
}

function Add-MultiList {
    <#
    .SYNOPSIS
        Adds a multi-list control for selecting multiple items from a list.

    .DESCRIPTION
        The MultiList control provides a dual-list interface where users can move items
        between available and selected lists. Returns an array of Sitecore items.

    .PARAMETER WithSearch
        When specified, uses "multilist search" editor which includes a search box for filtering items.
        Best for large datasets (100+ items).
    #>
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder,
        [Parameter(Mandatory = $true)]
        [string]$Name,
        [string]$Title = "",
        [array]$Value = @(),
        [string]$Root = "/sitecore/content/",
        [string]$Source = "",
        [string]$Tooltip = "",
        [switch]$Mandatory,
        [switch]$WithSearch,
        [string]$Tab = "",
        [int]$Columns = 0,
        [int]$GroupId = 0,
        [int]$ParentGroupId = 0,
        [string]$HideOnValue = "",
        [string]$ShowOnValue = ""
    )

    $editor = if ($WithSearch.IsPresent) { "multilist search" } else { "multilist" }

    # Remove WithSearch from parameters before passing to Add-DialogField
    $params = $PSBoundParameters
    $params.Remove('WithSearch') | Out-Null

    return Add-DialogField @params -Editor $editor
}

function Add-LinkField {
    <#
    .SYNOPSIS
        Adds a link/URL input field.

    .DESCRIPTION
        Provides a text field optimized for entering URLs and links.
        Supports both internal Sitecore links and external URLs.
    #>
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder,
        [Parameter(Mandatory = $true)]
        [string]$Name,
        [string]$Title = "",
        [string]$Value = "",
        [string]$Tooltip = "",
        [string]$Placeholder = "",
        [switch]$Mandatory,
        [string]$Tab = "",
        [int]$Columns = 0,
        [int]$GroupId = 0,
        [int]$ParentGroupId = 0,
        [string]$HideOnValue = "",
        [string]$ShowOnValue = ""
    )

    return Add-DialogField @PSBoundParameters -Editor "link"
}

function Add-TristateCheckbox {
    <#
    .SYNOPSIS
        Adds a three-state checkbox (Yes/No/Not Set).

    .DESCRIPTION
        Provides a checkbox with three states: checked, unchecked, and indeterminate.
        Useful for nullable boolean values or optional settings.
        Returns: 1 (checked), 0 (unchecked), or null (indeterminate).
    #>
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder,
        [Parameter(Mandatory = $true)]
        [string]$Name,
        [string]$Title = "",
        [object]$Value = $null,
        [string]$Tooltip = "",
        [switch]$Mandatory,
        [string]$Tab = "",
        [int]$Columns = 0,
        [int]$GroupId = 0,
        [int]$ParentGroupId = 0,
        [string]$HideOnValue = "",
        [string]$ShowOnValue = ""
    )

    return Add-DialogField @PSBoundParameters -Editor "tristate"
}

function Add-RuleField {
    <#
    .SYNOPSIS
        Adds a Sitecore rules engine editor.

    .DESCRIPTION
        Provides a visual interface for editing Sitecore conditional rules.
        Commonly used for personalization, workflow, and conditional rendering rules.
        Returns the rules as an XML string in Sitecore rule format.

    .PARAMETER Source
        The rules context path (e.g., "Rules.ConditionalRenderings" or custom rule definitions).
    #>
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder,
        [Parameter(Mandatory = $true)]
        [string]$Name,
        [string]$Title = "",
        [string]$Value = "",
        [string]$Tooltip = "",
        [string]$Source = "",
        [switch]$Mandatory,
        [string]$Tab = "",
        [int]$Columns = 0,
        [int]$GroupId = 0,
        [int]$ParentGroupId = 0,
        [string]$HideOnValue = "",
        [string]$ShowOnValue = ""
    )

    return Add-DialogField @PSBoundParameters -Editor "rule"
}

function Add-RuleActionField {
    <#
    .SYNOPSIS
        Adds a Sitecore rule action editor.

    .DESCRIPTION
        Provides a visual interface for editing Sitecore rule actions.
        Used for configuring actions to be executed when rules are triggered.
        Returns the actions as an XML string in Sitecore rule format.

    .PARAMETER Source
        The rule actions context path (e.g., action definitions in the rules engine).
    #>
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder,
        [Parameter(Mandatory = $true)]
        [string]$Name,
        [string]$Title = "",
        [string]$Value = "",
        [string]$Tooltip = "",
        [string]$Source = "",
        [switch]$Mandatory,
        [string]$Tab = "",
        [int]$Columns = 0,
        [int]$GroupId = 0,
        [int]$ParentGroupId = 0,
        [string]$HideOnValue = "",
        [string]$ShowOnValue = ""
    )

    return Add-DialogField @PSBoundParameters -Editor "rule action"
}

# Helper utility functions

function Test-DialogBuilder {
    <#
    .SYNOPSIS
        Validates a dialog builder configuration without showing the dialog.

    .DESCRIPTION
        Checks for common configuration issues such as:
        - Duplicate field names
        - Invalid conditional visibility chains
        - Orphaned ParentGroupIds
        - Missing required parameters
        - Performance concerns (too many fields)

    .PARAMETER DialogBuilder
        The dialog builder instance to validate.

    .PARAMETER WarningsOnly
        Only show warnings, don't throw errors for critical issues.

    .EXAMPLE
        $dialog = New-DialogBuilder -Title "Test"
        Test-DialogBuilder -DialogBuilder $dialog

    .RETURNS
        $true if validation passes, $false otherwise.
    #>
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder,

        [switch]$WarningsOnly
    )

    $hasErrors = $false
    $hasWarnings = $false

    # Validate DialogBuilder structure
    if (-not $DialogBuilder.ContainsKey('Parameters') -or -not $DialogBuilder.ContainsKey('_Variables')) {
        Write-Error "Invalid DialogBuilder object. Did you create it with New-DialogBuilder?"
        return $false
    }

    Write-Host "Validating dialog: $($DialogBuilder.Title)" -ForegroundColor Cyan
    Write-Host ""

    # Check for fields
    if ($DialogBuilder.Parameters.Count -eq 0) {
        Write-Warning "Dialog has no fields defined."
        $hasWarnings = $true
    }

    # Check for too many fields (performance)
    if ($DialogBuilder.Parameters.Count -gt 50) {
        Write-Warning "Dialog has $($DialogBuilder.Parameters.Count) fields. Consider splitting into multiple dialogs or tabs for better performance."
        $hasWarnings = $true
    }

    # Check for duplicate field names
    $fieldNames = @{}
    foreach ($param in $DialogBuilder.Parameters) {
        if ($fieldNames.ContainsKey($param.Name)) {
            Write-Error "Duplicate field name detected: '$($param.Name)'"
            $hasErrors = $true
        }
        $fieldNames[$param.Name] = $true
    }

    # Check conditional visibility configuration
    $groupIds = @{}
    foreach ($param in $DialogBuilder.Parameters) {
        if ($param.ContainsKey('GroupId') -and $param.GroupId -gt 0) {
            $groupIds[$param.GroupId] = $param.Name
        }
    }

    # Validate ParentGroupId references
    foreach ($param in $DialogBuilder.Parameters) {
        if ($param.ContainsKey('ParentGroupId') -and $param.ParentGroupId -gt 0) {
            if (-not $groupIds.ContainsKey($param.ParentGroupId)) {
                Write-Error "Field '$($param.Name)' references ParentGroupId $($param.ParentGroupId) but no field defines this GroupId."
                $hasErrors = $true
            }

            # Check that HideOnValue or ShowOnValue is specified
            if (([string]::IsNullOrEmpty($param.HideOnValue) -and [string]::IsNullOrEmpty($param.ShowOnValue))) {
                Write-Warning "Field '$($param.Name)' has ParentGroupId but no HideOnValue or ShowOnValue specified."
                $hasWarnings = $true
            }
        }
    }

    # Check for mandatory fields without editors that support it
    foreach ($param in $DialogBuilder.Parameters) {
        if ($param.ContainsKey('Mandatory') -and $param.Mandatory) {
            $editor = if ($param.ContainsKey('Editor')) { $param.Editor } else { "auto" }
            if ($editor -eq "info" -or $editor -eq "marquee") {
                Write-Warning "Field '$($param.Name)' is marked Mandatory but uses editor '$editor' which doesn't support validation."
                $hasWarnings = $true
            }
        }
    }

    # Summary
    Write-Host ""
    if ($hasErrors) {
        Write-Host "Validation FAILED with errors." -ForegroundColor Red
        if (-not $WarningsOnly) {
            return $false
        }
    } elseif ($hasWarnings) {
        Write-Host "Validation completed with warnings." -ForegroundColor Yellow
    } else {
        Write-Host "Validation PASSED." -ForegroundColor Green
    }

    return -not $hasErrors
}

function Copy-DialogBuilder {
    <#
    .SYNOPSIS
        Creates a deep copy of a dialog builder instance.

    .DESCRIPTION
        Useful for creating variations of a dialog configuration without
        modifying the original. All parameters and settings are cloned.

    .PARAMETER DialogBuilder
        The dialog builder instance to copy.

    .EXAMPLE
        $dialog1 = New-DialogBuilder -Title "Original"
        $dialog2 = Copy-DialogBuilder -DialogBuilder $dialog1

    .RETURNS
        A new dialog builder instance with copied configuration.
    #>
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder
    )

    # Validate DialogBuilder structure
    if (-not $DialogBuilder.ContainsKey('Parameters') -or -not $DialogBuilder.ContainsKey('_Variables')) {
        throw "Invalid DialogBuilder object. Did you create it with New-DialogBuilder?"
    }

    # Create new builder with same properties
    $newBuilder = @{
        Title = $DialogBuilder.Title
        Description = $DialogBuilder.Description
        Width = $DialogBuilder.Width
        Height = $DialogBuilder.Height
        OkButtonName = $DialogBuilder.OkButtonName
        CancelButtonName = $DialogBuilder.CancelButtonName
        ShowHints = $DialogBuilder.ShowHints
        Icon = $DialogBuilder.Icon
        Parameters = @()
        _Variables = @{}
    }

    # Deep copy parameters
    foreach ($param in $DialogBuilder.Parameters) {
        $newParam = @{}
        foreach ($key in $param.Keys) {
            $newParam[$key] = $param[$key]
        }
        $newBuilder.Parameters += $newParam
    }

    # Copy variables
    foreach ($key in $DialogBuilder._Variables.Keys) {
        $newBuilder._Variables[$key] = $DialogBuilder._Variables[$key]
    }

    return $newBuilder
}

function Remove-DialogField {
    <#
    .SYNOPSIS
        Removes a field from the dialog builder by name.

    .DESCRIPTION
        Allows removal of previously added fields from the dialog configuration.
        This is useful when building dialogs dynamically based on conditions.

    .PARAMETER DialogBuilder
        The dialog builder instance.

    .PARAMETER Name
        The name of the field to remove.

    .EXAMPLE
        $dialog | Remove-DialogField -Name "optionalField"

    .RETURNS
        The dialog builder instance (for chaining).
    #>
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder,

        [Parameter(Mandatory = $true)]
        [string]$Name
    )

    # Validate DialogBuilder structure
    if (-not $DialogBuilder.ContainsKey('Parameters') -or -not $DialogBuilder.ContainsKey('_Variables')) {
        throw "Invalid DialogBuilder object. Did you create it with New-DialogBuilder?"
    }

    # Remove from Parameters array
    $DialogBuilder.Parameters = @($DialogBuilder.Parameters | Where-Object { $_.Name -ne $Name })

    # Remove from _Variables
    if ($DialogBuilder._Variables.ContainsKey($Name)) {
        $DialogBuilder._Variables.Remove($Name)
    }

    return $DialogBuilder
}

function Export-DialogBuilderConfig {
    <#
    .SYNOPSIS
        Exports dialog builder configuration to JSON format.

    .DESCRIPTION
        Exports the dialog structure to JSON for documentation, debugging,
        or sharing dialog configurations. The exported JSON can be used
        for analysis or regenerating dialogs.

    .PARAMETER DialogBuilder
        The dialog builder instance to export.

    .PARAMETER FilePath
        Optional file path to save the JSON. If not specified, returns JSON string.

    .EXAMPLE
        $json = Export-DialogBuilderConfig -DialogBuilder $dialog
        $json | Out-File "dialog-config.json"

    .EXAMPLE
        Export-DialogBuilderConfig -DialogBuilder $dialog -FilePath "C:\temp\dialog.json"
    #>
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [hashtable]$DialogBuilder,

        [string]$FilePath = ""
    )

    # Validate DialogBuilder structure
    if (-not $DialogBuilder.ContainsKey('Parameters') -or -not $DialogBuilder.ContainsKey('_Variables')) {
        throw "Invalid DialogBuilder object. Did you create it with New-DialogBuilder?"
    }

    # Create exportable structure (remove internal _Variables)
    $exportObj = @{
        Title = $DialogBuilder.Title
        Description = $DialogBuilder.Description
        Width = $DialogBuilder.Width
        Height = $DialogBuilder.Height
        OkButtonName = $DialogBuilder.OkButtonName
        CancelButtonName = $DialogBuilder.CancelButtonName
        ShowHints = $DialogBuilder.ShowHints
        Icon = $DialogBuilder.Icon
        Parameters = $DialogBuilder.Parameters
    }

    $json = $exportObj | ConvertTo-Json -Depth 10

    if (-not [string]::IsNullOrEmpty($FilePath)) {
        $json | Out-File -FilePath $FilePath -Encoding UTF8
        Write-Host "Dialog configuration exported to: $FilePath" -ForegroundColor Green
    }

    return $json
}

Usage Examples

Basic text controls

$dialog = New-DialogBuilder -Title "Basic Text Controls" -Description "Examples of text input fields available in SPE dialogs." -Width 500 -Height 400 -OkButtonName "Submit" -ShowHints |
    Add-TextField -Name "singleLineText" -Title "Single Line Text" -Tooltip "A simple single-line text input" -Placeholder "Enter text here..." |
    Add-MultiLineTextField -Name "multiLineText" -Title "Multi-Line Text" -Lines 3 -Tooltip "A multi-line text area for longer content" -Placeholder "Enter multiple lines of text..." |
    Add-TextField -Name "passwordField" -Title "Password" -Tooltip "Password input - characters are masked" -Placeholder "Enter password..." -IsPassword

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    Write-Host "Single Line Text: $singleLineText" -ForegroundColor Green
    Write-Host "Multi-Line Text: $multiLineText" -ForegroundColor Green
    Write-Host "Password: $passwordField" -ForegroundColor Green
}

Number controls

$dialog = New-DialogBuilder -Title "Number Input Controls" -Description "Examples of numeric input fields." -Width 400 -Height 300 -OkButtonName "Submit" -ShowHints |
    Add-TextField -Name "integerValue" -Title "Integer Value" -Value 100 -IsNumber -Tooltip "Enter a whole number" -Columns 6 |
    Add-TextField -Name "floatValue" -Title "Decimal Value" -Value 1.5 -IsNumber -Tooltip "Enter a decimal number" -Columns 6

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    Write-Host "Integer Value: $integerValue" -ForegroundColor Green
    Write-Host "Float Value: $floatValue" -ForegroundColor Green

    # Demonstrate the returned types
    Write-Host "`nReturned Types:" -ForegroundColor Cyan
    Write-Host "Integer Type: $($integerValue.GetType().Name)"
    Write-Host "Float Type: $($floatValue.GetType().Name)"
}

Checkbox control

$dialog = New-DialogBuilder -Title "Checkbox Control" -Description "Example of checkbox input that returns a boolean value." -Width 400 -Height 250 -OkButtonName "Submit" -ShowHints |
    Add-Checkbox -Name "enableFeature" -Title "Enable Feature" -Value $true -Tooltip "Check to enable, uncheck to disable" |
    Add-Checkbox -Name "includeSubitems" -Title "Include Subitems" -Value $false -Tooltip "Process child items as well" |
    Add-Checkbox -Name "publishAfterSave" -Title "Publish After Save" -Value $false -Tooltip "Automatically publish changes"

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    Write-Host "Enable Feature: $enableFeature" -ForegroundColor Green
    Write-Host "Include Subitems: $includeSubitems" -ForegroundColor Green
    Write-Host "Publish After Save: $publishAfterSave" -ForegroundColor Green

    # Example conditional logic based on checkbox values
    if ($enableFeature) {
        Write-Host "`nFeature is enabled!" -ForegroundColor Cyan
    }
}

Dropdown combo controls

# Define options as an ordered hashtable
$priorityOptions = [ordered]@{
    "Low" = "1"
    "Medium" = "2"
    "High" = "3"
    "Critical" = "4"
}

$actionOptions = [ordered]@{
    "Create" = "create"
    "Update" = "update"
    "Delete" = "delete"
    "Archive" = "archive"
}

$actionTooltips = [ordered]@{
    "create" = "Create a new item in Sitecore"
    "update" = "Modify an existing item"
    "delete" = "Remove the item permanently"
    "archive" = "Move the item to archive"
}

$dialog = New-DialogBuilder -Title "Dropdown Controls" -Description "Examples of combo/dropdown selection controls." -Width 450 -Height 350 -OkButtonName "Submit" -ShowHints |
    Add-Dropdown -Name "selectedPriority" -Title "Priority Level" -Value "2" -Options $priorityOptions -Tooltip "Select the priority for this task" |
    Add-Dropdown -Name "selectedAction" -Title "Action Type" -Value "update" -Options $actionOptions -OptionTooltips $actionTooltips -Tooltip "Choose the action to perform"

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    Write-Host "Selected Priority: $selectedPriority" -ForegroundColor Green
    Write-Host "Selected Action: $selectedAction" -ForegroundColor Green
}

Checklist control

# Define options with bitmask values
$daysOfWeek = [ordered]@{
    "Monday" = 1
    "Tuesday" = 2
    "Wednesday" = 4
    "Thursday" = 8
    "Friday" = 16
    "Saturday" = 32
    "Sunday" = 64
}

$languageOptions = [ordered]@{
    "English" = 1
    "German" = 2
    "French" = 4
    "Spanish" = 8
    "Japanese" = 16
}

# Pre-select some items
$selectedDays = @(1, 4, 16)  # Monday, Wednesday, Friday
$selectedLanguages = @(1)  # English

$dialog = New-DialogBuilder -Title "Checklist Controls" -Description "Select multiple options using checklists." -Width 450 -Height 450 -OkButtonName "Submit" -ShowHints |
    Add-Checklist -Name "selectedDays" -Title "Days of the Week" -Value $selectedDays -Options $daysOfWeek -Tooltip "Select which days to run the scheduled task" |
    Add-Checklist -Name "selectedLanguages" -Title "Target Languages" -Value $selectedLanguages -Options $languageOptions -Tooltip "Select languages for content translation"

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    Write-Host "Selected Days (values): $($selectedDays -join ', ')" -ForegroundColor Green
    Write-Host "Selected Languages (values): $($selectedLanguages -join ', ')" -ForegroundColor Green

    # Map values back to display names
    Write-Host "`nSelected Day Names:" -ForegroundColor Cyan
    foreach ($day in $daysOfWeek.GetEnumerator()) {
        if ($selectedDays -contains $day.Value) {
            Write-Host "  - $($day.Key)"
        }
    }
}

Radio button control

# Define options for radio buttons
$publishMode = [ordered]@{
    "Smart Publish" = 1
    "Incremental Publish" = 2
    "Full Republish" = 3
}

$targetDatabase = [ordered]@{
    "Web" = "web"
    "Preview" = "preview"
    "Staging" = "staging"
}

# Pre-select an option
$selectedPublishMode = 1
$selectedDatabase = "web"

$dialog = New-DialogBuilder -Title "Radio Button Controls" -Description "Select exactly one option from each group." -Width 450 -Height 400 -OkButtonName "Submit" -ShowHints |
    Add-RadioButtons -Name "selectedPublishMode" -Title "Publish Mode" -Value $selectedPublishMode -Options $publishMode -Tooltip "Choose how content should be published" |
    Add-RadioButtons -Name "selectedDatabase" -Title "Target Database" -Value $selectedDatabase -Options $targetDatabase -Tooltip "Select the destination database"

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    Write-Host "Selected Publish Mode: $selectedPublishMode" -ForegroundColor Green
    Write-Host "Selected Database: $selectedDatabase" -ForegroundColor Green

    # Use the selection in logic
    switch ($selectedPublishMode) {
        1 { Write-Host "`nPerforming Smart Publish..." -ForegroundColor Cyan }
        2 { Write-Host "`nPerforming Incremental Publish..." -ForegroundColor Cyan }
        3 { Write-Host "`nPerforming Full Republish..." -ForegroundColor Cyan }
    }
}

Date Time control

# Set default values
$startDateTime = [System.DateTime]::Now.AddDays(-7)
$endDateTime = [System.DateTime]::Now
$publishDate = [System.DateTime]::Now.AddDays(1)

$dialog = New-DialogBuilder -Title "Date and Time Controls" -Description "Select dates and times for your operation." -Width 500 -Height 400 -OkButtonName "Submit" -ShowHints |
    Add-DateTimePicker -Name "startDateTime" -Title "Start Date/Time" -Value $startDateTime -Tooltip "Select the starting date and time" |
    Add-DateTimePicker -Name "endDateTime" -Title "End Date/Time" -Value $endDateTime -Tooltip "Select the ending date and time" |
    Add-DateTimePicker -Name "publishDate" -Title "Publish Date (Date Only)" -Value $publishDate -Tooltip "Select the date for publishing" -DateOnly

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    Write-Host "Date/Time Controls return System.DateTime objects:" -ForegroundColor Cyan
    Write-Host ""

    Write-Host "Start DateTime: $startDateTime" -ForegroundColor Green
    Write-Host "  Type: $($startDateTime.GetType().FullName)"
    Write-Host ""

    Write-Host "End DateTime: $endDateTime" -ForegroundColor Green
    Write-Host "  Type: $($endDateTime.GetType().FullName)"
    Write-Host ""

    Write-Host "Publish Date: $publishDate" -ForegroundColor Green
    Write-Host "  Type: $($publishDate.GetType().FullName)"
    Write-Host ""

    # Calculate duration
    $duration = $endDateTime - $startDateTime
    Write-Host "Duration: $($duration.Days) days, $($duration.Hours) hours" -ForegroundColor Yellow
}

Single item picker with a tree

$dialog = New-DialogBuilder -Title "Single Item Picker" -Description "Select a single item from the content tree." -Width 500 -Height 350 -OkButtonName "Select" -ShowHints |
    Add-ItemPicker -Name "selectedItem" -Title "Select Content Item" -Root "/sitecore/content/" -Value (Get-Item "master:\content\Home") -Tooltip "Browse and select an item from the content tree" |
    Add-ItemPicker -Name "templateItem" -Title "Select Template" -Root "/sitecore/templates/" -Value (Get-Item "master:\templates\System\Templates\Template") -Tooltip "Browse and select a template"

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    Write-Host "Item Picker returns Sitecore Item objects:" -ForegroundColor Cyan
    Write-Host ""

    if ($selectedItem) {
        Write-Host "Selected Content Item:" -ForegroundColor Green
        Write-Host "  Name: $($selectedItem.Name)"
        Write-Host "  Path: $($selectedItem.ItemPath)"
        Write-Host "  ID: $($selectedItem.ID)"
        Write-Host "  Template: $($selectedItem.TemplateName)"
    } else {
        Write-Host "No content item selected" -ForegroundColor Yellow
    }

    Write-Host ""

    if ($templateItem) {
        Write-Host "Selected Template:" -ForegroundColor Green
        Write-Host "  Name: $($templateItem.Name)"
        Write-Host "  Path: $($templateItem.ItemPath)"
        Write-Host "  ID: $($templateItem.ID)"
    } else {
        Write-Host "No template selected" -ForegroundColor Yellow
    }
}

Dropdown item selection controls

# Source parameters for different item types
$templateSource = "DataSource=/sitecore/templates/sample&DatabaseName=master&IncludeTemplatesForDisplay=Template Folder,Template&IncludeTemplatesForSelection=Template"
$contentSource = "DataSource=/sitecore/content/home"
$mediaSource = "StartSearchLocation=/sitecore/media library/Images"

$dialog = New-DialogBuilder -Title "Dropdown Item Selection" -Description "Select items using compact dropdown controls." -Width 600 -Height 400 -OkButtonName "Select" -ShowHints |
    Add-Droplink -Name "selectedTemplate" -Title "Template (Droplink)" -Source $templateSource -Tooltip "Flat dropdown list - returns Item object" |
    Add-Droptree -Name "selectedMedia" -Title "Media Item (Droptree)" -Source $mediaSource -Tooltip "Tree dropdown - returns Item object" |
    Add-Droplist -Name "selectedContentPath" -Title "Content Path (Droplist)" -Source $contentSource -Tooltip "Flat dropdown list - returns string"

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    Write-Host "Dropdown Controls:" -ForegroundColor Cyan
    Write-Host ""

    # Droplink returns Item object
    Write-Host "Droplink (returns Item):" -ForegroundColor Green
    if ($selectedTemplate) {
        Write-Host "  Name: $($selectedTemplate.Name)"
        Write-Host "  Path: $($selectedTemplate.ItemPath)"
        Write-Host "  ID: $($selectedTemplate.ID)"
        Write-Host "  Type: $($selectedTemplate.GetType().Name)"
    } else {
        Write-Host "  (none selected)" -ForegroundColor Yellow
    }

    Write-Host ""

    # Droptree returns Item object
    Write-Host "Droptree (returns Item):" -ForegroundColor Green
    if ($selectedMedia) {
        Write-Host "  Name: $($selectedMedia.Name)"
        Write-Host "  Path: $($selectedMedia.ItemPath)"
        Write-Host "  ID: $($selectedMedia.ID)"
        Write-Host "  Type: $($selectedMedia.GetType().Name)"
    } else {
        Write-Host "  (none selected)" -ForegroundColor Yellow
    }

    Write-Host ""

    # Droplist returns String
    Write-Host "Droplist (returns String):" -ForegroundColor Green
    if ($selectedContentPath) {
        Write-Host "  Value: $selectedContentPath"
        Write-Host "  Type: $($selectedContentPath.GetType().Name)"
    } else {
        Write-Host "  (none selected)" -ForegroundColor Yellow
    }
}

<#
    DROPDOWN ITEM SELECTION CONTROLS:

    Three dropdown-based controls for compact item selection:

    - Droplink: Flat dropdown list, returns Item object
    - Droptree: Dropdown with tree navigation, returns Item object
    - Droplist: Flat dropdown list, returns string (path/ID)

    Use these when you want a more compact interface than the full item picker tree.
    They work well for selecting from a limited set of items or when screen space is limited.

    Source Parameter Formats:
    - DataSource: DataSource=/path&DatabaseName=master&IncludeTemplatesForDisplay=<templates>&IncludeTemplatesForSelection=<templates>
    - StartSearchLocation: StartSearchLocation=/sitecore/content/home
#>

Grouped dropdown controls

# Source parameter controls what items are displayed
$templateSource = "DataSource=/sitecore/templates&DatabaseName=master&IncludeTemplatesForDisplay=Node,Folder,Template,Template Folder&IncludeTemplatesForSelection=Template"
$contentSource = "DataSource=/sitecore/content&DatabaseName=master&IncludeTemplatesForDisplay=Folder&IncludeTemplatesForSelection=Folder"

$dialog = New-DialogBuilder -Title "Grouped Dropdown Controls" -Description "Select items from grouped dropdown lists." -Width 550 -Height 350 -OkButtonName "Select" -ShowHints |
    Add-GroupedDroplink -Name "selectedTemplate" -Title "Grouped Droplink (Returns Item)" -Source $templateSource -Tooltip "Items grouped by folder - returns Item object" |
    Add-GroupedDroplist -Name "selectedContentPath" -Title "Grouped Droplist (Returns String)" -Source $contentSource -Tooltip "Items grouped by folder - returns string value"

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    Write-Host "Grouped Dropdown Controls:" -ForegroundColor Cyan
    Write-Host ""

    # Grouped Droplink returns Item object
    Write-Host "Grouped Droplink (returns Item):" -ForegroundColor Green
    if ($selectedTemplate) {
        Write-Host "  Name: $($selectedTemplate.Name)"
        Write-Host "  Path: $($selectedTemplate.ItemPath)"
        Write-Host "  ID: $($selectedTemplate.ID)"
        Write-Host "  Type: $($selectedTemplate.GetType().Name)"
    } else {
        Write-Host "  (none selected)" -ForegroundColor Yellow
    }

    Write-Host ""

    # Grouped Droplist returns String
    Write-Host "Grouped Droplist (returns String):" -ForegroundColor Green
    if ($selectedContentPath) {
        Write-Host "  Value: $selectedContentPath"
        Write-Host "  Type: $($selectedContentPath.GetType().Name)"
    } else {
        Write-Host "  (none selected)" -ForegroundColor Yellow
    }
}

<#
    GROUPED DROPDOWNS:

    These are the grouped UI variants of droplink and droplist controls.
    They have identical functionality but display items organized by their
    parent folders instead of a flat list - making navigation easier for large item sets.

    Relationship to standard controls:
    - groupeddroplink = droplink with grouped UI (returns Item object)
    - groupeddroplist = droplist with grouped UI (returns string)

    Key Difference between grouped variants:
    - groupeddroplink: Returns the actual Sitecore Item object
    - groupeddroplist: Returns a string representation

    Use groupeddroplink when you need to work with the Item object.
    Use groupeddroplist when you only need the item's path or ID.

    Source Parameter Format:
    DataSource=/path/to/items&DatabaseName=master&IncludeTemplatesForDisplay=<templates>&IncludeTemplatesForSelection=<templates>
#>

User and role pickers

$dialog = New-DialogBuilder -Title "User and Role Pickers" -Description "Select users and roles for permission management." -Width 550 -Height 450 -OkButtonName "Select" -ShowHints |
    Add-UserPicker -Name "selectedUser" -Title "Select User(s)" -Multiple -Tooltip "Select one or more users" |
    Add-RolePicker -Name "selectedRole" -Title "Select Role(s)" -Multiple -Domain "sitecore" -Tooltip "Select one or more roles from the sitecore domain" |
    Add-UserRolePicker -Name "selectedUserOrRole" -Title "Select User(s) or Role(s)" -Multiple -Domain "sitecore" -Tooltip "Select any combination of users and roles"

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    Write-Host "User and Role Pickers return string values:" -ForegroundColor Cyan
    Write-Host ""

    Write-Host "Selected Users:" -ForegroundColor Green
    if ($selectedUser) {
        $selectedUser | ForEach-Object { Write-Host "  - $_" }
    } else {
        Write-Host "  (none selected)" -ForegroundColor Yellow
    }

    Write-Host ""
    Write-Host "Selected Roles:" -ForegroundColor Green
    if ($selectedRole) {
        $selectedRole | ForEach-Object { Write-Host "  - $_" }
    } else {
        Write-Host "  (none selected)" -ForegroundColor Yellow
    }

    Write-Host ""
    Write-Host "Selected Users or Roles:" -ForegroundColor Green
    if ($selectedUserOrRole) {
        $selectedUserOrRole | ForEach-Object { Write-Host "  - $_" }
    } else {
        Write-Host "  (none selected)" -ForegroundColor Yellow
    }
}

Info display controls

$dialog = New-DialogBuilder -Title "Information Display Controls" -Description "Display important information to users." -Width 550 -Height 400 -OkButtonName "Continue" -ShowHints |
    Add-Marquee -Name "marqueeMessage" -Title "Marquee - Scrolling Message" -Value "This is an important scrolling message that catches attention!" |
    Add-InfoText -Name "infoMessage" -Title "Info - Static Information" -Value "This is static informational text that provides context or instructions to the user. It does not scroll and is easier to read for longer messages." |
    Add-TextField -Name "userInput" -Title "Your Response" -Tooltip "Enter your response after reading the information above"

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    Write-Host "User acknowledged the information and provided:" -ForegroundColor Cyan
    Write-Host "Response: $userInput" -ForegroundColor Green
}

Tabbed dialog

$dialog = New-DialogBuilder -Title "Tabbed Dialog Example" -Description "Controls organized into logical tabs." -Width 600 -Height 500 -OkButtonName "Save" -ShowHints |
    Add-TextField -Name "itemName" -Title "Item Name" -Tooltip "Enter the name for the new item" -Placeholder "Enter name..." -Tab "General" |
    Add-TextField -Name "itemTitle" -Title "Display Title" -Tooltip "The title shown to users" -Placeholder "Enter title..." -Tab "General" |
    Add-MultiLineTextField -Name "description" -Title "Description" -Lines 3 -Tooltip "Describe this item" -Tab "General" |
    Add-Checkbox -Name "isActive" -Title "Active" -Value $true -Tooltip "Enable or disable this item" -Tab "Settings" |
    Add-TextField -Name "priority" -Title "Priority" -Value 100 -IsNumber -Tooltip "Sort order priority" -Tab "Settings" |
    Add-DateTimePicker -Name "publishDate" -Title "Publish Date" -Value ([DateTime]::Now) -Tooltip "When to publish" -Tab "Settings" |
    Add-ItemPicker -Name "template" -Title "Template" -Root "/sitecore/templates/" -Value (Get-Item "master:\templates\sample\sample item") -Tooltip "Select a template" -Tab "Advanced" |
    Add-UserPicker -Name "targetUser" -Title "Owner" -Tooltip "Select the owner" -Tab "Advanced"

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    Write-Host "Tabbed Dialog Results:" -ForegroundColor Cyan
    Write-Host ""

    Write-Host "General Tab:" -ForegroundColor Green
    Write-Host "  Item Name: $itemName"
    Write-Host "  Title: $itemTitle"
    Write-Host "  Description: $description"

    Write-Host ""
    Write-Host "Settings Tab:" -ForegroundColor Green
    Write-Host "  Active: $isActive"
    Write-Host "  Priority: $priority"
    Write-Host "  Publish Date: $publishDate"

    Write-Host ""
    Write-Host "Advanced Tab:" -ForegroundColor Green
    Write-Host "  Template: $($template.Name)"
    Write-Host "  Owner: $targetUser"
}

Conditional visibility

# Define options for the controlling dropdown
$modeOptions = [ordered]@{
    "Simple Mode" = "simple"
    "Advanced Mode" = "advanced"
    "Expert Mode" = "expert"
}

$dialog = New-DialogBuilder -Title "Conditional Visibility Example" -Description "Controls appear/disappear based on your selection." -Width 550 -Height 450 -OkButtonName "Continue" -ShowHints |
    Add-Checkbox -Name "showAdvanced" -Title "Show Advanced Options" -Value $true -Tooltip "Toggle to show/hide advanced options" -GroupId 1 |
    Add-TextField -Name "advancedOption1" -Title "Advanced Option 1" -Tooltip "This field shows when checkbox is checked" -ParentGroupId 1 -HideOnValue "0" |
    Add-TextField -Name "advancedOption2" -Title "Advanced Option 2" -Tooltip "This field also shows when checkbox is checked" -ParentGroupId 1 -HideOnValue "0" |
    Add-Dropdown -Name "operationMode" -Title "Operation Mode" -Value "simple" -Options $modeOptions -Tooltip "Select mode to see different options" -GroupId 2 |
    Add-TextField -Name "simpleField" -Title "Simple Mode Field" -Tooltip "Visible only in Simple Mode" -ParentGroupId 2 -ShowOnValue "simple" |
    Add-TextField -Name "advancedField" -Title "Advanced Mode Field" -Tooltip "Visible only in Advanced Mode" -ParentGroupId 2 -ShowOnValue "advanced" |
    Add-TextField -Name "expertField" -Title "Expert Mode Field" -Tooltip "Visible only in Expert Mode" -ParentGroupId 2 -ShowOnValue "expert"

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    Write-Host "Conditional Visibility Results:" -ForegroundColor Cyan
    Write-Host ""

    Write-Host "Show Advanced: $showAdvanced" -ForegroundColor Green
    if ($showAdvanced) {
        Write-Host "  Advanced Option 1: $advancedOption1"
        Write-Host "  Advanced Option 2: $advancedOption2"
    }

    Write-Host ""
    Write-Host "Operation Mode: $operationMode" -ForegroundColor Green
    switch ($operationMode) {
        "simple" { Write-Host "  Simple Field: $simpleField" }
        "advanced" { Write-Host "  Advanced Field: $advancedField" }
        "expert" { Write-Host "  Expert Field: $expertField" }
    }
}

Column layout

$dialog = New-DialogBuilder -Title "Column Layout Example" -Description "Controls arranged in a responsive grid layout." -Width 650 -Height 500 -OkButtonName "Save" -ShowHints |
    Add-TextField -Name "fullWidthField" -Title "Full Width Field (12 columns)" -Tooltip "This field spans the full width" |
    Add-TextField -Name "firstName" -Title "First Name" -Tooltip "Half width" -Columns 6 |
    Add-TextField -Name "lastName" -Title "Last Name" -Tooltip "Half width" -Columns 6 |
    Add-TextField -Name "city" -Title "City" -Tooltip "One third width" -Columns 4 |
    Add-TextField -Name "state" -Title "State" -Tooltip "One third width" -Columns 4 |
    Add-TextField -Name "zip" -Title "ZIP Code" -Tooltip "One third width" -Columns 4 |
    Add-TextField -Name "email" -Title "Email Address" -Tooltip "Two thirds width" -Columns 8 |
    Add-TextField -Name "extension" -Title "Ext" -Tooltip "One third width" -Columns 4 |
    Add-MultiLineTextField -Name "notes" -Title "Additional Notes" -Lines 2 -Tooltip "Main content area" -Columns 9 |
    Add-Checkbox -Name "isUrgent" -Title "Urgent" -Value $false -Tooltip "Mark as urgent" -Columns 3

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    Write-Host "Column Layout Results:" -ForegroundColor Cyan
    Write-Host ""
    Write-Host "Full Width: $fullWidthField" -ForegroundColor Green
    Write-Host "Name: $firstName $lastName" -ForegroundColor Green
    Write-Host "Location: $city, $state $zip" -ForegroundColor Green
    Write-Host "Email: $email (ext: $extension)" -ForegroundColor Green
    Write-Host "Notes: $notes" -ForegroundColor Green
    Write-Host "Urgent: $isUrgent" -ForegroundColor Green
}

Mandatory fields

$dialog = New-DialogBuilder -Title "Required Fields Example" -Description "Fields marked with * are required." -Width 500 -Height 400 -OkButtonName "Submit" -ShowHints |
    Add-TextField -Name "requiredField" -Title "Required Text Field" -Tooltip "This field must be filled in" -Placeholder "This field is required..." -Mandatory |
    Add-TextField -Name "optionalField" -Title "Optional Text Field" -Tooltip "This field is optional" -Placeholder "This field is optional..." |
    Add-TextField -Name "requiredNumber" -Title "Required Number" -Value 0 -IsNumber -Tooltip "A number must be entered" -Mandatory |
    Add-ItemPicker -Name "requiredItem" -Title "Required Item Selection" -Root "/sitecore/content/" -Value (Get-Item "master:\content\home") -Tooltip "An item must be selected" -Mandatory |
    Add-MultiLineTextField -Name "optionalMultiline" -Title "Optional Notes" -Lines 3 -Tooltip "Additional notes (optional)"

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    Write-Host "Form submitted successfully!" -ForegroundColor Cyan
    Write-Host ""
    Write-Host "Required Field: $requiredField" -ForegroundColor Green
    Write-Host "Optional Field: $optionalField" -ForegroundColor Green
    Write-Host "Required Number: $requiredNumber" -ForegroundColor Green

    if ($requiredItem) {
        Write-Host "Required Item: $($requiredItem.Name)" -ForegroundColor Green
    }

    Write-Host "Optional Notes: $optionalMultiline" -ForegroundColor Green
} else {
    Write-Host "Dialog was cancelled" -ForegroundColor Yellow
}

Dialog customization

$dialog = New-DialogBuilder -Title "Custom Dialog Example" -Description "This dialog demonstrates all available customization options for Read-Variable dialogs." -Icon "Office/32x32/coffee.png" -Width 550 -Height 400 -OkButtonName "Process Items" -CancelButtonName "Abort" -ShowHints |
    Add-TextField -Name "inputText" -Title "Sample Input" -Tooltip "This tooltip appears when ShowHints is enabled" -Placeholder "Enter something..." |
    Add-Checkbox -Name "confirm" -Title "I understand the implications" -Value $false -Tooltip "Check to confirm"

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    Write-Host "Dialog completed with custom settings!" -ForegroundColor Green
    Write-Host "Input: $inputText"
    Write-Host "Confirmed: $confirm"
} else {
    Write-Host "User clicked the custom cancel button" -ForegroundColor Yellow
}

Simple dialog

$dialog = New-DialogBuilder -Title "Simple Dialog Example" -Description "A straightforward dialog for quick data collection." -Width 500 -Height 450 -OkButtonName "Finish" |
    Add-TextField -Name "inputText" -Title "Single Line Text" -Value "Some Text" -Tooltip "Enter a single line of text" -Placeholder "Enter text here..." |
    Add-MultiLineTextField -Name "multiLineText" -Title "Multi Line Text" -Value "Multiple lines`nof text" -Lines 3 -Tooltip "Enter multiple lines" -Placeholder "Enter detailed text..." |
    Add-DateTimePicker -Name "startDate" -Title "Start Date" -Value ([System.DateTime]::Now.AddDays(-5)) -Tooltip "Select a start date" |
    Add-UserPicker -Name "selectedUser" -Title "Select User" -Multiple -Tooltip "Choose a user for this operation" |
    Add-ItemPicker -Name "targetItem" -Title "Target Item" -Root "/sitecore/content/" -Value (Get-Item "master:\content\home") -Tooltip "Select the target location"

$result = Show-Dialog -DialogBuilder $dialog

if ($result -ne "ok") {
    Write-Host "Operation cancelled by user" -ForegroundColor Yellow
    Exit
}

# Process the collected data
Write-Host "Dialog Results:" -ForegroundColor Cyan
Write-Host ""
Write-Host "Text: $inputText" -ForegroundColor Green
Write-Host "Multi-line: $multiLineText" -ForegroundColor Green
Write-Host "Start Date: $startDate" -ForegroundColor Green
Write-Host "User: $selectedUser" -ForegroundColor Green

if ($targetItem) {
    Write-Host "Target Item: $($targetItem.ItemPath)" -ForegroundColor Green
}

Comprehensive example

# Pre-define some default values
$publishModes = [ordered]@{
    "Smart Publish" = "smart"
    "Republish" = "republish"
    "Incremental" = "incremental"
}

$targetDatabases = [ordered]@{
    "Web" = 1
    "Preview" = 2
}

$languageOptions = [ordered]@{
    "English" = 1
    "German" = 2
    "French" = 4
    "Spanish" = 8
}

$selectedLanguages = @(1)  # English pre-selected

# Build the dialog
$dialog = New-DialogBuilder -Title "Content Publishing Wizard" -Description "Configure and execute content publishing operations." -Icon "Office/32x32/document_up.png" -Width 650 -Height 600 -OkButtonName "Publish" -ShowHints |
    Add-ItemPicker -Name "sourceItem" -Title "Source Item" -Root "/sitecore/content/" -Value (Get-Item "master:\content\home") -Tooltip "Select the root item to publish" -Tab "Source" -Mandatory |
    Add-Checkbox -Name "includeSubitems" -Title "Include Subitems" -Value $true -Tooltip "Publish all descendant items" -Tab "Source" -Columns 6 |
    Add-Checkbox -Name "includeRelated" -Title "Include Related Items" -Value $false -Tooltip "Also publish referenced items" -Tab "Source" -Columns 6 |
    Add-Checklist -Name "targetDbs" -Title "Target Databases" -Options $targetDatabases -Tooltip "Select destination databases" -Tab "Targets" |
    Add-Checklist -Name "selectedLanguages" -Title "Languages" -Value $selectedLanguages -Options $languageOptions -Tooltip "Select languages to publish" -Tab "Targets" |
    Add-RadioButtons -Name "publishMode" -Title "Publish Mode" -Value "smart" -Options $publishModes -Tooltip "Select publishing mode" -Tab "Options" |
    Add-Checkbox -Name "schedulePublish" -Title "Schedule for Later" -Value $false -Tooltip "Check to schedule publication" -Tab "Options" -GroupId 1 |
    Add-DateTimePicker -Name "scheduledTime" -Title "Scheduled Time" -Value ([DateTime]::Now.AddHours(1)) -Tooltip "When to publish" -Tab "Options" -ParentGroupId 1 -HideOnValue "0" |
    Add-Checkbox -Name "sendNotification" -Title "Send Notification" -Value $false -Tooltip "Notify users when complete" -Tab "Notifications" -GroupId 2 |
    Add-UserPicker -Name "notifyUsers" -Title "Notify Users" -Multiple -Tooltip "Select users to notify" -Tab "Notifications" -ParentGroupId 2 -HideOnValue "0" |
    Add-RolePicker -Name "notifyRoles" -Title "Notify Roles" -Multiple -Domain "sitecore" -Tooltip "Select roles to notify" -Tab "Notifications" -ParentGroupId 2 -HideOnValue "0" |
    Add-MultiLineTextField -Name "notificationMessage" -Title "Custom Message" -Lines 3 -Tooltip "Add a custom message to the notification" -Placeholder "Optional message to include..." -Tab "Notifications" -ParentGroupId 2 -HideOnValue "0"

$result = Show-Dialog -DialogBuilder $dialog

if ($result -ne "ok") {
    Write-Host "Publishing cancelled by user" -ForegroundColor Yellow
    Exit
}

# Display collected settings
Write-Host ("=" * 50) -ForegroundColor Cyan
Write-Host "PUBLISHING CONFIGURATION" -ForegroundColor Cyan
Write-Host ("=" * 50) -ForegroundColor Cyan
Write-Host ""

Write-Host "SOURCE:" -ForegroundColor Green
Write-Host "  Item: $($sourceItem.ItemPath)"
Write-Host "  Include Subitems: $includeSubitems"
Write-Host "  Include Related: $includeRelated"
Write-Host ""

Write-Host "TARGETS:" -ForegroundColor Green
Write-Host "  Databases: $($targetDbs -join ', ')"
Write-Host "  Languages: $($selectedLanguages -join ', ')"
Write-Host ""

Write-Host "OPTIONS:" -ForegroundColor Green
Write-Host "  Mode: $publishMode"
if ($schedulePublish) {
    Write-Host "  Scheduled: $scheduledTime"
} else {
    Write-Host "  Scheduled: Immediate"
}
Write-Host ""

if ($sendNotification) {
    Write-Host "NOTIFICATIONS:" -ForegroundColor Green
    Write-Host "  Users: $($notifyUsers -join ', ')"
    Write-Host "  Roles: $($notifyRoles -join ', ')"
    if ($notificationMessage) {
        Write-Host "  Message: $notificationMessage"
    }
}

Write-Host ""
Write-Host "Ready to execute publishing operation!" -ForegroundColor Yellow

Debugging dialog configuration

# Build a complex dialog
$dialog = New-DialogBuilder -Title "User Management" -Description "Create or modify user accounts" -Width 600 -Height 500 -ShowHints |
    Add-TextField -Name "userName" -Title "Username" -Mandatory -Tab "Account" |
    Add-TextField -Name "email" -Title "Email Address" -Mandatory -Tab "Account" |
    Add-Checkbox -Name "isAdmin" -Title "Administrator" -Value $false -Tab "Permissions" -GroupId 1 |
    Add-RolePicker -Name "adminRoles" -Title "Admin Roles" -Multiple -Tab "Permissions" -ParentGroupId 1 -HideOnValue "0" |
    Add-DateTimePicker -Name "expiryDate" -Title "Account Expiry" -Value ([DateTime]::Now.AddYears(1)) -Tab "Settings"

# Debug the dialog structure before showing it
Debug-DialogBuilder -DialogBuilder $dialog

# Output:
# ================================================================================
# DIALOG BUILDER DEBUG INFO
# ================================================================================
#
# Dialog Properties:
#   Title       : User Management
#   Description : Create or modify user accounts
#   Dimensions  : 600 x 500
#   OK Button   : OK
#   Cancel Button: Cancel
#   Show Hints  : True
#
# Fields: 5
#
#   [Tab: Account]
#     - userName [auto] [REQUIRED]
#     - email [auto] [REQUIRED]
#
#   [Tab: Permissions]
#     - isAdmin [checkbox]
#       Controls Group: 1
#     - adminRoles [role multiple]
#       Controlled by Group: 1 - Hide when parent = '0'
#
#   [Tab: Settings]
#     - expiryDate [date time]
#
# ================================================================================

# Inspect with values
Debug-DialogBuilder -DialogBuilder $dialog -ShowValues

# Show the dialog
$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    Write-Host "User created: $userName ($email)" -ForegroundColor Green
}

Custom validation

# Validation with multiple password requirements
$minPasswordLength = 8

$dialog = New-DialogBuilder -Title "User Registration" -Description "Create a new user account with password validation." -Width 500 -Height 450 -ShowHints |
    Add-TextField -Name "userName" -Title "Username" -Mandatory -Placeholder "Enter username..." -Tooltip "Username must be unique" |
    Add-TextField -Name "password" -Title "Password" -IsPassword -Mandatory -Placeholder "Enter password..." -Tooltip "Password must meet complexity requirements" |
    Add-TextField -Name "confirmPassword" -Title "Confirm Password" -IsPassword -Mandatory -Placeholder "Re-enter password..." -Tooltip "Must match password" |
    Add-TextField -Name "email" -Title "Email Address" -Mandatory -Placeholder "[email protected]" -Tooltip "Valid email required"

# Custom validator scriptblock
$validator = {
    # Access field values through $variables collection
    $pass = $variables.password.Value
    $confirmPass = $variables.confirmPassword.Value
    $emailValue = $variables.email.Value

    # Validate password length
    if ($pass.Length -lt $minPasswordLength) {
        $variables.password.Error = "Password must be at least $minPasswordLength characters long"
        return
    }

    # Validate password complexity
    $validationErrors = @()
    if (-not ($pass -match "[^a-zA-Z0-9]")) {
        $validationErrors += "special character"
    }
    if (-not ($pass -match "[0-9]")) {
        $validationErrors += "number"
    }
    if (-not ($pass -cmatch "[a-z]")) {
        $validationErrors += "lowercase character"
    }
    if (-not ($pass -cmatch "[A-Z]")) {
        $validationErrors += "uppercase character"
    }

    if ($validationErrors.Count -gt 0) {
        $variables.password.Error = "Password must contain at least one: " + ($validationErrors -join ", ")
        return
    }

    # Validate password confirmation
    if ($pass -ne $confirmPass) {
        $variables.confirmPassword.Error = "Passwords do not match"
        return
    }

    # Validate email format
    if ($emailValue -notmatch "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$") {
        $variables.email.Error = "Please enter a valid email address"
        return
    }
}

$result = Show-Dialog -DialogBuilder $dialog -Validator $validator

if ($result -eq "ok") {
    Write-Host "User registration completed successfully!" -ForegroundColor Green
    Write-Host "Username: $userName"
    Write-Host "Email: $email"
}
else {
    Write-Host "User registration cancelled" -ForegroundColor Yellow
}

Field-level validation

# Individual field validation using the Validator parameter on specific fields
# Note: Field-level validators are passed directly to Read-Variable parameters

$dialog = New-DialogBuilder -Title "Item Creation" -Description "Create a new content item with validation." -Width 500 -Height 400 -ShowHints

# Add field with custom validator using Add-DialogField
$dialog | Add-DialogField -Name "itemName" -Title "Item Name" -Value "" -Mandatory -Tooltip "Enter item name (no special characters)" |
    Add-DialogField -Name "displayName" -Title "Display Name" -Value "" -Mandatory -Tooltip "The display name for the item"

# Note: For field-level validation, you would need to add a Validator property to the parameter hashtable
# This is demonstrated in the comprehensive validation example above using the dialog-level validator

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    Write-Host "Item Name: $itemName" -ForegroundColor Green
    Write-Host "Display Name: $displayName" -ForegroundColor Green
}

Validation with external parameters

# Pass external variables to validator using closure or script scope
$minLength = 6
$maxLength = 20
$existingUserNames = @("admin", "user", "guest")

$dialog = New-DialogBuilder -Title "Username Validation" -Description "Validate against existing usernames." -Width 500 -Height 300 -ShowHints |
    Add-TextField -Name "userName" -Title "Username" -Mandatory -Tooltip "Choose a unique username"

$validator = {
    $name = $variables.userName.Value

    # Check length
    if ($name.Length -lt $minLength) {
        $variables.userName.Error = "Username must be at least $minLength characters"
        return
    }

    if ($name.Length -gt $maxLength) {
        $variables.userName.Error = "Username must not exceed $maxLength characters"
        return
    }

    # Check for special characters
    if ($name -match "[^a-zA-Z0-9_]") {
        $variables.userName.Error = "Username can only contain letters, numbers, and underscores"
        return
    }

    # Check against existing usernames
    if ($existingUserNames -contains $name) {
        $variables.userName.Error = "Username '$name' is already taken"
        return
    }
}

$result = Show-Dialog -DialogBuilder $dialog -Validator $validator

if ($result -eq "ok") {
    Write-Host "Username '$userName' is available!" -ForegroundColor Green
}

Multi-item selection controls

# Using TreeList and MultiList for selecting multiple items
$dialog = New-DialogBuilder -Title "Multi-Item Selection" -Description "Select multiple items using different controls." -Width 600 -Height 500 -ShowHints |
    Add-TreeList -Name "treeListItems" -Title "Select from Tree" -Root "/sitecore/content/" -Tooltip "Select multiple items from tree view" -Tab "TreeList" |
    Add-MultiList -Name "multiListItems" -Title "Select from List" -Root "/sitecore/content/" -Tooltip "Select multiple items from dual-list interface" -Tab "MultiList"

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    Write-Host "TreeList Selection:" -ForegroundColor Cyan
    if ($treeListItems) {
        $treeListItems | ForEach-Object {
            Write-Host "  - $($_.Name) [$($_.ID)]" -ForegroundColor Green
        }
    } else {
        Write-Host "  (none selected)" -ForegroundColor Yellow
    }

    Write-Host ""
    Write-Host "MultiList Selection:" -ForegroundColor Cyan
    if ($multiListItems) {
        $multiListItems | ForEach-Object {
            Write-Host "  - $($_.Name) [$($_.ID)]" -ForegroundColor Green
        }
    } else {
        Write-Host "  (none selected)" -ForegroundColor Yellow
    }
}

TreeList and MultiList with Source parameter

# The Source parameter provides advanced filtering capabilities for TreeList and MultiList controls
# Use it to filter by template types, restrict paths, and control what items can be selected

$dialog = New-DialogBuilder -Title "Template Selection" -Description "Select templates using Source parameter filtering." -Width 700 -Height 600 -ShowHints |
    Add-TreeList -Name "selectedTemplates" -Title "Select Templates (TreeList)" `
        -Source "DataSource=/sitecore/templates&DatabaseName=master&IncludeTemplatesForDisplay=Node,Folder,Template,Template Folder&IncludeTemplatesForSelection=Template" `
        -Tooltip "Tree view showing folders but only templates are selectable" -Tab "TreeList" |
    Add-MultiList -Name "systemTemplates" -Title "Select System Templates (MultiList)" `
        -Source "DataSource=/sitecore/templates/System&DatabaseName=master&IncludeTemplatesForDisplay=Template Folder,Template&IncludeTemplatesForSelection=Template" `
        -Tooltip "Dual-list interface filtered to system templates only" -Tab "MultiList"

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    Write-Host "Selected Templates (TreeList):" -ForegroundColor Cyan
    if ($selectedTemplates) {
        $selectedTemplates | ForEach-Object {
            Write-Host "  - $($_.Name) [$($_.TemplateName)] at $($_.ItemPath)" -ForegroundColor Green
        }
    } else {
        Write-Host "  (none selected)" -ForegroundColor Yellow
    }

    Write-Host ""
    Write-Host "System Templates (MultiList):" -ForegroundColor Cyan
    if ($systemTemplates) {
        $systemTemplates | ForEach-Object {
            Write-Host "  - $($_.Name) [$($_.ID)]" -ForegroundColor Green
        }
    } else {
        Write-Host "  (none selected)" -ForegroundColor Yellow
    }
}

Common Source parameter patterns

# Here are common Source parameter patterns for TreeList and MultiList controls

# Pattern 1: Select only specific template types from content
$dialog = New-DialogBuilder -Title "Content Selection" -Width 600 -Height 500 |
    Add-TreeList -Name "pages" -Title "Select Pages or Articles" `
        -Source "DataSource=/sitecore/content&DatabaseName=master&IncludeTemplatesForSelection=Page,Article" `
        -Tooltip "Only Page and Article items can be selected"

# Pattern 2: Select media items (images only)
$dialog = New-DialogBuilder -Title "Media Selection" -Width 600 -Height 500 |
    Add-MultiList -Name "images" -Title "Select Images" `
        -Source "DataSource=/sitecore/media library&DatabaseName=master&IncludeTemplatesForSelection=Jpeg,Png,Image" `
        -Tooltip "Select image files from media library"

# Pattern 3: Show navigation structure but limit selection
$dialog = New-DialogBuilder -Title "Navigation Builder" -Width 600 -Height 500 |
    Add-TreeList -Name "navItems" -Title "Select Navigation Items" `
        -Source "DataSource=/sitecore/content/home&DatabaseName=master&IncludeTemplatesForDisplay=Folder,Page,Article&IncludeTemplatesForSelection=Page,Article" `
        -Tooltip "Navigate through folders but only select Page or Article items"

# Pattern 4: Restrict to specific branch with template filtering
$dialog = New-DialogBuilder -Title "Product Selection" -Width 600 -Height 500 |
    Add-MultiList -Name "products" -Title "Select Products" `
        -Source "DataSource=/sitecore/content/products&DatabaseName=master&IncludeTemplatesForSelection=Product,Product Variant" `
        -Tooltip "Select products from the product catalog"

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    # Process selected items
    Write-Host "Selected items: $($products.Count)" -ForegroundColor Green
}

Source parameter reference

The Source parameter accepts a query string with these common parameters:

Parameter Description Example
DataSource Root path for item selection DataSource=/sitecore/content
DatabaseName Database to query (default: master) DatabaseName=master
IncludeTemplatesForDisplay Template types shown in tree/list IncludeTemplatesForDisplay=Folder,Page
IncludeTemplatesForSelection Template types that can be selected IncludeTemplatesForSelection=Page,Article
ExcludeTemplatesForDisplay Template types hidden from view ExcludeTemplatesForDisplay=System Folder
ExcludeTemplatesForSelection Template types that cannot be selected ExcludeTemplatesForSelection=Folder

Notes:

  • Separate multiple template names with commas
  • Template names are case-sensitive
  • IncludeTemplatesForDisplay controls what appears in the tree/list
  • IncludeTemplatesForSelection controls what can actually be selected
  • Use both together to show navigation structure while limiting valid selections
  • When using Source, it typically overrides the Root parameter

MultiList with Search for large datasets

# When dealing with large item collections, use -WithSearch parameter
# This adds a search box to filter items, making selection much easier

$dialog = New-DialogBuilder -Title "Large Dataset Selection" -Description "Using multilist search for better UX with many items." -Width 700 -Height 600 -ShowHints |
    Add-MultiList -Name "searchableTemplates" -Title "Search and Select Templates" -WithSearch `
        -Source "DataSource=/sitecore/templates&DatabaseName=master&IncludeTemplatesForDisplay=Template Folder,Template&IncludeTemplatesForSelection=Template" `
        -Tooltip "Use the search box to filter templates, then select from the results" |
    Add-MultiList -Name "searchableContent" -Title "Search Content Items" -WithSearch `
        -Source "DataSource=/sitecore/content&DatabaseName=master&IncludeTemplatesForSelection=Page,Article,Folder" `
        -Tooltip "Search and select content items by name"

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    Write-Host "Selected Templates (via search):" -ForegroundColor Cyan
    if ($searchableTemplates) {
        Write-Host "  Found $($searchableTemplates.Count) items" -ForegroundColor Green
        $searchableTemplates | Select-Object -First 5 | ForEach-Object {
            Write-Host "  - $($_.Name) at $($_.ItemPath)" -ForegroundColor Green
        }
        if ($searchableTemplates.Count -gt 5) {
            Write-Host "  ... and $($searchableTemplates.Count - 5) more" -ForegroundColor Yellow
        }
    }

    Write-Host ""
    Write-Host "Selected Content Items:" -ForegroundColor Cyan
    if ($searchableContent) {
        $searchableContent | ForEach-Object {
            Write-Host "  - $($_.Name) [$($_.TemplateName)]" -ForegroundColor Green
        }
    }
}

Using StartSearchLocation with item selectors

# StartSearchLocation parameter sets the initial location for item pickers
# This is particularly useful for narrowing the search scope in large content trees

$dialog = New-DialogBuilder -Title "Scoped Item Selection" -Description "Using StartSearchLocation to focus search scope." -Width 700 -Height 600 -ShowHints |
    Add-DialogField -Name "homePageItem" -Title "Select from Home" -Editor "droplink" `
        -Source "StartSearchLocation=/sitecore/content/home" `
        -Tooltip "Item picker starts at /sitecore/content/home" |
    Add-DialogField -Name "mediaItem" -Title "Select Media" -Editor "droptree" `
        -Source "DataSource=/sitecore/media library/Images" `
        -Tooltip "Tree picker focused on Images folder" |
    Add-MultiList -Name "multiplePages" -Title "Select Multiple Pages" -WithSearch `
        -Source "StartSearchLocation=/sitecore/content/home&IncludeTemplatesForSelection=Page,Article" `
        -Tooltip "Search for pages starting from home, filtered by template"

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    if ($homePageItem) {
        Write-Host "Selected Home Item: $($homePageItem.ItemPath)" -ForegroundColor Green
    }
    if ($mediaItem) {
        Write-Host "Selected Media: $($mediaItem.ItemPath)" -ForegroundColor Green
    }
    if ($multiplePages) {
        Write-Host "Selected $($multiplePages.Count) pages:" -ForegroundColor Green
        $multiplePages | ForEach-Object {
            Write-Host "  - $($_.Name)" -ForegroundColor Cyan
        }
    }
}

Combining DataSource and StartSearchLocation

# You can combine DataSource (for template filtering) with StartSearchLocation (for path scoping)
# This gives you fine-grained control over what users can select

$dialog = New-DialogBuilder -Title "Advanced Filtering" -Description "Combining multiple Source parameters." -Width 700 -Height 600 -ShowHints |
    Add-TreeList -Name "filteredItems" -Title "Product Pages Only" `
        -Source "DataSource=/sitecore/content&StartSearchLocation=/sitecore/content/products&IncludeTemplatesForSelection=Product Page,Product Category" `
        -Tooltip "Browse content tree but only select Product-related templates under /products" |
    Add-MultiList -Name "filteredSearch" -Title "Search Product Items" -WithSearch `
        -Source "DataSource=/sitecore/content&StartSearchLocation=/sitecore/content/products&DatabaseName=master&IncludeTemplatesForSelection=Product,Product Variant" `
        -Tooltip "Searchable list scoped to products with template filtering"

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    Write-Host "Tree Selection:" -ForegroundColor Cyan
    if ($filteredItems) {
        $filteredItems | ForEach-Object {
            Write-Host "  - $($_.Name) [$($_.TemplateName)]" -ForegroundColor Green
        }
    }

    Write-Host ""
    Write-Host "Search Selection:" -ForegroundColor Cyan
    if ($filteredSearch) {
        Write-Host "  Selected $($filteredSearch.Count) product items" -ForegroundColor Green
    }
}

When to use multilist vs multilist search

Standard MultiList (Add-MultiList or Editor="multilist"):

  • Best for small to medium datasets (< 100 items)
  • Shows all available items in a scrollable list
  • Drag-and-drop or button-based selection
  • Good when users need to see all options at once

MultiList with Search (Add-MultiList -WithSearch):

  • Best for large datasets (100+ items)
  • Includes a search/filter box at the top
  • Users type to filter, then select from filtered results
  • Essential for content trees with hundreds or thousands of items
  • Same Source parameter syntax as standard multilist

Note: Use the -WithSearch parameter with Add-MultiList or Add-TreeList to enable the search variant. Alternatively, use Add-DialogField with -Editor "multilist search" or -Editor "treelist search".

Using TemplateFilter parameter

# TemplateFilter provides an alternative way to filter by templates using template GUIDs

$dialog = New-DialogBuilder -Title "TemplateFilter Examples" -Description "Using TemplateFilter for template-based filtering." -Width 700 -Height 600 -ShowHints |
    Add-MultiList -Name "filteredByTemplateFilter" -Title "Using TemplateFilter" -WithSearch `
        -Source "DataSource=/sitecore/content&TemplateFilter={76036F5E-CBCE-46D1-AF0A-4143F9B557AA}" `
        -Tooltip "TemplateFilter uses template IDs for filtering"

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    Write-Host "TemplateFilter Results:" -ForegroundColor Cyan
    if ($filteredByTemplateFilter) {
        Write-Host "  Selected $($filteredByTemplateFilter.Count) items" -ForegroundColor Green
        $filteredByTemplateFilter | ForEach-Object {
            Write-Host "  - $($_.Name) [$($_.TemplateName)]" -ForegroundColor Green
        }
    }
}

TemplateFilter vs IncludeTemplatesForSelection

# Both approaches filter by template, but have different syntax and use cases

$dialog = New-DialogBuilder -Title "Template Filtering Comparison" -Width 700 -Height 600 -ShowHints |
    Add-MultiList -Name "byTemplateName" -Title "By Template Name" -WithSearch `
        -Source "DataSource=/sitecore/content&IncludeTemplatesForSelection=Sample Item,Article" `
        -Tooltip "Uses human-readable template names" -Tab "Name-Based" |
    Add-MultiList -Name "byTemplateId" -Title "By Template ID" -WithSearch `
        -Source "DataSource=/sitecore/content&TemplateFilter={76036F5E-CBCE-46D1-AF0A-4143F9B557AA}|{A87A00B1-E6DB-45AB-8B54-636FEC3B5523}" `
        -Tooltip "Uses template GUIDs - more precise and survives renames" -Tab "ID-Based"

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    Write-Host "Template Name Filtering: $($byTemplateName.Count) items" -ForegroundColor Green
    Write-Host "Template ID Filtering: $($byTemplateId.Count) items" -ForegroundColor Green
}

Combining multiple Source parameters

# You can combine DataSource, StartSearchLocation, and TemplateFilter
# for extremely precise control over item selection

$dialog = New-DialogBuilder -Title "Combined Filtering" -Description "Using multiple Source parameters together." -Width 700 -Height 600 -ShowHints |
    Add-MultiList -Name "combinedFilter" -Title "Multi-Parameter Selection" -WithSearch `
        -Source "DataSource=/sitecore/content&StartSearchLocation=/sitecore/content/home&TemplateFilter={76036F5E-CBCE-46D1-AF0A-4143F9B557AA}&DatabaseName=master" `
        -Tooltip "Combines DataSource, StartSearchLocation, TemplateFilter, and DatabaseName"

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok" -and $combinedFilter) {
    Write-Host "Selected Items with Combined Filtering:" -ForegroundColor Green
    $combinedFilter | ForEach-Object {
        Write-Host "  - $($_.Name) [$($_.TemplateName)] at $($_.ItemPath)" -ForegroundColor Cyan
    }
}

Source parameter quick reference

Template Filtering:

  • IncludeTemplatesForSelection=Template Name,Another Template - Filter by template name (human-readable)
  • TemplateFilter={GUID}|{GUID} - Filter by template ID (pipe-separated GUIDs)
  • ExcludeTemplatesForSelection=Template Name - Exclude specific templates

Path and Scope:

  • DataSource=/sitecore/content - Root path for item tree
  • StartSearchLocation=/sitecore/content/home - Starting point for search
  • DatabaseName=master - Database to query (default: master)

Display Control:

  • IncludeTemplatesForDisplay=Folder,Template - What shows in tree/list
  • ExcludeTemplatesForDisplay=System Folder - Hide from tree/list

Notes:

  • TemplateFilter uses template GUIDs and survives template renames
  • Multiple GUIDs in TemplateFilter are separated by pipe (|)
  • Combine parameters with & ampersand separator

Email and link fields

# Email and link fields with built-in validation
$dialog = New-DialogBuilder -Title "Contact Information" -Description "Email and URL input fields." -Width 500 -Height 350 -ShowHints |
    Add-TextField -Name "userEmail" -Title "Email Address" -IsEmail -Placeholder "[email protected]" -Mandatory -Tooltip "Enter a valid email address" |
    Add-LinkField -Name "websiteUrl" -Title "Website URL" -Placeholder "https://example.com" -Tooltip "Enter a valid URL"

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    Write-Host "Email: $userEmail" -ForegroundColor Green
    Write-Host "Website URL: $websiteUrl" -ForegroundColor Green
}

Tristate checkbox

# Three-state checkbox for nullable boolean values
$dialog = New-DialogBuilder -Title "Filter Options" -Description "Use tristate for optional filter settings." -Width 450 -Height 300 -ShowHints |
    Add-TristateCheckbox -Name "includeArchived" -Title "Include Archived Items" -Value $null -Tooltip "Yes=Include, No=Exclude, Not Set=Don't Filter" |
    Add-TristateCheckbox -Name "publishedOnly" -Title "Published Only" -Value 1 -Tooltip "Filter by publish status"

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    Write-Host "Include Archived: $includeArchived" -ForegroundColor Green  # Returns 1, 0, or $null
    Write-Host "Published Only: $publishedOnly" -ForegroundColor Green

    # Example conditional logic with tristate
    if ($includeArchived -eq 1) {
        Write-Host "Will include archived items" -ForegroundColor Cyan
    } elseif ($includeArchived -eq 0) {
        Write-Host "Will exclude archived items" -ForegroundColor Cyan
    } else {
        Write-Host "No archive filtering applied" -ForegroundColor Cyan
    }
}

Rule and rule action fields

# Sitecore rules engine integration for conditional rules and actions
$dialog = New-DialogBuilder -Title "Rules Configuration" -Description "Configure Sitecore conditional rules and actions." -Width 700 -Height 500 -ShowHints |
    Add-RuleField -Name "personalizationRules" -Title "Personalization Rules" -Source "Rules.ConditionalRenderings" -Tooltip "Define when this component should be visible" |
    Add-RuleActionField -Name "workflowActions" -Title "Workflow Actions" -Tooltip "Define actions to execute when conditions are met"

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    Write-Host "Personalization Rules (XML):" -ForegroundColor Green
    Write-Host $personalizationRules
    Write-Host "`nWorkflow Actions (XML):" -ForegroundColor Green
    Write-Host $workflowActions
}

Using Source parameter for data sources

# The Source parameter allows advanced control configurations
# DataSource points to a specific location, query defines the data query

$dialog = New-DialogBuilder -Title "Advanced Item Selection" -Description "Using Source parameter for complex scenarios." -Width 600 -Height 400 -ShowHints |
    Add-DialogField -Name "templateFolder" -Title "Template Folder" -Editor "droptree" -Source "DataSource=/sitecore/templates&DatabaseName=master" -Tooltip "Select template folder" |
    Add-DialogField -Name "contentItem" -Title "Content Item" -Editor "droplink" -Source "StartSearchLocation=/sitecore/content/home" -Tooltip "Select content item from specific location"

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    if ($templateFolder) {
        Write-Host "Template Folder: $($templateFolder.ItemPath)" -ForegroundColor Green
    }
    if ($contentItem) {
        Write-Host "Content Item: $($contentItem.ItemPath)" -ForegroundColor Green
    }
}

Testing and debugging dialogs

# Build a complex dialog for testing
$dialog = New-DialogBuilder -Title "Complex Dialog" -Width 700 -Height 600 -ShowHints |
    Add-TextField -Name "field1" -Title "Field 1" -Mandatory -Tab "Tab1" |
    Add-TextField -Name "field2" -Title "Field 2" -Tab "Tab1" |
    Add-Checkbox -Name "toggle" -Title "Show Advanced" -GroupId 1 -Tab "Tab2" |
    Add-TextField -Name "advanced1" -Title "Advanced Field" -ParentGroupId 1 -HideOnValue "0" -Tab "Tab2" |
    Add-TextField -Name "advanced2" -Title "Advanced Field 2" -ParentGroupId 1 -HideOnValue "0" -Tab "Tab2"

# Validate configuration before showing
Write-Host "Testing dialog configuration..." -ForegroundColor Cyan
$isValid = Test-DialogBuilder -DialogBuilder $dialog

if ($isValid) {
    # Show debug information
    Debug-DialogBuilder -DialogBuilder $dialog -ShowFullParameters

    # Export for documentation
    $json = Export-DialogBuilderConfig -DialogBuilder $dialog
    Write-Host "`nDialog configuration:" -ForegroundColor Cyan
    Write-Host $json

    # Show the dialog
    $result = Show-Dialog -DialogBuilder $dialog

    if ($result -eq "ok") {
        Write-Host "`nDialog completed successfully!" -ForegroundColor Green
    }
}
else {
    Write-Host "Dialog validation failed. Please fix errors before showing." -ForegroundColor Red
}

Dynamic dialog building

# Build dialogs dynamically based on conditions
$userRole = "Administrator"  # Could be determined at runtime

$dialog = New-DialogBuilder -Title "Dynamic Dialog" -Width 600 -Height 500 -ShowHints |
    Add-TextField -Name "userName" -Title "Username" -Mandatory

# Add role-specific fields
if ($userRole -eq "Administrator") {
    $dialog = $dialog |
        Add-Checkbox -Name "fullAccess" -Title "Grant Full Access" -Value $false |
        Add-RolePicker -Name "additionalRoles" -Title "Additional Roles" -Multiple -Domain "sitecore"
}
elseif ($userRole -eq "ContentEditor") {
    $dialog = $dialog |
        Add-ItemPicker -Name "homeItem" -Title "Home Item" -Root "/sitecore/content/" -Mandatory
}

# Conditionally add fields
$includeNotifications = $true
if ($includeNotifications) {
    $dialog = $dialog |
        Add-Checkbox -Name "sendEmail" -Title "Send Email Notification" -Value $true
}

$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    Write-Host "User configured for role: $userRole" -ForegroundColor Green
    Write-Host "Username: $userName"
}

Copying and modifying dialogs

# Create a base dialog template
$baseDialog = New-DialogBuilder -Title "Base Template" -Width 500 -Height 400 -ShowHints |
    Add-TextField -Name "name" -Title "Name" -Mandatory |
    Add-TextField -Name "description" -Title "Description"

# Create variations without modifying the original
$dialog1 = Copy-DialogBuilder -DialogBuilder $baseDialog
$dialog1.Title = "Create New Item"
$dialog1 = $dialog1 | Add-ItemPicker -Name "parentItem" -Title "Parent" -Mandatory

$dialog2 = Copy-DialogBuilder -DialogBuilder $baseDialog
$dialog2.Title = "Update Existing Item"
$dialog2 = $dialog2 | Add-Checkbox -Name "overwrite" -Title "Overwrite Existing"

# Show dialog1
$result = Show-Dialog -DialogBuilder $dialog1
if ($result -eq "ok") {
    Write-Host "Created: $name" -ForegroundColor Green
}

Removing fields conditionally

# Build dialog with all possible fields
$dialog = New-DialogBuilder -Title "Configurable Dialog" -Width 600 -Height 500 |
    Add-TextField -Name "required1" -Title "Required Field 1" -Mandatory |
    Add-TextField -Name "required2" -Title "Required Field 2" -Mandatory |
    Add-TextField -Name "optional1" -Title "Optional Field 1" |
    Add-TextField -Name "optional2" -Title "Optional Field 2" |
    Add-TextField -Name "advanced1" -Title "Advanced Field 1"

# Remove fields based on user preferences or context
$showAdvanced = $false
$showOptional = $true

if (-not $showAdvanced) {
    $dialog = $dialog | Remove-DialogField -Name "advanced1"
}

if (-not $showOptional) {
    $dialog = $dialog |
        Remove-DialogField -Name "optional1" |
        Remove-DialogField -Name "optional2"
}

$result = Show-Dialog -DialogBuilder $dialog

All available field types and options

This comprehensive example demonstrates all available field types and common parameter combinations supported by the Dialog Builder functions. Use this as a reference when building complex dialogs.

<#
    .SYNOPSIS
        Comprehensive example demonstrating ALL available dialog field types and parameters.

    .DESCRIPTION
        This example showcases every field type, editor variant, and common parameter combination
        available in the Dialog Builder API. Use this as a reference guide for building dialogs.

    .NOTES
        This example is for demonstration purposes. In practice, you wouldn't need
        all these controls in a single dialog.
#>

# Define option sets for various controls
$comboOptions = [ordered]@{
    "Option 1" = "opt1"
    "Option 2" = "opt2"
    "Option 3" = "opt3"
}

$radioOptions = [ordered]@{
    "Choice A" = 1
    "Choice B" = 2
    "Choice C" = 3
}

$checklistOptions = [ordered]@{
    "Item 1" = 1
    "Item 2" = 2
    "Item 3" = 4
    "Item 4" = 8
}

$optionTooltips = [ordered]@{
    "opt1" = "This is option 1"
    "opt2" = "This is option 2"
    "opt3" = "This is option 3"
}

# Template source for item pickers
$templateSource = "DataSource=/sitecore/templates&DatabaseName=master&IncludeTemplatesForDisplay=Template Folder,Template&IncludeTemplatesForSelection=Template"

# Build the comprehensive dialog
$dialog = New-DialogBuilder `
    -Title "Complete Field Type Reference" `
    -Description "Demonstrates all available dialog field types and parameters" `
    -Icon "Office/32x32/book_open.png" `
    -Width 1050 `
    -Height 700 `
    -OkButtonName "Process" `
    -CancelButtonName "Abort" `
    -ShowHints |

    # === TEXT INPUT CONTROLS (Tab 1) ===
    Add-InfoText -Name "textInfo" -Title "Text Input Controls" -Value "Various text input field types" -Tab "Text Inputs" |
    Add-TextField -Name "basicText" -Title "Basic Text Field" -Value "default value" -Placeholder "Enter text..." -Tooltip "Standard single-line text input" -Tab "Text Inputs" |
    Add-TextField -Name "passwordText" -Title "Password Field" -IsPassword -Placeholder "Enter password..." -Tooltip "Masked password input" -Tab "Text Inputs" |
    Add-TextField -Name "emailText" -Title "Email Field" -IsEmail -Placeholder "[email protected]" -Tooltip "Email validation" -Tab "Text Inputs" |
    Add-TextField -Name "numberText" -Title "Number Field" -Value 42 -IsNumber -Tooltip "Numeric input (integer or decimal)" -Tab "Text Inputs" |
    Add-LinkField -Name "linkText" -Title "Link/URL Field" -Placeholder "https://example.com" -Tooltip "URL input field" -Tab "Text Inputs" |
    Add-MultiLineTextField -Name "multiText" -Title "Multi-Line Text" -Lines 3 -Placeholder "Enter multiple lines..." -Tooltip "Multi-line text area" -Tab "Text Inputs" |
    Add-TextField -Name "mandatoryText" -Title "Mandatory Text" -Mandatory -Placeholder "Required field..." -Tooltip "Required field example" -Tab "Text Inputs" |

    # === BOOLEAN CONTROLS (Tab 2) ===
    Add-InfoText -Name "boolInfo" -Title "Boolean Controls" -Value "Checkbox and tristate controls" -Tab "Boolean" |
    Add-Checkbox -Name "simpleCheckbox" -Title "Simple Checkbox" -Value $true -Tooltip "Standard boolean checkbox" -Tab "Boolean" |
    Add-Checkbox -Name "groupCheckbox" -Title "Checkbox with GroupId" -Value $false -Tooltip "Controls visibility of other fields" -GroupId 1 -Tab "Boolean" |
    Add-TextField -Name "conditionalField" -Title "Conditional Field" -Tooltip "Visible when checkbox is checked" -ParentGroupId 1 -HideOnValue "0" -Tab "Boolean" |
    Add-TristateCheckbox -Name "tristateBox" -Title "Tristate Checkbox" -Value $null -Tooltip "Three states: Yes (1), No (0), Not Set (null)" -Tab "Boolean" |

    # === DATE/TIME CONTROLS (Tab 3) ===
    Add-InfoText -Name "dateInfo" -Title "Date and Time Controls" -Value "Date and time picker controls" -Tab "Date/Time" |
    Add-DateTimePicker -Name "dateTimeField" -Title "Date/Time Picker" -Value ([DateTime]::Now) -Tooltip "Date and time selection" -Tab "Date/Time" |
    Add-DateTimePicker -Name "dateOnlyField" -Title "Date Only Picker" -Value ([DateTime]::Now.Date) -DateOnly -Tooltip "Date selection without time" -Tab "Date/Time" |
    Add-DateTimePicker -Name "mandatoryDate" -Title "Mandatory Date" -Value ([DateTime]::Now) -Mandatory -Tooltip "Required date field" -Tab "Date/Time" |

    # === ITEM SELECTION (Tab 4) ===
    Add-InfoText -Name "itemInfo" -Title "Item Selection Controls" -Value "Various item picker controls returning Item objects or strings" -Tab "Items" |
    Add-ItemPicker -Name "basicItemPicker" -Title "Item Picker (Tree)" -Root "/sitecore/content/" -Value (Get-Item "master:\content\Home") -Tooltip "Full tree-based item picker" -Tab "Items" |
    Add-Droplink -Name "droplinkField" -Title "Droplink (Returns Item)" -Source $templateSource -Tooltip "Flat dropdown - returns Item object" -Tab "Items" |
    Add-Droptree -Name "droptreeField" -Title "Droptree (Returns Item)" -Source $templateSource -Tooltip "Dropdown with tree navigation - returns Item" -Tab "Items" |
    Add-Droplist -Name "droplistField" -Title "Droplist (Returns String)" -Source $templateSource -Tooltip "Flat dropdown - returns string (path/ID)" -Tab "Items" |
    Add-GroupedDroplink -Name "groupedDroplink" -Title "Grouped Droplink" -Source $templateSource -Tooltip "Grouped dropdown - returns Item" -Tab "Items" |
    Add-GroupedDroplist -Name "groupedDroplist" -Title "Grouped Droplist" -Source $templateSource -Tooltip "Grouped dropdown - returns string" -Tab "Items" |

    # === MULTI-ITEM SELECTION (Tab 5) ===
    Add-InfoText -Name "multiItemInfo" -Title "Multi-Item Selection" -Value "Controls for selecting multiple items" -Tab "Multi-Items" |
    Add-TreeList -Name "treelistField" -Title "TreeList" -Source $templateSource -Tooltip "Tree-based multi-item picker" -Tab "Multi-Items" |
    Add-TreeList -Name "treelistSearch" -Title "TreeList with Search" -WithSearch -Source $templateSource -Tooltip "TreeList with search box for large datasets" -Tab "Multi-Items" |
    Add-MultiList -Name "multilistField" -Title "MultiList" -Source $templateSource -Tooltip "Dual-list multi-item picker" -Tab "Multi-Items" |
    Add-MultiList -Name "multilistSearch" -Title "MultiList with Search" -WithSearch -Source $templateSource -Tooltip "MultiList with search for large datasets" -Tab "Multi-Items" |

    # === OPTION SELECTION (Tab 6) ===
    Add-InfoText -Name "optionInfo" -Title "Option Selection Controls" -Value "Dropdowns, radio buttons, and checklists with predefined options" -Tab "Options" |
    Add-Dropdown -Name "comboField" -Title "Dropdown (Combo)" -Value "opt2" -Options $comboOptions -Tooltip "Dropdown with custom options" -Tab "Options" |
    Add-Dropdown -Name "comboWithTooltips" -Title "Dropdown with Tooltips" -Value "opt1" -Options $comboOptions -OptionTooltips $optionTooltips -Tooltip "Options have individual tooltips" -Tab "Options" |
    Add-RadioButtons -Name "radioField" -Title "Radio Buttons" -Value 2 -Options $radioOptions -Tooltip "Single selection radio group" -Tab "Options" |
    Add-Checklist -Name "checklistField" -Title "Checklist" -Value @(1, 4) -Options $checklistOptions -Tooltip "Multiple selection checklist with bitmask values" -Tab "Options" |

    # === USER/ROLE SELECTION (Tab 7) ===
    Add-InfoText -Name "userInfo" -Title "User and Role Pickers" -Value "Security principal selection controls" -Tab "Users/Roles" |
    Add-UserPicker -Name "singleUser" -Title "Single User" -Tooltip "Select one user" -Tab "Users/Roles" |
    Add-UserPicker -Name "multipleUsers" -Title "Multiple Users" -Multiple -Tooltip "Select multiple users" -Tab "Users/Roles" |
    Add-RolePicker -Name "singleRole" -Title "Single Role" -Domain "sitecore" -Tooltip "Select one role from sitecore domain" -Tab "Users/Roles" |
    Add-RolePicker -Name "multipleRoles" -Title "Multiple Roles" -Multiple -Domain "sitecore" -Tooltip "Select multiple roles" -Tab "Users/Roles" |
    Add-UserRolePicker -Name "singleUserRole" -Title "User or Role" -Domain "sitecore" -Tooltip "Select one user or role" -Tab "Users/Roles" |
    Add-UserRolePicker -Name "multipleUserRoles" -Title "Multiple Users/Roles" -Multiple -Domain "sitecore" -Tooltip "Select multiple users and/or roles" -Tab "Users/Roles" |

    # === ADVANCED CONTROLS (Tab 8) ===
    Add-InfoText -Name "advancedInfo" -Title "Advanced Controls" -Value "Specialized controls for specific scenarios" -Tab "Advanced" |
    Add-RuleField -Name "ruleField" -Title "Rule Field" -Source "Rules.ConditionalRenderings" -Tooltip "Sitecore rules engine - conditions only" -Tab "Advanced" |
    Add-RuleActionField -Name "ruleActionField" -Title "Rule Action Field" -Tooltip "Sitecore rules engine - conditions and actions" -Tab "Advanced" |
    Add-Marquee -Name "marqueeField" -Title "Marquee Display" -Value "This is a scrolling message!" -Tab "Advanced" |

    # === LAYOUT EXAMPLES (Tab 9) ===
    Add-InfoText -Name "layoutInfo" -Title "Layout Options" -Value "Column-based layout using the Columns parameter (12-column grid)" -Tab "Layout" |
    Add-TextField -Name "fullWidth" -Title "Full Width (12 columns)" -Placeholder "Default full width" -Tooltip "Columns=12 (default)" -Tab "Layout" |
    Add-TextField -Name "halfWidth1" -Title "Half Width 1" -Placeholder "6 columns" -Columns 6 -Tooltip "Columns=6" -Tab "Layout" |
    Add-TextField -Name "halfWidth2" -Title "Half Width 2" -Placeholder "6 columns" -Columns 6 -Tooltip "Columns=6" -Tab "Layout" |
    Add-TextField -Name "thirdWidth1" -Title "Third 1" -Placeholder "4 cols" -Columns 4 -Tooltip "Columns=4" -Tab "Layout" |
    Add-TextField -Name "thirdWidth2" -Title "Third 2" -Placeholder "4 cols" -Columns 4 -Tooltip "Columns=4" -Tab "Layout" |
    Add-TextField -Name "thirdWidth3" -Title "Third 3" -Placeholder "4 cols" -Columns 4 -Tooltip "Columns=4" -Tab "Layout" |
    Add-TextField -Name "twoThirds" -Title "Two-Thirds Width" -Placeholder "8 columns" -Columns 8 -Tooltip "Columns=8" -Tab "Layout" |
    Add-TextField -Name "oneThird" -Title "One-Third Width" -Placeholder "4 columns" -Columns 4 -Tooltip "Columns=4" -Tab "Layout" |

    # === VISIBILITY CONTROL (Tab 10) ===
    Add-InfoText -Name "visibilityInfo" -Title "Conditional Visibility" -Value "Fields that show/hide based on other field values" -Tab "Visibility" |
    Add-Checkbox -Name "visibilityToggle" -Title "Show Advanced Fields" -Value $false -Tooltip "Toggle to show/hide advanced options" -GroupId 2 -Tab "Visibility" |
    Add-TextField -Name "visibleWhenChecked1" -Title "Advanced Field 1" -Placeholder "Hidden when unchecked" -Tooltip "Visible when checkbox is checked" -ParentGroupId 2 -HideOnValue "0" -Tab "Visibility" |
    Add-TextField -Name "visibleWhenChecked2" -Title "Advanced Field 2" -Placeholder "Hidden when unchecked" -Tooltip "Also visible when checked" -ParentGroupId 2 -HideOnValue "0" -Tab "Visibility" |
    Add-Dropdown -Name "modeSelector" -Title "Mode" -Value "basic" -Options ([ordered]@{"Basic"="basic";"Advanced"="advanced";"Expert"="expert"}) -Tooltip "Select mode" -GroupId 3 -Tab "Visibility" |
    Add-TextField -Name "basicModeField" -Title "Basic Mode Only" -Placeholder "Visible in Basic mode" -Tooltip "Only visible when Basic selected" -ParentGroupId 3 -ShowOnValue "basic" -Tab "Visibility" |
    Add-TextField -Name "advancedModeField" -Title "Advanced Mode Only" -Placeholder "Visible in Advanced mode" -Tooltip "Only visible when Advanced selected" -ParentGroupId 3 -ShowOnValue "advanced" -Tab "Visibility" |
    Add-TextField -Name "expertModeField" -Title "Expert Mode Only" -Placeholder "Visible in Expert mode" -Tooltip "Only visible when Expert selected" -ParentGroupId 3 -ShowOnValue "expert" -Tab "Visibility"

# Display the dialog
$result = Show-Dialog -DialogBuilder $dialog

if ($result -eq "ok") {
    Write-Host ("=" * 80) -ForegroundColor Cyan
    Write-Host "COMPREHENSIVE DIALOG RESULTS" -ForegroundColor Cyan
    Write-Host ("=" * 80) -ForegroundColor Cyan
    Write-Host ""

    # Display results organized by category
    Write-Host "TEXT INPUTS:" -ForegroundColor Green
    Write-Host "  Basic Text: $basicText"
    Write-Host "  Password: $(if($passwordText){'*' * $passwordText.Length}else{'(empty)'})"
    Write-Host "  Email: $emailText"
    Write-Host "  Number: $numberText"
    Write-Host "  Link: $linkText"
    Write-Host "  Multi-line: $multiText"
    Write-Host "  Mandatory: $mandatoryText"
    Write-Host ""

    Write-Host "BOOLEAN CONTROLS:" -ForegroundColor Green
    Write-Host "  Simple Checkbox: $simpleCheckbox"
    Write-Host "  Group Checkbox: $groupCheckbox"
    if ($groupCheckbox) {
        Write-Host "  Conditional Field: $conditionalField"
    }
    Write-Host "  Tristate: $tristateBox (1=Yes, 0=No, null=Not Set)"
    Write-Host ""

    Write-Host "DATE/TIME:" -ForegroundColor Green
    Write-Host "  DateTime: $dateTimeField"
    Write-Host "  Date Only: $dateOnlyField"
    Write-Host "  Mandatory Date: $mandatoryDate"
    Write-Host ""

    Write-Host "ITEM SELECTION:" -ForegroundColor Green
    if ($basicItemPicker) {
        Write-Host "  Item Picker: $($basicItemPicker.ItemPath)"
    }
    if ($droplinkField) {
        Write-Host "  Droplink: $($droplinkField.Name) (Item)"
    }
    if ($droptreeField) {
        Write-Host "  Droptree: $($droptreeField.Name) (Item)"
    }
    Write-Host "  Droplist: $droplistField (String)"
    if ($groupedDroplink) {
        Write-Host "  Grouped Droplink: $($groupedDroplink.Name) (Item)"
    }
    Write-Host "  Grouped Droplist: $groupedDroplist (String)"
    Write-Host ""

    Write-Host "MULTI-ITEM SELECTION:" -ForegroundColor Green
    Write-Host "  TreeList: $($treelistField.Count) items"
    Write-Host "  TreeList Search: $($treelistSearch.Count) items"
    Write-Host "  MultiList: $($multilistField.Count) items"
    Write-Host "  MultiList Search: $($multilistSearch.Count) items"
    Write-Host ""

    Write-Host "OPTION SELECTION:" -ForegroundColor Green
    Write-Host "  Combo: $comboField"
    Write-Host "  Combo with Tooltips: $comboWithTooltips"
    Write-Host "  Radio: $radioField"
    Write-Host "  Checklist: $($checklistField -join ', ')"
    Write-Host ""

    Write-Host "USER/ROLE SELECTION:" -ForegroundColor Green
    Write-Host "  Single User: $singleUser"
    Write-Host "  Multiple Users: $($multipleUsers -join ', ')"
    Write-Host "  Single Role: $singleRole"
    Write-Host "  Multiple Roles: $($multipleRoles -join ', ')"
    Write-Host "  User or Role: $singleUserRole"
    Write-Host "  Multiple Users/Roles: $($multipleUserRoles -join ', ')"
    Write-Host ""

    Write-Host "ADVANCED CONTROLS:" -ForegroundColor Green
    Write-Host "  Name-Value List: $nameValueField"
    Write-Host "  Icon: $iconField"
    Write-Host "  Rule Field Length: $($ruleField.Length) chars"
    Write-Host "  Rule Action Field Length: $($ruleActionField.Length) chars"
    Write-Host ""

    Write-Host "VISIBILITY CONTROLS:" -ForegroundColor Green
    Write-Host "  Toggle: $visibilityToggle"
    if ($visibilityToggle) {
        Write-Host "  Advanced Field 1: $visibleWhenChecked1"
        Write-Host "  Advanced Field 2: $visibleWhenChecked2"
    }
    Write-Host "  Mode: $modeSelector"
    switch ($modeSelector) {
        "basic" { Write-Host "  Basic Mode Field: $basicModeField" }
        "advanced" { Write-Host "  Advanced Mode Field: $advancedModeField" }
        "expert" { Write-Host "  Expert Mode Field: $expertModeField" }
    }

    Write-Host ""
    Write-Host ("=" * 80) -ForegroundColor Cyan
}
else {
    Write-Host "Dialog was cancelled" -ForegroundColor Yellow
}

Key Takeaways from This Example:

  1. Text Input Variants: Standard, password, email, number, link, multi-line
  2. Boolean Controls: Checkbox, tristate checkbox with conditional visibility
  3. Date/Time Controls: Full date/time picker and date-only picker
  4. Item Selection: Tree picker, droplink, droptree, droplist, and grouped variants
  5. Multi-Item Selection: TreeList and MultiList with optional search
  6. Option Selection: Dropdown (combo), radio buttons, checklist with bitmask values
  7. User/Role Pickers: Single and multiple variants for users, roles, or combined
  8. Advanced Controls: Name-value list, icon selector, rule editors, marquee
  9. Layout Options: 12-column grid with various column widths (4, 6, 8, 12)
  10. Conditional Visibility: Using GroupId, ParentGroupId, HideOnValue, ShowOnValue
  11. Tabs: Organizing fields across multiple tabs for better UX
  12. Tooltips and Placeholders: Providing user guidance
  13. Mandatory Fields: Required field validation

Reference Documentation

Complete Editor Types Reference

The following editor types are available for use with Add-DialogField or the -Editor parameter:

Editor Type Description Return Type Convenience Function
text (default) Single-line text input String Add-TextField
password Masked password input String Add-TextField -IsPassword
email Email input with validation String Add-TextField -IsEmail
link URL/link input field String Add-LinkField
number Numeric input Int/Double Add-TextField -IsNumber
checkbox Boolean checkbox Boolean Add-Checkbox
tristate Three-state checkbox Int/null Add-TristateCheckbox
date Date picker (no time) DateTime Add-DateTimePicker -DateOnly
date time Date and time picker DateTime Add-DateTimePicker
item Single item picker with tree Item Add-ItemPicker
treelist Multi-item picker with tree Item[] Add-TreeList
multilist Multi-item dual-list selector Item[] Add-MultiList
droplink Dropdown item selector (flat list) Item Add-Droplink
droptree Dropdown tree item selector Item Add-Droptree
droplist Dropdown list (flat list) String Add-Droplist
groupeddroplink Grouped variant of droplink Item Add-GroupedDroplink
groupeddroplist Grouped variant of droplist String Add-GroupedDroplist
combo Dropdown with options String Add-Dropdown
radio Radio button group String/Int Add-RadioButtons
checklist Multiple checkbox selection Int[] Add-Checklist
user Single user picker String Add-UserPicker
user multiple Multiple user picker String[] Add-UserPicker -Multiple
role Single role picker String Add-RolePicker
role multiple Multiple role picker String[] Add-RolePicker -Multiple
user role Combined user/role picker String Add-UserRolePicker
user role multiple Multiple user/role picker String[] Add-UserRolePicker -Multiple
rule Sitecore rules engine editor String Add-RuleField
rule action Sitecore rule action editor String Add-RuleActionField
info Read-only informational text String Add-InfoText
marquee Scrolling text display String Add-Marquee

Return Types Quick Reference

Control Type PowerShell Type Example Value
Text Field [String] "Hello World"
Email Field [String] "[email protected]"
Link Field [String] "https://example.com"
Number Field [Int] or [Double] 42 or 3.14
Checkbox [Boolean] $true or $false
Tristate Checkbox [Int] or $null 1, 0, or $null
Date/Time Picker [DateTime] [DateTime]::Now
Item Picker [Sitecore.Data.Items.Item] Item object
TreeList/MultiList [Sitecore.Data.Items.Item[]] Array of Items
User Picker [String] or [String[]] "sitecore\admin"
Role Picker [String] or [String[]] "sitecore\Author"
Dropdown [String] "option1" (the value)
Radio Buttons [String] or [Int] Depends on options
Checklist [Int[]] @(1, 2, 4) (bitmask values)
Icon Selector [String] "Office/32x32/document.png"
Name-Value List [String] "key1=value1&key2=value2"
Rule Field [String] XML rule definition
Rule Action Field [String] XML rule action definition

Validation Patterns

When using the -Validator parameter with Show-Dialog, the validator scriptblock has access to:

  • $variables - Collection of all dialog fields
  • $variables.<fieldName>.Value - The current value of a field
  • $variables.<fieldName>.Error - Set this to display an error message

Validator Best Practices:

  1. Always return from the validator after setting an error
  2. Access external variables through closure or script scope
  3. Validate all interdependent fields in a single validator
  4. Provide clear, actionable error messages
  5. Check field values in logical order (required fields first)

Performance Considerations

Recommended Limits:

  • Fields per dialog: < 50 (optimal: 15-25)
  • Tabs per dialog: < 10 (optimal: 3-5)
  • Conditional visibility groups: < 20
  • Dialog dimensions: 400x300 to 1200x800 pixels

Performance Tips:

  1. Use tabs to organize large numbers of fields
  2. Limit the depth of conditional visibility chains
  3. Use appropriate Root paths for item pickers to reduce tree size
  4. Consider breaking very large dialogs into wizard-style multi-step dialogs
  5. Use Test-DialogBuilder to identify configuration issues early

Common Patterns and Integration

Report Integration:

# Use dialog builder in a report script
$dialog = New-DialogBuilder -Title "Report Parameters" -Width 500 -Height 400 |
    Add-ItemPicker -Name "rootItem" -Title "Root Item" -Mandatory |
    Add-DateTimePicker -Name "fromDate" -Title "From Date" -DateOnly |
    Add-DateTimePicker -Name "toDate" -Title "To Date" -DateOnly

$result = Show-Dialog -DialogBuilder $dialog
if ($result -ne "ok") { Exit }

# Use $rootItem, $fromDate, $toDate in your report logic
Get-ChildItem -Path $rootItem.ItemPath -Recurse |
    Where-Object { $_.Created -ge $fromDate -and $_.Created -le $toDate }

Context Menu Integration:

# In a context menu script, use current item as default
$contextItem = Get-Item .

$dialog = New-DialogBuilder -Title "Process Items" -Width 500 -Height 400 |
    Add-ItemPicker -Name "sourceItem" -Title "Source" -Value $contextItem -Mandatory |
    Add-Checkbox -Name "includeSubitems" -Title "Include Subitems" -Value $true

$result = Show-Dialog -DialogBuilder $dialog
if ($result -ne "ok") { Exit }

# Process the selected item(s)

Toolbox Integration:

# Create reusable dialogs for toolbox commands
function Get-PublishingParameters {
    $dialog = New-DialogBuilder -Title "Publishing Options" -Width 550 -Height 450 -ShowHints |
        Add-Checkbox -Name "smartPublish" -Title "Smart Publish" -Value $true |
        Add-Checkbox -Name "publishSubitems" -Title "Include Subitems" -Value $true |
        Add-Checklist -Name "languages" -Title "Languages" -Options ([ordered]@{"English"=1;"German"=2}) -Value @(1)

    $result = Show-Dialog -DialogBuilder $dialog
    if ($result -ne "ok") { return $null }

    return @{
        SmartPublish = $smartPublish
        PublishSubitems = $publishSubitems
        Languages = $languages
    }
}

# Use in multiple scripts
$params = Get-PublishingParameters
if ($params) {
    # Execute publishing with $params
}

Troubleshooting

Common Issues

Issue: Variables not available after Show-Dialog

# ❌ Wrong - using Get-Variable incorrectly
$result = Show-Dialog -DialogBuilder $dialog
$value = Get-Variable -Name "userName"  # Returns VariableInfo object

# ✓ Correct - variables are automatically in scope
$result = Show-Dialog -DialogBuilder $dialog
Write-Host $userName  # Variable is directly accessible

Issue: Item picker shows empty value

# ❌ Wrong - not initializing Item fields
Add-DialogField -Name "item" -Editor "item"  # Will fail

# ✓ Correct - provide initial value or Root
Add-ItemPicker -Name "item" -Root "/sitecore/content/" -Value (Get-Item "master:/sitecore")

Issue: Conditional visibility not working

# ❌ Wrong - missing GroupId on controlling field
Add-Checkbox -Name "toggle" -Title "Show Advanced"  # No GroupId
Add-TextField -Name "advanced" -ParentGroupId 1 -HideOnValue "0"  # References non-existent group

# ✓ Correct - GroupId on controlling field
Add-Checkbox -Name "toggle" -Title "Show Advanced" -GroupId 1
Add-TextField -Name "advanced" -ParentGroupId 1 -HideOnValue "0"

Issue: Validation not triggering

# ❌ Wrong - not accessing through $variables collection
$validator = { if ($userName -eq "") { ... } }  # Won't work

# ✓ Correct - use $variables collection
$validator = { if ($variables.userName.Value -eq "") { $variables.userName.Error = "Required" } }

Version History and Migration

Migrating from Direct Read-Variable Usage

Before (Read-Variable):

$result = Read-Variable -Parameters `
    @{ Name = "userName"; Value=""; Title="User Name"; Mandatory=$true },
    @{ Name = "isActive"; Value=$false; Editor="checkbox" } `
    -Title "User Dialog" -Width 500 -Height 400

After (Dialog Builder):

$dialog = New-DialogBuilder -Title "User Dialog" -Width 500 -Height 400 |
    Add-TextField -Name "userName" -Title "User Name" -Mandatory |
    Add-Checkbox -Name "isActive" -Value $false

$result = Show-Dialog -DialogBuilder $dialog

Benefits:

  • ✓ More readable and maintainable
  • ✓ Automatic variable initialization
  • ✓ Type inference
  • ✓ Better error messages
  • ✓ Validation and debugging tools
  • ✓ Chainable fluent API

Additional Resources

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment