arrow-left

Only this pageAll pages
gitbookPowered by GitBook
triangle-exclamation
Couldn't generate the PDF for 176 pages, generation stopped at 100.
Extend with 50 more pages.
1 of 100

v3

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

API

Loading...

Loading...

Loading...

Loading...

Loading...

Automation

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

User Interfaces

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

What's New in v3?

New features in PowerShell Universal v3.

hashtag
SQL Server Support

You can now persist jobs, identities and app tokens in a SQL server database to allow for multi-node instances that provide high availability and load balancing.

hashtag
Improved Editing Experience

Features such as live logging and advanced dashboard and repository editors of the admin console have been added to make editing scripts in PowerShell Universal easier to develop and debug.

hashtag
Desktop Features

PowerShell Universal Desktop now offers integrations like file associations, hot keys, system events and custom protocols to trigger scripts when certain things happen on your system.

hashtag
Translations

A built in translation provider is available in your dashboards, scripts, and APIs to provide the proper language when returning data back to your end users.

hashtag
New Dashboard Components

New dashboard components such as the data grid, stack, badge, timeline and schema form allow you to bring even more functionality to your user interfaces.

Supported Browsers

Universal uses a variety of modern web frameworks and can have issues with older browsers such as Internet Explorer.

The current version of the following web browsers is supported: Chromearrow-up-right, Firefoxarrow-up-right, Safariarrow-up-right, and Microsoft Edgearrow-up-right

Data Visualization

Feedback

Data Display

Surfaces

Inputs

Input controls for Universal Dashboard

Navigation

Layout

HTML

Define static HTML using Universal Dashboard.

You can define static HTML using New-UDHtml. This cmdlet does not create React components but rather allows you to define static HTML. Any valid HTML string is supported.

The following creates an unordered list.

New-UDHtml -Markup "<ul><li>First</li><li>Second</li><li>Third</li></ul>"

hashtag
API

New-UDHtmlarrow-up-right

Error Boundary

Error boundary component for Universal Dashboard.

The New-UDErrorBoundary component is used for isolating portions of a dashboard to contain components that may throw an error. Many Universal Dashboard components use the error boundary component internally.

If you'd like to isolate a portion of your dashboard to prevent the entire page from failing to load, you can use the following syntax.

New-UDErrorBoundary -Content {
    throw "Oh no!"
}

If any error is thrown from the content, you will see an error such as thing.

hashtag
API

System Requirements

hashtag
Windows

  • Optional*: or greater

About Automation

Run and schedule scripts with automation

hashtag
Run Scripts

You can run in PowerShell Universal. PowerShell Universal integrates deeply with the PowerShell host to provide a UI for param blocks, output rich objects, display progress and even allow the user to provide feedback.

Queues

Custom job queues for scripts.

You can assign computers to queues by using application settings. By default, every computer is assigned to the default queue and a queue specific to the computer itself. When you assign a computer to a custom queue, that queue will be available in the admin console and you can use the queue for ad-hoc script execution and schedules.

circle-exclamation

Queues with no active computers will queue jobs indefinitely.

Tree View

Tree view component for Universal Dashboard.

New-UDTreeView allows you to create a tree of items and, optionally, dynamically expand the list when clicked.

hashtag
Basic Tree View

Create a basic tree view by using the New-UDTreeNode cmdlet.

Image

Image component for dashboards.

hashtag
Image by URL

Display an image based on a URL. You can host URLs using .

hashtag

Protect Section

Protect sections based on roles.

The Protect-UDSection cmdlet hides it's content if a user does not have the specified roles.

Markdown

Markdown display for Universal Dashboard.

New-UDMarkdown accepts a markdown string and renders it as HTML elements within a dashboard.

hashtag
API

