PoshUI Authoring Guide & Best Practices
Scope
This guide covers the three original modules — Wizard, Dashboard and Workflow — as of PoshUI 1.3.1. It does not cover PoshUI.Canvas (added in 1.4.0), which has its own authoring documentation: About Canvas, the Capability Reference, and the Agent Authoring Guide for LLM-assisted authoring.
A practical, accurate reference for writing PoshUI scripts — Wizards, Dashboards, and Workflows — with a deep focus on the Dashboard module and ScriptCards (including dot-sourcing external PowerShell files).
Every cmdlet signature and example in this guide was extracted from and executed against the PoshUI source in this repo (PoshUI 1.3.1). Examples are validated to build without error. This document is designed to be fed to an LLM as authoring context.
1. Mental model
PoshUI is a PowerShell-module front end over a compiled .NET Framework 4.8 / WPF executable (PoshUI.exe). You describe a UI with familiar PowerShell cmdlets; the module serializes that description and hands it to the EXE, which renders a Windows 11–style window and streams results back.
There are three independent modules. Pick exactly one per script.
| Module | Use it for | Entry cmdlet |
|---|---|---|
| PoshUI.Wizard | Step-by-step input forms with validation, then run logic | New-PoshUIWizard |
| PoshUI.Dashboard | Monitoring + clickable tools (cards: metrics, charts, tables, status, ScriptCards) | New-PoshUIDashboard |
| PoshUI.Workflow | Sequential task execution with progress, approval gates, reboot/resume | New-PoshUIWorkflow |
The universal build pattern
Every script follows the same shape:
Import-Module .\PoshUI\PoshUI.Dashboard\PoshUI.Dashboard.psd1 # 1. one module only
New-PoshUIDashboard -Title '...' # 2. create the definition
Set-UIBranding ... # 3. (optional) branding
Set-UITheme ... # 4. (optional) custom colors
Add-UIStep -Name '...' ... # 5. one or more steps (= pages)
Add-UI<Control> -Step '...' ... # 6. controls/cards on each step
Show-PoshUIDashboard # 7. launch the window (blocks until closed)How it runs under the hood: Wizard/Workflow generate a PowerShell
param()-block script that the EXE AST-parses; Dashboard serializes to JSON. You normally never see this — but it explains two rules below (safe identifiers, and "values are data, not code").
2. Golden rules (read before generating any script)
- Import only one PoshUI module per script. All three export overlapping names (
Add-UIStep,Set-UIBranding,Add-UICard, …). Importing two clobbers cmdlets. -Nameis an internal identifier;-Title/-Labelis what the user sees. A control/step-Namemust be a safe identifier: start with a letter or underscore, then letters/digits/underscores, max 64 chars. (ServerName,Disk_Check1✓ —Disk Check,1st,evil'; calc✗.) The generator rejects unsafe names.-Namemust be unique within its step.- Icons are either a Segoe MDL2 glyph in the form
'', or a path to a PNG/ICO via-IconPath. SeeDocs/FLUENT_ICONS_REFERENCE.mdfor glyphs.-IconPathwins over-Iconwhen both are given. - Use here-strings (
@"..."@) for multi-line text (card content, descriptions) rather than`n. - Values are treated as data, not code. PoshUI escapes every value you pass into the generated script, so apostrophes and special characters are safe. Do not expect a value to "execute."
- Never put secrets in
-DefaultParameters/defaults or persisted state. Secret-named fields andSecureString/PSCredentialare auto-redacted before any state is written, but don't rely on it — pass secrets at runtime. Show-*blocks until the user closes the window and returns results. For headless/CI validation of a definition, build it and inspect withGet-PoshUIDashboard/Get-PoshUIDashboard -AsJsoninstead of launching.
3. Dashboard module (primary focus)
A Dashboard is a set of steps, each rendered as a page (sidebar entry) containing a responsive grid of cards.
3.1 Create the dashboard
New-PoshUIDashboard -Title 'Admin Tools' `
-Description 'Ops console' `
-GridColumns 3 ` # 1–6 cards per row (default 3)
-Theme 'Dark' # Light | Dark | Auto (default Auto = follow system)Other useful params: -Icon (window/taskbar icon, glyph or path), -SidebarHeaderText, -SidebarHeaderIcon, -SidebarHeaderIconOrientation (Left|Right|Top|Bottom), -AllowCancel, -LogPath.
3.2 Branding & theme
Set-UIBranding -WindowTitle 'Admin' `
-SidebarHeaderText 'Quick Tools' `
-SidebarHeaderIcon '' `
-SidebarHeaderIconOrientation 'Top'
# Custom colors — independent palettes for light and dark (any subset of 24 slots)
Set-UITheme -Light @{ AccentColor = '#FF6B35' } `
-Dark @{ AccentColor = '#FF6B35'; Background = '#1A1A2E' }Color slots (hex #RRGGBB or #AARRGGBB): AccentColor, AccentDark, AccentDarker, AccentLight, Background, ContentBackground, CardBackground, SidebarBackground, SidebarText, SidebarHighlight, TextPrimary, TextSecondary, ButtonBackground, ButtonForeground, InputBackground, InputBorder, BorderColor, TitleBarBackground, TitleBarText, SuccessColor, WarningColor, ErrorColor, plus non-color FontFamily, CornerRadius.
3.3 Add a step (= a dashboard page)
Add-UIStep -Name 'Tools' -Title 'Administrative Tools' -Type 'Dashboard' -Icon ''For dashboards, always pass
-Type 'Dashboard'. Add multiple steps to get multiple pages in the sidebar. A banner at the top of a page:powershellAdd-UIBanner -Step 'Tools' -Name 'B1' -Title 'Administrative Tools' ` -Subtitle 'Common monitoring and maintenance tasks' -BackgroundColor '#0078D4'
3.4 Card catalog
All Add-UI*Card cmdlets share -Step -Name -Title (all required) plus -Description, -Icon/-IconPath, -Category.
| Cmdlet | Purpose | Key params |
|---|---|---|
Add-UIScriptCard | Clickable tool that runs a script with a parameter dialog + live console | -ScriptBlock or -ScriptPath, -DefaultParameters, -Category, -Tags |
Add-UIMetricCard | Single KPI value, trend, gauge, target bar | -Value (number or scriptblock), -Unit, -Format, -Trend, -Target, -ShowGauge, -ShowSparkline, -SparklineData, -RefreshScript |
Add-UIChartCard | Line/Bar/Area/Pie/Donut chart | -ChartType, -Data (array/hashtable or scriptblock), -ShowLegend, -RefreshScript |
Add-UITableCard | Sortable/filterable/exportable data grid | -Data (objects or scriptblock), -RefreshScript |
Add-UIStatusCard | List of items with auto-colored status dots | -Data (@(@{Label;Status})), -RefreshScript |
Add-UICard | Static info panel (text/links/gradient) | -Content, -LinkUrl, -BackgroundColor, -GradientStart/End, … |
Live data: for MetricCard, ChartCard, TableCard, StatusCard, if you pass a scriptblock to -Value/-Data, it is run once for the initial render and automatically reused as the card's refresh action (the refresh button re-runs it). You can also pass an explicit -RefreshScript.
StatusCard auto-coloring (by the Status string): green = Online/Running/Healthy/OK/Active/Up/Connected/Success; amber = Warning/Degraded/Slow/Pending/Starting; red = Offline/Stopped/Error/Critical/Down/Failed/Disconnected; gray = Maintenance/Disabled/Unknown.
# Metric (static and dynamic)
Add-UIMetricCard -Step 'Tools' -Name 'CPU' -Title 'CPU Usage' -Value 42 -Unit '%' -Trend 'up' -Target 80
Add-UIMetricCard -Step 'Tools' -Name 'Mem' -Title 'Memory' -Value { 11 } -Unit 'GB' -Target 16 -ShowGauge
# Chart
$data = @(@{Month='Jan';Sales=100}, @{Month='Feb';Sales=150}, @{Month='Mar';Sales=120})
Add-UIChartCard -Step 'Tools' -Name 'Sales' -Title 'Sales' -ChartType 'Bar' -Data $data
Add-UIChartCard -Step 'Tools' -Name 'ProcCPU' -Title 'Top Procs' -ChartType 'Line' `
-Data { Get-Process | Select-Object -First 5 Name, CPU }
# Table (live)
Add-UITableCard -Step 'Tools' -Name 'Svcs' -Title 'Services' `
-Data { Get-Service | Select-Object -First 20 Name, Status, StartType }
# Status
Add-UIStatusCard -Step 'Tools' -Name 'Health' -Title 'Service Health' -Icon '' -Data @(
@{Label='Active Directory'; Status='Online'}
@{Label='DNS'; Status='Warning'}
@{Label='Legacy App'; Status='Offline'}
)
# Info panel
Add-UICard -Step 'Tools' -Name 'Notes' -Title 'Notes' -Icon '' -BackgroundColor '#107C10' -Content @"
Guidelines:
- Run health checks before maintenance
- Escalate anything red
"@4. ScriptCard deep-dive
A ScriptCard is the heart of an actionable dashboard. It renders as a tile; when the user clicks it, PoshUI:
- Auto-discovers the script's parameters (by AST-parsing its
param()block), - opens a dialog with one input control per parameter, pre-filled with defaults,
- executes the script in its own runspace with the user's values, and
- streams real-time console output into the dialog.
ScriptCards do not participate in form collection — they're independent, on-demand tools.
4.1 Two sources (mutually exclusive)
# (a) Inline scriptblock
Add-UIScriptCard -Step 'Tools' -Name 'DiskCheck' -Title 'Check Disk' `
-Description 'View disk usage' -Category 'Monitoring' -Icon '' `
-ScriptBlock {
param(
[ValidateSet('C','D','E')][string]$DriveLetter = 'C',
[switch]$Detailed
)
$d = Get-PSDrive -Name $DriveLetter
"Free on ${DriveLetter}: {0:N1} GB" -f ($d.Free/1GB)
if ($Detailed) { $d | Format-List }
}
# (b) External .ps1 file — parameters discovered from the file's param() block
Add-UIScriptCard -Step 'Tools' -Name 'FileTool' -Title 'File Processor' `
-Category 'Advanced' -ScriptPath 'C:\Tools\Process-Files.ps1'-DefaultParameters @{ ... } pre-fills/overrides the dialog; -Category and -Tags drive filtering in the grid.
Add-UIScriptCard -Step 'Tools' -Name 'Pinger' -Title 'Ping' `
-ScriptBlock { param([string]$HostName='localhost',[int]$Count=4) Test-Connection $HostName -Count $Count } `
-DefaultParameters @{ HostName = '8.8.8.8'; Count = 2 }4.2 Parameter auto-discovery — how to control the generated inputs
Design your param() block deliberately; this table is exactly how PoshUI maps it to controls:
In your param() | Becomes this control |
|---|---|
[string] | TextBox |
[int] / [long] / [double] / [decimal] | Numeric (with step) |
[bool] | Checkbox |
[switch] | Toggle |
[datetime] | Date picker |
[SecureString] / [PSCredential] | Password (masked) |
[string[]] | Multi-line TextBox (one value per line) |
[ValidateSet('A','B')] | Dropdown of the allowed values |
[ValidateRange(1,10)] | Numeric bounded 1–10 |
[ValidatePattern('...')] | TextBox with regex validation |
[ValidateScript({ Test-Path $_ -PathType Leaf })] | File picker |
[ValidateScript({ Test-Path $_ -PathType Container })] | Folder picker |
Param named *Folder/*Directory/*Dir | Folder picker |
Param named *File/*Path/ScriptPath/ConfigPath/LogPath | File picker |
Also honored: [Parameter(Mandatory)] and [ValidateNotNullOrEmpty()] mark the field required; [Parameter(HelpMessage='...')] becomes the field's tooltip; a = default literal pre-fills the input. Parameter names are auto-prettified for labels (DriveLetter → "Drive Letter").
Tip for the LLM: to get a clean dialog, give every parameter a sensible default, a
ValidateSet/ValidateRangewhere it applies, and aHelpMessage. Use type and validation to choose the control — you rarely need to configure the UI separately.
4.3 Dot-sourcing PowerShell files into ScriptCards
ScriptCards run in their own runspace inside PoshUI.exe, separate from the dashboard script. Two consequences drive the best practice:
- Functions defined in your dashboard script are not automatically available inside a card.
$PSScriptRoot/$PSCommandPathand the working directory are not guaranteed inside the card's runspace, so relative dot-source paths are unreliable.
Best practice: bake an absolute path to your library and dot-source it inside the card. Keep reusable logic in a .ps1 of functions, resolve its absolute path at build time, and embed that into the card's scriptblock with [scriptblock]::Create() + a here-string.
# Lib\DiskTools.ps1 -> contains: function Get-DiskReport { param([string]$DriveLetter='C') ... }
# In your dashboard script — resolve the absolute path WHILE BUILDING the dashboard:
$libPath = Join-Path $PSScriptRoot 'Lib\DiskTools.ps1' # absolute, resolved now
Add-UIScriptCard -Step 'Tools' -Name 'DiskReport' -Title 'Disk Report' -Category 'Storage' `
-ScriptBlock ([scriptblock]::Create(@"
param([ValidateSet('C','D','E')][string]`$DriveLetter = 'C')
. '$libPath' # absolute path baked in at build time
Get-DiskReport -DriveLetter `$DriveLetter
"@))Notes on the here-string:
- Use a double-quoted here-string so
$libPathexpands into the literal path, but escape every runtime$you want to survive into the card as`$(e.g.`$DriveLetter). - Auto-discovery still works: it parses the
param()block at the top, soDriveLetterbecomes a dropdown.
Alternative (often cleaner): make each tool a self-contained .ps1. Put the param() block at the top and reference it with -ScriptPath. If that script needs shared helpers, dot-source them by absolute path from inside the script:
# C:\Tools\New-CompanyUser.ps1
param(
[Parameter(Mandatory)][string]$UserName,
[ValidateSet('IT','Sales','Ops')][string]$Department = 'IT'
)
. 'C:\Tools\Lib\ADHelpers.ps1' # absolute path
New-CompanyUser -UserName $UserName -Department $DepartmentAdd-UIScriptCard -Step 'Users' -Name 'NewUser' -Title 'Create User' -ScriptPath 'C:\Tools\New-CompanyUser.ps1'Anti-patterns to avoid in cards: relying on $PSScriptRoot; dot-sourcing a relative path (. .\Lib\x.ps1); assuming a module imported by the dashboard script is loaded in the card (import it inside the card, or dot-source the functions).
5. Wizard module (high level)
Input-form flow: collect validated values across steps, then run a -ScriptBody where each control -Name is available as a $variable.
Import-Module .\PoshUI\PoshUI.Wizard\PoshUI.Wizard.psd1
New-PoshUIWizard -Title 'Server Setup' -Theme 'Auto'
Set-UIBranding -WindowTitle 'Server Setup' -SidebarHeaderText 'Acme' -SidebarHeaderIcon ''
Add-UIStep -Name 'Config' -Title 'Configuration' -Order 1 -Icon ''
Add-UICard -Step 'Config' -Title 'Welcome' -Content 'Fill in the fields below.' # NOTE: no -Name in Wizard
Add-UITextBox -Step 'Config' -Name 'ServerName' -Label 'Server Name' -Mandatory
Add-UIDropdown -Step 'Config' -Name 'Environment' -Label 'Environment' -Choices @('Dev','Test','Prod') -Mandatory
Add-UIOptionGroup -Step 'Config' -Name 'Edition' -Label 'Edition' -Options @('Standard','Datacenter') -Orientation 'Horizontal' -Default 'Standard'
Add-UINumeric -Step 'Config' -Name 'CpuCount' -Label 'CPU Cores' -Minimum 1 -Maximum 64 -Default 4
Add-UIDate -Step 'Config' -Name 'GoLive' -Label 'Go-Live Date' -Default ([datetime]'2026-07-01')
Add-UIPassword -Step 'Config' -Name 'AdminPwd' -Label 'Admin Password' -MinLength 8 -Mandatory
Show-PoshUIWizard -ScriptBody {
Write-Host "Configuring $ServerName in $Environment ($Edition, $CpuCount cores)"
# $AdminPwd is a [SecureString]
}Common controls: Add-UITextBox (+-Multiline), Add-UIPassword, Add-UICheckbox, Add-UIToggle, Add-UIDropdown, Add-UIListBox, Add-UIFilePath, Add-UIFolderPath, Add-UINumeric, Add-UIDate, Add-UIOptionGroup, Add-UIMultiLine, plus display: Add-UIBanner, Add-UICard.
Dynamic / cascading dropdowns — pass a -ScriptBlock whose param() names another control; it re-evaluates when that control changes:
Add-UIDropdown -Step 'S' -Name 'Env' -Label 'Environment' -Choices @('Dev','Prod')
Add-UIDropdown -Step 'S' -Name 'Server' -Label 'Server' -ScriptBlock {
param($Env)
if ($Env -eq 'Prod') { @('PROD01','PROD02') } else { @('DEV01') }
}6. Workflow module (high level)
Sequential tasks with progress, approval gates, error policy, and reboot/resume (state encrypted with DPAPI).
Import-Module .\PoshUI\PoshUI.Workflow\PoshUI.Workflow.psd1
New-PoshUIWorkflow -Title 'Server Deployment' -Description 'Provision + configure'
Set-UIBranding -WindowTitle 'Deployment' -SidebarHeaderText 'Acme Ops'
Add-UIStep -Name 'Deploy' -Title 'Deployment' -Order 1 -Type 'Workflow'
Add-UIWorkflowTask -Step 'Deploy' -Name 'Precheck' -Title 'Pre-flight checks' -Order 1 -ScriptBlock {
$PoshUIWorkflow.UpdateProgress(50, 'Checking prerequisites...')
$PoshUIWorkflow.WriteOutput('All prerequisites met', 'INFO')
}
Add-UIWorkflowTask -Step 'Deploy' -Name 'Approve' -Title 'Approval' -Order 2 `
-TaskType 'ApprovalGate' -ApprovalMessage 'Proceed with deployment?' -RequireReason
Add-UIWorkflowTask -Step 'Deploy' -Name 'Install' -Title 'Install role' -Order 3 -OnError 'Stop' -ScriptBlock {
$PoshUIWorkflow.UpdateProgress(10, 'Installing...')
# ... real work ...
$PoshUIWorkflow.UpdateProgress(100, 'Done')
}
Show-PoshUIWorkflowThe $PoshUIWorkflow context object (available inside every task scriptblock):
| Member | Purpose |
|---|---|
$PoshUIWorkflow.UpdateProgress(<percent>, '<message>') | Update the task's progress bar + status text |
$PoshUIWorkflow.WriteOutput('<text>', '<level>') | Write to the live console (level = INFO/WARN/ERROR) |
$PoshUIWorkflow.SetData('<key>', <value>) | Persist a value for later tasks / after resume |
$PoshUIWorkflow.GetData('<key>') | Read a value set earlier |
$PoshUIWorkflow.RequestReboot() | Request a reboot; the workflow resumes at the next task afterward |
Add-UIWorkflowTask key params: -ScriptBlock or -ScriptPath, -Order, -TaskType (Normal/ApprovalGate), -OnError (Stop/Continue), -Arguments, -ApprovalMessage, -RequireReason. Workflow steps (-Type Workflow) can be mixed with normal input steps (-Type Wizard) to collect parameters before the task sequence.
7. Cross-module differences & gotchas
These trip people up because the same-named cmdlet differs by module:
Add-UICardname parameter: Dashboard'sAdd-UICardrequires-Name; Wizard'sAdd-UICardhas no-Name(it auto-generates one) — pass-Step -Title -Contentpositionally/by name.- Implicit "current definition": each
New-PoshUI*sets the module's current definition; you don't pass it around. Only one definition is active at a time. Add-UIStep -Type: Dashboard pages need-Type 'Dashboard'; workflow task pages need-Type 'Workflow'; input forms are-Type 'Wizard'(default).Add-UIDate/Add-UINumericdefaults/bounds:-Default,-Minimum,-Maximum(and Numeric-Increment) are honored as of 1.3.1. On older builds they were silently ignored — bump the modules if defaults don't appear.- ScriptCard runspace isolation: see §4.3 — bake absolute paths; don't rely on
$PSScriptRootinside a card. - Validate headlessly:
Show-*opens a blocking GUI window. To check a definition without a display, build it then callGet-PoshUIDashboard/Get-PoshUIDashboard -AsJson(or for Wizard/Workflow, just build and avoidShow).
8. Complete, validated Dashboard example
A self-contained dashboard that combines every card type, both ScriptCard modes, and a dot-sourced library. (All builder calls in this script were executed successfully against PoshUI 1.3.1.)
Import-Module .\PoshUI\PoshUI.Dashboard\PoshUI.Dashboard.psd1
# A reusable function library that cards will dot-source (absolute path baked at build time)
$libPath = Join-Path $PSScriptRoot 'Lib\DiskTools.ps1'
New-PoshUIDashboard -Title 'Admin Tools' -Description 'Ops console' -GridColumns 3 -Theme 'Dark'
Set-UIBranding -WindowTitle 'Admin' -SidebarHeaderText 'Quick Tools' -SidebarHeaderIcon '' -SidebarHeaderIconOrientation 'Top'
Set-UITheme -Dark @{ AccentColor = '#FF6B35'; Background = '#1A1A2E' }
Add-UIStep -Name 'Tools' -Title 'Administrative Tools' -Type 'Dashboard' -Icon ''
Add-UIBanner -Step 'Tools' -Name 'B1' -Title 'Administrative Tools' -Subtitle 'Common tasks' -BackgroundColor '#0078D4'
# Monitoring cards (live data via scriptblocks)
Add-UIMetricCard -Step 'Tools' -Name 'CPU' -Title 'CPU Usage' -Value 42 -Unit '%' -Trend 'up' -Target 80 -Icon ''
Add-UITableCard -Step 'Tools' -Name 'Svcs' -Title 'Services' -Data { Get-Service | Select-Object -First 20 Name, Status }
Add-UIStatusCard -Step 'Tools' -Name 'Health' -Title 'Service Health' -Icon '' -Data @(
@{Label='Active Directory'; Status='Online'}
@{Label='DNS'; Status='Warning'}
)
# ScriptCard — inline, auto-discovered parameters
Add-UIScriptCard -Step 'Tools' -Name 'DiskCheck' -Title 'Check Disk' -Category 'Monitoring' -Icon '' -ScriptBlock {
param([ValidateSet('C','D','E')][string]$DriveLetter = 'C', [switch]$Detailed)
$d = Get-PSDrive -Name $DriveLetter
"Free on ${DriveLetter}: {0:N1} GB" -f ($d.Free/1GB)
}
# ScriptCard — dot-sourced library (absolute path baked in)
Add-UIScriptCard -Step 'Tools' -Name 'DiskReport' -Title 'Disk Report' -Category 'Storage' `
-ScriptBlock ([scriptblock]::Create(@"
param([ValidateSet('C','D','E')][string]`$DriveLetter = 'C')
. '$libPath'
Get-DiskReport -DriveLetter `$DriveLetter
"@))
Show-PoshUIDashboard9. Prompt scaffold for an LLM (paste before your request)
You are generating a PoshUI script (PowerShell + the PoshUI 1.3.1 modules). Follow these rules:
- Import exactly one module:
PoshUI.Wizard(input forms),PoshUI.Dashboard(monitoring + clickable tools), orPoshUI.Workflow(sequential tasks). Choose based on the task.- Structure:
New-PoshUI<X>→ optionalSet-UIBranding/Set-UITheme→Add-UIStep(Dashboards use-Type 'Dashboard', Workflows-Type 'Workflow') → add controls/cards →Show-PoshUI<X>.-Nameis an internal identifier: start with a letter/underscore, only letters/digits/underscores, ≤64 chars, unique per step.-Title/-Labelis the user-facing text.- Icons are Segoe MDL2 glyphs like
''or a PNG/ICO via-IconPath. Multi-line text uses here-strings.- Dashboard cards:
Add-UIScriptCard(clickable tool),Add-UIMetricCard,Add-UIChartCard,Add-UITableCard,Add-UIStatusCard,Add-UICard. For live data pass a scriptblock to-Value/-Data.- For ScriptCards, design the
param()block to control the auto-generated dialog: use[ValidateSet]for dropdowns,[int]/[ValidateRange]for numerics,[switch]for toggles,[SecureString]for passwords,[ValidateScript({Test-Path $_ -PathType Leaf/Container})]for file/folder pickers,[Parameter(Mandatory)]for required,HelpMessagefor tooltips, and= defaultfor prefilled values.- To reuse functions in a ScriptCard, dot-source a
.ps1by absolute path baked at build time (do not rely on$PSScriptRootinside a card). Prefer self-contained.ps1tools referenced via-ScriptPath.- Workflows expose
$PoshUIWorkflowinside task scriptblocks:.UpdateProgress(pct,'msg'),.WriteOutput('text','INFO'),.SetData('k',v),.GetData('k'),.RequestReboot().- Wizard
Add-UICardhas no-Name; DashboardAdd-UICardrequires-Name.- Never hardcode secrets; pass them at runtime.