Optional*: PowerShell v7.2 or greater
  • .NET Framework v4.7.2arrow-up-right (only for Windows PowerShell)

  • hashtag
    Linux

    • Optional*: PowerShell v6.0 or greater

    • Validated Distributions: Ubuntu 18.04

    hashtag
    Mac OS

    • Optional*: PowerShell v6.0 or greater

    circle-info

    *PowerShell Universal packages a version of the PowerShell SDK. If you do not have a version of PowerShell installed, the integrated PowerShell version will be used.

    Windows PowerShell v5.1arrow-up-right

    Utilities

    Protect-UDSection -Role @("Administrator") -Content {
       New-UDTypography -Text 'Only Administrators see this'
    }
    New-UDMarkdown
    New-UDMarkdown -Markdown "
       # Header
       - List Item 1
       - List Item 2
       
       ## Sub Header
    "
    hashtag
    Configure a Queue

    To a configure a computer to a specific queue, use the UniversalAutomation \ Queues setting.

    hashtag
    appsettings.json

    Assign a machine to a queue using an appsettings.json file.

    hashtag
    Environment Variable

    Assign a machine to a queue using an environment variable.

    hashtag
    Using a Custom Queue

    Custom queues will be available within the Computer drop down in the script Run dialog, and trigger, script and schedule properties.

    $ENV:UniversalAutomation__Queues = "windows7"
    Image by Path

    Display an image based on a file local to the server.

    hashtag
    Image Size

    Change the size of the image using the -Width and -Height parameters.

    hashtag
    Attributes

    Apply additional attributes to the image.

    hashtag
    API

    • New-UDImagearrow-up-right

    Published Folders
    "UniversalAutomation": {
        "Queues": ["windows7"],
    }
    New-UDImage -Url "https://ironmansoftware.com/img/ps-logo.png"
    New-UDImage -Path C:\users\adamr\Desktop\ps-logo.png
    New-UDImage -Url "https://ironmansoftware.com/img/ps-logo.png" -Width 250 -Height 250
    New-UDImage -Url "https://ironmansoftware.com/img/ps-logo.png" -Attributes @{
        alt = "Ironman Software Logo"
    }
    hashtag
    Schedule Jobs

    You can schedule jobs to run continuously, at certain times or even when events happen within the PowerShell Universal platform.

    hashtag
    Ad-Hoc Commands

    Run ad-hoc commands in terminals in any of your configured environments and, optionally, as alternate credentials.

    scripts
    Basic Tree View

    hashtag
    Dynamic Tree View

    Dynamic tree views allow you to run PowerShell whenever a node is clicked. You can then return a list of nodes that should be rendered underneath the clicked node. You can also take other actions such as opening a modal or showing a toast.

    hashtag
    API

    • New-UDTreeViewarrow-up-right

    • New-UDTreeNodearrow-up-right

    New-UDErrorBoundaryarrow-up-right

    About

    Universal provides the ability to define REST API endpoints using PowerShell. When the endpoints are executed by a compatible HTTP client, the PowerShell script will execute and return the result to the end user.

    circle-info

    This feature is for developing custom APIs run by Universal. It not required for managing Universal. Universal provides a set of management APIs that are included with the platform.

    hashtag
    Execution Environment

    The REST API execution environment runs in your default PowerShell version. Unlike Automation jobs, which can also be run via the Universal management API, APIs that you define are run in a single PowerShell process. Because the PowerShell process is not started and stopped for each call to the endpoint, the API is much faster.

    You can define the that runs the PowerShell Universal API process by specifying the -ApiEnvironment on Set-PSUSetting. Changing this setting will cause the API process to restart.

    hashtag
    Per Endpoint Environment

    You can also define the environment used by specifying the Environment on the endpoint itself.

    hashtag
    Performance

    Performance is relative to the hardware and network conditions that you are running Universal on. That said, in ideal conditions you can expect the Universal APIs to service about 500 requests per second. This is with an entirely empty endpoint so any script that you add to that endpoint will reduce the throughput. The reduction of throughput will depend on the cmdlets and script executed within the API endpoint. There is no hard limit.

    See for detailed information about benchmark tests on Universal APIs.

    hashtag
    Variables

    Variables are listed on the .

    hashtag
    API

    Examples

    Examples of things you can do with dashboards.

    hashtag
    Display Processes

    This example displays processes in a table.

    New-UDDashboard -Title 'Processes' -Content {
        $Processes = Get-Process | Select-Object Id, Name
        New-UDTable -Columns @(
            New-UDTableColumn -Property 'Id' -Title 'Id'
            New-UDTableColumn -Property 'Name' -Title 'Name'
        ) -Data $Processes -ShowPagination
    }

    hashtag
    File System Browser

    Create a file system browser with a dynamic tree view.

    hashtag
    Create User Form

    This example shows how to create a local user account.

    hashtag
    Clock

    This example shows how to create a clock component in PowerShell Universal Dashboard.

    Terminals

    In-browser PowerShell terminals.

    circle-info

    Terminals require a licensearrow-up-right.

    Terminals are in-browser PowerShell consoles that you can execute arbitrary commands within. Terminals are configured to target an environment that you select and can optionally us Run As credentials to run as other users. The history of terminals is maintained within the PowerShell Universal database. You can reconnect to disconnected terminals as long as they haven't timed out.

    circle-info

    Terminal configurations are stored in terminals.ps1

    hashtag
    Configure A Terminal

    You can configure a new terminal by navigating to Automation \ Terminals and clicking Create New Terminal. You'll be able to select the environment and credential to run the terminal as.

    hashtag
    Use a Terminal

    To use a terminal, click the Open Terminal button for the terminal you wish to launch. Depending on your configuration, this may start a new PowerShell process based on the environment you selected.

    Once the terminal has launched, you'll be able to issue commands.

    hashtag
    Stop a Terminal

    To stop a terminal, you can navigate to the terminal instances tab on the Terminals page. Click the trash can to stop the terminal.

    hashtag
    Reconnect to a Terminal

    If you navigate away from PowerShell Universal, the terminal will go idle. You can reconnect to a terminal by clicking the Open Terminal button for the idle terminal instance.

    Terminals will time out automatically after 5 minutes. You can customize the timeout by setting the -IdleTimeout parameter of New-PSUTerminal.

    hashtag
    History

    Terminal history can be enabled per terminal configuration.

    When terminal history is enabled, you will be able to view the history of all commands that were executed within the terminal. Click the View Command History button for the instance in question.

    You will be able to review what the command was that ran, when it was ran, who started the terminal and what the output of the command was.

    Licensing

    Licensing options for PowerShell Universal

    PowerShell Universal is licensed per server. We provide licenses for individuals and organizations.

    You can purchase a license on our websitearrow-up-right.

    hashtag
    What's a server?

    A server is a single running instance of PowerShell Universal.

    hashtag
    What if I have multiple containers?

    The license applies to each container instance and not the container host. For example, if you have 10 container instances running, you will need 10 licenses.

    hashtag
    What if I have multiple sites on a single IIS server?

    Each website running PowerShell Universal will need a license and not a single license for the entire IIS server.

    hashtag
    Install a License

    To install a license, click Settings \ License. Click the Add License button to upload your license file. You can also install licenses using the Set-PSULicense cmdlet. Offline licenses do not require an internet connection but will need to be reinstalled when the subscription expires, in you wish to update the version of PowerShell Universal. Online licenses require an internet connection and access to https://ironmansoftware.com in order to verify subscription status.

    Proxy configuration can be done by clicking Settings \ General and configuring the proxy URI and, optionally, credentials. You can also configure proxy settings with the Set-PSUSetting cmdlet.

    hashtag
    Developer Licenses

    When a server license is purchased, you will be able to generate developer licenses for users building solutions for your team. Developer licenses do not allow remote access and are intended to be used locally. Do not use developer licenses when hosting a server for remote access for testing or production.

    You can generate a developer license on the Settings \ License page by clicking the Generate Developer License button.

    hashtag
    Licensed Features

    The following features of PowerShell Universal require a license.

    • Debugging Tools

    • Enterprise Authentication

      • OpenID Connect

    System Events

    Launch scripts when certain events happen in Windows.

    System Events in the Admin Console

    System events subscribe to WMI events within Windows and run scripts. You can then take action by running scripts.

    hashtag
    Defining a System Event

    To define a system event, you can use the New-PSUSystemEvent cmdlet within the systemEvents.ps1 file. The following example triggers the systemEvent.ps1 script when a pwsh.exe process is started.

    hashtag
    Accessing Event Data

    When a script is executed, you will receive a $TargetInstance parameter. This contains the WMI object that caused the event to trigger.

    Components

    A Universal Dashboard website is composed of components. In addition to the core component, you can also extend Universal Dashboard with a large set of community created components.

    There are two non-framework components that are built into PSU. These include the Nivo charts library as well as the UDMap component. Additional components can be downloaded from the UD Marketplacearrow-up-right.

    External components are distributed as PowerShell modules and can be used in a dashboard by using Import-Module.

    When building a dashboard, you can simply call the PowerShell cmdlets within your dashboard script to create a new component.

    hashtag
    Adding Components to Dashboards

    You can add component modules by clicking the Components button on the Dashboard page and then adding the components. This list will also include components downloaded from the Marketplace.

    hashtag
    Component Storage

    Each version of PowerShell Universal includes some built in components. These components are included in the local installation directory. During start up, they are deployed to the assets folder. By default, this folder is %ProgramData%\PowerShellUniversal\Dashboard\Components .

    You can change the assets folder by updating appsettings.json.

    hashtag
    Manual Component Installation

    You can manually install components into the assets folder by including the appropriate folder structure and files. All components need to be valid PowerShell modules.

    Each component should be in a folder with the module name and an additional folder with the version.

    hashtag
    Including Components in the Repository

    You can also include components within the code Repository. By including them in the repository, they will be downloaded when using . This functionality is only enabled when git sync is enabled.

    After a git pull is performed on the remote repository, Components will be automatically loaded and available within the Components page within PowerShell Universal. The structure and layout of the components folder is the same as the main assets folder.

    Tooltip

    Tooltip component for PowerShell Universal.

    Tooltips display informative text when users hover over an element.

    hashtag
    Basic Tooltip

    New-UDTooltip -Content {
        New-UDIcon -Icon 'User'
    } -TooltipContent {
        "User"
    }

    hashtag
    Placement

    Place the tooltip on top, bottom, left or right.

    hashtag
    Custom Content

    Tooltip content can contain any UD element.

    hashtag
    Tooltip Type

    Tooltips can be over various types including: "dark", "success", "warning", "error", "info", "light"

    Hidden

    Quickly and responsively toggle the visibility value of components and more with the hidden utilities.

    hashtag
    How it works

    Hidden works with a range of breakpoints e.g. xsUp or mdDown, or one or more breakpoints e.g. -Only 'sm' or -Only @('md', 'xl'). Ranges and individual breakpoints can be used simultaneously to achieve very customized behavior. The ranges are inclusive of the specified breakpoints.

    hashtag
    Up

    Using any breakpoint -Up parameter, the given children will be hidden at or above the breakpoint.

    hashtag
    Down

    Using any breakpoint -Down parameter, the given children will be hidden at or below the breakpoint.

    hashtag
    Only

    Using the breakpoint -Only parameter, the given children will be hidden at the specified breakpoint(s).

    The -Only parameter can be used in two ways:

    • list a single breakpoint

    • list an array of breakpoints

    hashtag
    API

    Date and Time

    Date and time component for Universal Dashboard.

    The New-UDDateTime component is used for formatting dates and times within the client's browser. By using the client's browser, you can format the time based on the local time zone and locale settings for the user.

    The date and time component uses DayJS. For a full list of custom formatting options, visit the DayJS documentationarrow-up-right.

    hashtag
    Basic Formatting

    By default, the date and time will be formatted using the LLL localized formatting template.

    Resulting output: August 16, 2018 8:02 PM

    hashtag
    Custom Formatting

    You can specify custom formatting strings using the .

    Resulting output: 25/01/2019

    hashtag
    Locale

    You can specify the locale to display the date and time in.

    Resulting output: 13 de septiembre de 2022 7:30

    hashtag
    API

    Alert

    Alert component for Universal Dashboard.

    Alerts provide a simple way to communicate information to a user.

    hashtag
    Simple Alerts

    Alerts have four different severities and can include text or other content.

    New-UDAlert -Severity 'error' -Text 'This is an error alert — check it out!' 
    New-UDAlert -Severity 'warning' -Text 'This is an warning alert — check it out!'
    New-UDAlert -Severity 'info' -Text 'This is an error info — check it out!' 
    New-UDAlert -Severity 'success' -Text 'This is an success alert — check it out!'
    Alert Types

    hashtag
    Advanced Alerts

    Alerts can contain any component and also a title.

    hashtag
    API

    Progress

    Progress component for Universal Dashboard

    hashtag
    Circular Progress

    New-UDProgress -Circular -Color Blue

    hashtag
    Linear Indeterminate

    hashtag
    Linear Determinate

    hashtag
    API

    Stack

    Stack components in one dimesion.

    The Stack component manages layout of immediate children along the vertical or horizontal axis with optional spacing and/or dividers between each child.

    hashtag
    Horizontal Stack

    Horizontally stacked items.

    New-UDStack -Content {
       New-UDPaper -Content { "Item 1" } -Elevation 3
       New-UDPaper -Content { "Item 2" } -Elevation 3
       New-UDPaper -Content { "Item 3" } -Elevation 3
    } -Spacing 2

    hashtag
    Vertical Stack

    Vertically stacked items.

    hashtag
    API

    • New-UDStack

    Typography

    Typography component for Universal Dashboard

    Use typography to present your design and content as clearly and efficiently as possible.

    Too many type sizes and styles at once can spoil any layout. A typographic scale has a limited set of type sizes that work well together along with the layout grid.

    hashtag
    All Typography Types

    hashtag
    Colored Text

    You can use the -Style parameter to define colors for your text.

    hashtag
    Theme-based Styling

    You can use styling by using the -Sx parameter of New-UDTypography. For example, to apply the secondary text color, you can use the following syntax.

    hashtag
    API

    Chip

    Chip component for Universal Dashboard.

    Chips are compact elements that represent an input, attribute, or action.

    Chips allow users to enter information, make selections, filter content, or trigger actions.

    While included here as a standalone component, the most common use will be in some form of input, so some of the behavior demonstrated here is not shown in context.

    hashtag
    Basic Chips

    hashtag
    Chips with Icons

    hashtag
    OnClick

    Shows a toast when the chip is clicked.

    hashtag
    OnDelete

    hashtag
    API

    Additional Resources

    hashtag
    Downloadsarrow-up-right

    Download the latest version of PowerShell Universal.

    hashtag

    Watch our free PowerShell Universal training course.

    hashtag

    The Ironman Software blog has articles about PowerShell Universal.

    hashtag

    Connect with the PowerShell Universal community.

    hashtag

    Purchase a license for the features of PowerShell Universal.

    hashtag

    File a bug report or feature request for PowerShell Universal.

    hashtag

    Samples that can be inserted into your PowerShell Universal system using the .

    hashtag

    Check out video tutorials for PowerShell Universal.

    Paper

    Paper component for Universal Dashboard

    In Material Design, the physical properties of paper are translated to the screen.

    The background of an application resembles the flat, opaque texture of a sheet of paper, and an application’s behavior mimics paper’s ability to be re-sized, shuffled, and bound together in multiple sheets.

    hashtag
    Paper

    New-UDPaper -Elevation 0 -Content {} 
    New-UDPaper -Elevation 1 -Content {} 
    New-UDPaper -Elevation 3 -Content {}

    hashtag
    Square Paper

    By default, paper will have rounded edges. You can reduce the rounding by using a square paper.

    hashtag
    Colored Paper

    The -Style parameter can be used to color paper. Any valid CSS can be included in the hashtable for a style.

    The following example creates paper with a red background.

    hashtag
    API

    Floating Action Button

    Floating action button component for Universal Dashboard

    A floating action button (FAB) performs the primary, or most common, action on a screen.

    A floating action button appears in front of all screen content, typically as a circular shape with an icon in its center. FABs come in two types: regular, and extended.

    Only use a FAB if it is the most suitable way to present a screen’s primary action.

    Only one floating action button is recommended per screen to represent the most common action.

    hashtag
    Floating Action Button

    hashtag
    OnClick

    hashtag
    API

    Grid Layout

    Drag and drop layout designer.

    hashtag
    Grid Layout

    The Grid Layout component is useful for defining layouts in a visual manner. You can drag and drop components using the web interface to automatically define the layout as JSON.

    hashtag
    Designing Layouts

    You can employ the -Design parameter to configure the layout of yourr page. This allows dynamic drag and drop of components that you place within the content of the grid layout. As you drag and resize components, the layout will be copied to your clipboard. Note: All components must possess a statid -Id

    hashtag
    Using Layouts

    Once you have configured the layout to fit your needs, you can paste the JSON into your script and assign it with the -Layout parameter. Remove the -Design parameter to lock elements in place.

    hashtag
    Allowing Users to Modify Layouts

    You can allow your users to dynamically modify layouts by using the -Draggable, -Resizable and -Persist parameters. The layout changes are stored locally so the next time each user visits a page, it will be loaded with their chosen layout.

    Expansion Panel

    Expansion Panel component for Universal Dashboard

    Expansion panels contain creation flows and allow lightweight editing of an element.

    An expansion panel is a lightweight container that may either stand alone or be connected to a larger surface, such as a card.

    hashtag
    Simple Expansion Panel

    New-UDExpansionPanelGroup -Children {
        New-UDExpansionPanel -Title "Hello" -Children {}
    
        New-UDExpansionPanel -Title "Hello" -Id 'expContent' -Children {
            New-UDElement -Tag 'div' -Content { "Hello" }
        }
    }

    hashtag
    API

    Badge

    hashtag
    Basic Badge

    Examples of badges containing text, using primary and secondary colors. The badge is applied to its children.

      New-UDBadge -BadgeContent { 4 } -Children {
          New-UDIcon -Icon Envelope -Size 2x
      } -Color primary

    hashtag
    Color

    hashtag
    API

    Link

    Link component for Universal Dashboard.

    Create a hyper link in a dashboard.

    hashtag
    Basic Link

    Create a basic link that goes to a web page.

    hashtag
    Change Style

    Adjust the underline and text style.

    hashtag
    Open in a New Window

    Open the link a new window when clicked.

    hashtag
    OnClick Event Handler

    Execute a PowerShell script block when the link is clicked.

    hashtag
    API

    Uninstall

    Uninstall PowerShell Universal

    hashtag
    Application Files

    Depending on how you installed PowerShell Universal, you will need to uninstall the application files.

    hashtag

    Button

    Button component for Universal Dashboard

    Buttons allow users to take actions, and make choices, with a single tap.

    hashtag
    Contained Button

    Contained buttons are high-emphasis, distinguished by their use of elevation and fill. They contain actions that are primary to your app.

    Rating

    Rating input component.

    hashtag
    Basic Rating

    hashtag

    Transfer List

    A transfer list (or "shuttle") enables the user to move one or more list items between lists.

    hashtag
    Simple Transfer List

    Create a simple transfer list.

    Tabs

    Tab component for Universal Dashboard

    Tabs make it easy to explore and switch between different views.

    Tabs organize and allow navigation between groups of content that are related and at the same level of hierarchy.

    hashtag
    Tabs

    Time Picker

    Time picker component for Universal Dashboard

    Time pickers pickers provide a simple way to select a single value from a pre-determined set.

    hashtag
    Time Picker

    Switch

    Switch component for Universal Dashboard

    Switches toggle the state of a single setting on or off.

    Switches are the preferred way to adjust settings on mobile. The option that the switch controls, as well as the state it’s in, should be made clear from the corresponding inline label.

    hashtag
    Switch

    Create a basic switch.

    Drawer

    Drawer component for Universal Dashboard

    hashtag
    Permanent Drawer

    A permanent drawer will be shown at all times. By default, it is show on the left side of the screen.

    List

    List component for Universal Dashboard.

    Lists are continuous, vertical indexes of text or images.

    Lists are a continuous group of text or images. They are composed of items containing primary and supplemental actions, which are represented by icons and text.

    hashtag
    List

    Checkbox

    Check component for Universal Dashboard

    Checkboxes allow the user to select one or more items from a set.

    hashtag
    Checkboxes

    Checkboxes can be disabled and checked by default

    AppBar

    AppBar component for Universal Dashboard

    The App Bar displays information and actions relating to the current screen.

    The top App Bar provides content and actions related to the current screen. It's used for branding, screen titles, navigation, and actions.

    hashtag
    AppBar with Custom Drawer

    Slider

    Slider component for Universal Dashboard.

    Sliders allow users to make selections from a range of values.

    Sliders reflect a range of values along a bar, from which users may select a single value. They are ideal for adjusting settings such as volume, brightness, or applying image filters.

    hashtag
    Slider

    New-UDTreeView -Node {
        New-UDTreeNode -Name 'Level 1' -Children {
            New-UDTreeNode -Name 'Level 2 - Item 1' 
            New-UDTreeNode -Name 'Level 2 - Item 2'
            New-UDTreeNode -Name 'Level 2 - Item 3' -Children {
                New-UDTreeNode -Name 'Level 3'
            }
        }
    }
    New-UDDashboard -Title 'File System' -Content {
        Get-PSDrive -PSProvider 'FileSystem' | ForEach-Object {
            New-UDTreeView -Node { New-UDTreeNode -Name $_.Name -Id "$($_.Name):\" } -OnNodeClicked {
                Get-ChildItem $EventData.Id | ForEach-Object {
                    New-UDTreeNode -Name $_.Name -Id $_.FullName -Leaf:$(-not $_.PSIsContainer)
                }
            }
        }
    }
    New-UDDashboard -Title 'Dashboard' -Content {
        New-UDTypography -Text 'Hello, world!'
    }
    @("h1", "h2", "h3", "h4", "h5", "h6", "subtitle1", "subtitle2", "body1", "body2", 
    "caption", "button", "overline", "srOnly", "inherit", 
    "display4", "display3", "display2", "display1", "headline", "title", "subheading") | ForEach-Object {
        New-UDTypography -Variant $_ -Text $_ -GutterBottom
        New-UDElement -Tag 'p' -Content {}
    }
    New-UDLink -Text 'Ironman Software' -Url https://www.ironmansoftware.com
    ZIP Installation

    If you installed using a provided ZIP file, you can simply stop the PowerShell Universal process or service and delete the folder you extracted to.

    hashtag
    MSI Installation

    If you installed with the Windows MSI, uninstall the application from Add\Remove Programs.

    hashtag
    Module Installation

    The Universal module installs the application files to the following locations by default.

    hashtag
    Windows

    • %ProgramData%\PowerShellUniversal

    hashtag
    Linux and Mac OS

    • %HOME%/.PowerShellUniversal

    hashtag
    Configuration Files

    Configuration files are stored in the repository folder. Once you have removed the application files, you can delete the configuration files. They are stored in the following locations by default:

    hashtag
    Windows

    • %ProgramData%\PowerShellUniversal

    • %ProgramData%\UniversalAutomation

    hashtag
    Linux

    • %HOME%/.PowerShellUniversal/

    hashtag
    Mac OS

    • %HOME%/.PowerShellUniversal/

    hashtag
    Desktop

    • %AppData%\PowerShellUniversal

    hashtag
    Database

    Removing the database depends on the database type used.

    hashtag
    LiteDB

    LiteDB databases are stored in a single file on the file system.

    hashtag
    Windows

    • %ProgramData%\PowerShellUniversal\database.db

    hashtag
    Linux and Mac OS

    • %HOME%/.PowerShellUniversal/database.db

    hashtag
    SQL

    SQL databases are stored on your SQL server and will require you to manually remove the database.

    hashtag
    IIS

    You may need to uninstall the IIS App Pool and Website when removing PowerShell Universal.

    Trainingarrow-up-right
    Blogarrow-up-right
    Forumsarrow-up-right
    Pricingarrow-up-right
    Issue Trackerarrow-up-right
    Samplesarrow-up-right
    PowerShell Universal extension for Visual Studio Codearrow-up-right
    Videosarrow-up-right
    New-PSUSystemEvent -Script "systemEvent.ps1" -Environment "Default" -Credential "Default" -Type "Create" -Condition "TargetInstance isa `"Win32_Process`" and TargetInstance.Name = `"pwsh.exe`"" -Name "PowerShell Started"
    New-UDTooltip -Content {
        New-UDIcon -Icon 'User'
    } -TooltipContent {
        "User"
    } -Place 'bottom'
    New-UDHiddenarrow-up-right
    DayJS formatting templatearrow-up-right
    New-UDDateTimearrow-up-right
    New-UDBadgearrow-up-right
    New-UDLinkarrow-up-right
    New-UDDashboard -Title 'Processes' -Content {
        Get-PSDrive -PSProvider 'FileSystem' | ForEach-Object {
            New-UDTreeView -Node { New-UDTreeNode -Name $_.Name -Id "$($_.Name):\" } -OnNodeClicked {
                Get-ChildItem $EventData.Id | ForEach-Object {
                    New-UDTreeNode -Name $_.Name -Id $_.FullName -Leaf:$(-not $_.PSIsContainer)
                }
            }
        }
    }
    New-UDDashboard -Title 'New User' -Content {
        New-UDForm -Content {
            New-UDTextbox -Id 'UserName' -Label "User Name"
            New-UDTextbox -Id 'Password' -Label 'Password' -Type 'password'
        } -OnSubmit {
            $Password = $EventData.Password | ConvertTo-SecureString -AsPlainText
            New-LocalUser -Name $EventData.UserName -Password $Password
            Show-UDToast "New user $($EventData.UserName) was created!"
        }
    }
    New-UDDashboard -Title 'Clock' -Content {
        New-UDDynamic -Id 'clock' -Content {
            (Get-Date).ToString('T')
        } -AutoRefresh -AutoRefreshInterval 1
        
        New-UDButton -Text 'Toggle Clock' -OnClick {
            Set-UDElement -Id 'clock' -Properties @{
                autoRefresh = -not( (Get-UDElement -Id 'clock').AutoRefresh)
            }
        }
    }
    param($TargetInstance)
    
    New-BurntToastNotification -Text "PowerShell Started! $TargetInstance"
    New-UDTooltip -Content {
        New-UDIcon -Icon 'User'
    } -TooltipContent {
        New-UDPaper -Children {
            "User"
        }
    }
    New-UDTooltip -Content {
        New-UDIcon -Icon 'User'
    } -TooltipContent {
        "User"
    } -Type 'success'
    innerWidth  |xs      sm       md       lg       xl
                |--------|--------|--------|--------|-------->
    width       |   xs   |   sm   |   md   |   lg   |   xl
    
    smUp        |   show | hide
    mdDown      |                     hide | show
    New-UDHidden -Up xl -Content {
        New-UDTypography 'xl'
    }
    New-UDHidden -Down xs -Content {
        New-UDTypography 'xs'
    }
    New-UDHidden -Only 'sm' -Content {
        New-UDTypography 'sm'
    }
    New-UDHidden -Only @('sm', 'xl') -Content {
        New-UDTypography 'sm,xl'
    }
    New-UDDateTime -InputObject (Get-Date)
    New-UDDateTime -InputObject (Get-Date) -Format 'DD/MM/YYYY'
    New-UDDateTime -InputObject (Get-Date) -Locale 'es'
    New-UDStack -Content {
       New-UDPaper -Content { "Item 1" } -Elevation 3
       New-UDPaper -Content { "Item 2" } -Elevation 3
       New-UDPaper -Content { "Item 3" } -Elevation 3
    } -Spacing 2 -Direction 'column'
    New-UDBadge -BadgeContent { 4 } -Children {
        New-UDIcon -Icon Envelope -Size 2x
    } -Color secondary
    New-UDBadge -BadgeContent { 4 } -Children {
        New-UDIcon -Icon Envelope -Size 2x
    } -Color success
        New-UDLink -Text 'Ironman Software' -Url https://www.ironmansoftware.com -Variant h2 -Underline always
    New-UDLink -Text 'Ironman Software' -Url https://www.ironmansoftware.com -OpenInNewWindow
    New-UDLink -Text 'Ironman Software' -OnClick {
        Show-UDToast "Hello!"
    }
    Set-UASettingarrow-up-right
    environment
    https://blog.ironmansoftware.com/webapp-benchmark-siege/arrow-up-right
    variables page
    New-PSUEndpointarrow-up-right
    Get-PSUEndpointarrow-up-right
    Remove-PSUEndpointarrow-up-right

    SAML2

  • WS-Federation

  • Windows Authentication

  • Custom Authentication Scripts

  • Enterprise Authorization

    • Access Controls

    • Custom Authorization Scripts

  • Git Support

  • Module Management

  • Non-Database Credential Vaults

  • SQL Support

  • Triggers

  • Terminals

  • Custom Login Page

  • Generate Developer License
    hashtag
    Outlined Button

    Outlined buttons are medium-emphasis buttons. They contain actions that are important, but aren’t the primary action in an app.

    hashtag
    Control Button Size

    You can control the pixel size of a button based on pixel size by using the Style parameter

    hashtag
    Buttons with icons and label

    Sometimes you might want to have icons for certain button to enhance the UX of the application as we recognize logos more easily than plain text. For example, if you have a delete button you can label it with a dustbin icon.

    hashtag
    Buttons with event handlers

    You can specify a script block to execute when the button is clicked

    hashtag
    Loading Button

    Loading buttons will display a loading icon while an event handler is running. This is useful for longer running events.

    hashtag
    API

    • New-UDButtonarrow-up-right

    OnChange

    Take action when the rating is changed.

    hashtag
    Maximum

    Change the maximum rating.

    hashtag
    Precision

    Change the precision for ratings.

    hashtag
    Size

    Change the size of the rating icons.

    hashtag
    Transfer List Value on Change

    Use the OnChange event handler to get the value of the selected items.

    hashtag
    Transfer List in a Form

    Transfer lists can be used within forms and steppers.

    hashtag
    API

    • New-UDTransferListarrow-up-right

    • New-UDTransferListItemarrow-up-right

    hashtag
    Vertical Tabs

    hashtag
    Dynamic Tabs

    Dynamic tabs will refresh their content when they are selected. You will need to include the -RenderOnActive parameter to prevent all the tabs from rendering even if they are not shown.

    hashtag
    Icons

    hashtag
    API

    • New-UDTabsarrow-up-right

    • New-UDTabarrow-up-right

    hashtag
    Locale

    Specify the locale of the time picker.

    hashtag
    24-Hour Time

    You can use the -DisableAmPm parameter to use 24-hour time.

    hashtag
    API

    New-UDTimePickerarrow-up-right

    New-UDTimePicker

    hashtag
    OnChange Event

    Respond to when a switch value is changed. The $EventData variable will include whether or not the switch was checked or unchecked.

    hashtag
    Get-UDElement Support

    You can retrieve the value of the switch within another component by using Get-UDElement. Use the Checked property to determine whether the switch is checked out not.

    hashtag
    API

    • New-UDSwitcharrow-up-right

    hashtag
    API
    • New-UDDrawerarrow-up-right

    hashtag

    New-UDDrawer -Variant 'permanent' -Content {
      New-UDList -Children {
            New-UDListItem -Label "Home"
            New-UDListItem -Label "Getting Started" -Children {
                New-UDListItem -Label "Installation" -OnClick {}
                New-UDListItem -Label "Usage" -OnClick {}
                New-UDListItem -Label "FAQs" -OnClick {}
                New-UDListItem -Label "System Requirements" -OnClick {}
                New-UDListItem -Label "Purchasing" -OnClick {}
            }
        }
    }
    Permanent Drawer
    hashtag
    OnClick Event Handler

    You can define an action to take when an item is clicked by using the -OnClick parameter of New-UDListItem.

    hashtag
    API

    • New-UDListarrow-up-right

    • New-UDListItemarrow-up-right

    hashtag
    Checkboxes with custom icon

    Create checkboxes that use any icon and style.

    hashtag
    Checkboxes with onChange script block

    Create checkboxes that fire script blocks when changed.

    hashtag
    Checkbox with custom label placement

    You can adjust where the label for the checkbox is placed.

    hashtag
    Get the value of a Checkbox

    You can use Get-UDElement to get the value of the checkbox. Get-UDElement will also return other properties of the checkbox component.

    The following example shows a toast message with the value of the checkbox.

    hashtag
    API

    • New-UDCheckboxarrow-up-right

    hashtag
    Footer

    To create an app bar that is pinned to the bottom of the page, you can use the -Footer parameter.

    hashtag
    Fixed AppBar

    A fixed AppBar will show even when the screen is scrolled. It will remain stuck to the top. This example creates an AppBar that is fixed with a div that is 10000 pixels high.

    hashtag
    API

    • New-UDAppBararrow-up-right

    hashtag
    Slider with minimum and maximum values

    hashtag
    Disabled Slider

    hashtag
    Slider with custom step size

    hashtag
    Slider with marks

    hashtag
    Range based slider

    hashtag
    OnChange event for slider

    hashtag
    API

    • New-UDSliderarrow-up-right

    git sync
    Add Components to a Dashboard
    New-UDAlert -Severity 'error' -Content { New-UDHtml 'This is an error alert — <strong>check it out!</strong>' } -Title "Error"
    New-UDAlert -Severity 'warning' -Content { New-UDHtml 'This is an warning alert — <strong>check it out!</strong>' } -Title "Warning"
    New-UDAlert -Severity 'info' -Content { New-UDHtml 'This is an error info — <strong>check it out!</strong>' } -Title "Info"
    New-UDAlert -Severity 'success' -Content { New-UDHtml 'This is an success alert — <strong>check it out!</strong>' } -Title "Success"
    New-UDAlertarrow-up-right
    Advanced Alerts
    New-UDProgress
    New-UDProgressarrow-up-right
    theme-based
    New-UDTypographyarrow-up-right
    New-UDChiparrow-up-right
    New-UDPaperarrow-up-right
    New-UDFloatingActionButton -Icon (New-UDIcon -Icon user) -Size Small
    New-UDFloatingActionButton -Icon (New-UDIcon -Icon user) -Size Medium
    New-UDFloatingActionButton -Icon (New-UDIcon -Icon user) -Size Large
    New-UDFloatingActionButtonarrow-up-right
    New-UDGridLayout -Content { 1..10 | ForEach-Object { New-UDPaper -Id "Paper$" -Content { New-UDTypography -Text $ } -Elevation 5 } } -Design
    New-UDExpansionPanelarrow-up-right
    New-UDExpansionPanelGrouparrow-up-right
    Terminals Page
    Open Terminal
    Run Commands in a Terminal
    Stop a Terminal
    Reconnect to a Terminal

    Security

    Authentication and authorization for REST APIs.

    REST API authentication requires a Universal API license. Once enabled, you will be able to enforce authentication and authorization on your endpoints.

    hashtag
    Defining Secure Endpoints

    You can define secure endpoints in the UI by enabling authentication.

    You can also define secure endpoints using the .universal/endpoints.ps1 file or the Management API using New-PSUEndpoint.

    When authentication is enabled, it will enforce the use of one of the configured authentication methods. APIs support the following methods.

    • JWT App Tokens

    • Windows Authentication

    • Cookie Authentication

    hashtag
    Accessing Secure Endpoints

    Once you have defined a secure endpoint, you will need to provide authentication and authorization to access the endpoint.

    hashtag
    Authenticating with tokens

    circle-exclamation

    Note that if you are hosting in IIS and do not have Anonymous Authentication enabled, you will not be able to pass app tokens to the PowerShell Universal server.

    To authenticate with tokens, first, you need generate a new app token for use. You can use the Grant-PSUAppToken cmdlet to do so remotely or you can create an app token in the UI using the Settings Security AppTokens tab.

    Click Grant App Token to create a new one.

    Once you have created your app token, you can now use it to authenticate against the secure endpoint. To do so, pass the Authorization header along with the request.

    hashtag
    Authenticating with Windows Authentication

    To authenticate with , you can use the -UseDefaultCredentials parameter of Invoke-RestMethod and Invoke-WebRequest . This will perform negotiate authentication whether you are running inside IIS or a service.

    hashtag
    Authenticating with Cookies

    To authenticate with cookies, you will first need to call the login API to receive a valid cookie from the system. You can use Invoke-WebRequest to do so. Pass the user name and password as the body. Specify the -SessionVariable parameter to establish a session.

    Once you have successfully authenticated, you can use your $mySession variable to call secure endpoints.

    hashtag
    Enforcing Roles

    In addition to creating endpoints that require authentication, you can also enforce roles by define a role in the New-PSUEndpoint cmdlet or by selecting one in the UI. If a role is selected, it's possess the role.

    Windows and Cookie authentication will assign roles based on the Identity of the user and the role policies as they are applied.

    JWT app tokens will use the role that was defined when they were generated.

    hashtag
    API

    Dashboards

    Dashboards are the root component for your web page.

    Dashboards can contain one or more pages. The simplest dashboard will contain a single page with some content. You can call any PowerShell cmdlet that is available on your machine to populate your dashboard.

    Here's an example of simple dashboard that displays some text.

    hashtag
    New-UDDashboard

    The top-level cmdlet for dashboards is New-UDDashboard. You need to call it when returning a dashboard. You can use it with or without pages.

    hashtag
    Content

    The content of the dashboard is a series of components to display on the page. It's a script block that will return all the components in the order they will be rendered on the page. You can use the Grid component to layout items and display things like text with typography.

    hashtag
    Header Customization

    You can customize the header of the dashboard using several parameters.

    To change the navigation layout, use the -Navigation and -NavigationLayout parameters.

    hashtag
    Components

    Components are the individual widgets that you can place on you dashboard. There are components for displaying data, taking user input, adding text and images and more. Components can be downloaded as PowerShell modules and added to your dashboard.

    Components are be caused using the standard verb-name syntax for any PowerShell cmdlet.

    Learn more about .

    hashtag
    Pages

    You can specify multiple pages within a dashboard. Each page defines a route. As for v3, all pages are dynamic. PowerShell will execute on each page load to render the new page. Since UD is a single page application, the web browser does not need to refresh the entire web page when navigating between the different dashboard pages.

    Learn more about .

    hashtag
    Built-in Variables

    Built-in variables can be found on the .

    hashtag
    Debugging

    circle-info

    You can also use the with dashboards.

    When building a dashboard, you will likely run into issues with cmdlet calls or syntax. Dashboards will auto reload as you make changes to the dashboard files. If a dashboard fails to start, you can navigate to the admin page, click Dashboards and click the Info button next to your dashboard.

    The Log tab will show all the logging coming from the PowerShell execution from within in your dashboard. This should allow you to easily see errors and warnings coming from your dashboard.

    You can use Write-Debug to add additional log messages to your dashboard. To enable debug logging, you will have to set the $DebugPreference variable at the top of your dashboard script.

    hashtag
    Menu

    You can customize the dashboard menu by using the -Menu parameter.

    Dynamic Regions

    Dynamic regions allow you control the reload of data within the region.

    New-UDDynamic allows you to define a dynamic region. Pages themselves are dynamic in nature. This means that every time a page is loaded, it runs the PowerShell for that page. Sometimes, you may want to reload a section of a page rather than the whole page itself. This is when you will want to use dynamic regions.

    hashtag
    Basic Dynamic Region

    This dynamic region reloads when the button is clicked.

    hashtag
    Arguments List

    An array of arguments may be passed to the dynamic region.

    circle-info

    Note that the arguments are static and do not change when Sync-UDElement is invoked.

    hashtag
    Auto Refresh

    Dynamic regions enable the ability to auto refresh components after a certain amount of time. The entire region's script block will be run when autorefreshing.

    circle-info

    If you have multiple related components that use the same data, consider putting them in the same dynamic region to improve performance.

    hashtag
    Loading Component

    Sometimes refreshing a dynamic component may take some time. For example, if you are querying another service's REST API or a data. Dynamic regions support configuration of the component that shows when the region is reloading. By default, nothing is shown. This can be any Universal Dashboard component.

    hashtag
    API

    Custom Components

    Build custom components.

    Components in PowerShell Universal Dashboard are exposed as functions. You can combine built in components to produce your own custom components.

    hashtag
    Example: People Picker

    People Picker

    The below example creates a New-UDPeoplePicker component from existing UD components. You can use the New-UDPeoplePicker component in your dashboards. This function can either be defined within your dashboard directly or within a .

    This example users a published folder of avatars.

    Dashboards

    Dashboards are individual websites created with Universal Dashboard. You can define settings for a dashboard and start and stop the dashboard from within the Universal administrative interface.

    hashtag
    Adding a Dashboard

    Dashboards can be added to Universal using the Add Dashboard button from the Dashboard / Dashboards page.

    Name

    Name is displayed throughout the UI and returned from the Universal cmdlets.

    Base URL

    The base URL is the URL that you will access to view this dashboard. This URL needs to be unique within this instance. You can specify the / root URL if you wish. You will have to visit /admin to login to the administrative page if you set the dashboard to the root URL.

    File Name

    The full file name to the dashboard file. This file needs to return a dashboard using New-UDDashboard.

    Environment

    The to run the dashboard within.

    Authentication

    Enables authentication for the dashboard.

    Roles

    Defines the role that is required to access the dashboard.

    AutoStart

    Determines whether the dashboard should start (or restart) when the server starts or changes are made to the dashboard files.

    hashtag
    Starting and Stopping Dashboards

    Similar to jobs, dashboards run in separate PowerShell processes. You can start and stop a dashboard process by clicking the Start or Stop button from the Dashboards page.

    hashtag
    Viewing Diagnostic Information

    You can view diagnostic information for a dashboard by clicking the Info button on the Dashboards page. This will show your start information for the dashboard as well as any error that were encountered when starting the dashboard.

    hashtag
    Viewing the Dashboard

    You can view the dashboard by clicking the View button. This will take you to the Base URL for the dashboard.

    hashtag
    Executing Commands with the Dashboard

    On the dashboard information page, click on the Console tab to view the UD console. The console allows you to run scripts from within the UD runspace so you can better debug the state of your script. You can evaluate variables and run commands that are available to the dashboard. You will be running in the context of your user in regards to the runspace but the process will be running as the service account user.

    hashtag
    Persistent Runspaces

    Persistent runspaces allow you to maintain runspace state within your dashboard endpoints. This is important for users that perform some sort of initialization within their endpoints that they do not want to execute on subsequent calls.

    By default, runspaces will be reset after each execution. This will cause variables, modules and functions defined during the execution of an endpoint.

    To enable persistent runspaces, you will need to configure an for your API. Set the -PersistentRunspace parameter to enable this feature. This is configured in the environments.ps1 script.

    You will need to ensure that the environment is used by the dashboard.

    hashtag
    Automatically Granting App Tokens

    You can automatically grant app tokens to users that visit dashboards. This is useful if you want to invoke the management API for PowerShell Universal from within a dashboard. Your dashboard will need to have authentication enabled and you will have to use the -GrantAppToken switch parameter on New-PSUDashboard.

    From within your dashboard, you can now invoke the management API without having to worry about app token management. The API will be invoked in the context of the user that is visiting the dashboard.

    hashtag
    Disable Error Toasts

    By default, dashboards will display a toast message when an error is generated within an endpoint script. To avoid this behavior, you can use the -DisableErrorToast parameter of New-UDDashboard

    hashtag
    Disable Startup Logging

    When starting a dashboard, information about the variables and modules is displayed within the dashboard log. If you wish to suppress this information, you can use the -DisableStartupLogging parameter.

    hashtag
    Variables Available in Dashboards

    Built-in variables are listed on the

    Menu

    New-UDMenu component for Universal Dashboard.

    circle-info

    Available in PowerShell Universal 2.5 or later.

    The menu component can be used to provide a drop down list of options for the user to select.

    hashtag
    Basic Menu

    Create a basic menu.

    hashtag
    Button Styles

    You can edit the style of the menu by adjusting the variant parameter.

    hashtag
    Values

    You can use the value parameter to define a value that differs from the text displayed.

    hashtag
    OnChange Event Handler

    Use the -OnChange parameter to specify a script block to call when a new value is selected. The value of the selected item will be available in $EventData.

    hashtag
    API

    Rate Limiting

    Rate limiting options for Universal.

    circle-info

    Rate limiting requires a licensearrow-up-right.

    PowerShell Universal provides the ability to rate limit requests made to the web server. Rate limiting can be configured on a per endpoint and per period. By default, the client IP address is used to rate limit clients.

    Configuration data for rate limits are stored in the ratelimits.ps1 file.

    hashtag
    Configuring Rate Limiting

    To configure rate limiting, you can visit the APIs / Rate Limiting page. Click the Add button and define a new rate limit rule.

    circle-exclamation

    Rate limiting affects all URLs for the server. If you enforce rate limiting that isn't correctly configured, you can negatively affect the management API.

    hashtag
    Method

    The Method is the HTTP method to for this rule. If you use * , all HTTP methods will be affected by this rule. You can also select a single method by picking it from the drop down.

    hashtag
    Endpoint

    The endpoint is the URL that you are rate limiting. You can rate limit all URLs by using a *. You can define specific URLs by define the relative path: /api/user.

    hashtag
    Limit

    The number of request in the time frame before rate limiting kicks in.

    hashtag
    Period

    The period over which the rate limit is counted. For example, if you select a period of 10 minutes and a limit of 100, then up to 100 requests can be made to the method and endpoint you have selected.

    hashtag
    Allow Lists

    To disable rate limiting for particular IP Addresses, clients and endpoints you can add them to the rate limiting allow lists. You will find these by clicking the settings button.

    hashtag
    API

    Skeleton

    A skeleton component for PowerShell Universal Dashboard.

    A skeleton is a form of a loading component that can show a placeholder while data is received.

    hashtag
    Variants

    There are three variants that you can use for a skeleton. You can use a circle, text or a rectangle. You can also define the height and width of the skeleton.

    New-UDSkeleton
    New-UDSkeleton -Variant circle -Width 40 -Height 40
    New-UDSkeleton -Variant rect -Width 210 -Height 118
    Skeletons

    hashtag
    Animations

    Skeletons will use the pulsate animation by default. You can also disable animation or use a wave animation.

    hashtag
    API

    Code Editor

    Code editor component for Universal Dashboard.

    The code editor component allows you to host the Microsoft Monaco arrow-up-righteditor within your dashboards.

    hashtag
    Creating a Code Editor

    You can create a new code editor with the New-UDCodeEditor cmdlet. Specifying the -Language parameter will enable syntax highlighting for that language. You will need to specify a height in pixels.

    hashtag
    Populating Code

    Use the -Code parameter to specify code that will be populated within the code editor when it loads.

    hashtag
    Retrieving code from another component

    You can retrieve code from another component using the Get-UDElement cmdlet and accessing the code property of the hashtable that is returned.

    hashtag
    Setting code from another component

    You can set code from another component using the Set-UDElement cmdlet. Specify the code value in a hashtable passed to the -Properties parameter.

    hashtag
    Options

    circle-exclamation

    The documentation is for an upcoming feature of PowerShell Universal .

    The Monaco editor supports a wide range of options. If you wish to use options that aren't available on the New-UDCodeEditor cmdlet, you can use the -Options parameter and pass a hashtable of options instead.

    For a full list of options, check the interface.

    About

    About User Interfaces in PowerShell Universal.

    PowerShell Universal provides two ways of creating User Interfaces: Dashboards and Pages. Dashboards are highly interactive interfaces authored in PowerShell. Pages are simple drag and drop interfaces that can call scripts and APIs.

    hashtag
    Dashboards

    Dashboard Editor

    Dashboards offer a higher level of customization, interactivity and complexity. They are developed using the PowerShell Universal Dashboard module.

    Some examples of interfaces you can create:

    • Wizard-like input forms with validation and custom step logic

    • Highly interactive tables that can sort, filter, export and page directly from a SQL server

    • Continuously updating charts that monitor server performance or resource usage

    hashtag
    Pages

    Pages provide a basic method of creating user interfaces with a drag and drop designer. The controls are more limited, and the logic of your interface is limited to scripts or APIs that you have created with PowerShell Universal.

    Some examples of interfaces you can create:

    • Simple forms that accept various parameters, return output and display progress

    • Charts that display data generated from APIs or scripts

    • Simple tables that sort, page and export data generated by scripts or APIs.

    hashtag
    Which do I use?

    This will depend on your use case. Pages are much easier to get started with and do not have the learning curve of dashboards. Dashboards are much more robust but will require learning a new PowerShell module to create them.

    If you are looking to expose simple forms that perform actions, return simple results and display data that has been generated in scripts, then Pages will be for you.

    If you are looking to create a web interface that is similar to Windows Forms or WPF, then Dashboards are likely what you will want to use.

    Note, you can .

    Radio

    Radio component for Universal Dashboard

    Radio buttons allow the user to select one option from a set.

    Use radio buttons when the user needs to see all available options. If available options can be collapsed, consider using a dropdown menu because it uses less space.

    Radio buttons should have the most commonly used option selected by default.

    hashtag
    Simple Radio

    hashtag
    OnChange

    An event handler that is called when the radio group is changed. the $Body variable will contain the current value.

    hashtag
    Default Value

    Set the default value of the radio group.

    hashtag
    Custom Formatting

    You can use custom formatting within the radio group. The below example will place the radio buttons next to each other instead of on top of each other.

    hashtag
    API

    Backdrop

    Backdrop component for Universal Dashboard.

    The backdrop component places an overlay over the drop of the entire page. It's useful for displaying loading states.

    hashtag
    Basic Backdrop

    To create a basic backdrop, you can use the New-UDBackdrop cmdlet and include content to show within the backdrop. The content will be centered on the page. To show the backdrop, use the -Open switch parameter.

    New-UDBackdrop -Content {
        New-UDTypography -Text "Loading..." -Variant h2
    } -Open

    hashtag
    OnClick Handler

    The backdrop provides an -OnClick handler that you can use to close the backdrop when clicked. You can use Set-UDElement to open and close the backdrop.

    hashtag
    API

    Date Picker

    Date Picker component for Universal Dashboard

    Date pickers pickers provide a simple way to select a single value from a pre-determined set.

    Date pickers can be used in Forms and Steppers.

    hashtag
    OnChange Event Handler

    The OnChange event handler is called when the date changes. You can access the current date by using the $Body variable.

    hashtag
    Variant

    You can customize how the date picker is shown. The default is the inline variant that displays the date picker popup inline with the input control. You can also use the dialog variant that pops the date picker up in the middle of the screen. Finally, the static variant displays the date picker without having to click anything.

    hashtag
    Locale

    To set the locate of the date picker, specify the -Locale parameter.

    hashtag
    Minimum and Maximum

    By default, the user can select any date. To specify minimum and maximum dates, using the -Minimum and -Maximum parameters.

    hashtag
    API

    Upload

    Component for uploading files in Universal Dashboard.

    The UDUpload component is used to upload files to Universal Dashboard. You can process files the user uploads. You will receive the data for the file, a file name and the type of file if it can be determined by the web browser.

    This component works with UDForm and UDStepper.

    hashtag
    Uploading a File

    Uploads a file and shows the contents via a toast.

    The body of the OnUpload script block is a JSON string with the following format.

    The $EventData is an object with the following structure.

    hashtag
    Uploading a File with a Form

    Uploads a file as part of a UDForm.

    The body of the OnSubmit script block is the same one you will see with any form and the file will be contains as one of the fields within the form.

    hashtag
    Example: Uploading a file and save to it the temp directory

    This example allows a user to upload a file. Once the file is uploaded, it will be saved to the temporary directory.

    hashtag
    API

    Get Started

    Get started with PowerShell Universal

    hashtag
    Install PowerShell Universal

    You'll need to install the PowerShell Universal server. but you can use the command line below to get started quickly.

    You can install PowerShell Universal as a service. Ensure that PowerShell is running as administrator or the service won't install correctly.

    Schedules

    Schedules can be assigned to scripts and allow you to define frequency and other parameters for a script such as run as credentials.

    circle-info

    Schedules are stored in the schedules.ps1 configuration file.

    hashtag

    Editor

    A text editor component for Universal Dashboard.

    The editor component is based on . It's a block editor that accepts text, links, lists, code and images.

    When working with the editor, you can receive data about the current document via the OnChange parameter. By default, data is returned in the Editor.js .

    hashtag
    Creating an Editor

    Icon

    Icon component for Universal Dashboard

    icons to include in your dashboard. Icon names are slightly different than those shown on the FontAwesome website. For example, if you want to use the network-wired icon, you would use the following string.

    hashtag
    Finding an Icon

    We include FontAwesome v6 with PowerShell Universal. You can use Find-UDIcon to search through the list of included icons.

    Autocomplete

    Autocomplete component for Universal Dashboard

    The autocomplete is a normal text input enhanced by a panel of suggested options.

    hashtag
    Static List of Options

    Creates a basic autocomplete with a static list of options

    Modal

    Modal component for Universal Dashboard.

    Modals inform users about a task and can contain critical information, require decisions, or involve multiple tasks.

    hashtag
    Basic

    Select

    Select component for Universal Dashboard

    Select components are used for collecting user provided information from a list of options.

    hashtag
    Simple Select

    Create a simple select with multiple options.

    Card

    Card component for Universal Dashboard

    Cards contain content and actions about a single subject.

    Cards are surfaces that display content and actions on a single topic. They should be easy to scan for relevant and actionable information. Elements, like text and images, should be placed on them in a way that clearly indicates hierarchy.

    hashtag
    Simple Card

    Although cards can support multiple actions, UI controls, and an overflow menu, use restraint and remember that cards are entry points to more complex and detailed information.

    Set-PSUSetting -ApiEnvironment '7.1'
    New-PSUEndpoint -Url /environment -Environment Integrated -Endpoint {
        $PSUEnvironment
    }
     New-UDButton -Variant 'contained' -Text 'Default'
    New-UDButton -Variant 'outlined' -Text 'Default'
    New-UDButton -Id "Submit" -Text "Submit" -Style @{ Width = "150px"; Height = "100px" }
    New-UDButton -Icon (New-UDIcon -Icon trash) -Text 'Delete'
    New-UDButton -Text 'Message Box' -OnClick {
        Show-UDToast -Message 'Hello, world!'
    }
    New-UDButton -Text 'Message Box' -OnClick {
        Show-UDToast -Message 'Hello, world!'
        Start-Sleep 10
    } -ShowLoading
    New-UDRating 
    New-UDRating -OnChange {
        Show-UDToast $EventData
    }
    New-UDRating -Max 10
    New-UDRating -Precision .5
    New-UDRating -Size large
    New-UDTransferList -Item {
        New-UDTransferListItem -Name 'test1' -Value 1
        New-UDTransferListItem -Name 'test2' -Value 2
        New-UDTransferListItem -Name 'test3' -Value 3
        New-UDTransferListItem -Name 'test4' -Value 4
        New-UDTransferListItem -Name 'test5' -Value 5
    } 
    New-UDTransferList -Item {
        New-UDTransferListItem -Name 'test1' -Value 1
        New-UDTransferListItem -Name 'test2' -Value 2
        New-UDTransferListItem -Name 'test3' -Value 3
        New-UDTransferListItem -Name 'test4' -Value 4
        New-UDTransferListItem -Name 'test5' -Value 5
    } -OnChange {
        Show-UDToast ($EventData | ConvertTo-Json)
    }
    New-UDForm -Content {
        New-UDTransferList -Item {
            New-UDTransferListItem -Name 'test1' -Value 1
            New-UDTransferListItem -Name 'test2' -Value 2
            New-UDTransferListItem -Name 'test3' -Value 3
            New-UDTransferListItem -Name 'test4' -Value 4
            New-UDTransferListItem -Name 'test5' -Value 5
        }
    } -OnSubmit {
        Show-UDToast ($EventData | ConvertTo-Json)
    }
    New-UDTabs -Tabs {
        New-UDTab -Text 'Item One' -Content { New-UDTypography -Text 'Item One' -Variant 'h2' }
        New-UDTab -Text 'Item Two' -Content { New-UDTypography -Text 'Item Two' -Variant 'h2' }
        New-UDTab -Text 'Item Three' -Content { New-UDTypography -Text 'Item Three' -Variant 'h2' }
    }
    New-UDTabs -Tabs {
        New-UDTab -Text 'Item One' -Content { New-UDTypography -Text 'Item One' -Variant 'h2' }
        New-UDTab -Text 'Item Two' -Content { New-UDTypography -Text 'Item Two' -Variant 'h2' }
        New-UDTab -Text 'Item Three' -Content { New-UDTypography -Text 'Item Three' -Variant 'h2' }
    } -Orientation vertical
    New-UDTabs -Tabs {
        New-UDTab -Text 'Item One' -Content { Get-Date } -Dynamic
        New-UDTab -Text 'Item Two' -Content { Get-Date } -Dynamic
        New-UDTab -Text 'Item Three' -Content { Get-Date } -Dynamic
    } -RenderOnActive
    New-UDTabs -Tabs {
        New-UDTab -Text 'Item One' -Content { New-UDTypography -Text 'Item One' -Variant 'h2' } -Icon (New-UDIcon -Icon Users)
        New-UDTab -Text 'Item Two' -Content { New-UDTypography -Text 'Item Two' -Variant 'h2' } -Icon (New-UDIcon -Icon Desktop)
        New-UDTab -Text 'Item Three' -Content { New-UDTypography -Text 'Item Three' -Variant 'h2' } -Icon (New-UDIcon -Icon Exclamation)
    }
    New-UDTimePicker -Locale fr
    New-UDTimePicker -DisableAmPm
    New-UDSwitch -Checked $true 
    New-UDSwitch -Checked $true -Disabled
    New-UDSwitch -OnChange { Show-UDToast -Message $EventData }
    New-UDSwitch -Id 'switch' 
    New-UDButton -Text 'Click' -OnClick {
        Show-UDToast -Message (Get-UDElement -Id 'switch').checked
    }
    New-UDList -Content {
        New-UDListItem -Label 'Inbox' -Icon (New-UDIcon -Icon envelope -Size 3x) -SubTitle 'New Stuff'
        New-UDListItem -Label 'Drafts' -Icon (New-UDIcon -Icon edit -Size 3x) -SubTitle "Stuff I'm working on "
        New-UDListItem -Label 'Trash' -Icon (New-UDIcon -Icon trash -Size 3x) -SubTitle 'Stuff I deleted'
        New-UDListItem -Label 'Spam' -Icon (New-UDIcon -Icon bug -Size 3x) -SubTitle "Stuff I didn't want"
    }
    New-UDList -Content {
        New-UDListItem -Label 'Inbox' -Icon (New-UDIcon -Icon envelope -Size 3x) -SubTitle 'New Stuff'
        New-UDListItem -Label 'Drafts' -Icon (New-UDIcon -Icon edit -Size 3x) -SubTitle "Stuff I'm working on "
        New-UDListItem -Label 'Trash' -Icon (New-UDIcon -Icon trash -Size 3x) -SubTitle 'Stuff I deleted'
        New-UDListItem -Label 'Spam' -Icon (New-UDIcon -Icon bug -Size 3x) -SubTitle "Stuff I didn't want" -OnClick {
            Show-UDToast -Message 'Clicked'
        }
    }
    New-UDCheckBox
    New-UDCheckBox -Disabled
    New-UDCheckBox -Checked $true
    New-UDCheckBox -Checked $true -Disabled
    $Icon = New-UDIcon -Icon angry -Size lg -Regular
    $CheckedIcon = New-UDIcon -Icon angry -Size lg
    New-UDCheckBox -Icon $Icon -CheckedIcon $CheckedIcon -Style @{color = '#2196f3'}
    New-UDCheckBox -OnChange {
        Show-UDToast -Title 'Checkbox' -Message $Body
    }
    New-UDCheckBox -Label 'Demo' -LabelPlacement start
    New-UDCheckBox -Label 'Demo' -LabelPlacement top
    New-UDCheckBox -Label 'Demo' -LabelPlacement bottom
    New-UDCheckBox -Label 'Demo' -LabelPlacement end
    New-UDCheckbox -Id 'MyCheckbox' 
    
    New-UDButton -Text 'Get Value' -OnClick {
        Show-UDToast -Message (Get-UDElement -Id 'MyCheckbox').checked
    }
    $Drawer = New-UDDrawer -Children {
        New-UDList -Children {
            New-UDListItem -Label "Home"
            New-UDListItem -Label "Getting Started" -Children {
                New-UDListItem -Label "Installation" -OnClick {}
                New-UDListItem -Label "Usage" -OnClick {}
                New-UDListItem -Label "FAQs" -OnClick {}
                New-UDListItem -Label "System Requirements" -OnClick {}
                New-UDListItem -Label "Purchasing" -OnClick {}
            }
        }
    }
    
    New-UDAppBar -Position relative -Children { New-UDElement -Tag 'div' -Content { "Title" } } -Drawer $Drawer
    New-UDAppBar -Children { "Hello" } -Footer
    New-UDAppBar -Position fixed -Children { New-UDElement -Tag 'div' -Content { "Title" } }
    
    New-UDElement -Tag 'div' -Content {
    
    } -Attributes @{
        style = @{
            height = "10000px"
        }
    }
    New-UDSlider -Value 1
    New-UDSlider -Min 10 -Max 1000
    New-UDSlider -Disabled
    New-UDSlider -Min 10 -Max 1000 -Step 100
    New-UDSlider -Marks
    New-UDSlider -Value @(1, 10)
    New-UDSlider -OnChange {
        Show-UDToast -Message $Body 
        Set-TestData $Body
    }
      "UniversalDashboard": {
        "AssetsFolder": "%ProgramData%\\PowerShellUniversal\\Dashboard",
      },
    New-UDProgress -PercentComplete 75
    New-UDTypography -Text 'My Text' -Style @{ color = 'blue' }
    
    New-UDTypography -Text 'Secondar' -Sx @{
        color = 'text.secondary'
    }
     New-UDChip -Label 'Basic'
    New-UDChip -Label 'Basic' -Icon (New-UDIcon -Icon 'user')
    New-UDChip -Label 'OnClick' -OnClick {
        Show-UDToast -Message 'Hello!'
    }
    New-UDChip -Label 'OnDelete' -OnClick {
        Show-UDToast -Message 'Goodbye!'
    }
    New-UDPaper -Square -Content {}
    New-UDPaper  -Content { } -Style @{ 
         backgroundColor = 'red'
    }
    New-UDFloatingActionButton -Icon (New-UDIcon -Icon user) -OnClick {
        Show-UDToast -Message "Hello!"
    }
    $Layout = '{"lg":[{"w":7,"h":7,"x":5,"y":0,"i":"grid-element-Paper1","moved":false,"static":false},{"w":7,"h":5,"x":5,"y":7,"i":"grid-element-Paper2","moved":false,"static":false},{"w":1,"h":1,"x":0,"y":0,"i":"grid-element-Paper3","moved":false,"static":false},{"w":1,"h":1,"x":0,"y":1,"i":"grid-element-Paper4","moved":false,"static":false},{"w":1,"h":1,"x":0,"y":2,"i":"grid-element-Paper5","moved":false,"static":false},{"w":1,"h":1,"x":0,"y":3,"i":"grid-element-Paper6","moved":false,"static":false},{"w":1,"h":1,"x":0,"y":4,"i":"grid-element-Paper7","moved":false,"static":false},{"w":1,"h":1,"x":0,"y":5,"i":"grid-element-Paper8","moved":false,"static":false},{"w":1,"h":1,"x":0,"y":6,"i":"grid-element-Paper9","moved":false,"static":false},{"w":1,"h":1,"x":0,"y":7,"i":"grid-element-Paper10","moved":false,"static":false}]}' 
    New-UDGridLayout -Content { 1..10 | ForEach-Object { New-UDPaper -Id "Paper$" -Content { New-UDTypography -Text $ } -Elevation 5 } } -Layout $Layout
    New-UDGridLayout -Content { 1..10 | ForEach-Object { New-UDPaper -Id "Paper$" -Content { New-UDTypography -Text $ } -Elevation 5 } } -Draggable -Resizable -Persist
    New-UDDashboard -Title 'My New Dashboard' -Content {
        New-UDTypography -Text 'Hello!'
    }
    New-UDDashboard -Title "Hello, World!" -Content {
        New-UDDynamic -Id 'date' -Content {
            New-UDTypography -Text "$(Get-Date)"
        }
    
        New-UDButton -Text 'Reload Date' -OnClick { Sync-UDElement -Id 'date' }
    }
    New-UDDatePicker
    New-UDUpload -OnUpload {
        Show-UDToast $Body
    } -Text 'Upload'
    components here
    Pages here
    variables page
    Debugging Tools
    Module
    New-UDUploadarrow-up-right
    New-UDDashboard -Title 'My New Dashboard' -Content {
        New-UDTypography -Text 'Hello!'
    }
    New-UDDashboard -Content {
    } -Navigation (
        New-UDList -Children {
            New-UDListItem -Label "Home"
            New-UDListItem -Label "Getting Started" -Children {
                New-UDListItem -Label "Installation" -OnClick {}
                New-UDListItem -Label "Usage" -OnClick {}
                New-UDListItem -Label "FAQs" -OnClick {}
                New-UDListItem -Label "System Requirements" -OnClick {}
                New-UDListItem -Label "Purchasing" -OnClick {}
            }
        }
    ) -NavigationLayout permanent
    New-UDPage -Content {
        New-UDTextbox
    }
    $Pages = @()
    $Pages += New-UDPage -Name 'My Home Page' -Content {}
    $Pages += New-UDPage -Name 'Diagnostics' -Content {}
    New-UDDashboard -Pages $Pages -Title 'Dashboard'
    $DebugPreference = 'Continue'
    New-UDDashboard -Title 'Dashboard' -Content {
    
    } -Menu {
        New-UDMenuItem -Text 'Profile' -OnClick {
            Show-UDModal -Content {
                New-UDTypography -Text 'Welcome to your profile!'
            }
        }
    }
    function Get-User {
        1..100 | ForEach-Object {
            [PSCustomObject]@{
                UserName = "User$_"
                First = "Bill"
                Last = $_
                Avatar = (Get-ChildItem "$Repository\Avatars" | Get-Random).Name
            }
        }
    }
    
    function New-UDPeoplePicker {
       $Session:Users = [System.Collections.Generic.List[object]]::new()
    
        New-UDAutocomplete -OnLoadOptions {
            Get-User | Where-Object { $_.UserName -like "*$UserName*" } | Select-Object -First 5 -ExpandProperty 'UserName' | ConvertTo-Json 
        } -OnChange {
            $Session:Users.Add((Get-User | Where-Object { $_.UserName -eq $EventData })) | Out-Null
            Sync-UDElement -Id 'users'
        }
    
        New-UDDynamic -Id 'users' -Content {
            New-UDList -Children {
                $Session:Users | ForEach-Object {
                    New-UDListItem -Label $_.UserName -SubTitle "$($_.First) $($_.Last)" -AvatarType 'Avatar' -SecondaryAction {
                        $UserName = $_.UserName
                        New-UDIconButton -Icon (New-UDIcon -Icon 'Trash') -OnClick {
                            $RemoveUser = $Session:Users | Where-Object { $_.UserName -eq $UserName }
                            $Session:Users.Remove($RemoveUser) 
                            Sync-UDElement -Id 'users'
                        }
                    } -Source "/avatars/$($_.Avatar)"
    
                }    
            }
        }
    }
    
    New-UDDashboard -Title 'PowerShell Universal' -Content {
        New-UDPeoplePicker
    }
    {
      data: "base64 encoded string of data",
      name: "file name of the file uploaded",
      type: "file type as determined by the browser"
    }
    public class Upload
    {
        public string Name { get; set; }
        public string FileName { get; set; }
        public DateTime TimeStamp { get; set; }
        public string ContentType { get; set; }
        public string Type => ContentType;
    }
    New-UDForm -Content {
        New-UDUpload -Id 'myFile' -Text 'Upload File'
    } -OnSubmit {
        Show-UDToast $Body 
    }
    New-UDUpload -Text 'Upload Image' -OnUpload {
        $Data = $Body | ConvertFrom-Json 
        $bytes = [System.Convert]::FromBase64String($Data.Data)
        [System.IO.File]::WriteAllBytes("$env:temp\$($Data.Name)", $bytes)
    }
    New-PSUApiResponsearrow-up-right
  • Set-PSUSettingarrow-up-right

  • Windows Authentication
    New-PSUEndpointarrow-up-right
    Get-PSUEndpointarrow-up-right
    Remove-PSUEndpointarrow-up-right

    Web pages that behave much like desktop applications with feedback like modals, notifications and interaction between controls.

    embed Dashboards in Pages
    Page Editor

    You can learn more about desktop mode herearrow-up-right.

    You can install PowerShell Universal using the following shell script.

    Install-Module Universal
    Install-PSUServer

    You can install PowerShell Universal using the Universal PowerShell module.

    Install-Module Universal
    Install-PSUServer -AddToPath
    Start-PSUServer -Port 5000
    wget https://imsreleases.blob.core.windows.net/universal/production/2.4.0/Universal.linux-arm.2.4.0.zip
    unzip Universal.linux-arm.2.3.2.zip -d ./PSU
    chmod +x ./PSU/Universal.Server
    ./PSU/Universal.Server
    

    hashtag
    Open PowerShell Universal

    By default, PowerShell Universal is running on port 5000 of localhost. You can access the admin console with the username admin and admin.

    hashtag
    Create an API

    APIs allow you to call PowerShell scripts over HTTP. To create an API, click API \ Endpoints and click Create New Endpoint. Specify a URL.

    Next, click details on the API that was created an enter the following command into the editor.

    Save the script and then click the Execute button to test it out.

    You can also execute the API via Invoke-RestMethod.

    hashtag
    Create a Script

    To create a script, click Automation \ Scripts and then click Create New Script.

    Enter the following script into the editor and save.

    Once the script is saved, click Run.

    hashtag
    Create a Dashboard

    To create a new PowerShell-based user interface (dashboard), you can click User Interfaces \ Dashboard and then Create New Dashboard.

    After clicking Ok, click the Details button to edit the PowerShell script. Add the following script to the editor.

    Save the dashboard, click the Restart button and then click the View button. Click the Click Me button.

    Learn more about the various features of PowerShell Universal

    • APIs

    • Automation

    • Dashboards

    There are a lot of ways to do so
    Install-Module Universal
    Install-PSUServer
    Scheduling a Job

    To schedule a job, you can do so from the Automation / Schedules page and by clicking the New Schedule button. You can also schedule a script by click the Schedule option from the script's page.

    Schedules can be defined based on simple selections like Every Minute or Every Hour or you can define CRON expressions yourself for more configurable schedules. You can also run One Time schedules that run once at a later date.

    You can also define which user the scheduled job will run under as well as which PowerShell version to use.

    Create a Schedule

    hashtag
    Simple Schedules

    Simple schedules are really just helpers for various standard CRON schedules. When you select one, it will define a CRON schedule for your script.

    hashtag
    CRON

    CRON schedules use CRON expressions to define schedules. PowerShell Universal takes advantage of Chronos. For examples of valid expressions, click herearrow-up-right.

    hashtag
    One Time

    One time schedules will run once in the future. You can select the time and day of when they will run.

    hashtag
    Continuous

    Continuous schedules will run over and over again. You can define a delay between each scheduled job run.

    hashtag
    Parameters

    Schedules support setting parameters for scripts. For example, if you have a script that accepts a parameter, you can choose to pass a value to the parameter during the schedule.

    Within the modal for defining the schedule, you will have the option to set the parameter value.

    When editing schedules from PowerShell, you can define the parameters on the New-PSUSchedule cmdlet. This cmdlet accepts dynamic parameters so that you can pass the values in for your schedule.

    hashtag
    Environments

    When creating a schedule, you have the option to specify the environment for your job to run. By default, it will use the default environment. You can define an environment in the UI by using the Environment drop down. You can define an environment using the -Environment parameter in New-PSUSchedule.

    hashtag
    Run As

    You can define which user to run the schedule as by using the Run As selector in the UI. The Run As selector contains a list of PSCredential variables you have defined. You will need to define a PSCredential variable before the Run As selector is visible. By default, scheduled jobs will run under the credentials of the user that is running PowerShell Universal.

    You can define a Run As user in a script by using the -Credential parameter. The value should be the name of the variable that contains your credential.

    hashtag
    Computer

    You can select the computer or computers to run the schedule on. By default, schedules will run on any available computer. If you select All Computers, the schedule will run on all computers connect to the PSU cluster. If you select a specific computer, the schedule will run on only that computer.

    hashtag
    Conditions

    Conditions can be defined that determine whether a schedule should be run. This is useful if you are using the same repository scripts for multiple environments. Currently, conditions cannot be defined within the admin console. Conditions are passed the current script and schedule as parameters. The condition scriptblock is run within the integrated environment.

    The condition needs to return true or false. Below is an example of a condition where the schedule will only run if there is an environment variable named Slot that contains the value production.

    hashtag
    Pausing Schedules

    You can pause a schedule by setting the Paused property. When a schedule is paused, it will not run. This is useful to stop a schedule from running but not delete it.

    hashtag
    Time Out

    You can set a time out for scheduled jobs. The time out is the number of minutes before the scheduled job is canceled.

    hashtag
    Random Delay

    The Random Delay property causes a schedule to start anywhere between 0 and 60 seconds from the scheduled time. This is useful when running many schedules at the same time. For example, if you had 10 schedules that start at midnight, you may want to set a random delay to limit resource contention on the PowerShell Universal service.

    hashtag
    API

    • New-PSUSchedulearrow-up-right

    • Get-PSUSchedulearrow-up-right

    • Remove-PSUSchedulearrow-up-right

    To create a basic editor, use the New-UDEditor cmdlet.

    The editor will be available and you can add new blocks by clicking the plus button.

    hashtag
    Working with Data

    If you define a script block for the -OnChange event handler. The $EventData variable will contain the current status of the editor. By default, this returns the Editor.JS JSON block formatarrow-up-right.

    You can also use the HTML render plugin by specifying the -Format parameter.

    To specify the default data for the editor, use the -Data parameter. You need to specify the JSON block format.

    hashtag
    Image Support

    In order to support images, you will need to provide a published folder in which to upload the images. Once a published folder is defined, images can be uploaded directly in the editor. They will be placed within the directory and then served through the request path.

    hashtag
    API

    hashtag
    New-UDEditor

    Name
    Type
    Description
    Required

    Id

    string

    The ID of this component.

    Data

    Hashtable

    The Editor.JS data for this component

    OnChange

    Editor.jsarrow-up-right
    JSON formatarrow-up-right
    circle-exclamation

    The UniversalDashboard.FontAwesomeIcons enum should not be used and is only included for backwards compatibility. Many of the icons are no longer a part of FontAwesome 6.

    hashtag
    Icon

    Create icons by specifying their names. You can use the icon reference below to find icons.

    hashtag
    Size

    Set the size of the icon. Valid values are: xs, sm, lg, 2x, 3x, 4x, 5x, 6x, 7x, 8x, 9x, 10x

    hashtag
    Rotation

    Rotate icons. The value represents the degrees of rotation.

    hashtag
    Border

    Add a border to your icon.

    hashtag
    Style

    Apply CSS styles to your icon.

    hashtag
    Visually Search for Icons

    hashtag
    Complete Icon List

    hashtag
    Custom Icons

    You can use custom icon sets available on the PowerShell Universal Modulesarrow-up-right page. First, install the module and then use the icon with other components.

    Within your dashboard, call the icon cmdlet.

    hashtag
    API

    New-UDIconarrow-up-right

    FontAwesome arrow-up-right
    hashtag
    Dynamic List of Options

    When text is typed, it can be filtered with OnLoadOptions. $Body will contain the current text that is typed.

    This example filters the array with Where-Object.

    hashtag
    OnChange

    $Body contains the currently selected item. The OnChange event will fire when the user selects one or more items.

    hashtag
    Icon

    You can place an icon before an autocomplete by using the -Icon parameter.

    hashtag
    OnEnter

    OnEnter is triggered when the user presses the enter key within the autocomplete.

    hashtag
    Options

    You can use New-UDAutoCompleteOption to specify name and values.

    hashtag
    API

    • New-UDAutocompletearrow-up-right

    hashtag
    Full Screen

    hashtag
    Full Width

    Full width modals take up the full width as defined by the -MaxWidth parameter.

    hashtag
    Persistent

    Persistent modals do not close when you click off of them. You will have to close it with Hide-UDModal.

    hashtag
    Hide a Modal

    You can use the Hide-UDModal button to hide a modal that is currently show.

    hashtag
    Styling

    You can style modules using the -Style, -HeaderStyle, -ContentStyle and -FooterStyle parameters. Style is applied to the entire modal itself and the individual section styles are only applied to those sections. The value for these parameters are hashtables of CSS values.

    hashtag
    API

    • Show-UDModalarrow-up-right

    • Hide-UDModalarrow-up-right

    hashtag
    Grouped Select

    Create a select with groups of selections.

    hashtag
    OnChange

    Execute a PowerShell event handler when the value of the select is changed. $EventData[0] for the single item that was selected.

    hashtag
    Multiple Select

    Execute a PowerShell event handler when the more than one value of the select is changed. $EventData is an array of the selected items.

    hashtag
    Get-UDElement

    Retrieve the value of the select from another component.

    hashtag
    API

    • New-UDSelectarrow-up-right

    • New-UDSelectOptionarrow-up-right

    • New-UDSelectGrouparrow-up-right


    hashtag

    hashtag
    Advanced Card

    You can use the body, header, footer and expand cmdlets to create advanced cards. The below example creates a card with various features based on a Hyper-V VM.

    hashtag
    API

    • New-UDCardarrow-up-right

    • New-UDCardBodyarrow-up-right

    • New-UDCardExpandarrow-up-right

    New-UDDynamicarrow-up-right
    Reload on button click
    utilizing the arguments list
    Auto refresh dynamic region
    Loading component for dynamic region
    environment
    environment
    variables page.
    New-UDMenuarrow-up-right
    New-UDMenuItemarrow-up-right
    New-UDSkeleton
    New-UDSkeleton -Animation disabled
    New-UDSkeleton -Animation wave
    New-UDSkeletonarrow-up-right
    Animations
    IEditorConsturctionOptionsarrow-up-right
    New-UDRadioarrow-up-right
    New-UDRadioGrouparrow-up-right
    New-UDBackdrop -Id 'backdrop' -Content {
        New-UDTypography -Text "Loading..." -Variant h2
    } -Open -OnClick {
        Set-UDElement -Id 'backdrop' -Properties @{
            open = $false
        }
    }
    New-UDBackdroparrow-up-right
    Backdrop component
    New-UDDatePickerarrow-up-right
    New-PSURateLimitarrow-up-right
    Set-PSUSettingarrow-up-right

    Element

    Information about UDElements.

    The New-UDElement cmdlet allows you to create custom React elements within your dashboard. Similar to New-UDHtml, you can define HTML elements using New-UDElement. Unlike, New-UDHtml, you can update elements, set auto refresh and take advantage of the React component system.

    hashtag
    Create an Element

    You need to specify the -Tag and -Content when creating an element. The below example creates a div tag.

    You can nest components within each other to create HTML structures. For example, you could create an unordered list with the following example.

    hashtag
    Setting Attributes

    You can select attributes of an element (like HTML attributes) by using the -Attributes parameter. This parameter accepts a hashtable of attribute name and values. The below example creates red text.

    You can wrap any component with New-UDElement and add an event handler.

    hashtag
    Auto Refreshing Elements

    You can define the -AutoRefresh, -RefreshInterval and -Endpoint parameters to create an element the refreshes on a certain interval. The below example creates an element that refreshes every second and displays the current time.

    hashtag
    Setting Element Properties Dynamically

    You can use the Set-UDElement cmdlet to set element properties and content dynamically. The following example sets the content of the element to the current time.

    You can also set attributes by using the -Properties parameter of Set-UDElement. The following example sets the current time and changes the color to red.

    hashtag
    Adding Child Elements

    You can add child elements using Add-UDElement. The following example adds child list items to an unordered list.

    hashtag
    Clearing Child Elements

    You can clear the child elements of an element by using Clear-UDElement. The following example clears all the list items from an unordered list.

    hashtag
    Forcing an Element to Reload

    You can force an element to reload using Sync-UDElement. The following example causes the div to reload with the current date.

    hashtag
    Removing an Element

    You can remove an element by using Remove-UDElement.

    hashtag
    API

    • ****


    Triggers

    Trigger scripts when events happen with PowerShell Universal.

    circle-info

    Triggers require a licensearrow-up-right.

    Triggers allow for automation jobs to be started when certain events happen within PowerShell Universal. For example, this allows you to take action when jobs complete, the server starts or dashboards stop. Triggers are useful for assigning global error handling or sending notifications when certain things happen.

    circle-info

    Triggered jobs will not cause additional triggers to start. Triggers are stored in the triggers.ps1.

    hashtag
    Trigger Events

    The following types of events can be assigned a trigger.

    • Job Started

    • Job Completed

    • Job Requesting Feedback

    hashtag
    New User Login

    The user login event takes place when a user accesses PowerShell Universal. The script will receive a $Userparameter with user information.

    hashtag
    User Login

    The user login event takes place when a user accesses PowerShell Universal. The script will receive a $data parameter with user information. The data structure is shown below.

    hashtag
    Use of a Revoked App Token

    The app token event takes place when a revoked app token is used. The script will receive a $data parameter that contains the contents of the app token as a string.

    hashtag
    Git Sync

    This trigger occurs when a git sync is run. This trigger will fire for both successful and unsuccessful git syncs.

    You will receive the following object in the $data parameter.

    hashtag
    Global Triggers

    Global triggers will start the assigned script whenever the event type is invoked.

    For example, the Script.ps1 will be run whenever any job is run.

    hashtag
    Resource Triggers

    Resource triggers will start the assigned script when the event takes place on the selected resource.

    For example, the Script.ps1 will be run whenever the Dashboard is stopped.

    hashtag
    Event Metadata

    Whenever a job is started from a trigger, it will be provided with metadata about object that caused the event to trigger.

    Triggers related to jobs will be provided a $Job parameter.

    Triggers related to dashboards will be provided a $Dashboard parameter.

    Triggers related to the server status will not receive a parameter.

    hashtag
    Conditions

    Using the -Condition parameter of New-PSUTrigger, you can determine whether or not a trigger should be run based on local conditions on the server. Return $true or $false from the condition.

    For example, you can disable a trigger if the Environment environment variable is not set to production.

    hashtag
    API

    Timeline

    Time line control for PowerShell Universal Dashboard

    The timeline control can be used to display a sequence of events over time.

    hashtag
    Basic Timeline

    Create a basic timeline with information on both sides of the timeline.

    hashtag
    Alternating Timeline

    hashtag
    Colors

    hashtag
    Icons

    hashtag
    API

    • New-UDTimeline

    • New-UDTimelineItem

    Grid

    Grid layout component for Universal Dashboard.

    The responsive layout grid adapts to screen size and orientation, ensuring consistency across layouts.

    The grid creates visual consistency between layouts while allowing flexibility across a wide variety of designs. Material Design’s responsive UI is based on a 12-column grid layout.

    hashtag
    Basic Layout

    hashtag
    Spacing

    Adjust the spacing between items in the grid

    hashtag
    Row and Columns

    You can also use the New-UDRow and New-UDColumn functions when working with the grid.

    hashtag
    API

    Transitions

    Transition component for Universal Dashboard.

    Transitions allow you to transition components in and out of view within your dashboard using various animations. You can take advantage of interactive cmdlets like Set-UDElement to change the transition state and cause an element to move in.

    In the following example, we have a card that transitions in via a Fade. Clicking the switch the toggle the card in and out.

    The resulting effect looks like this.

    Transition a card

    hashtag
    Collapse

    The collapse transition will collapse a section in and out. You can specify a collapse height to only collapse a portion of the section.

    hashtag
    Fade

    A fade transition fades a component in and out as seen in the previous example. You can configure the timeout value to specify the number of seconds it takes to complete the transition.

    hashtag
    Slide

    The slide transition moves a component into position. You can determine the position of the slide by specifying the -SlideDirection parameter.

    hashtag
    Grow

    The grow transition will fade and grow a component into place.

    hashtag
    Zoom

    The zoom transition will zoom a component into place.

    hashtag
    API

    Error Handling

    Error handling for Universal API.

    By default, endpoints will return a 200 OK message even if there are errors. If an error occurs, you will get a blank response from the endpoint. This document demonstrates different ways to handle errors within APIs.

    hashtag
    Automatically Returning Errors

    To automatically return errors from APIs, you can change the default behavior by setting the -ErrorAction parameter of New-PSUEndpoint

    New-PSUEndpoint -Url '/endpoint' -Method 'GET' -Endpoint {
       "Hello, world!"
    } -Authentication
    Invoke-RestMethod http://localhost:5000/auth -Headers @{ Authorization = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiQWRtaW4iLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9oYXNoIjoiMWUyY2IzNzAtMmMyNS00ZDU5LTk4YzgtMzc5MTFjMDAyZmI5Iiwic3ViIjoiUG93ZXJTaGVsbFVuaXZlcnNhbCIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvcm9sZSI6IkFkbWluaXN0cmF0b3IiLCJuYmYiOjE2MDU2NjEyNTUsImV4cCI6MTYzNzM2NzI1OCwiaXNzIjoiSXJvbm1hblNvZnR3YXJlIiwiYXVkIjoiUG" }
    Invoke-RestMethod http://localhost:5000/auth -UseDefaultCredentials
    Invoke-WebRequest http://localhost:5000/api/v1/signin -Body (@{ 
        UserName = "Admin"
        Password = "Any"
    } | ConvertTo-Json) -ContentType 'application/json' -SessionVariable mySession -Method POST
     Invoke-WebRequest http://localhost:5000/auth -WebSession $mySession
    Get-ComputerInfo
    PS C:\Users\adamr> Invoke-RestMethod http://localhost:5000/hello-world
    
    WindowsBuildLabEx                                       : 22000.1.amd64fre.co_release.210604-1628
    WindowsCurrentVersion                                   : 6.3
    WindowsEditionId                                        : Professional
    WindowsInstallationType                                 : Client
    WindowsInstallDateFromRegistry                          : 8/6/2021 4:05:12 PM
    WindowsProductId                                        : 00330-52452-93139-AAOEM
    WindowsProductName                                      : Windows 10 Pro
    WindowsRegisteredOrganization                           :
    Read-Host "What should I say?"
    
    1..100 | ForEach-Object {
        Write-Progress -PercentComplete $_ -Activity "Processing..."
    }
    
    Get-Service
    New-UDDashboard -Title "Hello, World!" -Content {
        New-UDButton -Text "Click Me" -OnClick {
            Show-UDToast -Message 'Success!!'
        }
    }
    param($UserName)
    
    $UserName
    New-PSUSchedule -Script "MyScript.ps1" -Cron '* * * * *' -UserName 'adam'
    New-PSUSchedule -Script "MyScript.ps1" -Cron '* * * * *' -Environment '7.1'
    New-PSUSchedule -Script "MyScript.ps1" -Cron '* * * * *' -Credential 'MyUser'
    New-PSUSchedule -Script "MyScript.ps1" -Cron '* * * * *' -Computer 'PSUNODE1'
    New-PSUSchedule -Script "MyScript.ps1" -Cron '* * * * *' -Condition {
      $ENV:Slot -eq 'production'
    }
    New-UDEditor
    New-UDEditor -OnChange {
        Show-UDToast $EventData
    }
    New-UDEditor -OnChange {
        Show-UDToast $EventData
    } -Format 'html'
    New-UDEditor -Data $Data
    New-UDEditor -PublishedFolder 'MyImages'
    New-UDIcon -Icon 'NetworkWired'
    Find-UDIcon User
    New-UDIcon -Icon 'AddressBook'
        New-UDIcon -Icon 'AddressBook' -Size 'sm'
        New-UDIcon -Icon 'AddressBook' -Size 'lg'
        New-UDIcon -Icon 'AddressBook' -Size '5x'
        New-UDIcon -Icon 'AddressBook' -Size '10x'
    New-UDIcon -Icon 'AddressBook' -Size '5x' -Rotation 90
    New-UDIcon -Icon 'AddressBook' -Size '5x' -Border
    New-UDIcon -Icon 'AddressBook' -Size '5x' -Style @{
        backgroundColor = "red"
    }
    New-UDTextbox -Id 'txtIconSearch' -Label 'Search' 
    New-UDButton -Text 'Search' -OnClick {
        Sync-UDElement -Id 'icons'
    }
    
    New-UDElement -tag 'p' -Content {}
    
    New-UDDynamic -Id 'icons' -Content {
        $IconSearch = (Get-UDElement -Id 'txtIconSearch').value
        if ($null -ne $IconSearch -and $IconSearch -ne '')
        {
            $Icons =$Icons = Find-UDIcon -Name $IconSearch
        }
    
        foreach($icon in $icons) {
            try{
                New-UDChip -Label $icon -Icon (New-UDIcon -Icon $icon)
            }
            catch{
                New-UDChip -Label "$icon Unknown" 
            }
        }
    }
     https://github.com/FortAwesome/Font-Awesome/blob/6.x/metadata/icons.json
    Install-Module Universal.Icons.Tabler
    New-UDButton -Icon (New-UDTablerIcon -Icon "Tb3DRotate")
    New-UDAutocomplete -Options @('Test', 'Test2', 'Test3', 'Test4')
    New-UDAutocomplete -OnLoadOptions { 
        @('Test', 'Test2', 'Test3', 'Test4') | Where-Object { $_ -like "*$Body*" } | ConvertTo-Json
    }
    New-UDAutocomplete -OnLoadOptions { 
        @('Test', 'Test2', 'Test3', 'Test4') | Where-Object { $_ -like "*$Body*" } | ConvertTo-Json
    } -OnChange {
        Show-UDToast $Body 
    }
    New-UDAutocomplete -Options @("Test", "No", "Yes") -Icon (New-UDIcon -Icon 'Users') 
    New-UDAutocomplete -Options @("Test", "No", "Yes") -onEnter {
        Show-UDToast ((Get-UDElement -Id 'ac').value)
    } -Id 'ac'
    New-UDAutocomplete -Options @(
        New-UDAutoCompleteOption -Name 'Adam D' -Value '1'
        New-UDAutoCompleteOption -Name 'Sarah F' -Value '2'
        New-UDAutoCompleteOption -Name 'Tom S' -Value '3'
    )
    New-UDButton -Text 'Basic' -OnClick {
        Show-UDModal -Content {
            New-UDTypography -Text "Hello"
        }
    }
    New-UDButton -Text 'Full Screen' -OnClick {
        Show-UDModal -Content {
            New-UDTypography -Text "Hello"
        } -Footer {
            New-UDButton -Text "Close" -OnClick { Hide-UDModal }
        }  -FullScreen
    }
    New-UDButton -Text 'Full Width' -OnClick {
        Show-UDModal -Content {
            New-UDTypography -Text "Hello"
        } -FullWidth -MaxWidth 'md'
    }
    New-UDButton -Text 'Persistent' -OnClick {
        Show-UDModal -Content {
            New-UDTypography -Text "Hello"
        } -Footer {
            New-UDButton -Text "Close" -OnClick { Hide-UDModal }
        } -Persistent
    }
    New-UDButton -Text 'Basic' -OnClick {
        Show-UDModal -Content {
            New-UDTypography -Text "Hello"
        }
        Start-Sleep 5
        Hide-UDModal
    }
    New-UDButton -Text 'Styling' -OnClick {
        Show-UDModal -Content {
            New-UDTypography -Text "Hello"
        } -Style @{
            backgroundColor = "red"
        }
    }
    New-UDSelect -Option {
        New-UDSelectOption -Name 'One' -Value 1
        New-UDSelectOption -Name 'Two' -Value 2
        New-UDSelectOption -Name 'Three' -Value 3
    }
    New-UDSelect -Option {
        New-UDSelectGroup -Name 'Group One' -Option {
            New-UDSelectOption -Name 'One' -Value 1
            New-UDSelectOption -Name 'Two' -Value 2
            New-UDSelectOption -Name 'Three' -Value 3
        }
        New-UDSelectGroup -Name 'Group Two' -Option {
            New-UDSelectOption -Name 'Four' -Value 4
            New-UDSelectOption -Name 'Five' -Value 5
            New-UDSelectOption -Name 'Size' -Value 6
        }
    }
    New-UDSelect -Option {
        New-UDSelectOption -Name 'One' -Value 1
        New-UDSelectOption -Name 'Two' -Value 2
        New-UDSelectOption -Name 'Three' -Value 3
    } -OnChange { Show-UDToast -Message $EventData[0] }
    New-UDSelect -Multiple -Option {
        New-UDSelectOption -Name 'One' -Value 1
        New-UDSelectOption -Name 'Two' -Value 2
        New-UDSelectOption -Name 'Three' -Value 3
    } -OnChange { 
        Show-UDToast -Message (ConvertTo-json -InputObject $EventData) 
    }
      New-UDSelect -Option {
          New-UDSelectOption -Name 'One' -Value 1
          New-UDSelectOption -Name 'Two' -Value 2
          New-UDSelectOption -Name 'Three' -Value 3
      } -Id 'select' -DefaultValue 2
    
      New-UDButton  -Text 'OnBoard' -OnClick {
        $Element = Get-UDElement -Id 'select'
        if ($Element.Value)
        {
          Show-UDToast -Message $Element.Value
        }
        else 
        {
          Show-UDToast -Message $Element.DefaultValue
        }
      }
    New-UDCard -Title 'Simple Card' -Content {
        "This is some content"
    }
    $Header = New-UDCardHeader -Avatar (New-UDAvatar -Content { "R" } -Sx @{ backgroundColor = "#f44336" }) -Action (New-UDIconButton -Icon (New-UDIcon -Icon 'EllipsisVertical')) -Title 'Shrimp and Chorizo Paella' -SubHeader 'September 14, 2016';
    $Media = New-UDCardMedia -Image 'https://mui.com/static/images/cards/paella.jpg'
    $Body = New-UDCardBody -Content {
        New-UDTypography -Text ' This impressive paella is a perfect party dish and a fun meal to cook together with your guests. Add 1 cup of frozen peas along with the mussels, if you like.' -Sx @{
            color = 'text.secondary'
        } -Variant body2
    }
    $Footer = New-UDCardFooter -Content {
        New-UDIconButton -Icon (New-UDIcon -Icon 'Heart')
        New-UDIconButton -Icon (New-UDIcon -Icon 'ShareAlt')
    }
    $Expand = New-UDCardExpand -Content {
        $Description = @"
        Heat oil in a (14- to 16-inch) paella pan or a large, deep skillet over
        medium-high heat. Add chicken, shrimp and chorizo, and cook, stirring
        occasionally until lightly browned, 6 to 8 minutes. Transfer shrimp to a
        large plate and set aside, leaving chicken and chorizo in the pan. Add
        pimentón, bay leaves, garlic, tomatoes, onion, salt and pepper, and cook,
        stirring often until thickened and fragrant, about 10 minutes. Add
        saffron broth and remaining 4 1/2 cups chicken broth; bring to a boil.
        New-UDTypography -Text $Description
    }
    New-UDCard -Header $Header -Media $Media -Body $Body -Footer $Footer -Expand $Expand -Sx @{
        maxWidth = 345
        border   = '2px solid #f0f2f5'
    }
    New-UDDynamic -Id 'dynamic_01' -Content {
                    New-UDTypography -Text "This is an $($ArgumentList[0])
                     an $($ArgumentList[1]) in a UDDynamic"
                     } -ArgumentList @('example of', 'arguments list') 
        New-UDDynamic -Id 'date' -Content {
            New-UDTypography -Text "$(Get-Date)" -Variant h3
            New-UDTypography -Text "$(Get-Random)" -Variant h3
        } -AutoRefresh -AutoRefreshInterval 1
        New-UDDynamic -Content {
            Start-Sleep -Seconds 3
            New-UDTypography -Text "Done!"
        } -LoadingComponent {
            New-UDProgress -Circular
        }
    New-PSUEnvironment -Name 'Env' -Path 'powershell.exe' -PersistentRunspace
    New-PSUDashboard -Name 'Dashboard' -BaseUrl '/' -Framework "UniversalDashboard:Latest" -Authenticated -GrantAppToken
    New-UDDashboard -Title "Hello, World!" -Content {
        New-UDButton -Text 'Job' -OnClick {
            Invoke-UAScript -Name 'Test.ps1'
        }
    }
    New-PSUDashboard -Name 'Dashboard' -BaseUrl '/' -Framework "UniversalDashboard:Latest" -Authenticated -DisableErrorToast
    New-UDDashboard -Title "Hello, World!" -Content {
        New-UDButton -Text 'Job' -OnClick {
            throw "Exception
        }
    } 
    New-PSUDashboard -Name 'Dashboard' -BaseUrl '/' -Framework "UniversalDashboard:Latest" -DisableStartupLogging
    New-UDMenu -Content {
       New-UDMenuItem -Text 'Item 1'
       New-UDMenuItem -Text 'Item 1'
       New-UDMenuItem -Text 'Item 1'
    }
    New-UDMenu -Content {
       New-UDMenuItem -Text 'Item 1'
       New-UDMenuItem -Text 'Item 1'
       New-UDMenuItem -Text 'Item 1'
    } -Variant outlined
    New-UDMenu -Content {
       New-UDMenuItem -Text 'Item 1' -Value 'item1'
       New-UDMenuItem -Text 'Item 1' -Value 'item2'
       New-UDMenuItem -Text 'Item 1' -Value 'item3'
    }
    New-UDMenu -Text 'Click Me' -OnChange {
        Show-UDToast $EventData
    } -Children {
        New-UDMenuItem -Text 'Test'
        New-UDMenuItem -Text 'Test2'
        New-UDMenuItem -Text 'Test3'
    }
    New-UDCodeEditor -Height '500' -Language 'powershell'
    New-UDCodeEditor -Height '500' -Language 'powershell' -Code '#Hello, world!'
    New-UDCodeEditor -Height '500' -Language 'powershell' -Code '#Hello, world!' -Id 'editor'
    
    New-UDButton -Text 'Get Code' -OnClick {
        Show-UDToast -Message (Get-UDElement -id 'editor').Code
    }
    New-UDCodeEditor -Height '500' -Language 'powershell' -Code '#Hello, world!' -Id 'editor'
    
    New-UDButton -Text 'Get Code' -OnClick {
        Set-UDElement -Id 'editor' -Properties @{
            code = "# Hello!"
        }
    }
    New-UDCodeEditor -Language powershell -Height 100 -Options @{ fontSize = 10 }
    New-UDRadioGroup -Label "Day" -Content {
        New-UDRadio -Label Monday -Value 'monday'
        New-UDRadio -Label Tuesday -Value 'tuesday'
        New-UDRadio -Label Wednesday -Value 'wednesday'
        New-UDRadio -Label Thursday -Value 'thursday'
        New-UDRadio -Label Friday  -Value 'friday'
        New-UDRadio -Label Saturday -Value 'saturday'
        New-UDRadio -Label Sunday -Value 'sunday'
    }
    New-UDRadioGroup -Label "Day" -Content {
        New-UDRadio -Label Monday -Value 'monday'
        New-UDRadio -Label Tuesday -Value 'tuesday'
        New-UDRadio -Label Wednesday -Value 'wednesday'
        New-UDRadio -Label Thursday -Value 'thursday'
        New-UDRadio -Label Friday  -Value 'friday'
        New-UDRadio -Label Saturday -Value 'saturday'
        New-UDRadio -Label Sunday -Value 'sunday'
    } -OnChange { Show-UDToast -Message $Body }
        }
    New-UDRadioGroup -Label "Day" -Content {
        New-UDRadio -Label Monday -Value 'monday'
        New-UDRadio -Label Tuesday -Value 'tuesday'
        New-UDRadio -Label Wednesday -Value 'wednesday'
        New-UDRadio -Label Thursday -Value 'thursday'
        New-UDRadio -Label Friday  -Value 'friday'
        New-UDRadio -Label Saturday -Value 'saturday'
        New-UDRadio -Label Sunday -Value 'sunday'
    } -Value 'sunday'
    New-UDRadioGroup -Label "Day" -Content {
        New-UDRow -Columns {
            New-UDColumn -LargeSize 1 -Content {
                New-UDRadio -Label Monday -Value 'monday'        
            }
            New-UDColumn -LargeSize 1 -Content {
                New-UDRadio -Label Sunday -Value 'sunday'
            }
        }
    }
    New-UDDatePicker -OnChange {
        Show-UDToast -Message $body
    }
    New-UDDatePicker -Variant static
    New-UDDatePicker -Locale fr
    New-UDDatePicker -Minimum ((Get-Date).AddDays(-15)) -Maximum ((Get-Date).AddDays(15))
    New-UDTimeline -Children {
        New-UDTimelineItem -Content {
            'Breakfast'
        } -OppositeContent {
            '7:45 AM'
        } 
        New-UDTimelineItem -Content {
            'Welcome Message'
        } -OppositeContent {
            '9:00 AM'
        }
        New-UDTimelineItem -Content {
            'State of the Shell'
        } -OppositeContent {
            '9:30 AM'
        }
        New-UDTimelineItem -Content {
            'General Session'
        } -OppositeContent {
            '11:00 AM'
        }
    }
    New-UDGrid -Container -Content {
        New-UDGrid -Item -ExtraSmallSize 12 -Content {
            New-UDPaper -Content { "xs-12" } -Elevation 2
        }
        New-UDGrid -Item -ExtraSmallSize 6 -Content {
            New-UDPaper -Content { "xs-6" } -Elevation 2
        }
        New-UDGrid -Item -ExtraSmallSize 6 -Content {
            New-UDPaper -Content { "xs-6" } -Elevation 2
        }
        New-UDGrid -Item -ExtraSmallSize 3 -Content {
            New-UDPaper -Content { "xs-3" } -Elevation 2
        }
        New-UDGrid -Item -ExtraSmallSize 3 -Content {
            New-UDPaper -Content { "xs-3" } -Elevation 2
        }
        New-UDGrid -Item -ExtraSmallSize 3 -Content {
            New-UDPaper -Content { "xs-3" } -Elevation 2
        }
        New-UDGrid -Item -ExtraSmallSize 3 -Content {
            New-UDPaper -Content { "xs-3" } -Elevation 2
        }
    }
    New-UDTransition -Id 'test' -Content {
        New-UDCard -Text "Hey"
    } -In -Fade -Timeout 1000
    
    New-UDSwitch -OnChange {
        Set-UDElement -Id 'test' -Properties @{
            in = $EventData -eq 'True'
        }
    } -Checked $true
    Add-UDElementarrow-up-right
  • Clear-UDElementarrow-up-right

  • Sync-UDElementarrow-up-right

  • ****Select-UDElementarrow-up-right

  • Get-UDElementarrow-up-right
    Set-UDElementarrow-up-right
    Remove-UDElementarrow-up-right
    New-UDElement -Tag 'div' -Content { 'Hello' }
    New-UDElement -Tag 'ul' -Content {
        New-UDElement -Tag 'li' -Content { 'First' }
        New-UDElement -Tag 'li' -Content { 'Second' }
        New-UDElement -Tag 'li' -Content { 'Third' }
    }
    New-UDElement -Tag 'div' -Content { 'Hello' } -Attributes @{
        style = @{
            color = 'red'
        }
    }
    New-UDElement -Tag div -Content {
        New-UDIcon -Icon "user"
    } -Attributes @{
        onClick = {
            Show-UDToast "Nice!"
        }
    }
    New-UDElement -Tag 'div' -Endpoint {
        Get-Date
    } -AutoRefresh -RefreshInterval 1
    New-UDElement -Tag 'div' -Id 'myElement' -Content { }
    
    New-UDButton -Text 'Click Me' -OnClick {
        Set-UDElement -Id 'myElement' -Content { Get-Date }
    }
        New-UDElement -Tag 'div' -Id 'myElement' -Content { }
    
        New-UDButton -Text 'Click Me' -OnClick {
            Set-UDElement -Id 'myElement' -Content { Get-Date } -Properties @{ Attributes = @{ style = @{ color = "red" } } }
        }
    New-UDElement -Tag 'ul' -Content {
    
    } -Id 'myList'
    
    New-UDButton -Text 'Click Me' -OnClick {
        Add-UDElement -ParentId 'myList' -Content {
            New-UDElement -Tag 'li' -Content { Get-Date }
        }
    }
    New-UDElement -Tag 'ul' -Content {
        New-UDElement -Tag 'li' -Content { 'First' }
        New-UDElement -Tag 'li' -Content { 'Second' }
        New-UDElement -Tag 'li' -Content { 'Third' }
    }  -Id 'myList'
    
    New-UDButton -Text 'Click Me' -OnClick {
        Clear-UDElement -Id 'myList'
    }
    New-UDElement -Tag 'div' -Endpoint {
        Get-Date
    } -Id 'myDiv'
    
    New-UDButton -Text 'Click Me' -OnClick {
        Sync-UDElement -Id 'myDiv'
    }
    New-UDElement -Tag 'div' -Endpoint {
        Get-Date
    } -Id 'myDiv'
    
    New-UDButton -Text 'Click Me' -OnClick {
        Remove-UDElement -Id 'myDiv'
    }
    New-UDTimeline -Children {
        New-UDTimelineItem -Content {
            'Breakfast'
        } -OppositeContent {
            '7:45 AM'
        } 
        New-UDTimelineItem -Content {
            'Welcome Message'
        } -OppositeContent {
            '9:00 AM'
        }
        New-UDTimelineItem -Content {
            'State of the Shell'
        } -OppositeContent {
            '9:30 AM'
        }
        New-UDTimelineItem -Content {
            'General Session'
        } -OppositeContent {
            '11:00 AM'
        }
    } -Position alternate
    New-UDDashboard -Title 'PowerShell Universal' -Content {
            New-UDTimeline -Children {
                New-UDTimelineItem -Content {
                    'Breakfast'
                } -OppositeContent {
                    '7:45 AM'
                }  -Color 'error'
                New-UDTimelineItem -Content {
                    'Welcome Message'
                } -OppositeContent {
                    '9:00 AM'
                } -Color 'info'
                New-UDTimelineItem -Content {
                    'State of the Shell'
                } -OppositeContent {
                    '9:30 AM'
                } -Color 'success'
                New-UDTimelineItem -Content {
                    'General Session'
                } -OppositeContent {
                    '11:00 AM'
                } -Color 'grey'
            } -Position alternate
    }
    New-UDTimeline -Children {
        New-UDTimelineItem -Content {
            'Breakfast'
        } -OppositeContent {
            '7:45 AM'
        }  -Icon (New-UDIcon -Icon Microsoft)
        New-UDTimelineItem -Content {
            'Welcome Message'
        } -OppositeContent {
            '9:00 AM'
        } -Icon (New-UDIcon -Icon Apple)
        New-UDTimelineItem -Content {
            'State of the Shell'
        } -OppositeContent {
            '9:30 AM'
        } -Icon (New-UDIcon -Icon NetworkWired)
        New-UDTimelineItem -Content {
            'General Session'
        } -OppositeContent {
            '11:00 AM'
        } -Icon (New-UDIcon -Icon User)
    } -Position alternate
    Job Failed
  • Dashboard Started

  • Dashboard Stopped

  • Server Started

  • Server Stopping

  • User Login

  • Use of a Revoked App Token

  • PowerShell Protect Event

  • API Authentication Failed

  • API Error

  • New User Login

  • Git Sync

  • License Expired

  • License Expiring

  • Get-PSUTriggerarrow-up-right
    New-PSUTriggerarrow-up-right
    Remove-PSUTriggerarrow-up-right
    Set-PSUTriggerarrow-up-right
    to
    Stop
    . Any errors will cause an 500 Internal Server Error to be returned with a list of the errors and stack trace.

    Terminating errors will always return a 500 Internal Server Error.

    You will notice different behavior in Windows PowerShell and PowerShell 7 when calling REST APIs that return errors. In Windows PowerShell, you will receive a generic error that doesn't return the error message.

    In PowerShell 7, when an error is returned, you will see the error message returned.

    You can retrieve the error message in Windows PowerShell, by using the following syntax.

    hashtag
    Manually Returning Errors

    To manually return errors, you need to use the New-PSUApiResponse cmdlet. This cmdlet allows you to define the status code and body for the response.

    In this example, we are returning a 404 error code from the endpoint.

    Similar to the automatic error codes, error codes returned manually will as display better in PowerShell 7. Here's an example of calling the endpoint.

    If called from Windows PowerShell, you will receive an error similar to the one returned automatically.

    You can choose to return error codes if certain conditions are met by using your PowerShell script within the endpoint.

    hashtag
    API

    • New-PSUEndpointarrow-up-right

    • Get-PSUEndpointarrow-up-right

    • Remove-PSUEndpointarrow-up-right

    ScriptBlock

    The script block event handler to call when the editor data changes.

    Format

    string

    Whether to return either json or html in the OnChange script block.

    New-UDGridarrow-up-right
    New-UDTransitionarrow-up-right
    Collapse Transition
    Slide Transition
    Grow Transition
    Zoom Transition
    New-UDCardFooterarrow-up-right
    New-UDCardHeaderarrow-up-right
    New-UDCardMediaarrow-up-right

    Scripts

    PowerShell scripts to execute within PowerShell Universal.

    PowerShell scripts can be created within PowerShell Universal to execute manually, on a scheudle or when events happen within the platform. They are stored on disk and also persisted to a local or remote Git repository.

    circle-info

    Script properties are stored in the scripts.ps1 configuration file.

    hashtag
    Add a New Script

    To add a new script, you can click the New Script button within the Automation / Scripts page. There are various settings you can provide for the script.

    hashtag
    Script Options

    hashtag
    Name

    Name of the script as shown in Universal Automation. This will also be the name used to persist the script to disk. This setting needs to be unique within the current folder.

    hashtag
    Description

    A description of the script. This is shown in various places within the UA UI and also returned by the Universal cmdlets.

    hashtag
    Disable Manual Invocation

    Prevents a script from being run manually. This is enforced in the UI as well as the web server and cmdlets.

    hashtag
    Manual Time

    This setting is used to track the amount of time saved.

    hashtag
    Max Job History

    Defaults to 100. It defines the amount of jobs that are stored when running this script. Jobs are also cleaned up based on the server-wide job retention duration setting from within the Settings / General page.

    hashtag
    Error Action

    Changes how the script reacts when there is an error within the script. By default, terminating and non-terminating errors are ignored and the script will always be successful. You can change this setting to stop to cause scripts to fail immediately when an error is encountered.

    If you wish to write errors directly to the error pane without causing changes in how the script is handled (for example in an exception handler), you can use Write-PSUError to output the error record and it will appear in the error tab of the job.

    hashtag
    Environment

    Allows you to define the required PowerShell environment for the script. By default, it uses the server-wide default PowerShell environment. PowerShell environments are automatically located the first the Universal Server starts up or read from the environments.ps1 file. You can also add Environment on the Settings / Environments page.

    hashtag
    Timeout

    The number of minutes before the script will timeout. The default value of 0 means the script will run forever. Once a script reaches it's time out, it will be cancelled.

    hashtag
    Anonymous

    The anonymous setting allows the script to be run when the user is not authenticated. This is useful when using scripts in Pages.

    hashtag
    Discard Pipeline

    When checked, this will disable the storage of pipeline output. This will greatly reduce the CPU and storage overhead of jobs. The script will still write to the information, warning, and error streams.

    hashtag
    Concurrent Jobs

    Defines the maximum concurrent jobs the script can be run. Defaults to 100.

    hashtag
    Running a Script

    You can run a script in the UI by click the Run button the Automation / Scripts page or by clicking View and then Run. In each case, you will be presented with the Run Dialog that allows you to select various settings for the job.

    hashtag
    Running a Script With Parameters

    circle-info

    Learn more about .

    PowerShell Universal automatically determines the parameters as defined within your scripts. It takes advantage of static code analysis to determine the type, default values and some validation that is then presented within the UI.

    For example, you may have a script with the following parameters.

    The result is a set of input options that are based on the types of parameters.

    hashtag
    Running a Script as Another User

    circle-info

    The integrated does not support running as alternate credentials.

    You can run scripts as another user by configuring . PowerShell Universal uses the Microsoft Secret Management module to integrate with secret providers. See variables for more information on secrets.

    To run as another user, simply add or import a PSCredential variable. From there, you can select the credential from within the run dialog.

    hashtag
    Running a Script on Another Computer

    You can use the Computer drop down to select other machines to run a script on. The default value is to run on any computer that is available.

    hashtag
    Running a Script on All Computers

    You can run a script on all computers by selecting the All Computers option from the Computer drop down.

    hashtag
    Remoting

    Note that you can use PowerShell remoting by taking advantage of Invoke-Command . We do not support the use of Enter-PSSession or Import-PSSession.

    hashtag
    Comment-Based Help

    You can use comment-based to define the description, a synopsis, parameter based help, and links for your scripts. These will be displayed within the PowerShell Universal UI.

    This above will yield the following user interface. The synopsis will be shown as the short description and a longer description can be shown in the description section. Links will appear under the description.

    hashtag
    API

    Installation

    Installation instructions for PowerShell Universal.

    hashtag
    MSI Install (Windows)

    The MSI install will create a PowerShell Universal service. By default, PowerShell Universal will be listening on port 5000. You will be able to navigate to http://localhost:5000 and login with admin and password admin.

    MSI downloads are available on our .

    hashtag
    MSI Parameters

    The following table contains the parameters you can specify if running msiexec against our MSI install for automation purposes.

    Parameter
    Description
    Default Value

    hashtag
    Example

    Below is an example of how to run msiexec.exe to install PowerShell Universal and provide parameters to the installer.

    hashtag
    ZIP Install

    You can also download the ZIP from our if you would like to xcopy deploy the files on Windows or Linux.

    hashtag
    Windows

    You can start Universal by unzipping the contents, unblocking the files and then executing Universal.Server.exe.

    hashtag
    Linux

    You can use the following command line on Linux to install and start PowerShell Universal.

    hashtag
    PowerShell Module

    You can use the PowerShell Universal PowerShell module to install the Universal server. To install the module, use Install-Module.

    To install the Universal server, you can use Install-PSUServer.

    If you run this command on Windows, a Windows service will be created and started on your machine. If you run this command on Linux, a systemd service will be created and started. If you run this command on Mac OS, the PowerShell Universal server will be downloaded and extracted.

    hashtag
    Chocolatey Package (Windows)

    circle-exclamation

    Chocolatey packages for PowerShell Universal are usually available within a week of release but will not be available the day of a release.

    You can install PowerShell Universal using the . The package runs the MSI install. It will install Universal as a service and open a web browser after the install.

    You can login with the "admin" user and any password.

    hashtag
    Docker

    See the .

    hashtag
    IIS Install

    Please visit the for information on how to configure PowerShell Universal as an IIS website.

    hashtag
    Antivirus Configuration

    PowerShell Universal takes full advantage of PowerShell and the PowerShell SDK. It includes PowerShell scripts directly in the product. You will want to consider configuring antivirus to allow for execution of PowerShell scripts in PowerShell Universal.

    hashtag
    Directories

    The following directories will contain scripts and executable files that may need to be excluded from antivirus checks.

    The following are examples from a standard Windows system. Changing paths within appsettings.json or within the installer will require changing which directories are execluded.

    Path
    Description

    hashtag
    Executables

    It may be necessary to exclude certain executables that will run PowerShell scripts. The below is a list of executables that will run PowerShell from PowerShell Universal.

    Name
    Description

    hashtag
    Next Steps

    At this point, Universal is up and running. You can navigate to the admin console by visiting http://localhost:5000 by default. The default username is admin with a password of admin.

    Parameters

    Parameters for PowerShell Universal jobs.

    hashtag
    Parameters

    Jobs support automatically generating forms with parameters based on your script's param block. The type of control will change based on the type you define in the block. Parameters that are mandatory will also be required by the UI.

    hashtag
    Basic Parameters

    Parameters can be simply defined without any type of parameter attribute and they will show up as text boxes in the UI.

    hashtag
    Parameters Types

    Universal supports various types of parameters. You can use String, String[], Int, DateTime, Boolean, Switch and Enum types.

    hashtag
    String

    You can define string parameters by specifying the [String] type of by not specifying a type at all. Strings will generate a textbox.

    hashtag
    String Arrays

    You can specify string arrays by using the [String[]] type specifier. String arrays will generate a multi-tag select box.

    hashtag
    Date and Time

    You can use the [DateTime] type specifier to create a date and time selector.

    hashtag
    Boolean

    You can use a [Bool] type selector to create a switch.

    hashtag
    Integer

    You can define a number selector by using the [Int] type specifier.

    hashtag
    Switch Parameter

    You can define a switch parameter using the [Switch] type specifier to create a switch.

    hashtag
    Enumerations

    You can use System.Enum values to create select boxes. For example, you could use the System.DayOrWeek to create a day of the week selection box.

    hashtag
    PSCredential

    When you specify a PSCredential , the user will be presented with a drop down of credentials available as .

    hashtag
    File

    You can allow users to upload files by using the [File] type.

    Files will be available as a PSUFile object in your scripts. This object has a byte[] array that you can use to process the file.

    For example, you can get the string content for the file by converting it using the Encoding classes.

    hashtag
    Display Name

    You can use the DisplayNameAtrribute to set a display name for the script parameter.

    hashtag
    Help Messages

    You can define help messages for your parameters by using the HelpMessage property of the Parameter attribute.

    hashtag
    Required Parameters

    You can use the Parameter attribute to define required parameters.

    hashtag
    Default Value

    You can use both static and default values for parameters. The default value is calculated when the job is about to be run.

    hashtag
    Passing Parameters from PowerShell

    You can pass parameters from PowerShell using the Invoke-PSUScript cmdlet. This cmdlet supports dynamic parameters. If you have a param block on your script, these parameters will automatically be added to Invoke-PSUScript.

    For example, I had a script named Script1.ps1 and the contents were are follows.

    I could then invoke that script using this syntax.

    The result would be that Hello was output in the job log and pipeline.

    hashtag
    Parameter Sets

    PowerShell Universal supports parameter sets. When a parameter set is defined, a drop down is provided that allows for switching between the sets.

    Textbox

    Textbox component for Universal Dashboard

    A textbox lets users enter and edit text.

    hashtag
    Textbox

    hashtag
    Password Textbox

    A password textbox will mask the input.

    hashtag
    Multiline

    You can create a multiline textbox by using the -Multiline parameter. Pressing enter will add a new line. You can define the number of rows and the max number of rows using -Rows and -RowsMax.

    hashtag
    Interaction

    hashtag
    Retrieving a textbox value

    You can use Get-UDElement to get the value of a textbox

    hashtag
    Setting the textbox value

    hashtag
    Icons

    You can set the icon of a textbox by using the -Icon parameter and the New-UDIcon cmdlet.

    hashtag
    Mask

    The textbox mask is accomplished using react-imask. You can specify RegEx and pattern matching.

    This example creates a mask for US based phone numbers.

    hashtag
    Unmasking

    The default behavior of -Mask is to return the masked value in forms and Get-UDElement. You can return the unmasked value by specifying the -Unmask parameter.

    hashtag
    OnEnter

    The -OnEnter event handler is executed when the user presses enter in the text field. It is useful for performing other actions, like clicking a button, on enter.

    hashtag
    OnBlur

    The -OnBlur event handler is executed when the textbox loses focus.

    hashtag
    OnValidate

    Use the -OnValidate event handler to validate input typed in the textbox.

    hashtag
    API

    @{
        Name = "username"
        Roles = @()
    }
    @{
        UserName = 'username'
        RemoteIpAddress = ''
        LocalPort = ''
        RemotePort = ''
    }
    public class GitStatus 
    {
        public long Id { get; set; }
        public string CommitId { get; set; }
        public DateTime Timestamp { get; set; }
        public TimeSpan SyncTime { get; set; }
        public int Changes { get; set; }
        public string Location { get; set; }
        public string Remote { get; set; }
        public GitStatusResult Result { get; set; }
        public string ResultMessage { get; set; }
        public string ComputerName { get; set; }
    }
    New-PSUTrigger -Name 'Trigger' -EventType JobStarted -TriggerScript Script.ps1
    New-PSUTrigger -Name 'Trigger' -EventType DashboardStopped -TriggerScript Script.ps1 -Dashboard 'Dashboard'
    param($Job)
    
    $Job
    param($Dashboard)
    
    $Dashboard
    New-PSUTrigger -Condition {
       $Env:Environment -eq 'production'
    }
    New-PSUEndpoint -Url "/error" -Endpoint { 
       throw "Uh oh!"
    } -ErrorAction stop
    
    New-PSUEndpoint -Url /error2 -Endpoint {
        Write-Error "Whoa!"
    } -ErrorAction Stop
    PS C:\Users\adamr> invoke-restmethod http://localhost:5000/error2
    invoke-restmethod : The remote server returned an error: (500) Internal Server Error.
    At line:1 char:1
    + invoke-restmethod http://localhost:5000/error2
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], Web
       Exception
        + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
    PS C:\Users\adamr\Desktop> invoke-restmethod http://localhost:5000/error 
    
    Invoke-RestMethod: Uh oh!
    at , : line 2
    at , : line 1
    
    PS C:\Users\adamr\Desktop> invoke-restmethod http://localhost:5000/error2
    
    Invoke-RestMethod: Whoa
    at , : line 2
    at , : line 1
    PS C:\Users\adamr> try { invoke-restmethod http://localhost:5000/error2 } catch { [System.IO.StreamReader]::new($_.Exception.Response.GetResponseStream()).ReadToEnd()}
    Whoa!
    at <ScriptBlock>, <No file>: line 2
    at <ScriptBlock>, <No file>: line 1
    New-PSUEndpoint -Url /broken -Endpoint {
        New-PSUApiResponse -StatusCode 404 -Body 'Failed!'
    }
    PS C:\Users\adamr\Desktop> invoke-restmethod http://localhost:5000/broken
    
    Invoke-RestMethod: Failed!
    PS C:\Users\adamr> invoke-restmethod http://localhost:5000/broken
    invoke-restmethod : The remote server returned an error: (404) Not Found.
    At line:1 char:1
    + invoke-restmethod http://localhost:5000/broken
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], Web
       Exception
        + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
    New-PSUEndpoint -Url /user/:name -Endpoint {
        if ($Name -eq 'User')
        {
            @{ UserName = "Adam" }
        }
        else
        {
            New-PSUApiResponse -StatusCode 404 -Body 'Unknown user!'    
        }
    
    }
    New-UDDynamic -Id 'spacingGrid' -Content {
        $Spacing = (Get-UDElement -Id 'spacingSelect').value
    
        New-UDGrid -Spacing $Spacing -Container -Content {
            New-UDGrid -Item -ExtraSmallSize 3 -Content {
                New-UDPaper -Content { "xs-3" } -Elevation 2
            }
            New-UDGrid -Item -ExtraSmallSize 3 -Content {
                New-UDPaper -Content { "xs-3" } -Elevation 2
            }
            New-UDGrid -Item -ExtraSmallSize 3 -Content {
                New-UDPaper -Content { "xs-3" } -Elevation 2
            }
            New-UDGrid -Item -ExtraSmallSize 3 -Content {
                New-UDPaper -Content { "xs-3" } -Elevation 2
            }
        }
    }
    
    New-UDSelect -Id 'spacingSelect' -Label Spacing -Option {
        for($i = 0; $i -lt 10; $i++)
        {
            New-UDSelectOption -Name $i -Value $i
        }
    } -OnChange { Sync-UDElement -Id 'spacingGrid' } -DefaultValue 3
    New-UDRow -Columns {
        New-UDColumn -SmallSize 12 -Content {
            New-UDPaper -Content { "xs-12" } -Elevation 2
        }
        New-UDColumn -SmallSize 12 -Content {
            New-UDPaper -Content { "xs-12" } -Elevation 2
        }
    }
    New-UDTransition -Id 'test' -Content {
        New-UDCard -Text "Hey"
    } -In -Collapse -CollapseHeight 100 -Timeout 1000
    
    New-UDSwitch -OnChange {
        Set-UDElement -Id 'test' -Properties @{
            in = $EventData -eq 'True'
        }
    } -Checked $true
    New-UDTransition -Id 'test' -Content {
        New-UDCard -Text "Hey"
    } -In -Fade -Timeout 1000
    
    New-UDSwitch -OnChange {
        Set-UDElement -Id 'test' -Properties @{
            in = $EventData -eq 'True'
        }
    } -Checked $true
    New-UDTransition -Id 'test' -Content {
        New-UDCard -Text "Hey"
    } -In -Slide -SlideDirection 'left' -Timeout 1000
    
    New-UDSwitch -OnChange {
        Set-UDElement -Id 'test' -Properties @{
            in = $EventData -eq 'True'
        }
    } -Checked $true
    New-UDTransition -Id 'test' -Content {
        New-UDCard -Text "Hey"
    } -In -Grow -Timeout 1000
    
    New-UDSwitch -OnChange {
        Set-UDElement -Id 'test' -Properties @{
            in = $EventData -eq 'True'
        }
    } -Checked $true
    New-UDTransition -Id 'test' -Content {
        New-UDCard -Text "Hey"
    } -In -Zoom -Timeout 1000
    
    New-UDSwitch -OnChange {
        Set-UDElement -Id 'test' -Properties @{
            in = $EventData -eq 'True'
        }
    } -Checked $true
    New-UDTextbox -Label 'Standard' -Placeholder 'Textbox'
    New-UDTextbox -Label 'Disabled' -Placeholder 'Textbox' -Disabled
    New-UDTextbox -Label 'Textbox' -Value 'With value'
    New-PSUApiResponsearrow-up-right
    Set-PSUSettingarrow-up-right

    The LiteDB or SQL connection string.

    %ProgramData%\UniversalAutomation\database.db

    DATABASETYPE

    LiteDB or SQL

    LiteDB

    STARTSERVICE

    Whether to start the service after install (0 or 1)

    1

    SERVICEACCOUNT

    The service account to set for the Windows service

    None

    SERVICEACCOUNTPASSWORD

    The service account password to set for the Windows Service

    None

    INSTALLFOLDER

    The installation folder for PowerShell Universal

    %ProgramFiles(x86)%\Universal

    TCPPORT

    The TCP port the HTTP server will be listening on.

    5000

    REPOFOLDER

    The repository folder to save the configuration files to.

    %ProgramData%\UniversalAutomation\Repository

    %ProgramData%\PowerShellUniversal

    Contains log files and appsettings.json

    %ProgramData%\UniversalAutomation

    Contains PowerShell scripts and artifacts. Contains the single file database when not using SQL integration.

    %ProgramFiles(x86)\Universal

    Contains PowerShell Universal application executables, libraries and modules.

    Universal.Server.exe

    The PowerShell Universal core service.

    Universal.Agent.exe

    The PowerShell Universal agent environment executable.

    pwsh.exe

    PowerShell 7.x

    PowerShell.exe

    PowerShell 5.x

    download pagearrow-up-right
    Downloads pagearrow-up-right
    Chocolatey packagearrow-up-right
    Docker page
    IIS hosting documentation

    CONNECTIONSTRING

     Start-Process msiexec.exe -ArgumentList "/I C:\Users\adamr\Downloads\PowerShellUniversal.3.5.1.msi /q /norestart /L*V `"C:\users\adamr\desktop\msi.log.txt`" STARTSERVICE=0" -Wait -NoNewWindow
    Expand-Archive -Path .\Universal.zip -DestinationPath .\Universal
    Get-ChildItem .\Universal -Recurse | Unblock-File
    Start-Process .\Universal\Universal.Server.exe
     wget https://imsreleases.blob.core.windows.net/universal/production/2.0.0/Universal.linux-x64.2.0.0.zip
     sudo apt install unzip 
     unzip Universal.linux-x64.2.0.0.zip -d PSU
     chmod +x ./PSU/Universal.Server
     ./PSU/Universal.Server
    Install-Module Universal
    Install-PSUServer -LatestVersion
    choco install powershelluniversal
    Get-PSUScriptarrow-up-right
    parameters here
    environment
    secret variables
    New-PSUScriptarrow-up-right
    Remove-PSUScriptarrow-up-right
    Set-PSUScriptarrow-up-right
    variables
    Parameter Sets
    Pattern Maskarrow-up-right
    RegEx Maskarrow-up-right
    New-UDTextboxarrow-up-right

    Upgrading

    This document covers upgrading the PowerShell Universal application.

    hashtag
    Overview

    This document will cover the upgrade process for production PowerShell Universal instances. We will cover the following topics.

    1. Data Backup

    2. Upgrade Process

    3. Upgrade Validation

    The Universal application binaries can generally be upgraded without having to change the configuration or database manually, but we do recommend backups of production data.

    hashtag
    1. Data Backup

    PowerShell Universal uses a script-based configuration system alongside a database used for retention of entities such as app tokens, job history and identities. If possible, you will want to backup these items before running an upgrade for easy rollback in case an issue is encountered during validation.

    hashtag
    Database

    Backing up the database ensures that all apptokens, job history, identities and database secrets are retained in the case of an upgrade failure. SQL databases also may adjust the schema of the database and may require a rollback of not only the data, but also the schema of the tables in the database.

    hashtag
    LiteDB

    By default, PowerShell Universal uses a single file database called LiteDB. Unless configured otherwise, the database is stored in %ProgramData%\UniversalAutomation. You should have a database.db and possibility a database-log.db. Both of these files should be backed up. The service must be stopped in order to backup the files.

    hashtag
    SQL

    When using SQL for persistence, backup the entire database (including schema). There isn't necessarily a need to stop the PowerShell Universal service when backing up the database but it may continue to write to the database (for example when running scheduled jobs) after the backup has been completed.

    hashtag
    Configuration Scripts

    Scripts make up the main configuration data to backup when upgrading a production PowerShell Universal instance. For production, we recommend using a version control system. You can also take advantage of the built-in git integration. If you are using a two-way sync for PowerShell Universal git integration, consider tagging your git branch prior to the upgrade to allow for easy rollback to unexpected changes within the git repository.

    hashtag
    2. Upgrade Progress

    Below are sections for each type of system upgrade and the steps that you should take based on how you originally installed PSU.

    hashtag
    MSI

    When installing via the MSI, you will want to follow the same backup procedures above.

    hashtag
    appsettings.json

    You will want to back up the appsettings.json file stored in %ProgramData%\PowerShellUniversal. This file contains information such as port, data storage location and other server settings. Typically, the MSI will not make changes to this file once created. It will use the settings found for the upgraded version. That said, if necessary, the MSI will make changes to the appsettings file. These changes are considered breaking and will be listed in the changelog for the release.

    hashtag
    Service Account

    When running an MSI upgrade, the PSU service is not uninstalled, and thus, the service account will still be set once the service starts up.

    circle-info

    If you perform an uninstall and then an install using the MSI, then the service account will be removed.

    hashtag
    Upgrade Process

    Once all the configuration files and the database are backed up, you can run the new MSI installer. The installer may prompt for a restart of the machine if files are locked. The PSU MSI will uninstall all the files in the installation directory and install entirely new files.

    Once the MSI has completed, you can navigate to your PowerShell Universal admin console to perform installation validation.

    hashtag
    IIS

    Below you will find information about upgrading an IIS install.

    hashtag
    web.config

    In addition to the files listed to backup above, you will also want to consider backing up your web.config file. If you have made no changes to this file, you do not need to back it up.

    The web.config file that is included in the application installation directory will be overwritten during upgrades. If you have moved your web.config file to an alternate location, it will not be overwritten. When creating an IIS website, you can simply include the web.config file in the web app's directory and have the .

    hashtag
    Upgrade Process

    When upgrading with IIS, you will need to first stop your application pool to ensure that the binaries used by IIS are no longer in use and then replace the binaries with the new ones. To ensure that the upgrade works as expected, it's recommended to delete all the application files and then unzip the new ones into the same directory to avoid assembly conflicts.

    circle-info

    As with any installation from a ZIP file, make sure that you run Get-ChildItem -Recurse | Unblock-File from an elevated command prompt across the PowerShell Universal files to ensure they can be executed properly.

    Once you have copied the new files and unblocked them, start the app pool, navigate to the PowerShell Universal Admin Console and perform installation validation.

    hashtag
    Universal Module

    The Universal module can be used to upgrade installations of PowerShell Universal previously installed by the module.

    circle-exclamation

    Do not use the Universal module to upgrade instances installed via MSI.

    Follow the backup procedures above and then perform the upgrade.

    First, upgrade the local PowerShell Universal module and verify the expected version is installed.

    Next, run Update-PSUServer to download and unzip the new PSU instance.

    After the upgrade is complete, navigate to the PowerShell Universal Admin Console and begin upgrade validation.

    hashtag
    ZIP

    Perform the necessary backup procedures and download the latest ZIP of PowerShell Universal.

    Stop the PowerShell Universal service. Delete the existing PowerShell Universal application files. Extract the ZIP files to the same directory. Finally, run Unblock-File against the directory to ensure that PSU can execute properly. Always run this command as administrator.

    After the upgrade is complete, navigate to the PowerShell Universal Admin Console and begin upgrade validation.

    hashtag
    3. Upgrade Validation

    After running an upgrade, you should perform basic validation against your PSU server to ensure that it is fully functional.

    hashtag
    Notifications

    Verify that there are no errors within the notification drop down. They may be a sign of issues during the upgrade.

    hashtag
    Environments

    Verify that all environments are listed in the Settings \ Environments page. Although upgrades may not necessarily cause a change in environments, restarting the PowerShell Universal service (without an environments.ps1 file) will cause PSU to rediscover environments. Updates to PowerShell outside of PSU may cause issues with PSU after it restarts.

    hashtag
    Modules

    Upgrades to PowerShell Universal may change assembly versions of DLLs shipped with the platform. This can cause other modules to fail to load. While this may not be obvious at first, you may consider taking an inventory of modules used in your platform to ensure that the versions are consistent before and after the upgrade to limit changes.

    If you have installed a version of the Universal module outside of PowerShell Universal (for example, with Install-Module), you must make sure to update the module or it can conflict with the new one installed with PowerShell Universal.

    hashtag
    Dashboards

    The most common upgrade issues come due to changes in the dashboard framework. Dashboards can be complex and bug fixes or features can sometimes cause for certain user's dashboards while fixing issues pertaining to another user's dashboard. Please read the changelog before upgrading to understand the impact of changes made to the dashboard framework and consider testing the dashboard with development data before upgrading in production.

    hashtag
    Common Upgrade Issues

    hashtag
    IIS App Pool Does Not Start After Upgrade

    The most common upgrade issue is that Unblock-File is not called properly on the extracted files when performing an upgrade of a IIS ZIP install. Also make sure to run the Unblock-File command recursively and from within an administrative session.

    Another command issue is extracting the files over the top of the existing files. This can cause assembly conflicts and puts the application in an unknown state. Follow the IIS upgrade documentation and delete the files before extracting them.

    hashtag
    Command Not Found Errors

    When new functionality is added to PowerShell Universal it is typically done using new cmdlets. If older versions of the PowerShell Universal module are installed on the system, it can cause conflicts with the one shipped within the installation media. Ensure that you have removed older versions of the Universal module if you encounter these errors.

    hashtag
    Table\Column Not Found Error when using SQL Persistence

    This can happen if SQL schema upgrades are not being run during upgrades. If you set the RunMigrations setting to false in appsettings.json, you must run the migrations manually or the PowerShell Universal service will not function properly.

    hashtag
    Breaking Dashboard Component Change

    These changes can be visual or functional. Please ensure that you review the changelog for items that may be related to the change you are seeing. Consider posting the forums or opening a GitHub issue to see if the issue is as designed and if there is a viable workaround.

    circle-info

    We make the best possible effort to support everyone's' dashboards without breaking changes. That said, every configuration is pretty unique so we are more than happy to address issues you may encounter. Please, just let us know.

    hashtag
    License Issues after Upgrade

    The licensing model of PowerShell Universal provides licensed users the ability to upgrade to whatever is the newest version as long as they have an active perpetual or subscription license. If you attempt to upgrade a server that is no longer within the license window, the server will not function as expected. You will need to downgrade back to the previous version to restore functionality.

    Additionally, you may encounter issues due to the PSU service restart. When the service starts, it verifies license subscription status. If it fails to do so, it may not be licensed properly and cause other issues. The root cause is typically networking issues while attempting to access the IronmanSoftware.com website for activation. Offline license keys do not contact the IMS website for activation and will not encounter this issue.

    hashtag
    3.0 Breaking Changes

    If you are upgrading from 2.x, you will have a couple of breaking changes.

    hashtag
    Secret Variables Not Directly Defined

    For performance reasons, secret variables are no longer automatically included in environments. To use secret variables, use the new .

    hashtag
    UD v2 Framework Removed

    The UDv2 framework has been removed and is no longer supported. If you wish to use this framework, you can install it from the PowerShell Gallery.

    hashtag
    IIS Hosting Package

    If you are hosting in IIS, ensure that you install the .

    hashtag
    PowerShell Support

    PowerShell 7.2 or later is supported by PowerShell Universal v3.

    hashtag
    Migrating from LiteDB to SQL

    In the PowerShell Universal installation directory, there you will find the tool for moving data from a local LiteDB database to a SQL server database. It takes care of creating the dashboard, creating the schema and transferring data.

    circle-info

    Although we only read data from LiteDB, we recommend backing it up before running the tool.

    Once migrated, you will need to update the plugin setting within appsettings.json. Replace the UniversalAutomation.LiteDBv5 value with the string SQL. You can also set an environment variable to use the SQL plugin.

    You'll also need to replace the connection string value with your SQL Data \ ConnectionString.

    Similar to the plugin, you can use an environment variable instead of updating appsetings.json.

    The step by step process is as follows:

    1. Stop the PowerShell Universal service

    2. Backup the database and repository

    3. Run the data migration tool

    Once the service starts, it will be connected to SQL. Job data, identities, computers, and terminal instances will be stored in SQL.

    circle-info

    If you are encountering issues with upgrades, you can use the --ContinueOnError flag to continue processing data even if an error is encountered. Typically, errors are the result of job history that may be missing a referential entity. LiteDB is document based while SQL is a relational database so some data may not translate perfectly.

    Jobs

    Jobs are the history of scripts that have been run.

    Jobs are the result of running a script. Jobs are retained based on the script and server level settings.

    hashtag
    Viewing Jobs

    Jobs can be viewed by clicking the Automation / Jobs page. Click the View button to navigate to the job. Jobs in progress can also been cancelled.

    Job Output

    hashtag
    View Job Output

    Standard PowerShell streams such as information, host, error, warning and verbose are shown within the output pane.

    hashtag
    View Job Pipeline Output

    circle-info

    Storing large amounts of pipeline output can negatively affect performance. You can discard pipeline output by setting the Discard Pipeline setting on scripts.

    Pipeline output for jobs is also stored within PowerShell Universal. Any object that is written to the pipeline is stored as CliXml and available for view within the Pipeline Output tab.

    You can expand the tree view to see the objects and properties from the pipeline.

    hashtag
    Viewing Errors

    Any errors written to the error stream will be available on the Error tab within the job page.

    hashtag
    Feedback

    Some jobs will require feedback. Any script that contains a Read-Host call will wait until there is user interaction with that job. The job will be in a Waiting for Feedback state, and you can respond to that feedback by click the Response to Feedback button on the job page.

    To accept a SecureString with a password input field, you can use the -AsSecureString parameter of Read-Host.

    hashtag
    Invoking Jobs from PowerShell

    You can use Invoke-PSUScript to invoke jobs from the command line. You will need a valid to do so. Parameters are defined using dynamic parameters on the Invoke-PSUScript cmdlet.

    hashtag
    Call Scripts from Scripts

    You can also call UA scripts from UA scripts. When running a job in UA, you don't need to define an app token or the computer name manually. These will be defined for you. You can just call Invoke-PSUScript within your script to start another script. Both jobs will be shown in the UI. If you want to wait for the script to finish, use Wait-PSUJob.

    hashtag
    Waiting for a Script to Finished

    You can use the Wait-PSUJob cmdlet to wait for a job to finish. Pipe the return value of Invoke-PSUScript to Wait-UAJob to wait for the job to complete. Wait-PSUJob will wait indefinitely unless the -Timeout parameter is specified.

    hashtag
    Return Pipeline Data

    You can use the Get-PSUJobPipelineOutput cmdlet to return the pipeline output that was produced by a job. This pipeline output will be deserialized objects that were written to the pipeline during the job. You can access this data from where you have access to the PowerShell Universal Management API.

    hashtag
    Returning the last job's output

    It may be required to return the output from a script's last job run. In order to do this, you will need to use a combination of cmdlets to retrieve the script, the last job's ID and then return the pipeline or host output.

    hashtag
    Invoke a Script and Wait for Output

    The following example invokes a script, stores the job object in a $job variable, waits for the job to complete and then returns the pipeline and host output.

    If you are using PowerShell Universal 2.4 or later, you can use the -Wait parameter of Invoke-PSUScript to achieve this.

    hashtag
    Integrated Mode

    The integrated mode allows calling these cmdlets from within PowerShell Universal without an App Token or Computer Name. It uses the internal RPC channel to communicate.

    You can set the -Integrated parameter to switch to integrated mode. This parameter does not work outside of PowerShell Universal.

    The following cmdlets support integrated mode.

    • Get-PSUScript

    • Invoke-PSUScript

    • Get-PSUJob

    hashtag
    Invoking Jobs with REST

    You can call jobs over REST using the management API for PowerShell Universal. You will need a valid app token to invoke jobs.

    hashtag
    Call Scripts with REST

    To call a script, you call an HTTP POST to the script endpoint with the ID of the script you wish to execute.

    hashtag
    Providing Parameters

    You can provide parameters to the job via a query string. Parameters will be provided to your script as strings.

    hashtag
    Setting the Environment

    You can set the environment by pass in the environment property to the job context. The property must be the name of an environment defined within your PSU instance.

    hashtag
    Setting the Run As account

    You can set the run as account by passing in the name of a PSCredential variable to the Credential property.

    hashtag
    Variables Defined in Jobs

    Variables defined in jobs can be found on the .

    hashtag
    Experimental Feature: Job Run ID

    The default behavior for PowerShell Universal is to track jobs based on an autoincrementing int64-based ID. Every time a new job is run, the job is one higher in ID than the last. Because of this behavior, it is easy to guess other job IDs and can potentially lead to a security risk.

    In order to avoid this issue, you can enable the JobRunID experimental feature. Although internally the system still creates jobs with ascending numeric IDs, you cannot access jobs based on those IDs. Instead, a new field called RunID is used. RunID utilizes a GUID rather than an ID for look ups. This greatly reduces the ability for an attacker to guess a job ID.

    You will need to enable this feature to use it.

    hashtag
    API

    New-PSUScript -Name Script.ps1 -Path Script.Ps1 -ConcurrentJobs 1
    param(
        $Test,
        [DateTime]$Time, 
        [int]$Number,
        [PSCredential]$Credential,
        [System.ConsoleColor]$Color
    )
    <#
    .SYNOPSIS 
    
    This is a script for pinging other computers. 
    
    .DESCRIPTION
    
    This script can ping other computers. 
    
    .PARAMETER HostName
    
    The host name or address to ping. 
    
    .LINK
    https://www.ironmansoftware.com
    #>
    param($HostName)
    
    Test-NetConnection $HostName
    param($Test)
    
    $Test
    param(
        [String]$Textbox,
        $Textbox2
    )
    param([String[]]$Array)
    param([DateTime]$DateTime)
    param([Bool]$Switch)
    param([Int]$Number)
    param([Switch]$Switch)
    param([System.DayOfWeek]$DayOfWeek)
    param(
        [PSCredential]$Credential
    )
    param(
        [File]$File
    )
    [Text.Encoding]::UTF8.GetString($File.Content)
    param(
        [ComponentModel.DisplayName("My Script")]
        $MyScript
    )
    param(
        [Parameter(HelpMessage = "Class you want to enroll in")]
        [string]$Class
    )
    param(
        [Parameter(Mandatory)]
        $RequiredParameter
    )
    
    $RequiredParameter
    param(
        $Parameter = "Hello, World",
        [DateTime]$ExecutionTime = Get-Date
    )
    
    $Parameter
    $ExecutionTime
    param($MyParameter)
    
    $MyParameter
    Invoke-PSUScript -Name 'Script.ps1' -MyParameter "Hello"
    param(
        [Parameter(ParameterSetName = 'Set1')]
        $Parameter1,
        [Parameter(ParameterSetName = 'Set2')]
        $Parameter2
    )
    New-UDTextbox -Label 'Password' -Type password
    New-UDTextbox -Multiline -Rows 4 -RowsMax 10
    New-UDTextbox -Id 'txtExample' 
    New-UDButton -OnClick {
        $Value = (Get-UDElement -Id 'txtExample').value 
        Show-UDToast -Message $Value
    } -Text "Get textbox value"
    New-UDTextbox -Id 'txtExample' -Label 'Label' -Value 'Value'
    
    New-UDButton -OnClick {
    
        Set-UDElement -Id 'txtExample' -Properties @{
            Value = "test123"
        }
    
    } -Text "Get textbox value"
    New-UDTextbox -Id "ServerGroups" -Icon (New-UDIcon -Icon 'server') -Value "This is my server"
    New-UDTextbox -Mask "+1 (000) 000-0000"
    New-UDTextbox -Mask "+1 (000) 000-0000" -Unmask
    New-UDTextbox -OnEnter {
        Invoke-UDEndpoint -Id 'submit' -Session
    }
    
    New-UDButton -Id 'submit' -OnClick {
        Show-UDToast -Message 'From Textbox'
    }
    New-UDTextbox -OnBlur {
        Show-UDToast "Blurred"
    }
    New-UDTextbox -OnValidate {
        if ($EventData.Length -lt 10)
        {
            New-UDValidationResult -ValidationError 'String needs to be longer than 10'
        }
    }
    Update the appsettings.json or environment variable to enable the SQL plugin and set the connection string.
  • Start the PowerShell Universal service

  • binaries stored in a different location
    secret scope
    .NET 6.0 hosting bundlearrow-up-right
    DataMigrator.exe
    Update-Module Universal
    Import-Module Universal -PassThru
    Update-PSUServer
    Get-ChildItem -Recurse | Unblock-File
    $ENV:Plugins__0 = "SQL"
    $Env:Data__ConnectionString = "Data Source=ServerName; Initial Catalog=DatabaseName; User Id=UserName; Password=UserPassword;"
    Get-PSUJobOutput
  • Get-PSUJobPipelineOutput

  • Get-PSUJobFeedback

  • Set-PSUJobFeedback

  • Wait-PSUJob

  • Get-PSUJobOutputarrow-up-right
  • Get-PSUJobPipelineOutputarrow-up-right

  • Wait-PSUJobarrow-up-right

  • App Token
    variables page
    Invoke-PSUScriptarrow-up-right
    Get-PSUJobarrow-up-right
    Get-PSUJobFeedbackarrow-up-right
    Standard Output
    Pipeline Output
    Errors
    Waiting for Feedback

    About

    A single pane of glass for managing and delegating access to your automation environment.

    PowerShell Universal Admin Console

    A single pane of glass for managing and delegating access to your automation environment.

    Universal provides an Administrator console, management REST API, PowerShell cmdlets and an idempotent configuration system using PowerShell scripts.

    hashtag
    Featured Template: Active Directory

    Curious what you can do with PowerShell Universal?

    This template includes features such as:

    • Object Search

    • User Management and Reports

    • Group Management

    hashtag
    APIs

    Expose scripts as RESTful HTTP APIs for integration from any platform.

    hashtag
    Automation

    Execute, schedule, secure and audit scripts in an easy-to-use, web-interface.

    hashtag
    User Interfaces

    Build web-based tools for internal users with highly interactive user interfaces that run your scripts.

    hashtag
    Hosting

    PowerShell Universal is cross-platform and can be hosted on-premise, in the cloud or even on a Raspberry Pi.

    • ac

    • and

    hashtag
    Security

    Grant role-based access to different aspects of your automation environment with your choice of authentication and authorization integrations.

    hashtag
    Desktop

    Create desktop automation and user interfaces that integrate with features of Windows.

    hashtag
    Development

    Take advantage of rich development tools such as IntelliSense, code formatting, error checking and debugger integration without leaving your browser.

    hashtag
    Platform

    Configure the platform to meet the needs of your environment.

    hashtag
    Community

    Join the growing community of users managing their automation environments with PowerShell Universal.

    hashtag
    Licensing

    Universal is licensed per server. Visit our on pricing.

    Many features of PowerShell Universal are .

    Stepper

    Stepper component for Universal Dashboard

    Steppers convey progress through numbered steps. It provides a wizard-like workflow.

    Steppers display progress through a sequence of logical and numbered steps. They may also be used for navigation. Steppers may display a transient feedback message after a step is saved. The stepper supports storing input data in the stepper context. It supports the following controls.

    • Autocomplete

    hashtag
    Stepper

    The $Body variable will contain a JSON string that contains the current state of the stepper. You will receive information about the fields that have been defined within the stepper and info about the current step that has been completed. The $Body JSON string will have the following format.

    hashtag
    Validating a Step

    You can validate a step in a stepper by specifying the OnValidateStep parameter. The script block will receive a $Body variable with JSON that provides information about the current state of the stepper. You will need to return a validation result using New-UDValidationResult to specify whether the current step state is valid.

    The JSON payload will have the following format. Note that steps are 0 indexed. If you want to validate the first step, check to make sure the step is 0.

    You will have to convert the JSON string to an object to work with in PowerShell and then return the validation result.

    hashtag
    Skipping Steps

    You can direct the user to a particular step in the OnValidateStep event handler. Use the New-UDValidationResult -ActiveStep parameter to move the user to any step after clicking next. Step indices are 0 based.

    This example moves the user to the last step after completing the first step.

    hashtag
    Disable Previous Button

    You can disable the previous button by using the -DisablePrevious parameter of New-UDValidationResult .

    This example disables the previous step whenever the user moves forward in the stepper.

    hashtag
    Vertical Steppers

    You can create a vertical stepper by setting the -Orientation parameter to vertical.

    hashtag
    API

    Map

    Map component for Universal Dashboard.

    The UDMap component is a robust control that provides a huge set of features. You can select base layers, configure togglable layers, set markers, define vectors and interact with other Universal Dashboard components.

    hashtag
    Basic Map

    This basic map defines a simple base layer using the wmflabs.org tile server. You can use your own custom tile server by specifying a URL. The map is position over Hailey, Idaho.

    Invoke-PSUScript -Script 'Script1.ps1' -RequiredParameter 'Hello'
    Invoke-PSUScript -Script 'Script1.ps1' -RequiredParameter 'Hello' | Wait-PSUJob
    Get-PSUJobPipelineOutput -JobId 10
    $Job = Get-PSUScript -Name 'Script.ps1' | Get-PSUJob -OrderDirection Descending -First 1
    Get-PSUJobPipelineOutput -Job $Job
    Get-PSUJobOutput -Job $Job
    Invoke-PSUScript -Script 'Script1.ps1' -RequiredParameter 'Hello' | Tee-Object -Variable job | Wait-PSUJob
    
    $Pipeline = Get-PSUJobPipelineOutput -Job $Job
    $HostOutput = Get-PSUJobOutput -Job $Job
    
    # Access the actual string returned by the job
    # $HostOutput may be an array 
    $HostOutput.Data
    $Pipeline = Invoke-PSUScript -Script 'Script1.ps1' -RequiredParameter 'Hello' -Wait
    Invoke-PSUScript -Script 'Script.ps1' -Integrated
    Invoke-RestMethod http://localhost:5000/api/v1/script/7 -Method POST -Body "" -Headers @{ Authorization = "Bearer appToken" } -ContentType 'application/json'
    $Parameters = @{
        Uri = "http://localhost:5000/api/v1/script/path/PNP.ps1?Server=tester&Domain=test" 
        Method = "POST"
        Headers = @{Authorization = "Bearer $Apptoken"}
        ContentType = 'application/json'
        Body = '{}'
    }
    
    Invoke-RestMethod @Parameters
    $JobContext = @{
        Environment = "PowerShell 7"
    } | ConvertTo-Json
    
    Invoke-RestMethod http://localhost:5000/api/v1/script/7 -Method POST -Body $JobContext -Headers @{ Authorization = "Bearer appToken" } -ContentType 'application/json'
    $JobContext = @{
        Credential = "MyUser"
    } | ConvertTo-Json
    
    Invoke-RestMethod http://localhost:5000/api/v1/script/7 -Method POST -Body $JobContext -Headers @{ Authorization = "Bearer appToken" } -ContentType 'application/json'
    Set-PSUSetting -ExperimentalFeature ([PowerShellUniversal.ExperimentalFeatures]::JobRunId)
    Infrastructure Reports
    Rate Limitingarrow-up-right
  • Large File Supportarrow-up-right

  • Open API Documentationarrow-up-right

  • File Hostingarrow-up-right

  • Automatic Form Generationarrow-up-right
  • Feedback Integrationarrow-up-right

  • Pipeline Outputarrow-up-right

  • Event Triggersarrow-up-right

  • Concurrency Controlsarrow-up-right

  • Ad-Hoc Terminalsarrow-up-right

  • Chartsarrow-up-right
  • Dynamic Regionsarrow-up-right

  • Steppers (Wizards)arrow-up-right

  • Transitionsarrow-up-right

  • Drag and Drop Pagesarrow-up-right

  • Integration with Scripts and APIsarrow-up-right

  • Extensible Platformarrow-up-right

  • Custom Styling and Brandingarrow-up-right

  • Windows Servicearrow-up-right

  • HTTPSarrow-up-right

  • Client Certificatearrow-up-right
  • SAML2arrow-up-right

  • Windows Authenticationarrow-up-right

  • Script-Based Authorizationarrow-up-right

  • Claims-Based Authorizationarrow-up-right

  • Script Access Controlsarrow-up-right

  • Custom and Built-In Rolesarrow-up-right

  • System Eventsarrow-up-right
  • User Interfacesarrow-up-right

  • PowerShell Modulearrow-up-right
  • Management APIarrow-up-right

  • Visual Studio Code Extensionarrow-up-right

  • Performance Profilerarrow-up-right

  • Desktop Modearrow-up-right

  • Hotkeysarrow-up-right

  • Variablesarrow-up-right
  • Password and Secret Managementarrow-up-right

  • Git Integrationarrow-up-right

  • Application Insights Integrationarrow-up-right

  • Issue Trackerarrow-up-right
    Check out our featured Active Directory template. arrow-up-right
    HTTP Endpointsarrow-up-right
    Custom Responsesarrow-up-right
    Token-Based Authenticationarrow-up-right
    Schedulingarrow-up-right
    Run As Supportarrow-up-right
    Mutliple Environmentsarrow-up-right
    Interactive Dashboardsarrow-up-right
    Input Formsarrow-up-right
    Customizable Tablesarrow-up-right
    Windows, Linux and Marrow-up-right
    Docker Containersarrow-up-right
    Azurearrow-up-right
    IISarrow-up-right
    OpenID Connectarrow-up-right
    WS-Federationarrow-up-right
    Basic Authenticationarrow-up-right
    File Associationsarrow-up-right
    Hotkeysarrow-up-right
    Protocol Handlersarrow-up-right
    Rich Editing Experiencearrow-up-right
    Code-First Configurationarrow-up-right
    Debugging Toolsarrow-up-right
    PowerShell 7 Supportarrow-up-right
    Windows PowerShell Supportarrow-up-right
    PowerShell Modulesarrow-up-right
    Forumsarrow-up-right
    Discordarrow-up-right
    Templatesarrow-up-right
    website for more information arrow-up-right
    free
    Active Directory Dashboard
    Execute PowerShell with HTTP
    Run PowerShell Scripts
    Universal Dashboard
    Host in Azure
    Security Settings
    Development Tools in PowerShell Universal
    Module Management
    Community Forums
    hashtag
    Layer Control

    You can enable the layer control by using the New-UDMapLayerControl cmdlet. This map defines several layers with components that you can toggle on and off. You can only have one base layer selected as a time. Map overlay layers can toggle on and off.

    hashtag
    Markers

    Markers are used to highlight particular locations.

    hashtag
    Custom Icons

    You can specify custom icons for markers using the -Icon parameter.

    hashtag
    Popups

    You can create a popup when clicking the marker by using the -Popup parameter and the New-UDMapPopup cmdlet.

    hashtag
    Heatmaps

    Heatmaps can be defined by creating a heatmap layer. The intesity and location of the heatmap clusters can be defined by using the New-UDMapHeatmapLayer cmdlet.

    hashtag
    Marker Clusters

    Marker clusters group together markers that are close to each other. As you zoom in or out, the clusters will either combine or explode.

    hashtag
    Interactive Maps

    Maps provide a series of interactive capabilities for add components to and manipulating the map.

    Checkbox
    Date Picker
    Radio
    Select
    Slider
    Switch
    Textbox
    Time Picker
    Upload
    New-UDStepperarrow-up-right
    New-UDSteparrow-up-right
    New-UDValidationResultarrow-up-right

    Pages

    Information about Universal Dashboard pages.

    A dashboard can consist of one or more pages. A page can have a particular name and URL. You can define a URL that accepts one or more variables in the URL to define a dynamic page.

    hashtag
    Creating a new page

    Within the dashboard editor, expand the Pages navigation menu and click New Page.

    Form

    Form component for Universal Dashboard

    Forms provide a way to collect data from users.

    Forms can include any type of control you want. This allows you to customize the look and feel and use any input controls.

    Data entered via the input controls will be sent back to the the OnSubmit script block when the form is submitted. Within the OnSubmit event handler, you will access to the $EventData variable that will contain properties for each of the fields in the form.

    For example, if you have two fields, you will have two properties on $EventData

    New-UDMap -Endpoint {
        New-UDMapRasterLayer -TileServer 'https://tiles.wmflabs.org/bw-mapnik/{z}/{x}/{y}.png' 
    } -Latitude 43.52107 -Longitude -114.31644 -Zoom 13 -Height '100vh'
    New-UDMap -Endpoint {
        New-UDMapLayerControl -Content {
            New-UDMapBaseLayer -Name 'Black and White' -Content {
                New-UDMapRasterLayer -TileServer 'https://tiles.wmflabs.org/bw-mapnik/{z}/{x}/{y}.png' 
            } -Checked
            New-UDMapBaseLayer -Name 'Color' -Content {
                New-UDMapRasterLayer -TileServer 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png' 
            }
            New-UDMapOverlay -Name 'Marker' -Content {
                New-UDMapMarker -Latitude 51.505 -Longitude -0.09 
            } -Checked
            New-UDMapOverlay -Name 'Marker 2' -Content {
                New-UDMapMarker -Latitude 51.555 -Longitude -0.00 
            } -Checked
        }
    } -Latitude 51.505 -Longitude -0.09 -Zoom 13 -Height '100vh'
    New-UDMap -Endpoint {
        New-UDMapRasterLayer -TileServer 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png' 
        New-UDMapMarker -Latitude "51.100" -Longitude "-0.5"
    } -Latitude 51.505 -Longitude -0.09 -Zoom 13 -Height '100vh'
    New-UDMap -Endpoint {
        New-UDMapRasterLayer -TileServer 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png' 
        New-UDMapMarker -Latitude "51.100" -Longitude "-0.5"
    } -Latitude 51.505 -Longitude -0.09 -Zoom 13 -Height '100vh' -Icon (New-UDMapIcon -Url = "https://ironmansoftware.com/img/ps-logo.png")
    }
    New-UDMapMarker -Latitude "51.$RandomLat" -Longitude "-0.$Random" -Popup (
        New-UDMapPopup -Content {
            New-UDAlert -Text "Hello"
        } -MinWidth 200
    )
    New-UDMap -Endpoint {
        New-UDMapRasterLayer -TileServer 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png' 
        New-UDMapHeatmapLayer -Points @(
            @(-37.9019339833, 175.3879181167, "625"),
            @(-37.90920365, 175.4053418167, "397"),
            @(-37.9057407667, 175.39478875, "540"),
            @(-37.9243174333, 175.4220341833, "112"),
            @(-37.8992012333, 175.3666729333, "815"),
            @(-37.9110874833, 175.4102195833, "360"),
            @(-37.9027096, 175.3913196333, "591"),
            @(-37.9011183833, 175.38410915, "655"),
            @(-37.9234701333, 175.4155696333, "181"),
            @(-37.90254175, 175.3926162167, "582"),
            @(-37.92450575, 175.4246711167, "90"),
            @(-37.9242924167, 175.4289432833, "47"),
            @(-37.8986079833, 175.3685293333, "801")
        )
    } -Height '100vh'
    New-UDMap -Endpoint {
        New-UDMapRasterLayer -TileServer 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png' 
        New-UDMapMarkerClusterLayer -Id 'cluster-layer' -Markers @(
            1..100 | ForEach-Object {
                $Random = Get-Random -Minimum 0 -Maximum 100
                $RandomLat = $Random + 400
                New-UDMapMarker -Latitude "51.$RandomLat" -Longitude "-0.$Random"
            }
        )
    } -Latitude 51.505 -Longitude -0.09 -Zoom 13 -Height '100vh'
    New-UDButton -Text 'Add Circle' -OnClick {
        Add-UDElement -ParentId 'Feature-Group' -Content {
            New-UDMapVectorLayer -Id 'Vectors' -Circle -Latitude 51.505 -Longitude -0.09 -Radius 500 -Color blue -FillColor blue -FillOpacity .5 
        }
    }
    
    New-UDButton -Text 'Remove Circle' -OnClick {
        Remove-UDElement -Id 'Vectors' 
    }
    
    New-UDButton -Text 'Add Marker' -OnClick {
        Add-UDElement -ParentId 'Feature-Group' -Content {
            New-UDMapMarker -Id 'marker' -Latitude 51.505 -Longitude -0.09 -Popup (
                New-UDMapPopup -Content {
                    New-UDCard -Title "Test"
                } -MaxWidth 600
            ) 
        }
    }
    
    New-UDButton -Text 'Remove Marker' -OnClick {
        Remove-UDElement -Id 'marker' 
    }
    
    New-UDButton -Text 'Add Layer' -OnClick {
        Add-UDElement -ParentId 'layercontrol' -Content {
            New-UDMapOverlay -Id 'MyNewLayer' -Name "MyNewLayer" -Content {
                New-UDMapFeatureGroup -Id 'Feature-Group2' -Content {
                    1..100 | % {
                        New-UDMapVectorLayer -Id 'test' -Circle -Latitude "51.$_" -Longitude -0.09 -Radius 50 -Color red -FillColor blue -FillOpacity .5        
                    }
                }
            } -Checked
    
        }
    }
    
    New-UDButton -Text 'Remove Layer' -OnClick {
        Remove-UDElement -Id 'MyNewLayer' 
    }
    
    New-UDButton -Text 'Move' -OnClick {
        Set-UDElement -Id 'map' -Attributes @{
            latitude = 51.550
            longitude = -0.09
            zoom = 10
        }
    }
    
    New-UDButton -Text "Add marker to cluster" -OnClick {
        Add-UDElement -ParentId 'cluster-layer' -Content {
            $Random = Get-Random -Minimum 0 -Maximum 100
            $RandomLat = $Random + 400
            New-UDMapMarker -Latitude "51.$RandomLat" -Longitude "-0.$Random"
        }
    }
    
    New-UDButton -Text "Add points to heatmap" -OnClick {
        Add-UDElement -ParentId 'heatmap' -Content {
            @(
                @(51.505, -0.09, "625"),
                @(51.505234, -0.0945654, "625"),
                @(51.50645, -0.098768, "625"),
                @(51.5056575, -0.0945654, "625"),
                @(51.505955, -0.095675, "625"),
                @(51.505575, -0.09657, "625"),
                @(51.505345, -0.099876, "625"),
                @(51.505768, -0.0923432, "625"),
                @(51.505567, -0.02349, "625"),
                @(51.50545654, -0.092342, "625"),
                @(51.5045645, -0.09342, "625")
            )
        }
    }
    
    New-UDButton -Text "Clear heatmap" -OnClick {
        Clear-UDElement -Id 'heatmap'
    }
    
    New-UDMap -Id 'map' -Endpoint {
        New-UDMapLayerControl -Id 'layercontrol' -Content {
            New-UDMapBaseLayer -Name "Black and White" -Content {
                New-UDMapRasterLayer -TileServer 'https://tiles.wmflabs.org/bw-mapnik/{z}/{x}/{y}.png' 
            } 
    
            New-UDMapBaseLayer -Name "Mapnik" -Content {
                New-UDMapRasterLayer -TileServer 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png' 
            } 
    
            New-UDMapBaseLayer -Name "Bing" -Content {
                New-UDMapRasterLayer -Bing -ApiKey 'asdf3rwf34afaw-sdfasdfa23feaw-23424dfsdfa' -Type Road
            } -Checked
    
            New-UDMapOverlay -Name "Markers" -Content {
                New-UDMapFeatureGroup -Id 'Feature-Group' -Content {
                    New-UDMapMarker -Id 'marker' -Latitude 51.505 -Longitude -0.09
                } -Popup (
                    New-UDMapPopup -Content {
                        New-UDCard -Title "Test123"
                    } -MaxWidth 600
                )
            } -Checked
    
            New-UDMapOverlay -Name 'Vectors' -Content {
                New-UDMapFeatureGroup -Id 'Vectors' -Content {
    
                }
            } -Checked
    
            New-UDMapOverlay -Name "Heatmap" -Content {
                New-UDMapHeatmapLayer -Id 'heatmap' -Points @() 
            } -Checked 
    
            New-UDMapOverlay -Name "Cluster" -Content {
                New-UDMapMarkerClusterLayer -Id 'cluster-layer' -Markers @(
                    1..100 | ForEach-Object {
                        $Random = Get-Random -Minimum 0 -Maximum 100
                        $RandomLat = $Random + 400
                        New-UDMapMarker -Latitude "51.$RandomLat" -Longitude "-0.$Random"
                    }
                )
            } -Checked
    
        }
    
    } -Latitude 51.505 -Longitude -0.09 -Zoom 13 -Height '100vh' -Animate
    New-UDStepper -Steps {
        New-UDStep -OnLoad {
            New-UDElement -tag 'div' -Content { "Step 1" }
            New-UDTextbox -Id 'txtStep1' -Value $EventData.Context.txtStep1
        } -Label "Step 1"
        New-UDStep -OnLoad {
            New-UDElement -tag 'div' -Content { "Step 2" }
            New-UDElement -tag 'div' -Content { "Previous data: $Body" }
            New-UDTextbox -Id 'txtStep2' -Value $EventData.Context.txtStep2
        } -Label "Step 2"
        New-UDStep -OnLoad {
            New-UDElement -tag 'div' -Content { "Step 3" }
            New-UDElement -tag 'div' -Content { "Previous data: $Body" }
            New-UDTextbox -Id 'txtStep3' -Value $EventData.Context.txtStep3
        } -Label "Step 3"
    } -OnFinish {
        New-UDTypography -Text 'Nice! You did it!' -Variant h3
        New-UDElement -Tag 'div' -Id 'result' -Content {$Body}
    }
    {
        context: {
            txtStep1: "value1",
            txtStep2: "value2",
            txtStep3: "value3"
        },
        currentStep: 0
    }
    {
        context: {
            field1: "value1" 
        },
        currentStep: 0
    }
    New-UDStepper -Steps {
        New-UDStep -OnLoad {
            New-UDElement -tag 'div' -Content { "Step 1" }
            New-UDTextbox -Id 'txtStep1' -Value $EventData.Context.txtStep1
        } -Label "Step 1"
        New-UDStep -OnLoad {
            New-UDElement -tag 'div' -Content { "Step 2" }
            New-UDElement -tag 'div' -Content { "Previous data: $Body" }
            New-UDTextbox -Id 'txtStep2' -Value $EventData.Context.txtStep2
        } -Label "Step 2"
        New-UDStep -OnLoad {
            New-UDElement -tag 'div' -Content { "Step 3" }
            New-UDElement -tag 'div' -Content { "Previous data: $Body" }
            New-UDTextbox -Id 'txtStep3' -Value $EventData.Context.txtStep3
        } -Label "Step 3"
    } -OnFinish {
        New-UDTypography -Text 'Nice! You did it!' -Variant h3
        New-UDElement -Tag 'div' -Id 'result' -Content {$Body}
    } -OnValidateStep {
        $Context = $EventData
        if ($Context.CurrentStep -eq 0 -and $Context.Context.txtStep1 -eq 'bad')
        {
            New-UDValidationResult 
        }
        else
        {
            New-UDValidationResult -Valid 
        }
    }
    New-UDStepper -Steps {
        New-UDStep -OnLoad {
            New-UDElement -tag 'div' -Content { "Step 1" }
            New-UDTextbox -Id 'txtStep1' -Value $EventData.Context.txtStep1
        } -Label "Step 1"
        New-UDStep -OnLoad {
            New-UDElement -tag 'div' -Content { "Step 2" }
            New-UDElement -tag 'div' -Content { "Previous data: $Body" }
            New-UDTextbox -Id 'txtStep2' -Value $EventData.Context.txtStep2
        } -Label "Step 2"
        New-UDStep -OnLoad {
            New-UDElement -tag 'div' -Content { "Step 3" }
            New-UDElement -tag 'div' -Content { "Previous data: $Body" }
            New-UDTextbox -Id 'txtStep3' -Value $EventData.Context.txtStep3
        } -Label "Step 3"
    } -OnFinish {
        New-UDTypography -Text 'Nice! You did it!' -Variant h3
        New-UDElement -Tag 'div' -Id 'result' -Content {$Body}
    } -OnValidateStep {
        $Context = $EventData
        if ($Context.CurrentStep -eq 0 -and $Context.Context.txtStep1 -eq 'bad')
        {
            New-UDValidationResult 
        }
        else
        {
            New-UDValidationResult -Valid -ActiveStep 2
        }
    }
    New-UDStepper -Steps {
        New-UDStep -OnLoad {
            New-UDElement -tag 'div' -Content { "Step 1" }
            New-UDTextbox -Id 'txtStep1' -Value $EventData.Context.txtStep1
        } -Label "Step 1"
        New-UDStep -OnLoad {
            New-UDElement -tag 'div' -Content { "Step 2" }
            New-UDElement -tag 'div' -Content { "Previous data: $Body" }
            New-UDTextbox -Id 'txtStep2' -Value $EventData.Context.txtStep2
        } -Label "Step 2"
        New-UDStep -OnLoad {
            New-UDElement -tag 'div' -Content { "Step 3" }
            New-UDElement -tag 'div' -Content { "Previous data: $Body" }
            New-UDTextbox -Id 'txtStep3' -Value $EventData.Context.txtStep3
        } -Label "Step 3"
    } -OnFinish {
        New-UDTypography -Text 'Nice! You did it!' -Variant h3
        New-UDElement -Tag 'div' -Id 'result' -Content {$Body}
    } -OnValidateStep {
        New-UDValidationResult -Valid -DisablePrevious
    }
    New-UDStepper -Steps {
        New-UDStep -OnLoad {
            New-UDElement -tag 'div' -Content { "Step 1" }
            New-UDTextbox -Id 'txtStep1' -Value $EventData.Context.txtStep1
        } -Label "Step 1"
        New-UDStep -OnLoad {
            New-UDElement -tag 'div' -Content { "Step 2" }
            New-UDElement -tag 'div' -Content { "Previous data: $Body" }
            New-UDTextbox -Id 'txtStep2' -Value $EventData.Context.txtStep2
        } -Label "Step 2"
        New-UDStep -OnLoad {
            New-UDElement -tag 'div' -Content { "Step 3" }
            New-UDElement -tag 'div' -Content { "Previous data: $Body" }
            New-UDTextbox -Id 'txtStep3' -Value $EventData.Context.txtStep3
        } -Label "Step 3"
    } -OnFinish {
        New-UDTypography -Text 'Nice! You did it!' -Variant h3
        New-UDElement -Tag 'div' -Id 'result' -Content {$Body}
    } -Orientation 'vertical'
    You can edit a page by clicking the link in the menu. The code editor will switch to the page's content.
    A page editor

    To reference the page in your dashboard, use Get-UDPage.

    Using a page in a dashboard

    hashtag
    Basic Page

    A basic page can be defined using the New-UDPage cmdlet. You could navigate to this page by visiting the /dashboard URL of your dashboard.

    hashtag
    Dashboard with Multiple Pages

    Dashboards can have multiple pages and those pages can be defined by passing an array of UDPages to New-UDDashboard

    You may want to organize your dashboard into multiple PS1 files. You can do this using pages.

    hashtag
    Page with a Custom URL

    A page can have a custom URL by using the -Url parameter. You could navigate to this page by visiting the /db URL of your dashboard.

    hashtag
    Page with Variables in URL

    You can define a page with variables in the URL to create pages that adapt based on that URL.

    hashtag
    Query string parameters

    Query string parameters are passed to pages and other endpoints as variables.

    For example, if you visited a page with the following query string parameter: http://localhost:5000/dashboard/Page1?test=123

    You would then have access to a $Test variable that contained the value 123.

    hashtag
    Role-Based Access

    circle-info

    This feature requires a license.

    You can prevent users from accessing pages based on their role by using the -Role parameter of pages. You can configure roles and role policies on the Security page.

    hashtag
    Header

    The following options are available for customizing the header.

    hashtag
    Position

    Use the -HeaderPosition parameter to adjust the behavior of the header.

    • absolute\fixed - Remains at the top of the page, even when scrolling

    • relative - Remains at the top of the page. Not visible when scrolling.

    hashtag
    Colors

    You can adjust the colors of the header by specifying the -HeaderColor and -HeaderBackgroundColor parameters. These colors will override the theme colors.

    hashtag
    Navigation

    You can customize the navigation of a page using the -Navigation and -NavigationLayout parameters. Navigation is defined using the List component. Navigation layouts are either permanent or temporary.

    hashtag
    Custom Navigation

    Custom navigation can be defined with a list. List items can include children to create drop down sections in the navigation.

    Custom navigation

    hashtag
    Dynamic Navigation

    Dynamic navigation can be used to execute scripts during page load to determine which navigation components to show based on variables like the user, IP address or roles.

    You can generate dynamic navigation by using the -LoadNavigation parameter. The value of the parameter should be a script block to execute when loading the navigation.

    hashtag
    Layouts

    The permanent layout creates a static navigation drawer on the left hand side of the page. It cannot be hidden by the user.

    Permanent navigation drawer

    The temporary layout creates a navigation drawer that can be opened using a hamburger menu found in the top left corner. This is the default setting.

    Temporary navigation drawer

    hashtag
    Horizontal Navigation

    Horizontal Navigation

    You can use New-UDAppBar with a blank page to create horizontal navigation.

    hashtag
    Logo

    You can display a logo in the navigation bar by using the -Logo parameter.

    First, setup a published folder to host your logo.

    Published assets folder

    Now, when creating your page, you can specify the path to the logo.

    The logo will display in the top left corner.

    Logo

    To customize the style of your logo, you can use a cascading style sheet and target the ud-logo element ID.

    hashtag
    Header Content

    You can define custom content to include in the header by using the -HeaderContent parameter.

    Button in Header

    hashtag
    Dynamic Page Title

    Page titles are static by default, but you can override this behavior by using -LoadTitle. It will be called when the page is loaded. This is useful when defining pages in multilingual dashboards.

    hashtag
    Static Pages

    Static pages allow for better performance by not executing PowerShell to load the content of the page. This can be useful when displaying data that does not require dynamic PowerShell execution. The page content is constructed when the dashboard is started.

    Static pages do not have access to user specific data. This includes variables such as:

    • $Headers

    • $User

    • $Roles

    You can still include dynamic regions within pages. These dynamic regions will have access to user data. Reloading the below example will update the date and time listed in the page.

    hashtag
    API

    New-UDPagearrow-up-right

    New Page Button
    .

    hashtag
    Supported Controls

    The following input controls automatically integrate with a form. The values that are set within these controls will be sent during validation and in the OnSubmit event handler.

    • Autocomplete

    • Checkbox

    • Date Picker

    hashtag
    Simple Form

    Simple forms can use inputs like text boxes and checkboxes.

    hashtag
    Formatting a Form

    Since forms can use any component, you can use standard formatting components within the form.

    hashtag
    Returning Components

    When a form is submitted, you can optionally return another component to replace the form on the page. You can return any Universal Dashboard component. All you need to do is ensure that the component is written to the pipeline within the OnSubmit event handler.

    hashtag
    Validating a Form

    Form validation can be accomplished by using the OnValidate script block parameter.

    hashtag
    Canceling a Form

    You can define an -OnCancel event handler to invoke when the cancel button is pressed. This can be used to take actions like close a modal.

    hashtag
    Displaying output without Replacing the form

    Although you can return components directly from a form, you may want to retain the form so users can input data again. To do so, you can use Set-UDElement and a placeholder element that you can set the content to.

    In this example, we have an empty form that, when submitted, will update the results element with a UDCard.

    hashtag
    Schema Forms

    Instead of defining all the layout and logic for forms using cmdlets, you can also define a form based on a hashtable of schema. This version of forms is based on react-jsonschema-formarrow-up-right.

    hashtag
    Fields

    You define fields that accept string, number, integer, enum and boolean types. This changes the type of input shown.

    hashtag
    Required Properties

    You can use the required property to set a list of required properties.

    circle-exclamation

    Note that the properties need to be lower case! For example, you need to ensure the keys in your properties hashtable are lower case and the list of required properties are also lower case.

    hashtag
    Ordering

    You can use the schemaUI property to modify the ordering of the fields.

    hashtag
    Arrays

    You can create forms that accept 0 to many objects. The user will be able to add and remove objects to the form.

    hashtag
    Script Forms

    You can automatically generate forms based on scripts in your PowerShell Universal environment. Script forms will generate input components based on the param block. Script forms automatically support progress and feedback.

    Script forms also support displaying the output as text or a table.

    hashtag
    API

    • New-UDFormarrow-up-right

    • New-UDFormValidationResultarrow-up-right

    Docker

    This page provides installation and configuration information for Docker.

    hashtag
    Docker

    hashtag
    Confirming Docker is installed correctly

    $Pages = @()
    $Pages += New-UDPage -Name 'Dashboard' -Content {
        New-UDTypography -Text 'Dashboard'
    }
    
    New-UDDashboard -Title 'Pages' -Pages $Pages
    $Pages = @()
    $Pages += New-UDPage -Name 'Dashboard One' -Content {
        New-UDTypography -Text 'Dashboard Two'
    }
    
    $Pages += New-UDPage -Name 'Dashboard Two' -Content {
        New-UDTypography -Text 'Dashboard Two'
    }
    
    New-UDDashboard -Title 'Pages' -Pages $Pages
    $UDScriptRoot = $PSScriptRoot
    $Pages = @()
    $Pages += New-UDPage -Name 'Dashboard One' -Content {
        . "$UDScriptRoot\db1.ps1"
    }
    
    $Pages += New-UDPage -Name 'Dashboard Two' -Content {
        . "$UDScriptRoot\db2.ps1"
    }
    
    New-UDDashboard -Title 'Pages' -Pages $Pages
    $Pages = @()
    $Pages += New-UDPage -Name 'Dashboard' -Url '/db' -Content {
        New-UDTypography -Text 'Dashboard'
    }
    
    New-UDDashboard -Title 'Pages' -Pages $Pages
    $Pages = @()
    $Pages += New-UDPage -Name 'Dashboard' -Url '/db/:user' -Content {
        New-UDTypography -Text 'Dashboard for user: $User'
    }
    
    New-UDDashboard -Title 'Pages' -Pages $Pages
    $Pages = @()
    $Pages += New-UDPage -Name 'Administrators' -Content {
        New-UDTypography -Text 'Dashboard for user: $User'
    } -Role 'Administrator'
    
    $Pages += New-UDPage -Name 'Operators' -Content {
        New-UDTypography -Text 'Dashboard for user: $User'
    } -Role 'Operator'
    
    New-UDDashboard -Title 'Pages' -Pages $Pages
    New-UDPage -HeaderPosition fixed -Content {
        New-UDElement -tag div -Attributes @{
            style = @{
                height = '150vh'
            }
        }
    }
    New-UDPage -Name 'Home' -Content {
    } -HeaderColor 'black' -HeaderBackgroundColor 'white'
    $Navigation = @(
        New-UDListItem -Label "Home"
        New-UDListItem -Label "Getting Started" -Children {
            New-UDListItem -Label "Installation" -Href '/Installation' 
            New-UDListItem -Label "Usage" -Href '/Usage' 
            New-UDListItem -Label "FAQs" -Href '/faqs' 
            New-UDListItem -Label "System Requirements" -Href'/requirements' 
            New-UDListItem -Label "Purchasing" -Href '/purchasing' 
        }
    )
    
    $Pages = @()
    $Pages += New-UDPage -Name 'Installation' -Content {
     New-UDTypography -Text "Installation"
    }
    
    $Pages += New-UDPage -Name 'Usage' -Content {
        New-UDTypography -Text "Usage"
    } 
    
    New-UDDashboard -Title "Hello, World!" -Pages $Pages -NavigationLayout permanent -Navigation $Navigation
    $Navigation = {
        New-UDListItem -Label "Home - $(Get-Date)"
        New-UDListItem -Label "Getting Started" -Children {
            New-UDListItem -Label "Installation" -Href '/installation' 
            New-UDListItem -Label "Usage" -Href '/usage' 
            New-UDListItem -Label "FAQs" -Href '/faqs' 
            New-UDListItem -Label "System Requirements" -Href'/requirements' 
            New-UDListItem -Label "Purchasing" -Href '/purchasing' 
        }
    }
    
    $Pages = @()
    $Pages += New-UDPage -Name 'Test' -Content {
     New-UDTypography -Text "Hello"
    } -NavigationLayout permanent -LoadNavigation $Navigation
    
    $Pages += New-UDPage -Name 'Test2' -Content {
        New-UDTypography -Text "Hello"
    } -NavigationLayout permanent -LoadNavigation $Navigation
    
    
    New-UDDashboard -Title "Hello, World!" -Pages $Pages
    $Pages = @()
    $Pages += New-UDPage -Name 'Test' -Content {
     New-UDTypography -Text "Hello"
    } -NavigationLayout permanent
    
    $Pages += New-UDPage -Name 'Test2' -Content {
        New-UDTypography -Text "Hello"
    } -NavigationLayout permanent
    
    
    New-UDDashboard -Title "Hello, World!" -Pages $Pages
    $Pages = @()
    $Pages += New-UDPage -Name 'Test' -Content {
     New-UDTypography -Text "Hello"
    } -NavigationLayout temporary
    
    $Pages += New-UDPage -Name 'Test2' -Content {
        New-UDTypography -Text "Hello"
    } -NavigationLayout temporary
    
    
    New-UDDashboard -Title "Hello, World!" -Pages $Pages
    New-UDDashboard -Title 'PowerShell Universal' -Pages @(
        New-UDPage -Name 'Page' -Content {
            New-UDAppBar -Children {
                New-UDTypography -Text "Title" -Variant h4 -Style @{
                    marginRight = "50px"
                }
                New-UDMenu -Variant text -Text "Settings" -Children {
                    New-UDMenuItem -Text 'Item 1' -OnClick { Invoke-UDRedirect "/item1" }
                    New-UDMenuItem -Text 'Item 2' -OnClick { Invoke-UDRedirect "/item1" }
                    New-UDMenuItem -Text 'Item 3' -OnClick { Invoke-UDRedirect "/item1" }
                }
                New-UDMenu -Variant text -Text "Options" -Children {
                    New-UDMenuItem -Text 'Item 1' -OnClick { Invoke-UDRedirect "/item1" }
                    New-UDMenuItem -Text 'Item 2' -OnClick { Invoke-UDRedirect "/item1" }
                    New-UDMenuItem -Text 'Item 3' -OnClick { Invoke-UDRedirect "/item1" }
                }
                New-UDMenu -Variant text -Text "Tools" -Children {
                    New-UDMenuItem -Text 'Item 1' -OnClick { Invoke-UDRedirect "/item1" }
                    New-UDMenuItem -Text 'Item 2' -OnClick { Invoke-UDRedirect "/item1" }
                    New-UDMenuItem -Text 'Item 3' -OnClick { Invoke-UDRedirect "/item1" }
                }
            } -DisableThemeToggle
        } -Blank
    ) 
    New-UDPage -Name 'Home' -Logo '/assets/favicon.png' -Content {
    }
    $Page = New-UDPage -Name 'Home' -Content {
    
    } -HeaderContent {
        New-UDButton -Icon (New-UDIcon -Icon Users) -Text 'User'
    }
    
    New-UDDashboard -Title "Dashboard" -Pages $Page
    New-UDPage -Name "Home" -LoadTitle { "Current Time" + (Get-Date) } -Content { } 
    New-UDPage -Name 'Static Page' -Content {
        New-UDTypography (Get-Date)
    } -Static
    New-UDPage -Name 'Static Page' -Content {
       New-UDDynamic -Content {
           New-UDTypography (Get-Date)
       }
    } -Static
    New-UDForm -Content {
        New-UDTextbox -Id 'txtTextField'
        New-UDCheckbox -Id 'chkCheckbox'
    } -OnSubmit {
        Show-UDToast -Message $EventData.txtTextField
        Show-UDToast -Message $EventData.chkCheckbox
    }
    New-UDForm -Content {
        New-UDTextbox -Id 'txtTextfield'
        New-UDCheckbox -Id 'chkCheckbox'
    } -OnSubmit {
        Show-UDToast -Message $EventData.txtTextfield
        Show-UDToast -Message $EventData.chkCheckbox
    }
    New-UDForm -Content {
    
        New-UDRow -Columns {
            New-UDColumn -SmallSize 6 -LargeSize 6 -Content {
                New-UDTextbox -Id 'txtFirstName' -Label 'First Name' 
            }
            New-UDColumn -SmallSize 6 -LargeSize 6 -Content {
                New-UDTextbox -Id 'txtLastName' -Label 'Last Name'
            }
        }
    
        New-UDTextbox -Id 'txtAddress' -Label 'Address'
    
        New-UDRow -Columns {
            New-UDColumn -SmallSize 6 -LargeSize 6  -Content {
                New-UDTextbox -Id 'txtState' -Label 'State'
            }
            New-UDColumn -SmallSize 6 -LargeSize 6  -Content {
                New-UDTextbox -Id 'txtZipCode' -Label 'ZIP Code'
            }
        }
    
    } -OnSubmit {
        Show-UDToast -Message $EventData.txtFirstName
        Show-UDToast -Message $EventData.txtLastName
    }
    New-UDForm -Content {
        New-UDTextbox -Id 'txtTextfield'
    } -OnSubmit {
        New-UDTypography -Text $EventData.txtTextfield
    }
    New-UDForm -Content {
        New-UDTextbox -Id 'txtValidateForm'
    } -OnValidate {
        $FormContent = $EventData
    
        if ($FormContent.txtValidateForm -eq $null -or $FormContent.txtValidateForm -eq '') {
            New-UDFormValidationResult -ValidationError "txtValidateForm is required"
        } else {
            New-UDFormValidationResult -Valid
        }
    } -OnSubmit {
        Show-UDToast -Message $Body
    }
    New-UDButton -Text 'On Form' -OnClick {
        Show-UDModal -Content {
            New-UDForm -Content {
                New-UDTextbox -Label 'Hello'
            } -OnSubmit {
                Show-UDToast -Message 'Submitted!'
                Hide-UDModal
            } -OnCancel {
                Hide-UDModal
            }
        }
    }
    New-UDForm -Content {
    
    } -OnSubmit {
       Set-UDElement -Id 'results' -Content {
          New-UDCard -Content { "Hello " + (Get-Date) }
       }
    }
    
    New-UDElement -Id 'results' -Tag 'div'
    New-UDForm -Schema @{
       title = "Test Form"
       type = "object"
       properties = @{
           name = @{
               type = "string"
           }
           age = @{
               type = "number"
           }
       }
    } -OnSubmit {
       # $EventData.formData.name
       # $EventData.formData.age
    }
    New-UDForm -Schema @{
       title = "Test Form"
       type = "object"
       properties = @{
           name = @{
               type = "string"
           }
           age = @{
               type = "number"
           }
       }
       required = @('name')
    } -OnSubmit {
       # $EventData.formData.name
       # $EventData.formData.age
    }
    New-UDForm -Schema @{
            title = "Test"
            type = "object"
            properties = @{
                hostname = @{
                    title = "Hostname"
                    type = "string"
                    }
                ipaddress= @{
                    title = "IP Address"
                    type = "string"
                    format = "ipv4"
                    }
                description = @{
                    title = "Server Description"
                    type = "string"
                    }
                servertype = @{
                    title = "Server Type"
                    type = "string"                            
                    enum = "App","DB"
                    }
                environment = @{
                    title = "Environment"
                    type = "string"
                    enum = "Prod", "Dev" , "QA"
                    }
                }
    		required = @('hostname','ipaddress','description','servertype','environment')                    
    	} -uiSchema @{
    		"ui:order" = @('environment','hostname','ipaddress','description')
    	} -OnSubmit {
    		Show-UDModal -Content {                        
    			New-UDTypography -Text $EventData.formData
    		} -Footer {
    			New-UDButton -Text "Close" -OnClick {Hide-UDModal}
    		} -Persistent
    	}
    New-UDForm -Schema @{
       title = "Test Form"
       type = "array"
       items = @{
          type = "object" 
           properties = @{
               name = @{
                   type = "string"
               }
               age = @{
                   type = "number"
               }
           }
       }
    } -OnSubmit {
       # $EventData[0].formData.name
       # $EventData[0].formData.age
    }
    New-UDForm -Script "Script.ps1" -OutputType 'text'

    NOTE: Note: Apple M1 devices: At the time of writing there are some issues on Apple M1 devices and, some ARM64/ARMv8 devices. Please review this forum threadarrow-up-right before proceeding.

    hashtag
    Docker

    Run the following command to confirm Docker is installed:

    Example Output:

    hashtag
    Docker Compose

    Docker Compose v1 uses the command docker-compose. As of June 2023 support ends for Docker Compose v1.

    Docker Compose v2 uses the command docker compose.

    If you are using Docker Compose v1 please adjust the commands accoridingly. More infromation on Docker Compose can be found herearrow-up-right.

    Run one of the following commands to check Docker Compose is installed:

    Docker Compose v1:

    Docker Compose v2:

    Example Output:

    hashtag
    A Docker Hello-World

    To ensure that Docker has the ability to pull and run container images run the following command:

    Example Output:

    hashtag
    Installation

    hashtag
    Using the pre-built Container

    In order to run PowerShell Universal, you can use the provided container image. The docker image is available on Docker Hubarrow-up-right .

    The prebuilt version allows you to run all free and paid features of PowerShell Universal.

    You can start the container by pulling the image and then running a container with the default port bound.

    hashtag
    Running a basic image

    hashtag
    Present an image to a different port

    If port 5000 is unavailable on your host, this can be switched to another port.

    e.g. Present on port 80

    hashtag
    Mount a volume

    The docker run command will allow you to mount a volume for persistent storage. This needs to be mounted to the /root folder.

    Mount a volume on container in Windows

    The following command mounts the folder C:\docker\volumes\PSU to /root on your container

    Mount a volume on Container on Mac and Linux

    The following command mounts the folder /docker/volumes/PSU to /root on your container

    hashtag
    Stopping a Container

    The following command removes a stopped container named PSU

    hashtag
    Removing a Container

    The following command stops a container named PSU

    The --force flag can be used to remove a running container

    hashtag
    Docker Compose

    Docker Compose allows you to use a yaml text file to standardize your build and script the deployment (or build) or multiple containers.

    The default name for any compose file is docker-compose.yml it is recommended you use this as your compose filename.

    hashtag
    Creating a Compose Script for Windows

    The following compose file will run a Powershell Universal container in Windows

    hashtag
    Creating a Compose Script for Mac / Linux

    The following compose file will run a Powershell Universal container on Mac's and Linux

    hashtag
    Starting Containers using Compose Scripts

    Using a Terminal shell, or PowerShell for Windows. cd to the directory with your docker-compose.yml script.

    Run the following command

    Example Output:

    hashtag
    Stopping Containers using Compose Scripts

    Using a Terminal shell, or PowerShell for Windows. cd to the directory with your docker-compose.yml script.

    Run the following command

    Example Output:

    hashtag
    Using Environment Variables and SQL Persistance

    You can add Environment variables into your Compose Scripts. Below is an example of:

    • Setting a node name

    • Adding SQL persistance

    • Adding a SQL Connection String

    hashtag
    Building a Custom Container

    In some cases, you may wish to build more features, modify, or hardcode Environment Variables into your container.

    For that, you will need to Create a Dockerfile

    NOTE: Dockerfiles' are case-sensitive and must start with a capital 'D'.

    To create a Docker image that can persist the Universal data, you can create a dockerfile like the one below.

    This Dockerfile exposes port 5000, creates a /data volume, sets configuration environment variables to store the Universal repository and database in the volume and then sets the Universal.Server as the entry point to the container.

    hashtag
    Writing a Dockerfile script for Linux

    hashtag
    Building a container

    From the path your Dockerfile is hosted in run the following command:

    hashtag
    Windows

    You can run a build with the build command.

    You can start the docker container with the run command and make sure to specify the volume to mount.

    hashtag
    SQL

    To use SQL persistence, you can define the plugin and connection string as follows.

    hashtag
    Time Zones

    To properly support time zones on Linux when scheduling jobs, you will need to include the tzdata package in your dockerfile along with an environment variable that specifies the server time zone.

    hashtag
    Summary

    This has been a very basic "How get get started" which allows you to get started running or building PSU Containers. All souces for commands have been linked in the referances session.

    hashtag
    References

    hashtag
    Running Containers

    https://docs.docker.com/engine/reference/commandline/run/

    https://docs.docker.com/engine/reference/commandline/stop/

    https://docs.docker.com/engine/reference/commandline/rm/

    https://docs.docker.com/compose/

    hashtag
    Building Containers

    https://docs.docker.com/engine/reference/commandline/build/

    docker version
    Client: Docker Engine - Community
     Version:           23.0.1
     API version:       1.42
     Go version:        go1.19.5
     Git commit:        a5ee5b1
     Built:             Thu Feb  9 19:47:01 2023
     OS/Arch:           linux/amd64
     Context:           default
    
    Server: Docker Engine - Community
     Engine:
      Version:          23.0.1
      API version:      1.42 (minimum version 1.12)
      Go version:       go1.19.5
      Git commit:       bc3805a
      Built:            Thu Feb  9 19:47:01 2023
      OS/Arch:          linux/amd64
      Experimental:     false
     containerd:
      Version:          1.6.18
      GitCommit:        2456e983eb9e37e47538f59ea18f2043c9a73640
     runc:
      Version:          1.1.4
      GitCommit:        v1.1.4-0-g5fd4c4d
     docker-init:
      Version:          0.19.0
      GitCommit:        de40ad0
    
    docker-compose version
    docker compose version
    Docker Compose version v2.16.0
    docker run hello-world
    Unable to find image 'hello-world:latest' locally
    latest: Pulling from library/hello-world
    2db29710123e: Pull complete 
    Digest: sha256:ffb13da98453e0f04d33a6eee5bb8e46ee50d08ebe17735fc0779d0349e889e9
    Status: Downloaded newer image for hello-world:latest
    
    Hello from Docker!
    This message shows that your installation appears to be working correctly.
    
    To generate this message, Docker took the following steps:
     1. The Docker client contacted the Docker daemon.
     2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
        (amd64)
     3. The Docker daemon created a new container from that image which runs the
        executable that produces the output you are currently reading.
     4. The Docker daemon streamed that output to the Docker client, which sent it
        to your terminal.
    
    To try something more ambitious, you can run an Ubuntu container with:
     $ docker run -it ubuntu bash
    
    Share images, automate workflows, and more with a free Docker ID:
     https://hub.docker.com/
    
    For more examples and ideas, visit:
     https://docs.docker.com/get-started/
    docker pull ironmansoftware/universal
    docker run --name 'PSU' -it -p 5000:5000 ironmansoftware/universal
    docker pull ironmansoftware/universal
    docker run --name 'PSU' -it -p 80:5000 ironmansoftware/universal
    docker pull ironmansoftware/universal
    docker run --name 'PSU' -it -p 5000:5000 -v C:\docker\volumes\PSU:/root ironmansoftware/universal 
    docker pull ironmansoftware/universal
    docker run --name 'PSU' -it -p 5000:5000 -v /docker/volumes/PSU:/root ironmansoftware/universal 
    docker stop PSU
    docker rm PSU
    docker rm --force PSU
    version: "3.7"
    services:
      PSU:
        container_name: PSU
        image: ironmansoftware/universal:latest
        ports:
          - 5000:5000
        restart: unless-stopped
        environment:
          - TZ=Europe/London
        volumes:
          - C:\docker\volumes\PSU:/root
    version: "3.7"
    services:
      PSU:
        container_name: PSU
        image: ironmansoftware/universal:latest
        ports:
          - 5000:5000
        restart: unless-stopped
        environment:
          - TZ=Europe/London
        volumes:
          - /docker/volumes/PSU:/root
    docker compose up -d
    Creating network "PSU_default" with the default driver
    Pulling PSU (ironmansoftware/universal:latest)...
    latest: Pulling from ironmansoftware/universal
    7608715873ec: Pull complete
    4e66273c6cfb: Pull complete
    2649c52300c2: Pull complete
    a20175666bc7: Pull complete
    65ce93bc0653: Pull complete
    Digest: sha256:d7ff98e6197d21070aac325c2efbefa393a4952d2e8ba6b1327dc97824ec4d55
    Status: Downloaded newer image for ironmansoftware/universal:latest
    Creating PSU ... done
    docker compose down
    [+] Running 2/2
     â ¿ Container PSU         Removed                                           0.5s
     â ¿ Network PSU_default   Removed                                           0.4s
    version: "3.7"
    services:
      PSU:
        container_name: PSU
        image: ironmansoftware/universal:latest
        ports:
          - 5000:5000
        restart: unless-stopped
        environment:
          - TZ=Europe/London
          - Plugins:0=SQL
          - Data__ConnectionString=Server=ServerName; Database=DatabaseName; User Id=UserName; Password=UserPassword;Encrypt=False
          - NodeName=mynodename
        volumes:
          - /docker/volumes/PSU:/root
    FROM ironmansoftware/universal:latest
    LABEL description="Universal - The ultimate platform for building web-based IT Tools" 
    
    EXPOSE 5000
    VOLUME ["/home/data"]
    ENV Data__RepositoryPath /home/data/Repository
    ENV Data__ConnectionString /home/data/database.db
    ENV UniversalDashboard__AssetsFolder /home/data/UniversalDashboard 
    ENV Logging__Path /home/data/logs/log.txt
    ENTRYPOINT ["./Universal/Universal.Server"]
    docker build . --tag=universal-persistent
    FROM ironmansoftware/universal:1.3.1-windowsservercore-1809
    LABEL description="Universal - The ultimate platform for building web-based IT Tools" 
    
    EXPOSE 5000
    VOLUME ["C:/data"]
    ENV Data__RepositoryPath C:/data/Repository
    ENV Data__ConnectionString C:/data/database.db
    ENV UniversalDashboard__AssetsFolder C:/data/UniversalDashboard 
    ENV Logging__Path C:/data/logs/log.txt
    ENTRYPOINT ["C:/ProgramData/Universal/Universal.Server.exe"]
    docker build . --tag=universal-persistent
    docker run -it --name powershelluniversal --mount source=psudata,target=/home/data --rm -d  -p 5000:5000/tcp universal-persistent:latest
    ENV Data__ConnectionString=Data Source=ServerName; Initial Catalog=DatabaseName; Integrated Security=SSPI;
    ENV Plugins:0=SQL
    ENV TZ Europe/Amsterdam
    RUN apt-get install -y tzdata
    Radio
    Select
    Slider
    Switch
    Textbox
    Time Picker
    Transfer List
    Upload

    Building Custom JavaScript Components

    This document outlines how to build custom Universal Dashboard components.

    Universal Dashboard is extensible and you can build custom JavaScript components and frameworks. This document will cover how to build custom components that integrate with the Universal Dashboard platform.

    circle-exclamation

    This is an advanced topic and not required if you simply want to use Universal Dashboard. There are a lot of existing custom components available on the .

    circle-info

    Look at our blog postarrow-up-right on how to get started with custom components for full end-to-end example.

    hashtag
    Technology Overview

    Below is a list of some of the technologies used when building Universal Dashboard components. You will not need to be an expert to produce a component but should be aware of what to search when you encounter a problem.

    hashtag
    React

    Universal Dashboard's client-side application is built using the React frameworkarrow-up-right. React makes it easy to build components that update the DOM only when necessary and has a pretty robust ecosystem of users. It's one of the most popular JavaScript frameworks at the time of this writing.

    hashtag
    Babel

    Babel arrow-up-rightis a transcompiler for JavaScript. It works well with React and allows you to use modern constructs while compiling for backwards compatibility of browsers. Universal Dashboard uses Babel for it's core component frameworks.

    hashtag
    Webpack

    Webpackarrow-up-right is an asset bundler. It's extremely customizable and is responsible for turning your JSX files into a bundle that can then be distributed with Universal Dashboard components.

    hashtag
    Structure

    There are some basic parts to a Universal Dashboard component. You will need to understand the structure in order to successfully build your own.

    hashtag
    PowerShell Module

    Universal Dashboard custom components are PowerShell modules. They export functions that can be used to create the component when run within a dashboard. The PowerShell module is also responsible for registering the JavaScript assets with Universal Dashboard.

    hashtag
    JavaScript Bundle

    The JavaScript bundle is produced by the Webpack bundling process. It consists of one or more JS files that you will need to register with UD.

    hashtag
    Example Component Module Structure

    The most basic structure for a UD component module will include a single JavaScript file, a PSM1 file to export a function and register the JavaScript and a PSD1 module manifest.

    hashtag
    Step-By-Step

    This following section will take you step-by-step through the different aspects of building a UD component. This assumes you are running PowerShell Universal 1.2 or later and using the PowerShell Universal Dashboard v3 framework.

    For a full example of a component, click herearrow-up-right.

    hashtag
    1. Installing Dependencies

    You will need to install the following dependencies before creating your component.

    • NodeJSarrow-up-right

    • InvokeBuildarrow-up-right

    hashtag
    2. Initialize the JavaScript Package

    After installing Node, you will have access to the npm command. You will need to initialize the node package to start. This will create a package.json file in your directory.

    Here is an examplearrow-up-right package.json that you can also use as a starting point.

    hashtag
    3. Install JavaScript Packages

    You will need several JavaScript packages to build your bundle. You will first want to install the dev dependencies. These are used to build your project.

    Next, you'll want to install the universal-dashboard package along with any other packages you wish to use in your component. We are using React95 in this example. We will build a control based on that library.

    hashtag
    4. Configure Babel

    You will need to create a .babelrc file to configure Babel for React.

    hashtag
    5. Configure Webpack

    Webpack is extremely customizable and sometimes very hard to get right. Below is a basic webpack.config.js file you can use to configure Webpack. You can safely change the ud95 entry key name and library value to one that matches your library.

    hashtag
    6. Component.jsx

    Now you can build your first component. You will need to export a single function component from your component.jsx file. We suggest the use of functional React components rather than class-based React components. We need to wrap the component in withComponentFeatures to ensure the component has access to the Universal Dashboard platform features.

    hashtag
    7. Index.js

    Once your component is completed, you'll need to add it to an index.js file. The entry point for your library is the first place Webpack will look. It will discover all other components from import statements in your code. The index.js file is where you should register your components. You can use the registerComponent function to do so.

    hashtag
    8. Bundle JavaScript

    To bundle the JavaScript, run the following command to start webpack. This will output a file into the dist folder.

    hashtag
    9. PowerShell Script

    Now you will need to create a PowerShell script that registers and creates your component.

    First, register the JavaScript with Universal Dashboard.

    Next, create a function that returns a hashtable that defines which component we are creating and which props to set.

    The type property of your hashtable needs to match with the first parameter of registerComponent that you called in your JavaScript.

    hashtag
    10. InvokeBuild (optional)

    We suggest the use of InvokeBuild to create a build script to run all the steps of packaging and staging your module. The below build script deletes the dist folder, runs an NPM install to install packages, runs an NPM build to bundle the JavaScript and then copies the PS module to the dist folder.

    hashtag
    Props

    Props are values that are either passed from the PowerShell hashtable provided by the user or by the Universal Dashboard withComponentsFeature high-order function.

    hashtag
    Standard

    The properties that you set in your hashtable in PowerShell will automatically be sent in as props to React component.

    For example, if you set the text property of the hashtable like this.

    Then you will have access to that prop in React.

    hashtag
    Endpoints

    Endpoints are special in the way they are registered and the way that they are passed as props to your component. You will need to call Register on the endpoint in PowerShell and pass in the Id and PSCmdlet variables.

    Endpoints are created from ScriptBlocks and are executed when that event happens.

    Universal Dashboard will automatically wire up the endpoint to a function within JavaScript. This means that you can use the props to call that endpoint.

    Notice the props.onClick function call. This will automatically call the PowerShell script block on the server.

    hashtag
    setState

    The setState prop is used to set the state of the component. This ensures that the state is tracked and your component will work with Get-UDElement.

    For example, with a text field, you'll want to call props.setState and pass in the new text value for the state.

    hashtag
    children

    The children prop is a standard React prop. If your component supports child items, such as a list or select box, you should use the standard props.children prop to ensure that the cmdlets Add-UDElement , Remove-UDElement and Clear-UDElement function correctly.

    hashtag
    Publishing to the Marketplace

    The Universal Dashboard Marketplacearrow-up-right is an aggregator of the PowerShell Gallery that lists Universal Dashboard components. The UD Marketplace automatically hooks into PowerShell Universal v1.3 or later where you can easily install additional components.

    To publish to the Marketplace, you simply need to publish to the PowerShell Gallery but include the ud-component tag in your module manifest. The marketplace syncs with the Gallery every hour and your component will be enabled for anyone to find after that.

    Universal Dashboard Marketplacearrow-up-right
    - UniversalDashboard.95
        - index.23adfdasf.js
        - UniversalDashboard.95.psd1
        - UniversalDashboard.95.psm1
    npm init
    npm install @babel/core --save-dev
    npm install @babel/plugin-proposal-class-properties --save-dev
    npm install @babel/plugin-syntax-dynamic-import --save-dev
    npm install @babel/polyfill --save-dev
    npm install @babel/preset-env --save-dev
    npm install @babel/preset-react --save-dev
    npm install babel-loader --save-dev
    npm install webpack --save-dev
    npm install webpack-cli --save-dev
    npm install universal-dashboard --save
    npm install react95 --save
    npm install styled-components --save
    {
        "presets": ["@babel/preset-react"]
    }
    var path = require('path');
    
    var BUILD_DIR = path.resolve(__dirname, 'dist');
    
    module.exports = (env) => {
      const isDev = env == 'development' || env == 'isolated';
    
      return {
        entry: {
          'ud95' : __dirname + '/index.js'
        },
        output: {
          library: "UD95",
          libraryTarget: "var",
          path: BUILD_DIR,
          filename: isDev ? '[name].bundle.js' : '[name].[hash].bundle.js',
          sourceMapFilename: '[name].[hash].bundle.map',
          publicPath: "/"
        },
        module : {
          rules : [
            { test: /\.(js|jsx)$/, exclude: [/node_modules/, /public/], loader: 'babel-loader'}
          ]
        },
        externals: {
          UniversalDashboard: 'UniversalDashboard',
          'react': 'react',
          'react-dom': 'reactdom'
        },
        resolve: {
          extensions: ['.json', '.js', '.jsx']
        }
      };
    }
    import React from 'react';
    import { withComponentFeatures } from 'universal-dashboard';
    import { Button } from 'react95';
    
    const UD95Button = props => {
    
        const p = {
            onClick: () => props.onClick()
        }
    
        return <Button {...p}>{props.text}</Button>
    }
    
    export default withComponentFeatures(UD95Button);
    import { registerComponent } from 'universal-dashboard'
    import UD95Button from './component';
    
    registerComponent("ud95-button", UD95Button);
    npm run build
    $JsFile = Get-ChildItem "$PSScriptRoot\ud95.*.js"
    $AssetId = [UniversalDashboard.Services.AssetService]::Instance.RegisterAsset($JsFile.FullName)
    function New-UD95Button {
        param(
            [Parameter()]
            [string]$Id = [Guid]::NewGuid(),
            [Parameter()]
            [string]$Text,
            [Parameter()]
            [Endpoint]$OnClick
        )
    
        if ($OnClick)
        {
            $OnClick.Register($Id, $PSCmdlet)
        }
    
        @{
            type = "ud95-button"
            isPlugin = $true 
            assetId = $AssetId
    
            id = $Id 
            text = $Text 
            onClick = $OnClick
        }
    }
    task Clean {
        Remove-Item "$PSScriptRoot\dist" -Recurse -Force
    }
    
    task NpmInstall {
        & {
            $ErrorActionPreference = 'SilentlyContinue'
    
            Push-Location $PSScriptRoot
            npm install
            Pop-Location
        }
    }
    
    task NpmBuild {
        & {
            $ErrorActionPreference = 'SilentlyContinue'
    
            Push-Location $PSScriptRoot
            npm run build
            Pop-Location
        }
    }
    
    task Stage {
        Copy-Item "$PSScriptRoot\UniversalDashboard.95.*" "$PSScriptRoot\dist"
    }
    
    task . Clean, NpmInstall, NpmBuild, Stage
    function New-UDText {
        param(
            [Parameter()]
            [string]$Text
        )
    
        @{
            type = "text"
            isPlugin = $true
            assetId = $AssetId 
    
            text = $Text
        }
    }
    import React from 'react';
    import { withComponentFeatures } from 'universal-dashboard';
    
    const UDText = props => {
        return <div>{props.text}</div>
    }
    
    export default withComponentFeatures(UDText);
    function New-UD95Button {
        param(
            [Parameter()]
            [string]$Id = [Guid]::NewGuid(),
            [Parameter()]
            [string]$Text,
            [Parameter()]
            [Endpoint]$OnClick
        )
    
        if ($OnClick)
        {
            $OnClick.Register($Id, $PSCmdlet)
        }
    
        @{
            type = "ud95-button"
            isPlugin = $true 
            assetId = $AssetId
    
            id = $Id 
            text = $Text 
            onClick = $OnClick
        }
    }
    New-UD95Button -Text 'Hello' -OnClick {
        Show-UDToast -Message 'Test' 
    }
    import React from 'react';
    import { withComponentFeatures } from 'universal-dashboard';
    import { Button } from 'react95';
    
    const UD95Button = props => {
    
        const p = {
            onClick: () => props.onClick()
        }
    
        return <Button {...p}>{props.text}</Button>
    }
    
    export default withComponentFeatures(UD95Button);
    const UDTextField = (props) => {
        const onChange = (e) => {
            props.setState({value: e.target.value})
        }
    
        return <TextField  {...props} onChange={onChange} />
    }
    
    export default withComponentFeatures(UDTextField);

    Endpoints

    Endpoint configuration for Universal APIs.

    Endpoints are defined by their URI and HTTP method. Calls made to the Universal server that match the API endpoint and method that you define will execute the API endpoint script.

    To invoke the above method, you could use Invoke-RestMethod.

    When defining endpoints in the management API, you can skip the New-PSUEndpoint call as it will be defined by the admin console.

    API Properties

    The only contents that you need to provide in the editor will be the script you wish to call.

    hashtag
    Variable URL

    URLs can contain variable segments. You can denote a variable segment using a colon (:). For example, the following URL would provide a variable for the ID of the user. The $Id variable will be defined within the endpoint when it is executed. Variables must be unique in the same endpoint URL.

    To call this API and specify the ID, you would do the following.

    hashtag
    Query String Parameters

    Query string parameters are automatically passed into endpoints as variables that you can then access. For example, if you had an endpoint that expected an $Id variable, it could be provided via the query string.

    The resulting Invoke-RestMethod call must then include the query string parameter.

    hashtag
    Security Considerations

    When accepting input via Query String parameters you may be vulnerable to . Consider using a param block to ensure that only valid parameters are provided to the endpoint.

    Below is an example of CWE-914. A $IsChallengePassed query string parameter could be included to bypass the challenge.

    In order to avoid this particular issue, you can use a param block.

    hashtag
    Headers

    Request headers are available in APIs using the $Headers variable. The variable is a hashtable. To access a header, use the following syntax.

    hashtag
    Cookies

    Request cookies are available in APIs using the $Cookies variable. The variable is a hashtable. To access a cookie, use the following syntax.

    Request cookies can be sent back using the New-PSUApiResponse cmdlet. Use the -Cookies parameter with a supplied hashtable.

    hashtag
    Body

    To access a request body, you will simply access the $Body variable. Universal $Body variable will be a string. If you expect JSON, you should use ConvertFrom-Json.

    To call the above endpoint, you would have to specify the body of Invoke-RestMethod.

    hashtag
    Live Log

    You can view the live log information for any endpoint by clicking the log tab. Live logs include URL, HTTP method, source IP address, PowerShell streams, status code, return Content Type and HTTP content length.

    hashtag
    Form Data

    You can pass data to an endpoint as form data. Form data will be passed into your endpoint as parameters.

    You can then use a hashtable with Invoke-RestMethod to pass form data.

    hashtag
    JSON Data

    You can pass JSON data to an endpoint and it will automatically bind to a param block.

    You can then send JSON data to the endpoint.

    hashtag
    Param Block

    You can use a param block within your script to enforce mandatory parameters and provide default values for optional parameters such as query string parameters. Variables such as $Body, $Headers and $User are provided automatically.

    In the below example, the $Name parameter is mandatory and the $Role parameter has a default value of Default.

    hashtag
    Returning Data

    Data returned from endpoints will be assumed to be JSON data. If you return an object from the endpoint script block, it will be automatically serialized to JSON. If you want to return another type of data, you can return a string formatted however you chose.

    hashtag
    Processing Files

    hashtag
    Uploading Files

    You can process uploaded files by using the $Data parameter to access the byte array of data uploaded to the endpoint.

    You could also save the file into a directory.

    hashtag
    Downloading Files

    You can send files down using the New-PSUApiResponse cmdlet.

    hashtag
    Returning Custom Responses

    You can return custom responses from endpoints by using the New-PSUApiResponse cmdlet in your endpoint. This cmdlet allows you to set the status code, content type and even specify the byte[] data for the content to be returned.

    You can also return custom body data by using the -Body parameter of New-PSUApiResponse.

    Invoking the REST method will return the custom error code.

    You can control the content type of the data that is returned by using the -ContentType parameter.

    hashtag
    Documenting APIs

    API documentation can be produced for your endpoints by creating a new OpenAPI definition and assigning endpoints to it. To create an OpenAPI definition, click APIs \ Documentation and then Create new Endpoint Documentation. You can set the name, URL, description and authentication details for the documentation.

    Once created, you can assign endpoints to the documentation by editing the endpoint.

    The documentation for your endpoint will appear within the Swagger dashboard. Select the definition with the Select a definition dropdown.

    All your custom endpoints will be listed.

    hashtag
    Help Text

    You can specify help text for your APIs using comment-based help. Including a synopsis, description and parameter descriptions will result in each of those pieces being documented in the OpenAPI documentation and Swagger page.

    For example, with a simple /get/:id endpoint, we could have comment-based help such as this.

    The resulting Swagger page will show each of these descriptions.

    hashtag
    Input and Output Types

    Types can be defined within an endpoint documentation scriptblock. Click the Edit Details button on the API documentation record.

    APIs can also be documented using input and output types by creating a PowerShell class and referencing it within your comment-based help. PowerShell Universal takes advantage of the .INPUTS and .OUTPUTS sections to specify accepted formats and define status code return values.

    Within the .INPUTS and .OUTPUTS , you will define a YAML block to provide this information. You can create types in the read-only section of the PowerShell Universal configuration file.

    hashtag
    Persistent Runspaces

    Persistent runspaces allow you to maintain runspace state between API calls. This is important for users that perform some sort of initialization within their endpoints that they do not want to execute on subsequent API calls.

    By default, runspaces will be reset after each execution. This will cause variables, modules and functions defined during the execution of the API to be removed.

    To enable persistent runspaces, you will need to configure an for your API. Set the -PersistentRunspace parameter to enable this feature. This is configured in the environments.ps1 script.

    You can then assign the API environment in the settings.ps1 script.

    hashtag
    Timeout

    By default, endpoints will not time out. To set a timeout for your endpoints, you can use the New-PSUEndpoint -Timeout parameter. The timeout is set in the number of seconds.

    hashtag
    External Endpoint Content

    You can define the path to an external endpoint content file by using the -Path parameter of New-PSUEndpoint. The path is relative to the .universal directory in Repository.

    The content of the endpoints.ps1 file is then this.

    hashtag
    Experimental Feature: C# APIs

    As of PowerShell Universal 3.5.0, you can now enable C# APIs as an experimental feature. To learn more about enabling experimental features, . C# APIs are significantly faster than PowerShell APIs (5 - 20 times faster).

    There is no UI for creating a C# API and you will need to do so using configuration files. First, you will need to create a .cs file that will run your API.

    You will have access to a request parameter that includes all the data about the API request.

    You will also have access to a ServiceProvider property that will allow you to access services within PowerShell Universal. These are currently not well documented but below is an example of restarting a dashboard.

    Some other useful services may include:

    • IDatabase

    • IApiService

    • IConfigurationService

    You can choose to return an ApiResponse from your endpoint.

    Once you have defined your C# endpoint file, you can add it by editing endpoints.ps1.

    C# endpoints are compiled and run directly in the PowerShell Universal service.

    hashtag
    API

    New-PSUEndpoint -Url '/endpoint' -Method 'GET' -Endpoint {
       "Hello, world!"
    }
    Invoke-RestMethod http://localhost:5000/endpoint
    IJobService
  • CWE-914: Improper Control of Dynamically-Identified Variablesarrow-up-right
    environment
    click here
    New-PSUEndpointarrow-up-right
    Get-PSUEndpointarrow-up-right
    Remove-PSUEndpointarrow-up-right
    API Content
    Endpoint Documentation
    Edit Endpoint
    Swagger Documentation for APIs
    Swagger Documentation for an API
    Edit Details for API Documentation
    New-PSUEndpoint -Url '/user/:id' -Method 'GET' -Endpoint {
       Get-User -Id $Id
    }
    Invoke-RestMethod http://localhost:5000/user/123
    New-PSUEndpoint -Url '/user' -Method 'GET' -Endpoint {
       Get-User -Id $Id
    }
    Invoke-RestMethod http://localhost:5000/user?Id=123
    New-PSUEndpoint -Url "/api/v1.0/CWE914Test" -Description "Vulnerable to CWE-914" -Endpoint {
    	if($ChallengeInputData -eq "AcceptableInput") {
    		$IsChallengePassed = $true
    	}
    	if($IsChallengePassed) {
    		"Challenge passed. Here is Sensitive Information"
    	} else {
    		"Challenge not passed"
    	}
    }
    New-PSUEndpoint -Url "/api/v1.0/CWE914Test" -Description "Not Vulnerable to CWE-914" -Endpoint {
    	Param(
    		$ChallengeInputData
    	)
    	if($ChallengeInputData -eq "AcceptableInput") {
    		$IsChallengePassed = $true
    	}
    	if($IsChallengePassed) {
    		"Challenge passed. Here is Sensitive Information"
    	} else {
    		"Challenge not passed"
    	}
    }
    $Headers['Content-Type']
    $Cookies['Request-Cookie']
    New-PSUApiResponse -StatusCode 200 -Cookies @{
        ResponseCookie = '123'
    }
    New-PSUEndpoint -Url '/user' -Method Post -Endpoint {
        $User = ConvertFrom-Json $Body 
        New-User $User
    }
    Invoke-RestMethod http://localhost:5000/user -Method Post -Body "{'username': 'adam'}"
    New-PSUEndpoint -Url '/user' -Method Post -Endpoint {
        param([Parameter(Mandatory)]$userName, $FirstName, $LastName)
         
        New-User $UserName -FirstName $FirstName -LastName $LastName
    }
    Invoke-RestMethod http://localhost:5000/user -Method Post -Body @{ 
        UserName = "adriscoll"
        FirstName = "Adam"
        LastName = "Driscoll"
    }
    New-PSUEndpoint -Url '/user' -Method Post -Endpoint {
        param([Parameter(Mandatory)]$userName, $FirstName, $LastName)
         
        New-User $UserName -FirstName $FirstName -LastName $LastName
    }
    Invoke-RestMethod http://localhost:5000/user -Method Post -Body (@{ 
        UserName = "adriscoll"
        FirstName = "Adam"
        LastName = "Driscoll"
    } | ConvertTo-Json) -ContentType 'application/json'
    New-PSUEndpoint -Url '/user/:name' -Endpoint {
        param([Parameter(Mandatory)$Name, $Role = "Default")
    }
    New-PSUEndpoint -Url '/file' -Method Post -Endpoint {
        $Data
    }
    
    PS C:\Users\adamr> iwr http://localhost:5000/file -method post -InFile '.\Desktop\add-dashboard.png'
    
    StatusCode        : 200
    StatusDescription : OK
    Content           : [137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,2,17,0,0,1,92,8,2,0,0,0,249,210,123,106,0,0,0,1,
                        115,82,71,66,0,174,206,28,233,0,0,0,4,103,65,77,65,0,0,177,143,11,252,97,5,0,0,0,9,112,72,89,115,0,
                        0,…
    New-PSUEndpoint -Url '/file' -Method Post -Endpoint {
        [IO.File]::WriteAllBytes("tempfile.dat", $Data)
    }
    New-PSUEndpoint -Url '/image' -Endpoint {
        $ImageData = [IO.File]::ReadAllBytes("image.jpeg")
        New-PSUApiResponse -ContentType 'image/jpg' -Data $ImageData
    }
    New-PSUEndpoint -Url '/file' -Method Get -Endpoint {
        New-PSUApiResponse -StatusCode 410
    }
    New-PSUEndpoint -Url '/file' -Method Get -Endpoint {
        New-PSUApiResponse -Body "Not what you're looking for." -StatusCode 404
    }
    PS C:\Users\adamr\Desktop> invoke-restmethod http://localhost:8080/file
    
    Invoke-RestMethod: Not what you're looking for.
    New-PSUEndpoint -Url '/file' -Method Get -Endpoint {
        New-PSUApiResponse -Body "<xml><node>1</node><node2>2</node2></xml>" -ContentType 'text/xml'
    }
    <# 
    .SYNOPSIS
    This is an endpoint
    
    .DESCRIPTION
    This is a description
    
    .PARAMETER ID
    This is an ID.
    
    #>
    param($ID)
        
    $Id
    #region PSUHeader 
    
    [Documentation()]
    class MyReturnType {
        [string]$Value
    }
    
    #endregion
    New-PSUEndpoint -Url "/documented" -Method @('GET') -Endpoint {
    <# 
    .SYNOPSIS
    This is an endpoint
        
    .DESCRIPTION
    This is a description
    
    .PARAMETER Id
    This is an ID.
    
    .PARAMETER AnotherOne
    This is AnotherOne
    
    .OUTPUTS
        200:
            Description: This is an output value. 
            Content:
                application/json: MyReturnType
    
        400:
            Description: Invalid input
    .INPUTS 
        Required: false
        Description: This is an input value.
        Content: 
            application/json: MyReturnType
    
    #>
    param($Id, $AnotherOne)
    } -Authentication
    New-PSUEnvironment -Name 'Env' -Path 'powershell.exe' -PersistentRunspace
    Set-PSUSetting -ApiEnvironment 'Env'
    New-PSUEndpoint -Url "/path" -Path "endpoint-path.ps1"
    public class ApiRequest
    {
        public long Id;
        public ICollection<KeyValue> Variables;
        public IEnumerable<ApiFile> Files { get; set; };
        public string Url;
        public ICollection<KeyValue> Headers;
        public byte[] Data;
        public int ErrorAction;
        public ICollection<KeyValue> Parameters;
        public string Method;
        public ICollection<KeyValue> Cookies;
        public string ClaimsPrincipal;
        public string ContentType;
    }
    var dm = ServiceProvider.GetService(typeof(IDashboardManager));
    var dashboard = dm.GetDashboard(1);
    dm.Restart(dashboard);
    return new ApiResponse {
        StatusCode = 404
    };
    New-PSUEndpoint -Url /csharp -Path endpoint.cs -Environment 'C#'
    New-PSUApiResponsearrow-up-right
    Set-PSUSettingarrow-up-right

    Charts

    Charting components for Universal Dashboard.

    Universal Dashboard provides several built-in charting solutions to help visualize your data retrieved from PowerShell.

    hashtag
    ChartJS

    Universal Dashboard integrates with ChartJSarrow-up-right.

    hashtag
    Creating a Chart

    To create a chart, use New-UDChartJS and New-UDChartJSData. The below chart shows the top ten CPU using processes.

    hashtag
    Types

    hashtag
    Bar

    hashtag
    Stacked Bar

    hashtag
    Horizontal Bar

    hashtag
    Bubble

    A bubble chart consists of x and y coordinates and an r value for the radius of the circles.

    hashtag
    Line

    hashtag
    Doughnut

    hashtag
    Pie

    hashtag
    Radar

    hashtag
    Colors

    Colors can be defined using the various color parameters of New-UDChartJS.

    hashtag
    Data Sets

    By default, you do not need to define data sets manually. A single data set is created automatically when you use the -DataProperty and -LabelProperty parameters. If you want to define multiple data sets for a single chart, you can use the -Dataset property in conjunction with New-UDChartJSDataset.

    hashtag
    Click Events

    You can take action when a user clicks the chart. This example shows a toast with the contents of the $Body variable. The $Body variable contains a JSON string with information about the elements that were clicked.

    hashtag
    Auto refreshing charts

    You can use New-UDDynamic to create charts that refresh on an interval.

    hashtag
    Monitors

    Monitors are a special kind of chart that tracks data over time. Monitors are good for displaying data such as server performance stats that change frequently. You return a single value from a monitor and it is graphed automatically over time.

    hashtag
    Options

    The New-UDChartJS cmdlet supports accepting advanced ChartJS options. You can use the -Options parameter to pass in a hashtable.

    This example hides the legend.

    hashtag
    Title

    You can include a title with the title option.

    hashtag
    Nivo Charts

    Universal Dashboard integrates with . Below you will find examples and documentation for using these charts.

    hashtag
    Creating a Chart

    All the Nivo charts can be created with New-UDNivoChart. You will specify a switch parameter for the different types of charts. Each chart type will take a well defined data format via the -Data parameter.

    hashtag
    Patterns

    Nivo provides the ability to specify patterns to display over data sets. You can configure these patterns with New-UDNivoPattern and New-UDNivoFill .

    hashtag
    Responsive Widths

    Nivo charts provide responsive widths so they will resize automatically when placed on a page or the browser is resized. A height is required when using responsive widths.

    hashtag
    Auto Refreshing Charts

    Like many components in Universal Dashboard v3, Nivo charts do not define auto-refresh properties themselves. Instead, you can take advantage of New-UDDynamic to refresh the chart on an interval.

    hashtag
    OnClick

    Nivo charts support OnClick event handlers. You will be provided with information about the data set that was clicked as JSON.

    hashtag
    Types of Charts

    hashtag
    Bar

    hashtag
    Bubble

    hashtag
    Calendar

    hashtag
    Heatmap

    hashtag
    Line

    hashtag
    Stream

    hashtag
    Treemap

    Nivo Chartsarrow-up-right

    Data Grid

    Data grid component for Universal Dashboard.

    The UDDataGrid component is an advanced version of the table that is useful for displaying large amounts of data. It supports many of the same features as the table but also provides complex filtering, row virtualization, multi-column sort and more.

    hashtag
    Simple Data Grid

    Data grids load their data via the -LoadRows event handler. You will need to return a hashtable that contains the row data and the total number of rows.

    Columns are defined using hashtables.

    circle-exclamation

    Prior to version 3.3., column field names must be in camel case. For example, the property Name would need to be name while the property FirstName would need to be firstName.

    hashtag
    Columns

    Columns are customizable using hashtables. You can find the supported properties below.

    Property
    Description
    Type\Value

    hashtag
    Rendering Custom Columns

    You can render custom components in columns by specifying render within the column hashtable. You can access the current row's data by using the $EventData or $Row variable

    In this example, the number is shown in the name column with a New-UDTypography component.

    hashtag
    Flexible Width Columns

    Column fluidity or responsiveness can be achieved by setting the flex property of a column.

    The flex property accepts a value between 0 and ∞. It works by dividing the remaining space in the grid among all flex columns in proportion to their flex value.

    For example, consider a grid with a total width of 500px that has three columns: the first with width: 200; the second with flex: 1; and the third with flex: 0.5. The first column will be 200px wide, leaving 300px remaining. The column with flex: 1 is twice the size of flex: 0.5, which means that final sizes will be: 200px, 200px, 100px.

    To set a minimum and maximum width for a flex column set the minWidth and the maxWidth property on the column.

    hashtag
    LoadRows

    The -LoadRows parameter is used to return data for the data grid. Table state will be provided to the event handler as $EventData. You will find the following properties within the $EventData object.

    Property
    Description
    Type

    hashtag
    Paging

    To implement paging, you can access the page and pageSize properties of the $EventData variable.

    hashtag
    Filtering

    The filter hashtable is included in the $EventData for the -LoadRows event handler when a filter is defined. The hashtable has a structure as follows.

    hashtag
    Items

    The items property contains an array of columns, operators and values. You can use these to filter your data.

    Property
    Description
    Type

    hashtag
    LinkOperator

    The link operator field is used to specify the link between the filters. This can be and or or.

    hashtag
    Sorting

    The $EventData object will contain a Sort property when the user sorts the data grid. It contains properties for each column that is sorted. The properties will start as 0 and increment as more columns are sorted.

    For example, you can access the first sorted column as follows.

    You will also receive the sort direction for each column.

    Property
    Description
    Type

    hashtag
    Detailed Content

    You can use the -LoadDetailedContent event handler to display additional information about the row you are expanding. Information about the current row is available in $EventData.row.

    hashtag
    Editing

    Tables provide editor support by specifying the -OnEdit event handler. The new row data will be provided as $EventData. You can chose to return updated row information (for example, adjusting something the user has entered) and return it from the event handler. If you do not return anything, the row will reflect what the user entered.

    The $EventData has the following format.

    Ensure that you provide the editable property to each column you wish for the user to edit.

    hashtag
    Custom Export

    To override the default export functionality, use the -OnExport event handler. $EventData will be an array of rows with their values. You should use Out-UDDataGridExport to return the data from -OnExport.

    hashtag
    Example: Static Data

    In this example, we generate an array of 10,000 records. We will create a new function, Out-UDDataGridData to manage the paging, sorting and filtering.

    hashtag
    Example: SQL Data

    In this example, we'll query the PowerShell Universal database with dbatools.

     $Data = Get-Process | Sort-Object -Property CPU -Descending | Select-Object -First 10 
     New-UDChartJS -Type 'bar' -Data $Data -DataProperty CPU -LabelProperty ProcessName
     $Data = Get-Process | Sort-Object -Property CPU -Descending | Select-Object -First 10 
     New-UDChartJS -Type 'bar' -Data $Data -DataProperty CPU -LabelProperty ProcessName
        $GraphPrep = @(
            @{ RAM = "Server1"; AvailableRam = 128; UsedRAM = 10 }
            @{ RAM = "Server2"; AvailableRam = 64; UsedRAM = 63 }
            @{ RAM = "Server3"; AvailableRam = 48; UsedRAM = 40 }
            @{ RAM = "Server4"; AvailableRam = 64;; UsedRAM = 26 }
            @{ RAM = "Server5"; AvailableRam = 128; UsedRAM = 120 }
        )
    
        $AvailableRamDataSet = New-UDChartJSDataset -DataProperty AvailableRAM -Label 'Available' -BackgroundColor blue
        $UsedRamDataset = New-UDChartJSDataset -DataProperty UsedRAM -Label 'Used' -BackgroundColor red
        $Options = @{
            Type          = 'bar'
            Data          = $GraphPrep
            Dataset       = @($AvailableRamDataSet, $UsedRamDataset)
            LabelProperty = "RAM"
            Options = @{
                scales = @{
                    xAxes = 
                    @{
                        stacked = $true
                    }            
                yAxes = 
                    @{
                        stacked = $true
                    }            
                }
            }
        } 
    
        New-UDChartJS @Options
        $Data = Get-Process | Sort-Object -Property CPU -Descending | Select-Object -First 10 
        New-UDChartJS -Type 'bar' -Data $Data -DataProperty CPU -LabelProperty ProcessName -Options @{
            indexAxis = "y"
            plugins = @{
                legend = @{
                    position = "right"
                }
            }
        }p
    $Data = @(
        @{ x = 1; y = 10; r = 15 }
        @{ x = 12; y = 25; r = 35 }
        @{ x = 8; y = 10; r = 95 }
        @{ x = 6; y = 95; r = 25 }
    )
    New-UDChartJS -Type 'bubble' -Data $Data 
     $Data = Get-Process | Sort-Object -Property CPU -Descending | Select-Object -First 10 
     New-UDChartJS -Type 'line' -Data $Data -DataProperty CPU -LabelProperty ProcessName
     $Data = Get-Process | Sort-Object -Property CPU -Descending | Select-Object -First 10 
     New-UDChartJS -Type 'doughnut' -Data $Data -DataProperty CPU -LabelProperty ProcessName
     $Data = Get-Process | Sort-Object -Property CPU -Descending | Select-Object -First 10 
     New-UDChartJS -Type 'pie' -Data $Data -DataProperty CPU -LabelProperty ProcessName
     $Data = Get-Process | Sort-Object -Property CPU -Descending | Select-Object -First 10 
     New-UDChartJS -Type 'radar' -Data $Data -DataProperty CPU -LabelProperty ProcessName
     $Data = Get-Process | Sort-Object -Property CPU -Descending | Select-Object -First 10 
    
     $Options = @{
       Type = 'bar'
       Data = $Data
       BackgroundColor = 'Red'
       BorderColor = '#c61d4a'
       HoverBackgroundColor = 'Blue'
       HoverBorderColor = '#451dc6'
       DataProperty = 'CPU'
       LabelProperty = 'ProcessName'
     }
    
     New-UDChartJS @Options
    $Data = Get-Process | Sort-Object -Property CPU -Descending | Select-Object -First 10 
    
     $CPUDataset = New-UDChartJSDataset -DataProperty CPU -Label CPU -BackgroundColor '#126f8c'
     $MemoryDataset = New-UDChartJSDataset -DataProperty HandleCount -Label 'Handle Count' -BackgroundColor '#8da322'
    
     $Options = @{
       Type = 'bar'
       Data = $Data
       Dataset = @($CPUDataset, $MemoryDataset)
       LabelProperty = "ProcessName"
     }
    
     New-UDChartJS @Options
     $Data = Get-Process | Sort-Object -Property CPU -Descending | Select-Object -First 10 
    
      $Options = @{
       Type = 'bar'
       Data = $Data
       DataProperty = 'CPU'
       LabelProperty = "ProcessName"
       OnClick = { 
          Show-UDToast -Message $Body
       }
     }
    
    
     New-UDChartJS @Options
    New-UDDynamic -Content {
        $Data = 1..10 | % { 
            [PSCustomObject]@{ Name = $_; value = get-random }
        }
        New-UDChartJS -Type 'bar' -Data $Data -DataProperty Value -Id 'test' -LabelProperty Name -BackgroundColor Blue
    } -AutoRefresh -AutoRefreshInterval 1
    New-UDChartJSMonitor -LoadData {
        Get-Random -Max 100 | Out-UDChartJSMonitorData
    } -Labels "Random" -ChartBackgroundColor "#297741" -RefreshInterval 1
     $Data = Get-Process | Sort-Object -Property CPU -Descending | Select-Object -First 10 
     New-UDChartJS -Type 'bar' -Data $Data -DataProperty CPU -LabelProperty ProcessName -Options @{  
     legend = @{  
         display = $false  
     }  
    }
    $Data = Get-Process | Sort-Object -Property CPU -Descending | Select-Object -First 10 
    New-UDChartJS -Type 'bar' -Data $Data -DataProperty CPU -LabelProperty ProcessName -Options @{
        plugins = @{
            legend = @{
                title = @{
                    display = $true
                    text    = 'Bar Chart'
                }
            }
        }
    }
    $Data = 1..10 | ForEach-Object { 
        $item = Get-Random -Max 1000 
        [PSCustomObject]@{
            Name = "Test$item"
            Value = $item
        }
    }
    New-UDNivoChart -Id 'autoRefreshingNivoBar' -Bar -Keys "value" -IndexBy 'name' -Data $Data -Height 500 -Width 1000
    $Data = @(
        @{
            country = 'USA'
            burgers = (Get-Random -Minimum 10 -Maximum 100)
            fries = (Get-Random -Minimum 10 -Maximum 100)
            sandwich = (Get-Random -Minimum 10 -Maximum 100)
        }
        @{
            country = 'Germany'
            burgers = (Get-Random -Minimum 10 -Maximum 100)
            fries = (Get-Random -Minimum 10 -Maximum 100)
            sandwich = (Get-Random -Minimum 10 -Maximum 100)
        }
        @{
            country = 'Japan'
            burgers = (Get-Random -Minimum 10 -Maximum 100)
            fries = (Get-Random -Minimum 10 -Maximum 100)
            sandwich = (Get-Random -Minimum 10 -Maximum 100)
        }
    )
    
    $Pattern = New-UDNivoPattern -Dots -Id 'dots' -Background "inherit" -Color "#38bcb2" -Size 4 -Padding 1 -Stagger
    $Fill = New-UDNivoFill -ElementId "fries" -PatternId 'dots'
    
    New-UDNivoChart -Definitions $Pattern -Fill $Fill -Bar -Data $Data -Height 400 -Width 900 -Keys @('burgers', 'fries', 'sandwich')  -IndexBy 'country'
    New-UDDynamic -Content {
        $Data = 1..10 | ForEach-Object { 
            $item = Get-Random -Max 1000 
            [PSCustomObject]@{
                Name = "Test$item"
                Value = $item
            }
        }
        New-UDNivoChart -Id 'autoRefreshingNivoBar' -Bar -Keys "Value" -IndexBy 'name' -Data $Data -Height 500 -Width 1000
    } -AutoRefresh
    $Data = @(
        @{
            country = 'USA'
            burgers = (Get-Random -Minimum 10 -Maximum 100)
            fries = (Get-Random -Minimum 10 -Maximum 100)
            sandwich = (Get-Random -Minimum 10 -Maximum 100)
        }
        @{
            country = 'Germany'
            burgers = (Get-Random -Minimum 10 -Maximum 100)
            fries = (Get-Random -Minimum 10 -Maximum 100)
            sandwich = (Get-Random -Minimum 10 -Maximum 100)
        }
        @{
            country = 'Japan'
            burgers = (Get-Random -Minimum 10 -Maximum 100)
            fries = (Get-Random -Minimum 10 -Maximum 100)
            sandwich = (Get-Random -Minimum 10 -Maximum 100)
        }
    )
    New-UDNivoChart -Bar -Data $Data -Height 400 -Width 900 -Keys @('burgers', 'fries', 'sandwich')  -IndexBy 'country' -OnClick {
        Show-UDToast -Message $EventData -Position topLeft
    }
    New-Example -Title 'Bar' -Description '' -Example {
        $Data = 1..10 | ForEach-Object { 
            $item = Get-Random -Max 1000 
            [PSCustomObject]@{
                Name = "Test$item"
                Value = $item
            }
        }
        New-UDNivoChart -Bar -Keys "Value" -IndexBy 'name' -Data $Data -Height 500 -Width 1000
    }
    $TreeData = @{
        Name     = "root"
        children = @(
            @{
                Name  = "first"
                children = @(
                    @{
                        Name = "first-first"
                        Count = 7
                    }
                    @{
                        Name = "first-second"
                        Count = 8
                    }
                )
            },
            @{
                Name  = "second"
                Count = 21
            }
        )
    }
    
    New-UDNivoChart -Bubble -Data $TreeData -Value "count" -Identity "name" -Height 500 -Width 800
    $Data = @()
    for($i = 365; $i -gt 0; $i--) {
        $Data += @{
            day = (Get-Date).AddDays($i * -1).ToString("yyyy-MM-dd")
            value = Get-Random
        }
    }
    
    $From = (Get-Date).AddDays(-365)
    $To = Get-Date
    
    New-UDNivoChart -Calendar -Data $Data -From $From -To $To -Height 500 -Width 1000 -MarginTop 50 -MarginRight 130 -MarginBottom 50 -MarginLeft 60
    $Data = @(
        @{
            state = "idaho"
            cats = 72307
            dogs = 23429
            moose = 23423
            bears = 784
        }
        @{
            state = "wisconsin"
            cats = 2343342
            dogs = 3453623
            moose = 1
            bears = 23423
        }
        @{
            state = "montana"
            cats = 9234
            dogs = 3973457
            moose = 23472
            bears = 347303
        }
        @{
            state = "colorado"
            cats = 345973789
            dogs = 0237234
            moose = 2302
            bears = 2349772
        }
    )
    New-UDNivoChart -Heatmap -Data $Data -IndexBy 'state' -keys @('cats', 'dogs', 'moose', 'bears')  -Height 500 -Width 1000 -MarginTop 50 -MarginRight 130 -MarginBottom 50 -MarginLeft 60
    [array]$Data = [PSCustomObject]@{
        id = "DataSet"
        data = (1..20 | ForEach-Object {
            $item = Get-Random -Max 500 
            [PSCustomObject]@{
                x = "Test$item"
                y = $item
            }
        })
    }
    New-UDNivoChart -Line -Data $Data -Height 500 -Width 1000 -LineWidth 1
    $Data = 1..10 | ForEach-Object { 
        @{
            "Adam" = Get-Random 
            "Alon" = Get-Random 
            "Lee" = Get-Random 
            "Frank" = Get-Random 
            "Bill" = Get-Random 
        }
    }
    
    New-UDNivoChart -Stream -Data $Data -Height 500 -Width 1000 -Keys @("adam", "alon", "lee", "frank", "bill")
    $TreeData = @{
        Name     = "root"
        children = @(
            @{
                Name  = "first"
                children = @(
                    @{
                        Name = "first-first"
                        Count = 7
                    }
                    @{
                        Name = "first-second"
                        Count = 8
                    }
                )
            },
            @{
                Name  = "second"
                Count = 21
            }
        )
    }
    
    New-UDNivoChart -Treemap -Data $TreeData -Value "count" -Identity "name" -Height 500 -Width 800

    A tooltip description of the column

    string

    DisableColumnMenu

    Disable the column menu for this column

    boolean

    DisableExport

    Disable exporting of the data in this column

    boolean

    Editable

    Whether or not this column can be edited

    boolean

    Field

    The field (property) to use when displaying the value in the column.

    String

    Filterable

    Whether this column can be used in filters.

    boolean

    Flex

    The flex property accepts a value between 0 and ∞. It works by dividing the remaining space in the grid among all flex columns in proportion to their flex value.

    float

    HeaderAlign

    How to align header text.

    left, center, right

    HeaderName

    The title to display in the header.

    String

    Hide

    Whether to hide the column

    boolean

    Hideable

    Whether a column can be hidden by the user.

    boolean

    HideSortIcon

    Whether to hide the sort icon for the column

    boolean

    MaxWidth

    The maximum width of the column

    integer

    MinWidth

    The minimum width of the column

    integer

    Pinnable

    Whether the column can be pinned.

    boolean

    Render

    A script block to render components in the column

    ScriptBlock

    Resizable

    Whether the column can be resized

    boolean

    Sortable

    Whether the column can be sorted.

    boolean

    Type

    The type of data within the column

    string, number, date, dateTime, boolean, actions

    Width

    How wide the column should be in pixels.

    Integer

    The sort options for the table

    Hashtable

    Align

    How to align the data within the column.

    Left, Center, Right

    CellClassName

    A CSS class to apply to cells in this column

    string

    ColSpan

    The number of columns this column should span.

    Integer

    Filter

    A filter object that you can use to construct filters against your data.

    Hashtable

    Page

    The current page. Starts at 0.

    Integer

    PageSize

    The number of records in a page.

    Integer

    ColumnField

    The name of the field to filter

    String

    OperatorValue

    The type of operator to use when filtering the data.

    String

    Value

    The value used to filter

    Object

    Field

    The field to sort.

    String

    Sort

    The direction to sort the field.

    asc, desc

    Description

    Sort

    New-UDDataGrid -LoadRows {
        $Data = @(
            @{ Name = 'Adam'; Number = Get-Random}
            @{ Name = 'Tom'; Number = Get-Random}
            @{ Name = 'Sarah'; Number = Get-Random}
        )
        @{
            rows = $Data 
            rowCount = $Data.Length
        }
    } -Columns @(
        @{ field = "name"}
        @{ field = "number"}
    ) -AutoHeight
    New-UDDataGrid -LoadRows {  
        $Rows = 1..100 | % {
            @{ Name = 'Adam'; Number = Get-Random}
        }
        @{
            rows = $Rows
            rowCount = $Rows.Length
        }
        
    } -Columns @(
        @{ field = "name"; render = { New-UDTypography $EventData.number }}
        @{ field = "number"}
    ) -AutoHeight
    New-UDDataGrid -LoadRows {  
        $Rows = 1..100 | % {
            @{ Name = 'Adam'; Number = "This column is a very long string. This column is a very long string. This column is a very long string. This column is a very long string. This column is a very long string. This column is a very long string."}
        }
        @{
            rows = $Rows
            rowCount = $Rows.Length
        }
        
    } -Columns @(
        @{ field = "name"; render = { New-UDTypography $EventData.number }}
        @{ field = "number"; flex = 1.0}
    ) -AutoHeight
    New-UDDataGrid -LoadRows {  
        $Rows = 1..100 | % {
            @{ Name = 'Adam'; Number = Get-Random}
        } 
        @{
            rows = $Rows | Select-Object -First $EventData.pageSize -Skip ($EventData.page * $EventData.pageSize)
            rowCount = $Rows.Length
        }
        
    } -Columns @(
        @{ field = "name"; }
        @{ field = "number"}
    ) -AutoHeight -Pagination
    @{
        items = @(
            @{ 
                columnField = "Name"
                overatorValue = "contains"
                value = "test"
            }
        )
        linkOperator = "and"
    }
    $EventData.Sort.'0'.field
    New-UDDataGrid -LoadRows {
        $Data = @(
            @{ Name = 'Adam'; Number = Get-Random }
            @{ Name = 'Tom'; Number = Get-Random }
            @{ Name = 'Sarah'; Number = Get-Random }
        )
        @{
            rows     = $Data 
            rowCount = $Data.Length
        }
    } -Columns @(
        @{ field = "Name" }
        @{ field = "number" }
    ) -AutoHeight -LoadDetailContent {
        Show-UDToast $Body
        New-UDAlert -Text $EventData.row.Name
    }
    @{
        newRow = @{}
        oldRow = @{}
    }
    New-UDDataGrid -LoadRows {
        $Data = @(
            @{ Name = 'Adam'; number = Get-Random }
            @{ Name = 'Tom'; number = Get-Random }
            @{ Name = 'Sarah'; number = Get-Random }
        )
        @{
            rows     = $Data 
            rowCount = $Data.Length
        }
    } -Columns @(
        @{ field = "Name"; editable = $true }
        @{ field = "number" ; editable = $true }
    ) -AutoHeight -OnEdit {
        Show-UDToast "Editing $Body" 
    }
    New-UDDataGrid -LoadRows {
        $Data = @(
            @{ Name = 'Adam'; Number = Get-Random}
            @{ Name = 'Tom'; Number = Get-Random}
            @{ Name = 'Sarah'; Number = Get-Random}
        )
        @{
            rows = $Data 
            rowCount = $Data.Length
        }
    } -Columns @(
        @{ field = "name"}
        @{ field = "number"}
    ) -AutoHeight -OnExport {
        $Data = $EventData | Select-Object -Expand name 
        Out-UDDataGridExport -Data $Data -FileName 'export.txt' | Out-String
    }
    New-UDDashboard -Title 'PowerShell Universal' -Content {
         $Data =  1..10000 | % {
            @{ Name = 'Adam'; Number = Get-Random }
        } 
        New-UDDataGrid -LoadRows {  
          $Data | Out-UDDataGridData -Context $EventData
        } -Columns @(
            @{ field = "name"; render = { 
                New-UDButton -Icon (New-UDIcon -Icon User) -OnClick { Show-UDToast $EventData.Name } } 
            }
            @{ field = "number" }
        ) -AutoHeight -Pagination
    }   
    function Out-UDSQLDataGrid {
        param(
            [Parameter(Mandatory)]
            $Context,
            [Parameter(Mandatory)]
            [string]$Table,
            [Parameter(Mandatory)]
            [string]$SqlInstance,
            [Parameter(Mandatory)]
            [string]$Database
        )
        End {
            $simpleFilter = @()
            if($null -ne $Context.Filter.Items -and $Context.Filter.Items.Count -gt 0) {
                $linkOperator = $Context.Filter.linkOperator #The link operator is 'AND' or 'OR'. It will always be one or the other for all properties
                foreach ($item in $Context.Filter.Items) {         
                    $simpleFilter += [PSCustomObject]@{
                        Property    = $item.columnField
                        Value       = $item.Value
                        Operator    = $item.operatorValue
                    }
                }
            }
    
            if($null -ne $simpleFilter -and $simpleFilter.Count -gt 0) {
                $count = 1
                foreach($filter in $simpleFilter) {
                    if ($count -gt 1) {
                        $SqlFilter += " $($linkOperator) "
                    } else {
                        $SqlFilter += " WHERE "
                    }
                    switch ($filter.Operator) {
                        "contains" { $SqlFilter += " $($filter.Property) LIKE '%$($filter.Value)%' " }
                        "equals" { $SqlFilter += " $($filter.Property) = '$($filter.Value)' " }
                        "startsWith" { $SqlFilter += " $($filter.Property) LIKE '$($filter.Value)%' " }
                        "endsWith" { $SqlFilter += " $($filter.Property) LIKE '%$($filter.Value)' " }
                        "isAnyOf" {
                            $count = 1
                            foreach($val in $filter.Value){
                                if($count -gt 1) {
                                    $list += ", '$val'"
                                } else {
                                    $list += "'$val'"
                                }  
                                $count += 1
                            }
                            $SqlFilter += " $($filter.Property) IN ($($list)) "
                        }
                        "isempty" { $SqlFilter += " TRIM ($($filter.Property)) IS NULL " }
                        "isnotempty" { $SqlFilter += " TRIM ($($filter.Property)) IS NOT NULL " }
                        "notequals" { $SqlFilter += " $($filter.Property) != '$($filter.Value)' " }
                        "notcontains" { $SqlFilter += " $($filter.Property) NOT LIKE '%$($filter.Value)%' " }
                    }
                    $count += 1
                }
            } else {
                $SqlFilter = $null
            }
            $totalCount = (Invoke-DbaQuery -SqlInstance $SqlInstance -Database $Database -Query "SELECT COUNT(*) As Count FROM $Table $SqlFilter" -SqlParameters $SqlParameters).Count
            $sort = $Context.Sort.'0'
            if ($sort)
            {
                $sqlSort = "ORDER BY $($sort.field) $($sort.Sort) "
            } else {
                $sqlSort = "ORDER BY (SELECT NULL)"
            }
            $sqlPage = "OFFSET $($Context.Page * $Context.PageSize) ROWS FETCH NEXT $($Context.PageSize) ROWS ONLY;"
            if($null -ne $SqlFilter) {
                $Query = "SELECT * FROM $Table $sqlFilter $sqlSort $sqlPage"
            } else {
                $Query = "SELECT * FROM $Table $sqlSort $sqlPage"
            }
            $Rows = Invoke-DbaQuery -SqlInstance $SqlInstance -Database $Database -Query $Query -As PSObject -SqlParameters $SqlParameters
            @{
                rows     = [Array]$Rows
                rowCount = $TotalCount
            }
        }   
    }
    
    New-UDDashboard -Title 'PowerShell Universal' -Content {
        New-UDDataGrid -LoadRows {  
          Out-UDSqlDataGrid -Context $EventData -SqlInstance "(localdb)\MSSQLLocalDb" -Database "PSU" -Table "Job"
        } -Columns @(
            @{ field = "id"; }
            @{ field = "startTime"; }
            @{ field = "status"; render = {
                if ($EventData.Status -eq 2) {
                    New-UDAlert -Severity 'Success' -Text 'Success'
                }
    
                if ($EventData.Status -eq 3) {
                    New-UDAlert -Severity 'Error' -Text 'Failed'
                }
            } }
        ) -AutoHeight -Pagination
    }

    Table

    Table component for Universal Dashboard

    Tables display sets of data. They can be fully customized.

    Tables display information in a way that’s easy to scan, so that users can look for patterns and insights. They can be embedded in primary content, such as cards.

    hashtag
    Simple Table

    A simple example with no frills. Table columns are defined from the data.

    hashtag
    Table with Custom Columns

    Define custom columns for your table.

    hashtag
    Table with Custom Column Rendering

    Define column rendering. Sorting and exporting still work for the table.

    hashtag
    Table Column Width

    Column width can be defined using the -Width parameter. You can also decide to truncate columns that extend past that width.

    hashtag
    Filters

    You can configure custom filters per column. The table supports text, select, fuzzy , slider, range, date , number, and autocomplete filters.

    hashtag
    Search

    To enable search, use the -ShowSearch parameter on New-UDTable.

    When using custom columns, you will need to add the -IncludeInSearch parameter to the columns you'd like to include in the search.

    hashtag
    Table with server-side processing

    Process data on the server so you can perform paging, filtering, sorting and searching in systems like SQL. To implement a server-side table, you will use the -LoadData parameter. This parameter accepts a ScriptBlock. The $EventData variable includes information about the state of the table. You can use cmdlets to process the data based on this information.

    hashtag
    $EventData Structure

    The $EventData object contains the following properties.

    Property Name
    Type
    Description

    hashtag
    Example

    hashtag
    Retrieving Displayed Data

    You may want to allow the user to take action on the current set of displayed data. To do so, use Get-UDElement in the input object you want to retrieve the data from and get the table by Id. Once you have the element, you can use the CurrentData property of the element to get an array of currently displayed rows.

    hashtag
    Paging

    By default, paging is disable and tables will grow based on how many rows of data you provide. You can enable paging by using the -ShowPagination cmdlet (alias -Paging). You can configure the page size using the -PageSize cmdlet.

    hashtag
    Disable Page Size All

    By default, the page size selector provides an option to show all rows. If you want to prevent users from doing this, use the -DisablePageSizeAll cmdlet.

    hashtag
    Pagination Location

    You can change the location of the pagination control by using the -PaginationLocation parameter. It accepts top, bottom and both.

    hashtag
    Sorting

    To enable sorting for a table, use the -ShowSort parameter. When you enable sorting, you will be able to click the table headers to sort the table by clicking the headers. By default, multi-sort is enabled. To multi-hold shift and click a column header.

    You can control which columns can be sorted by using New-UDTableColumn and -ShowSort parameter.

    hashtag
    Disable Sort Remove

    By default, the sorting of a table has 3 states. Unsorted, ascending and descending. If you would like to disable the unsorted state, use the -DisableSortRemove parameter of New-UDTable.

    hashtag
    Selection

    Tables support selection of rows. You can create an event handler for the OnRowSelected parameter to receive when a new row is selected or unselected or you can use Get-UDElement to retrieve the current set of selected rows.

    The following example creates a table with row selection enabled. A toast is show when clicking the row or when clicking the GET Rows button.

    The $EventData variable for the -OnRowSelected event will include all the columns as properties and a selected property as to whether the row was selected or unselected.

    For example, the service table data would look like this.

    hashtag
    Collapsible Rows

    You can include additional information within the table by using the -OnRowExpand parameter of New-UDTable. It accepts a ScriptBlock that you can use to return additional components.

    hashtag
    Exporting

    Tables support exporting the data within the table. You can export as CSV, XLSX, JSON or PDF. You can define which columns to include in an export and choose to export just the current page or all the data within the table.

    hashtag
    Hidden Columns

    Hidden columns allow you to include data that is not displayed in the table but is included in the exported data.

    The following hides the StartType column from the user but includes it in the export.

    hashtag
    Server-Side Exporting

    You can control the export functionality with a PowerShell script block. This is useful when exporting from server-side sources like SQL server tables.

    In this example, I have a SQL table that contains podcasts. When exporting, you will receive information about the current state of the table to allow you to customize what data is exported.

    hashtag
    Customizing Export Options

    You can decide which export options to present to your users using the -ExportOption cmdlet. The following example would only show the CSV export option.

    hashtag
    Customizing Labels

    You can use the -TextOption parameter along with the New-UDTableTextOption cmdlet to set text fields within the table.

    hashtag
    Refresh with a button

    hashtag
    Data Parameter

    You can externally refresh a table by putting the table within a dynamic region and using Sync-UDElement.

    This example creates a button to refresh the table.

    hashtag
    LoadData Parameter

    If you use the -LoadData parameter, you can sync the table directly. This has the benefit of maintaining the table state, such as the page and filtering, after the refresh.

    hashtag
    Show Refresh Button

    You can use the -ShowRefresh parameter to provide a refresh button for server-side tables.

    hashtag
    Alternating Row Colors

    You can use a theme to create a table with alternating row colors.

    hashtag
    API

    int

    The current page (starting with 0).

    PageSize

    int

    The selected page size.

    Properties

    string[]

    An array of properties being shown in the table.

    Search

    string

    A search string provided by the user.

    TotalCount

    int

    The total number of records before filtering or paging.

    New-UDTableTextOptionarrow-up-right

    Filters

    Hashtable[] @{ id = 'fieldName'

    value = 'filterValue' }

    A list of filter values. Each hashtable has an Id and a Value property.

    OrderBy

    Hashtable @{ field = "fieldName" }

    Property name to sort by.

    OrderDirection

    string

    asc or desc depending on the sort order.

    New-UDTablearrow-up-right
    New-UDTableColumnarrow-up-right
    Out-UDTableColumnarrow-up-right
    Pagination Location
    Row selection

    Page

    $Data = @(
        @{Dessert = 'Frozen yoghurt'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Ice cream sandwich'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Eclair'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Cupcake'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Gingerbread'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
    )
    
    New-UDTable -Data $Data
    $Data = @(
        @{Dessert = 'Frozen yoghurt'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Ice cream sandwich'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Eclair'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Cupcake'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Gingerbread'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
    ) 
    
    $Columns = @(
        New-UDTableColumn -Property Dessert -Title "A Dessert"
        New-UDTableColumn -Property Calories -Title Calories 
        New-UDTableColumn -Property Fat -Title Fat 
        New-UDTableColumn -Property Carbs -Title Carbs 
        New-UDTableColumn -Property Protein -Title Protein 
    )
    
    New-UDTable -Id 'customColumnsTable' -Data $Data -Columns $Columns
    $Data = @(
        @{Dessert = 'Frozen yoghurt'; Calories = 1; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Ice cream sandwich'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Eclair'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Cupcake'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Gingerbread'; Calories = 200; Fat = 6.0; Carbs = 24; Protein = 4.0}
    ) 
    
    $Columns = @(
        New-UDTableColumn -Property Dessert -Title Dessert -Render { 
            New-UDButton -Id "btn$($EventData.Dessert)" -Text "Click for Dessert!" -OnClick { Show-UDToast -Message $EventData.Dessert } 
        }
        New-UDTableColumn -Property Calories -Title Calories 
        New-UDTableColumn -Property Fat -Title Fat 
        New-UDTableColumn -Property Carbs -Title Carbs 
        New-UDTableColumn -Property Protein -Title Protein 
    )
    
    New-UDTable -Data $Data -Columns $Columns -Sort -Export
    $Data = @(
        @{Dessert = 'Frozen yoghurt'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Ice cream sandwich'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Eclair'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Cupcake'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Gingerbread'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
    ) 
    
    $Columns = @(
        New-UDTableColumn -Property Dessert -Title Dessert -Render { 
            New-UDButton -Id "btn$($EventData.Dessert)" -Text "Click for Dessert!" -OnClick { Show-UDToast -Message $EventData.Dessert } 
        }
        New-UDTableColumn -Property Calories -Title Calories -Width 5 -Truncate
        New-UDTableColumn -Property Fat -Title Fat 
        New-UDTableColumn -Property Carbs -Title Carbs 
        New-UDTableColumn -Property Protein -Title Protein 
    )
    
    New-UDTable -Data $Data -Columns $Columns -Sort
    $Data = @(
        @{Dessert = 'Frozen yoghurt'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Ice cream sandwich'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Eclair'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Cupcake'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Gingerbread'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
    ) 
    
    $Columns = @(
        New-UDTableColumn -Property Dessert -Title "A Dessert" -Filter -FilterType AutoComplete
        New-UDTableColumn -Property Calories -Title Calories -Filter -FilterType Range
        New-UDTableColumn -Property Fat -Title Fat -Filter -FilterType Range
        New-UDTableColumn -Property Carbs -Title Carbs -Filter -FilterType Range
        New-UDTableColumn -Property Protein -Title Protein -Filter -FilterType Range
    )
    
    New-UDTable -Id 'customColumnsTable' -Data $Data -Columns $Columns -ShowFilter
    $Data = @(
        @{Dessert = 'Frozen yoghurt'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Ice cream sandwich'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Eclair'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Cupcake'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Gingerbread'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
    )
    
    New-UDTable -Data $Data -ShowSearch
    $Data = @(
        @{Dessert = 'Frozen yoghurt'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Ice cream sandwich'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Eclair'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Cupcake'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Gingerbread'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
    ) 
    
    $Columns = @(
        New-UDTableColumn -Property Dessert -Title "A Dessert" -IncludeInSearch
        New-UDTableColumn -Property Calories -Title Calories 
        New-UDTableColumn -Property Fat -Title Fat 
        New-UDTableColumn -Property Carbs -Title Carbs 
        New-UDTableColumn -Property Protein -Title Protein 
    )
    
    New-UDTable -Id 'customColumnsTable' -Data $Data -Columns $Columns -ShowSearch
    $Columns = @(
        New-UDTableColumn -Property Name -Title "Name" -ShowFilter
        New-UDTableColumn -Property Value -Title "Value" -ShowFilter
    )
    
    $Data = 1..1000 | ForEach-Object {
      [PSCustomObject]@{
          Name = "Record-$_"
          Value = $_ 
      }
    }
    
    New-UDTable -Columns $Columns -LoadData {
        foreach($Filter in $EventData.Filters)
        {
            $Data = $Data | Where-Object -Property $Filter.Id -Match -Value $Filter.Value
        }
    
        $TotalCount = $Data.Count 
    
        if (-not [string]::IsNullOrEmpty($EventData.OrderBy.Field))
        {
            $Descending = $EventData.OrderDirection -ne 'asc'
            $Data = $Data | Sort-Object -Property ($EventData.orderBy.Field) -Descending:$Descending
        }
        
        $Data = $Data | Select-Object -First $EventData.PageSize -Skip ($EventData.Page * $EventData.PageSize)
    
        $Data | Out-UDTableData -Page $EventData.Page -TotalCount $TotalCount -Properties $EventData.Properties 
    } -ShowFilter -ShowSort -ShowPagination
    $Columns = @(
        New-UDTableColumn -Property Name -Title "Name" -ShowFilter
        New-UDTableColumn -Property Value -Title "Value" -ShowFilter
    )
    
    $Data = 1..1000 | ForEach-Object {
      @{
          Name = "Record-$_"
          Value = $_ 
      }
    }
    
    New-UDButton -Text 'Get Filtered Data' -OnClick {
        $Element = Get-UDElement -Id 'filteredTable'
        Show-UDModal -Content {
            New-UDElement -Tag 'pre' -Content {
               $Element | ConvertTo-Json
            }
        }
    }
    
    New-UDTable -Id 'filteredTable' -Columns $Columns -LoadData {
        foreach($Filter in $EventData.Filters)
        {
            $Data = $Data | Where-Object -Property $Filter.Id -Match -Value $Filter.Value
        }
    
        $TotalCount = $Data.Count 
    
        if (-not [string]::IsNullOrEmpty($EventData.OrderBy))
        {
            $Descending = $EventData.OrderDirection -ne 'asc'
            $Data = $Data | Sort-Object -Property $EventData.orderBy -Descending:$Descending
        }
        
        $Data = $Data | Select-Object -First $EventData.PageSize -Skip ($EventData.Page * $EventData.PageSize)
    
        $Data | Out-UDTableData -Page $EventData.Page -TotalCount $TotalCount -Properties $EventData.Properties 
    } -ShowFilter -ShowSort -ShowPagination
    $Data = @(
        @{Dessert = 'Frozen yoghurt'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Ice cream sandwich'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Eclair'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Cupcake'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Gingerbread'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
    ) 
    
    New-UDTable -Data $Data -Paging -PageSize 2
    $Data = @(
        @{Dessert = 'Frozen yoghurt'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Ice cream sandwich'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Eclair'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Cupcake'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Gingerbread'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
    ) 
    
    New-UDTable -Data $Data -ShowSort
        @{Dessert = 'Eclair'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Cupcake'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Gingerbread'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
    ) 
    
    $Columns = @(
        New-UDTableColumn -Property Dessert -Title "A Dessert" -ShowSort
        New-UDTableColumn -Property Calories -Title Calories 
        New-UDTableColumn -Property Fat -Title Fat 
        New-UDTableColumn -Property Carbs -Title Carbs -ShowSort
        New-UDTableColumn -Property Protein -Title Protein -ShowSort
    )
    
    New-UDTable -Id 'customColumnsTable' -Data $Data -Columns $Columns
    $Data = @(
        @{Dessert = 'Frozen yoghurt'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Ice cream sandwich'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Eclair'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Cupcake'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Gingerbread'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
    ) 
    
    New-UDTable -Data $Data -ShowSort -DisableSortRemove
    $Data = try { get-service -ea Stop | select Name,@{n = "Status";e={ $_.Status.ToString()}},@{n = "StartupType";e={ $_.StartupType.ToString()}},@{n = "StartType";e={ $_.StartType.ToString()}} } catch {}
    $Columns = @(
        New-UDTableColumn -Property Name -Title "Service Name" -ShowSort -IncludeInExport -IncludeInSearch -ShowFilter -FilterType text
        New-UDTableColumn -Property Status -Title Status -ShowSort -DefaultSortColumn -IncludeInExport -IncludeInSearch -ShowFilter -FilterType select 
        New-UDTableColumn -Property StartupType -Title StartupType -IncludeInExport -ShowFilter -FilterType select
        New-UDTableColumn -Property StartType -Title StartType -IncludeInExport -ShowFilter -FilterType select 
    )
    New-UDTable -Id 'service_table' -Data $Data -Columns $Columns -Title 'Services' -ShowSearch -ShowPagination -ShowSelection -Dense -OnRowSelection {
        $Item = $EventData
        Show-UDToast -Message "$($Item | out-string)"
    }
    New-UDButton -Text "GET Rows" -OnClick {
        $value = Get-UDElement -Id "service_table"
        Show-UDToast -Message "$( $value.selectedRows | Out-String )"
    }
    @{
       Id = 0
       Name = 'AESMService',
       Status = 'Running'
       StartupType = 'AutomaticDelayedStart'
       StartType = 'Automation'
       selected = $true
    }
    New-UDTable -Data (Get-Service) -OnRowExpand {
        New-UDAlert -Text $EventData.DisplayName
    } -Columns @(
        New-UDTableColumn -Title 'Name' -Property 'Name'
        New-UDTableColumn -Title 'Status' -Property 'Status'
    )
    $Data = try { get-service -ea Stop | select Name,@{n = "Status";e={ $_.Status.ToString()}},@{n = "StartupType";e={ $_.StartupType.ToString()}},@{n = "StartType";e={ $_.StartType.ToString()}} } catch {}
    $Columns = @(
        New-UDTableColumn -Property Name -Title "Service Name" -IncludeInExport
        New-UDTableColumn -Property Status -Title Status 
        New-UDTableColumn -Property StartupType
        New-UDTableColumn -Property StartType -IncludeInExport
    )
    New-UDTable -Id 'service_table' -Data $Data -Columns $Columns -Title 'Services' -ShowSearch -ShowPagination -Dense -Export
    $Data = try { get-service -ea Stop | select Name,@{n = "Status";e={ $_.Status.ToString()}},@{n = "StartupType";e={ $_.StartupType.ToString()}},@{n = "StartType";e={ $_.StartType.ToString()}} } catch {}
    $Columns = @(
        New-UDTableColumn -Property Name -Title "Service Name" -IncludeInExport
        New-UDTableColumn -Property Status -Title Status 
        New-UDTableColumn -Property StartupType
        New-UDTableColumn -Property StartType -IncludeInExport -Hidden
    )
    New-UDTable -Id 'service_table' -Data $Data -Columns $Columns -Title 'Services' -ShowSearch -ShowPagination -Dense -Export
    $Columns = @(
        New-UDTableColumn -Property Name -Title "Name" -ShowFilter -IncludeInExport
        New-UDTableColumn -Property Value -Title "Value" -ShowFilter -IncludeInExport
    )
    
    $Data = 1..1000 | ForEach-Object {
      [PSCustomObject]@{
          Name = "Record-$_"
          Value = $_ 
      }
    }
    
    New-UDTable -Columns $Columns -LoadData {
        foreach($Filter in $EventData.Filters)
        {
            $Data = $Data | Where-Object -Property $Filter.Id -Match -Value $Filter.Value
        }
    
        $TotalCount = $Data.Count 
    
        if (-not [string]::IsNullOrEmpty($EventData.OrderBy.Field))
        {
            $Descending = $EventData.OrderDirection -ne 'asc'
            $Data = $Data | Sort-Object -Property ($EventData.orderBy.Field) -Descending:$Descending
        }
        
        $Data = $Data | Select-Object -First $EventData.PageSize -Skip ($EventData.Page * $EventData.PageSize)
    
        $Data | Out-UDTableData -Page $EventData.Page -TotalCount $TotalCount -Properties $EventData.Properties 
    } -ShowFilter -ShowSort -ShowPagination  -Export -OnExport {
       $Query = $Body | ConvertFrom-Json
    
            <# Query will contain
                filters: []
                orderBy: undefined
                orderDirection: ""
                page: 0
                pageSize: 5
                properties: (5) ["dessert", "calories", "fat", "carbs", "protein"]
                search: ""
                totalCount: 0
                allRows: true
            #>
    
        $Data | ConvertTo-Json
    }
    $Data = try { get-service -ea Stop | select Name,@{n = "Status";e={ $_.Status.ToString()}},@{n = "StartupType";e={ $_.StartupType.ToString()}},@{n = "StartType";e={ $_.StartType.ToString()}} } catch {}
    $Columns = @(
        New-UDTableColumn -Property Name -Title "Service Name" -IncludeInExport
        New-UDTableColumn -Property Status -Title Status 
        New-UDTableColumn -Property StartupType
        New-UDTableColumn -Property StartType -IncludeInExport
    )
    New-UDTable -Id 'service_table' -Data $Data -Columns $Columns -Title 'Services' -ShowSearch -ShowPagination -Dense -Export -ExportOption "csv"
    $Data = @(
        @{Dessert = 'Frozen yoghurt'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Ice cream sandwich'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Eclair'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Cupcake'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
        @{Dessert = 'Gingerbread'; Calories = 159; Fat = 6.0; Carbs = 24; Protein = 4.0}
    ) 
    
    $Option = New-UDTableTextOption -Search "Search all these records"
    
    New-UDTable -Data $Data -TextOption $Option -ShowSearch
    New-UDDynamic -Id 'table' -Content {
        $Data = Get-Service
        New-UDTable -Data $Data -Paging
    } -LoadingComponent {
        "Loading"
    }
    
    New-UDButton -Text 'Refresh Table' -OnClick {
        Sync-UDElement -Id 'table'
    }
    New-UDButton -Text 'Table1' -OnClick { Sync-UDElement -Id 'Table1' }
    
    $Columns = @(
        New-UDTableColumn -Property Name -Title "Name" -ShowFilter -Render { $EventData.Name }
        New-UDTableColumn -Property Value -Title "Value" -ShowFilter
    )
    
    New-UDTable -Columns $Columns -LoadData {
        $Data = 1..1000 | ForEach-Object {
            @{
                Name = "Record-$_"
                Value = $_ 
            }
        }
        
        foreach($Filter in $EventData.Filters)
        {
            $Data = $Data | Where-Object -Property $Filter.Id -Match -Value $Filter.Value
        }
    
        $TotalCount = $Data.Count 
    
        if (-not [string]::IsNullOrEmpty($EventData.OrderBy))
        {
            $Descending = $EventData.OrderDirection -ne 'asc'
            $Data = $Data | Sort-Object -Property $EventData.orderBy -Descending:$Descending
        }
        
        $Data = $Data | Select-Object -First $EventData.PageSize -Skip ($EventData.Page * $EventData.PageSize)
    
        $Data | Out-UDTableData -Page $EventData.Page -TotalCount $TotalCount -Properties $EventData.Properties 
    } -ShowFilter -ShowSort -ShowPagination  -Id 'Table1'
    $Columns = @(
        New-UDTableColumn -Property Dessert -Title "A Dessert"
        New-UDTableColumn -Property Calories -Title Calories 
        New-UDTableColumn -Property Fat -Title Fat 
        New-UDTableColumn -Property Carbs -Title Carbs 
        New-UDTableColumn -Property Protein -Title Protein 
    )
    
    New-UDTable -ShowRefresh -Columns $Columns -LoadData {
        $Query = $Body | ConvertFrom-Json
    
        <# Query will contain
            filters: []
            orderBy: undefined
            orderDirection: ""
            page: 0
            pageSize: 5
            properties: (5) ["dessert", "calories", "fat", "carbs", "protein"]
            search: ""
            totalCount: 0
        #>
    
        @(
            @{Dessert = 'Frozen yoghurt'; Calories = (Get-Random); Fat = 6.0; Carbs = 24; Protein = 4.0}
            @{Dessert = 'Ice cream sandwich'; Calories = (Get-Random); Fat = 6.0; Carbs = 24; Protein = 4.0}
            @{Dessert = 'Eclair'; Calories = (Get-Random); Fat = 6.0; Carbs = 24; Protein = 4.0}
            @{Dessert = 'Cupcake'; Calories = (Get-Random); Fat = 6.0; Carbs = 24; Protein = 4.0}
            @{Dessert = 'Gingerbread'; Calories = (Get-Random); Fat = 6.0; Carbs = 24; Protein = 4.0}
        ) | Out-UDTableData -Page 0 -TotalCount 5 -Properties $Query.Properties 
    }
    $Theme = @{
        overrides = @{
            MuiTableRow = @{
                root = @{
                    '&:nth-of-type(odd)' = @{
                        backgroundColor = "rgba(0,0,0,0.04)"
                    }
                }
                head = @{
                    backgroundColor = "rgb(255,255,255) !important"
                }
            }
        }
    }
    
    New-UDDashboard -Content {
    $data = 1..10 | % { [PSCustomObject]@{ Item = $_}}
      New-UDTable -ShowPagination -PageSize 10 -PageSizeOptions @(10, 10) -DisablePageSizeAll -Columns @(
            New-UDTableColumn -Property 'Item' -Title 'Item' -Width 180 -Truncate
        ) -Data $Data -Dense -ShowSearch
    } -Theme $Theme