# Advanced Session Features

Advanced Displays, Integrations, PWA, LaunchLink, USB, ClipBoard, Keyboard Profiles, Mouse Modes, Multi-Language Config, Banners, Scripting

# Advanced Displays

Frame supports multiple monitors and 4k displays. This guide outlines the considerations, requirements, and steps to enable these features.

## 4k Display Support

### Considerations

Administrators serving Frame sessions to end users with 4k displays can enable 4k support easily. Frame recommends considering the following before doing so:

- Customers using CPU-only instances with 1-2 vCPU(s) should test to ensure the instance is able to support 4k rendering in addition to the apps/services running on the VM.
- Administrators may need to increase the number of vCPUs for users accessing Frame with more than one 4k display.

Reference the table below to understand infrastructure requirements for supporting 4k instances:

<figure id="bkmrk-instance-configurati"><table><thead><tr><th>Instance Configuration</th><th>4k Support</th></tr></thead><tbody><tr><td>GPU-enabled</td><td>Fully supported</td></tr><tr><td>1-2 vCPU(s)</td><td>Not Recommended, Admin should test</td></tr><tr><td>3+ vCPUs</td><td>Supported, Admin should test</td></tr></tbody></table>

</figure>### Enable 4k Displays

4k is enabled by default for GPU-enabled instances. If you wish to enable 4k for a CPU-only instance, please review the considerations mentioned above and then enable [**4K Displays**](https://docs.difr.com/books/platform-administrators-guide/page/session-settings#4K%20Displays) in Session Settings.

## Multiple Monitor Support

Multi-display configurations are useful for a variety of end user workflows. Frame's multi-monitor feature allows users to connect up to 4 displays at a time. End users may configure the display order as desired while in the session.

<p class="callout info"> Frame App supports the Frame multi-monitor feature automatically. If an end user has more than one monitor attached to their device, Frame App prompts the user if they want to use all of their monitors. Frame Administrators do not have to enable explicitly multi-monitor support for Frame App users.</p>

### Enhanced Multi-monitor Support

Users accessing Frame from Chrome or Chromium-based Edge browser can use the Enhanced Multi-monitor experience with automatic physical monitor layout detection.

<p class="callout info"> The Enhanced Multi-monitor feature is only available to users accessing Frame from Chrome or Chromium-based Edge version 100 or greater.</p>

When using Auto Layout or Add Monitor in a browser session, the customer administrator or user must add `https://use.difr.com` as one of the **Allowed to send pop-ups and use redirects** sites, under **Settings** &gt; **Privacy and security** &gt; **Site Settings** &gt; **Pop-ups and redirects** of their Chrome or Chromium-based Edge browser. This is discussed further in the [Google Chrome Help article](https://support.google.com/chrome/answer/95472#zippy=%2Callow-pop-ups-and-redirects-from-a-site).

Refer to our [Display Options documentation](https://docs.difr.com/books/desktop-users-guide/page/introduction#bkmrk-display-requirements) in our User Guide for details on how to use the Multi-monitor feature.

# Advanced Integrations

Access to Frame apps and desktops can be integrated several different ways within:

- Websites
- Internal portals or services
- Operating systems
- and custom workflows

This section talks about integration tools that can be leveraged for custom integrations.

The Advanced Integrations panel can be found under a Launchpad's settings menu in the Dashboard of an account. This panel allows administrators to choose:

- Specific settings
- An application or desktop
- An identity provider
- and instance type

the administrator would like to use together. Combining these components results in copyable links that can be easily used, shared, or deployed just about anywhere that accepts hyperlinks.

<figure id="bkmrk-">[![image.png](https://docs.difr.com/uploads/images/gallery/2026-01/scaled-1680-/CTmimage.png)](https://docs.difr.com/uploads/images/gallery/2026-01/CTmimage.png)

</figure><figure id="bkmrk--1">[![image.png](https://docs.difr.com/uploads/images/gallery/2026-01/scaled-1680-/wbNimage.png)](https://docs.difr.com/uploads/images/gallery/2026-01/wbNimage.png)

</figure>## PWA Links

<figure id="bkmrk--2">[![image.png](https://docs.difr.com/uploads/images/gallery/2026-01/scaled-1680-/HLUimage.png)](https://docs.difr.com/uploads/images/gallery/2026-01/HLUimage.png)

</figure>### What are PWAs?

PWAs (Progressive Web Apps) are web applications/websites that can be installed to local devices (Windows, Mac, Chrome OS, Linux, and more). Once installed, **these apps look, feel, and behave like native applications.**

PWA technology promotes a lot of best practices, offers a great experience, and is trending for a lot of other good reasons. Google has eliminated the traditional Chrome Apps in the Chrome Web Store in favor of PWAs, and Microsoft is working to integrate PWAs as first-class citizens in the Windows Store. Combining PWA technology with Frame has some added benefits that makes life easier:

- Frame PWAs are easy to use, install, manage, and customize.
- They are cross-platform. Install them on Windows, Mac, Linux, and Chrome OS from the same PWA link.
- Portability: simply disconnect from your Frame session and seamlessly continue work on a different device.

### Chromebooks/ChromeOS

Chromebooks are a great example: PWA technology with Frame allows Chromebook users to have an app like Adobe Photoshop easily accessible via the familiar Photoshop icon in their app drawer, or pinned to their shelf. It's easy to integrate these PWAs with your existing user authentication provider. For example, if you are using Google Workspace for authentication, installed PWAs can be synced between devices, making them as portable as ever. A user could have an app running on their Chromebook, disconnect their session, move to their laptop or desktop, and effortlessly launch the app from a native icon to resume their session.

<figure id="bkmrk-photoshop-launching-">![Photoshop Launching](https://docs.difr.com/uploads/images/gallery/2025-10/pwa-chrome-os-photoshop-launching.png) Photoshop Launching on a Chromebook

</figure><figure id="bkmrk-pwas-are-easy-to-fin">![Apps are easy to find](https://docs.difr.com/uploads/images/gallery/2025-10/pwa-chrome-os-easily-found.png) PWAs are easy to find!

</figure><figure id="bkmrk-photoshop-has-a-long">![Photoshop enjoying some shelf life](https://docs.difr.com/uploads/images/gallery/2025-10/pwa-chrome-os-app-info.png) Photoshop has a longer shelf life!

</figure>## Are PWAs right for my use case?

Frame PWAs are great for scenarios where users need long-term access to specific apps/desktops since they remove extra steps and clicks. However, there are some situations where Frame apps as a PWA may not be ideal. For example, short-term use cases like trials, training, and events might not make sense to have end-users installing your app if they are not going to use it again a short while later. For those situations, you may want to reach for [Launch links](https://docs.difr.com/books/platform-administrators-guide/page/advanced-integrations#bkmrk-what-are-launch-link) instead.

### Configuring PWA Links

Step 1. Choose an identify provider.

![](https://docs.difr.com/uploads/images/gallery/2025-10/advanced-integrations-select-idp.png)

Step 2. Choose a pool/instance type.

![](https://docs.difr.com/uploads/images/gallery/2025-10/advanced-integrations-select-pool.png)

<p class="callout info"> A single onboarded application or desktop can be used with multiple instance types. However, each instance type will have its own PWA link.</p>

Step 3. Copy the PWA link for your app or desktop by clicking the **Copy PWA link** button.

![](https://docs.difr.com/uploads/images/gallery/2025-10/copy-pwa-link.png)

That's it! You could test the links in a new tab to check for an install prompt and/or share it with a colleague or end user. Now that you have a PWA link, you've a few options for installation!

#### Manual PWA installation

To manually install a PWA (ideal for testing or smaller team sizes), open a PWA link on a device you would like to install it on. Once the page is loaded, look at Chrome's "omnibar" for a circular plus icon. Click it, then click **install**.

![](https://docs.difr.com/uploads/images/gallery/2025-10/pwa-chrome-install-prompt.png)

<p class="callout info"> Manual installation of PWAs is optional. Users can simply use the PWA link to launch the a session from within their browser (the option to install is still available).</p>

### Automatically install PWA Links with Managed Chrome

PWA links can be automatically deployed via Chrome to devices managed by administrative policies. There are two ways to manage Chrome:

- Cloud-managed (Google Workspace)
- Policies with on-premises tools

<p class="callout warning"> **Be Careful**  
 To ensure a great experience for your users, be sure your auth (identity provider and roles/permissions) and infrastructure capacity are properly configured before a large scale deployment of apps to your users.</p>

#### Deployment with Google Workspace (formerly G Suite) deployment-with-google

1. Workspace Admins need to log in to their Admin console and navigate to **Device Management** &gt; **Chrome** &gt; **Apps &amp; Extensions**.

![](https://docs.difr.com/uploads/images/gallery/2025-10/pwa-gsuite-add-by-url.png)

2. Click on the **Add** button at the bottom right of the page, and select **Add by URL** from the context menu. Paste your pre-configured Frame PWA link in the URL field and select “**Open website in Separate Window**, then click **save**.
3. Your PWA application should appear on signed-in Chrome devices within a few moments.

![](https://docs.difr.com/uploads/images/gallery/2025-10/pwa-gsuite-installed.png).

For more information, please read Google's documentation for [Adding Apps by URL](https://support.google.com/chrome/a/answer/6177447?hl=en).

#### Deployment with On-premises policies

Deploying PWA links with policies (Group Policies or otherwise) is pretty straight-forward. Please read Google's documentation on how to [Automatically install web apps](https://support.google.com/chrome/a/answer/9367354?hl=en).

### Uninstalling PWAs

PWAs are easy to uninstall. Users can simply uninstall them from the options menu at the top-right corner of the application. If you'd like to uninstall applications that were installed via Admin policies, simply remove the policy and give a small amount of time for the policy change to be reflected on connected devices – apps should be removed promptly.

### Troubleshooting PWAs

#### When my users visit a PWA link, there's no option to install

This can happen for a few different reasons.

**Troubleshooting tips:**

- Make sure your browser is fully up-to-date.
- Make sure your Browser and OS support PWAs. At the the time of writing, Firefox doesn't support Desktop PWAs but does Mozilla supports them on mobile.
- Make sure your **application's icon is at least 144x144px**, though 512x512 is recommended. Modern apps are typically fine but older apps might need a fresh coat of paint. Admins can upload custom app icons in the Dashboard.
- Try refreshing the page. Sometimes certain PWA assets take a while to download and the installation prompt isn't triggered.

#### Will my Frame PWA applications work when offline?

No. Frame requires an internet connection to work.

#### PWAs on mobile devices

While PWAs are cross-platform by nature, please be aware that some users may encounter different experiences with their apps due to smaller screen size and different input methods. Please be sure to test your apps on prospective devices/operating systems/browsers before recommending them to your users.

## Launch Links

### What are Launch links?

Launch links are an easy way for you to provide your users with a direct link to a specific app or desktop. When a user visits a Launch link, your chosen identity provider handles authentication. Once authenticated, loading these links will immediately start a Frame session for that user.

![](https://docs.difr.com/uploads/images/gallery/2025-10/launch-link-starting-session.png)

You can easily copy a Launch Link from the Advanced Integrations panel after configuring your desired identity provider and instance type.

![](https://docs.difr.com/uploads/images/gallery/2025-10/okta-copy-launch-link.png)

### Add a link to your website

Launch links are easy to tie to any website using standard HTML. For example:

```html
<a href="<paste your Launch link here>" target="_blank">
  A custom button
</a>

```

### Okta Chiclets

Already using Okta with Frame? Great! Launch links can be added as Okta Chiclets with the help of Okta's [**Bookmark App**](https://support.okta.com/help/s/article/How-do-you-create-a-bookmark-app?language=en_US). To get started, follow the steps below.

1. As an Okta Admin, let's add a new application.

![](https://docs.difr.com/uploads/images/gallery/2025-10/okta-applications.png)

2. Search for **Bookmark App** and select it.

![](https://docs.difr.com/uploads/images/gallery/2025-10/okta-search-applications.png)

3. Click on **Add**. Begin by adding the name of your Application into the *Application label* field.

![](https://docs.difr.com/uploads/images/gallery/2025-10/okta-add-bookmark.png)

4. Paste your **Launch link** (copied from Frame's Advanced Integrations dialog) into the URL field (be sure you've selected the right Okta identity provider before copying the link). Apply application visibility settings and click **Done**.

![](https://docs.difr.com/uploads/images/gallery/2025-10/okta-add-bookmark-app.png)

<p class="callout info"> As with PWA links above, a single onboarded application or desktop can be used with multiple instance types. However, each instance type will have its own Launch link.</p>

5. Click on your newly added Bookmark. Click the icon at the top left to update it for a better user experience.

![](https://docs.difr.com/uploads/images/gallery/2025-10/okta-customize-bookmark-icon.png)

1. Repeat these steps to add as many Launch links as you'd like for your users.
2. Finally, assign your Frame-powered Bookmark app(s) to your users/groups.

![](https://docs.difr.com/uploads/images/gallery/2025-10/okta-frame-apps-as-chiclets.png)

## Passing Data into Session

For customers who wish to pass data from the browser into the Frame session upon the user clicking on the onboarded application or desktop, these customers can add the `userData` name and corresponding value in the URL query string of the PWA or Launch URL. This mechanism can be used to pass user session context from a website into the workload VM for use by a custom script or application running within the workload VM.

An example of a Launch URL with the `userData` name-value pair in the query string would be:

```html
<a href="https://frame.nutanix.com/launch?terminalConfigId=1234567890&idp=nutanix-idp&userData=1234567890abcdef" target="_blank">
  A custom button
</a>

```

<p class="callout info"> If the userData value is a binary value, then it must be converted to a base64-encoded value before adding it to the query string. Once the userData value is passed into the remote VM, a script can base64-decode the value for further use.</p>

<p class="callout info"> Since the userData value is embedded in the URL and could be modified by the end user, the custom script or application within the workload VM should validate the userData value before using it.</p>

Details on how to obtain the `userData` value within the remote VM is discussed the section on [Retrieve userData from the remote system](https://docs.difr.com/link/176#bkmrk-retrieve-userdata-fr).

## Additional Query Parameters

Both Launch links and PWA links support a handful of URL search query parameters that allow you to customize the behavior of the links.

### Supported Query Params

- **`qlo`** - **true/false**. Forces a log out after a session closes.
- **`start`** - **true/false**. If true, the page will load and and wait for a user to start the session themselves. When a PWA is installed, this value is set to **true**.
- **`appName`** - Lets you customize the name of the application. Must be encoded as a URL-friendly search query *URI Component*.
- **`iconUrl`** - URI-Encoded URL of an icon/image you'd like front-and-center of the Launch PWA/Launch link.
- **`idp`** - Set when the URL is initially copied, but you can set it to your IdP of choice by its **integration name**.

**Desktop Launch Link example:**

```bash
https://use.difr.com/?terminalConfigId=$terminalConfigId&appId=desktop&appName=Acme%20Workspace&iconUrl=$UriEncodedIconUrl&start=true&qlo=true&idp=My-SAML-Provider

```

**Desktop PWA Example:**

```bash
https://use.difr.com/?terminalConfigId=$terminalConfigId&appId=desktop&appName=Acme%20Workspace&iconUrl=$UriEncodedIconUrl&start=true&qlo=true&idp=My-SAML-Provider

```

# USB Human Interface Device Support

This guide is intended for administrators wishing to integrate the use of USB Human Interface Device (HID) devices within their end user experience.

Frame now supports up to 10 USB HID input devices, such as 3D mice, game controllers, and joysticks, connected to the local endpoint, in addition to mouse and keyboard.

<p class="callout info"> **Considerations:**  
 - Frame Terminal running in a supported web browser only supports USB HID on Linux and macOS Chrome browser.  
 - Frame App fully supports USB HID on Linux, macOS, and Windows endpoints.</p>

## Requirements

For end users to use USB HID, the administrator must verify that the Frame Virtual USB driver has been installed on the Sandbox and published. The Frame Virtual USB driver is included in the Frame Guest Agent Installer and can also be downloaded using the Frame Agent Setup Tool (FAST). Both the FGA and FAST installers are available for download from our [Downloads page](https://files.difr.com/).

## Frame Virtual USB Driver

### Verification

Start by verifying you do have the Virtual USB driver installed in your Sandbox:

1. Power on the Sandbox if it is not already running.
2. Once you're in the Sandbox, verify that the Virtual USB driver has been installed by navigating to the Device Manager for your Sandbox. There will be a device named "Frame virtual devices". Selecting the Virtual USB Hub and examining the Driver Details will confirm that the Frame Virtual USB driver has been installed and operating correctly.

<figure id="bkmrk-device-manager---fra">![Device Manager](https://docs.difr.com/uploads/images/gallery/2025-10/hid-dev-manager1.png)

<figcaption>  
</figcaption></figure>### Installation

If the Frame virtual devices does not exist in the Device Manager, then:

1. Download the Frame Agent Setup Tool from the [Downloads page](https://files.difr.com/) inside the Sandbox and run the installer to install the **Virtual USB driver**.
2. When installation is complete, reboot your Sandbox to ensure that the Frame Guest Agent detects the Virtual USB driver.
3. You can follow the procedure above to verify that the Frame Virtual USB driver has been installed correctly.

## Frame Account Configuration

1. Once you have verified that the Virtual USB driver has been installed, close the Sandbox session and navigate to the "Settings" page in the account's Dashboard.
2. Under the "Session" tab, enable the USB Redirection toggle. Click "Save."

<figure id="bkmrk-session-settings---u">[![image.png](https://docs.difr.com/uploads/images/gallery/2026-01/scaled-1680-/672image.png)](https://docs.difr.com/uploads/images/gallery/2026-01/672image.png)

<figcaption>  
</figcaption></figure>3. You should now be able to test a USB Human Interface Device within your Sandbox.
4. Once you are ready to make USB HID support available to your users, publish the Sandbox to ensure the Frame Virtual USB driver is on your production workload VMs.

<p class="callout info"> Since the USB Redirection setting is in Session Settings, Frame Administrators can enable the USB Redirection policy at the Sandbox or for a specific Launchpad, instead of enabling the USB HID feature at the Frame account level.</p>

## End User Configuration

Depending on the combination of ways to access Frame, additional configuration may be required. The sections below detail additional setup instructions for your end users.

### Chrome on macOS or Linux

For users on macOS or Linux endpoints, they must use Chrome on macOS or Linux-based operating systems in order to use USB Human Interface Devices. End users should follow the steps below to complete configuration of USB HID support. Chrome users must enable the “Experimental Web Platform features” within the Chrome browser, as Google still considers USB HID and WebUSB support to be an experimental feature.

1. In a new Chrome browser tab, enter the following in the address bar:

```powershell
chrome://flags/#enable-experimental-web-platform-features

```

2. At the top of the page you will see the "Experimental Web Platform features" option. Use the drop-down menu to enable this feature.

<figure id="bkmrk-chrome-experimental-">![Chrome Experimental Web Platform features](https://docs.difr.com/uploads/images/gallery/2025-10/hid-chrome-enable.png)

<figcaption>Chrome Experimental Web Platform features</figcaption></figure>3. Click the "Relaunch" button at the lower right corner of the browser once the button appears at the bottom of the page to apply your changes.

<figure id="bkmrk-relaunch-chrome">![Relaunch Chrome](https://docs.difr.com/uploads/images/gallery/2025-10/hid-chrome-relaunch.png)

<figcaption>Relaunch Chrome</figcaption></figure>### Frame App on Linux

For USB devices that the user would like access to from their Linux endpoint, a `udev` rule must be created.

1. Create a file `50-usbdevices.rules` in `/etc/udev/rules.d`.
2. For each device, add a line as follows:

```powershell
SUBSYSTEMS=="usb", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c626", MODE="0664", GROUP="plugdev"

```

Replace `idVendor` and `idProduct` values with the actual values for the USB HID device. In the example above, the rule is written for device with `idVendor=046d` and `idProduct=c626` (the values are hexadecimal).

<p class="callout info"> The user running Frame application must be part of "plugdev" group.</p>

## Troubleshooting

- **Your device is not listed:**: If you find that your USB device is not showing up as an option in the device list, Frame is not recognizing your device. We recommend [creating a support case](https://docs.difr.com/books/dizzion-support/page/contact-support) for further evaluation.
- **Tooltip message “Not supported”**: Server does not support USB functionality. Either the Frame Guest Agent needs to be updated or the virtual USB driver needs to be installed. Note that driver may be installed, but Frame Guest Agent may need to be upgraded to the newer version of driver in order for the USB functionality to work properly.
- **Tooltip message “Cannot obtain devices from host”**: The application is having trouble accessing USB devices on the host machine (the machine where the application is installed and running).
- **Error message “Cannot plug in device”**: You may see this message after clicking on a device in the USB device list. This means that the Frame platform was unable to communicate with the USB device. We recommend creating a support case for further evaluation.
- **Error message "Cannot open connection to device: Access denied"**: When you click on your USB device in the list to "plug in" to your remote session, Frame could not open a connection to the device because the operating system is blocking the connection.
    
    
    - If Frame App is running on Linux, verify that the udev rules are applied to the local Linux endpoint. If udev rules are valid for Linux or the application is running on Windows or macOS, the operating system on your local endpoint is blocking the connection and will require further investigation.

### Testing your USB Device

You can open up a browser within your Frame session and visit an online resource such as https://gamepad-tester.com/ to test your USB HID devices. While we have tested and validated many brands and types of USB HID devices, there may be USB devices that do not work yet with Frame. If you would like to submit feedback, please [create a support case](https://docs.difr.com/books/dizzion-support/page/official-dizzion-support-guide).

# Clipboard Integration

The Clipboard Integration feature allows users to copy and paste content between their local device and their Frame session. This feature can be enabled by a Frame administrator in the Account or Launchpad Session Settings.

## Overview

Clipboard Integration in Frame enhances user productivity by providing seamless content transfer between local and remote environments. This feature is designed to support various use cases and accommodate different browser capabilities. Clipboard Integration in Frame offers two main functionalities:

1. **Clipboard Sync:** Automatically syncs clipboard content between local and Frame environments.
2. **Clipboard Manual Sync:** Provides a manual method for clipboard operations when automatic sync is not supported.

## Clipboard Sync

The Clipboard Sync feature automatically syncs clipboard content between your local device and Frame session, allowing copy and paste functionality. However, this feature has some limitations depending on the browser and content type.

#### Supported Content Types

- **Rich Text:** Applications that use HTML format support rich text clipboard operations. Some applications (e.g., office applications) may support this, but others, such as certain RTF editors, may not.
- **Images:** Only PNG images are supported for clipboard operations. Other image formats are not supported at this time.

### Limitations

- Copying content from a Word document that includes images and rich text is **supported**, but only if the application supports HTML format for clipboard operations.
- Clipboard Sync only works when clipboard sync is enabled by the user or administrator.
- The clipboard size limit is 10MB. Content larger than this will not be transferred.
- Bidirectional sync requires the use of `Ctrl+C` / `Ctrl+V` (Windows) or `Cmd+C` / `Cmd+V` (Mac). Rich text will not copy via mouse right-clicking alone.
- Copy-pasting from certain rich text editors may not work if they do not support HTML-based clipboard formats.

<figure id="bkmrk-">![Clipboard Sync Icon in Frame Session controls](https://docs.difr.com/uploads/images/gallery/2025-10/ngen-clipboardtoggle.png)

<figcaption>  
</figcaption></figure><p class="callout info"> To use Ctrl+C and Ctrl+V (Cmd+C and Cmd+V) for macOS) for copying rich text or files **within** your Frame session, Clipboard Sync **must be disabled**. When Clipboard Sync is enabled, you can still copy/paste rich text or files within the session by right-clicking and using the context menu.</p>

## Clipboard Manual Sync clipboard-manual-sync

For browsers that don't support Clipboard Sync, Frame provides a manual sync option:

1. Click the clipboard icon in Frame Session controls.
2. Use the dialog box to copy/paste text between your local machine and Frame session.

<figure id="bkmrk--1">![Clipboard Integration Icon in Frame Session controls](https://docs.difr.com/uploads/images/gallery/2025-10/ngen-clipboard.png)

<figcaption>  
</figcaption></figure>## Enable Clipboard Integration

The Clipboard Integration session setting is enabled by default on all Frame accounts. Administrators can disable/enable the Clipboard Integration and change its behavior for end users by clicking on “Settings” from the Dashboard menu on the left. From there, navigate to the “Session” tab. Under the “Features” section, enable/disable “Clipboard integration.”

Administrators can also choose the clipboard direction policy they would like to give their users access to:

- **Bidirectional**: This option enables users to copy/paste data between their local machine and their remote Frame session.
- **Local to remote**: This option limits users to only being able to copy data from their local machine to be pasted into their remote Frame session.
- **Remote to local**: This option limits users to only being able to copy data from their remote Frame session to be pasted into their local machine.

<figure id="bkmrk-settings-%3E-session--">![Settings > Session - Clipboard Integration](https://docs.difr.com/uploads/images/gallery/2025-10/ngen-clipboardadmin.png)

<figcaption>Settings &gt; Session - Clipboard Integration</figcaption></figure>Be sure to click **Save** to save your settings.

To read more about session settings, check out our [Session Settings](https://docs.difr.com/books/platform-administrators-guide/page/session-settings) documentation.

# Keyboard Profiles

Customers who need to map custom keyboard shortcuts on their end users' local device to keyboard shortcuts or actions within Frame sessions can use Frame's Keyboard Profile feature. Keyboard profiles consist of custom keyboard shortcut mappings that can be configured for a given keyboard language. Keyboard profiles are defined within Session Settings and can be applied at the account level and/or for a specific Launchpad, based on the needs of your end users.

Administrators can view, add, and modify keyboard profiles by navigating to the “Settings” page of the desired account and clicking on the “Session” tab or by navigating to a Launchpad and clicking on the kebab menu to reach "Session Settings".

<figure id="bkmrk-">[![image.png](https://docs.difr.com/uploads/images/gallery/2026-01/scaled-1680-/urUimage.png)](https://docs.difr.com/uploads/images/gallery/2026-01/urUimage.png)

<figcaption>  
</figcaption></figure>## Add a Keyboard Profile

1. If you would like to create a new keyboard profile from scratch, simply click on the blue “Add” link in the upper right corner of the “Keyboard profiles” section

<figure id="bkmrk-account-session-sett">![Account Session Settings - Add a Keyboard Profile](https://docs.difr.com/uploads/images/gallery/2025-10/keyboard-prof2.png)

<figcaption>Account Session Settings - Add a Keyboard Profile</figcaption></figure>2. Select the language of the endpoint devices and enter a name for your new profile. In this example, we will select the Serbian language and name our keyboard profile accordingly since the Windows OS in this account Sandbox has been configured to use Serbian as the default language. You can define multiple keyboard profiles, each corresponding to a specific language, as configured in your Frame account Sandbox.

<p class="callout info"> The operating systems in the tabs correlate with the user's \*\*endpoint operating system.\*\* For instance, if your users are accessing Frame/Frame App from Windows and macOS machines, you will want to specify your custom keyboard mapping under both the "Windows" and "macOS" tabs.</p>

<figure id="bkmrk--1">![Add a Keyboard Profile](https://docs.difr.com/uploads/images/gallery/2025-10/keyboard-prof3.png)

<figcaption>  
</figcaption></figure>3. If you already know which custom keyboard mappings you would like to apply, you can move on to the keyboard mapping section. If not, you can simply click “Add” to create your new keyboard profile and add/edit the keyboard mappings later.

## Edit a Keyboard Profile

1. Administrators can edit an existing keyboard profile by clicking on the kebab menu adjacent to the desired profile and selecting “Edit.”

<figure id="bkmrk--2">![Edit a Keyboard Profile](https://docs.difr.com/uploads/images/gallery/2025-10/keyboard-prof4.png)

<figcaption>  
</figcaption></figure><p class="callout info"> Default Keyboard ProfilesYou can edit your default keyboard profile for your account as desired; however, the default keyboard cannot be deleted from the account. If you would like to reset the default profile back to its original state, simply click on the adjacent kebab menu and select "Reset."</p>

<figure id="bkmrk--3">![Reset the Default Keyboard Profile](https://docs.difr.com/uploads/images/gallery/2025-10/keyboard-prof5.png)

<figcaption></figcaption></figure>## Add a New Keyboard Mapping

New keyboard mappings can be applied to existing or new keyboard profiles.

<p class="callout info"> It is important to note that some key combinations will not work in Frame Terminal or Frame App simply because they are intercepted by the endpoint's operating system (OS) or browser.</p>

For instance, CTRL + ALT + DEL on a Windows-based endpoint would not be passed into a Frame session because that key combination would be intercepted by the Windows OS. Similarly, CMD + P would be intercepted by the Safari browser on macOS as a print command and would not be passed into Frame browser-based session. For this reason, administrators should use the operating system tabs to apply their custom key mappings for **one or more of the four supported endpoint operating systems** their end users might use.

1. Start by adding/editing your keyboard profile (as shown in the sections above). Once you have opened the keyboard profile window, select the desired operating system tab and then click on the blue “Add New Keyboard Mapping” link. We will use macOS in this example.

<figure id="bkmrk--4">![Add new keyboard mapping](https://docs.difr.com/uploads/images/gallery/2025-10/keyboard-prof6.png)

<figcaption>  
</figcaption></figure>2. A new line will appear at the bottom of the list of shortcuts:

<figure id="bkmrk--5">![Add new keyboard mapping](https://docs.difr.com/uploads/images/gallery/2025-10/keyboard-map1.png)

<figcaption>  
</figcaption></figure>3. Click on the left side of the line to specify the client shortcut, as shown below. In this example, we're using the left command (⌘) key as our “modifier key” and entering the 4 key as our "shortcut key.”

<figure id="bkmrk-specifying-the-left-">![Defining the new keyboard mapping](https://docs.difr.com/uploads/images/gallery/2025-10/keyboard-map2.png)

<figcaption>Specifying the left ⌘ key plus the 4 key as the client side (local) shortcut</figcaption></figure>4. Click "Save" once you have specified the first portion of the key mapping.
5. Next, click on the right side of the line to add the corresponding shortcut/action that will occur when the keyboard shortcut is pressed on the client's endpoint.

- **Shortcut:** The first (shortcut) option can be used to designate a corresponding shortcut **within** the Frame session. For example, we could instruct Frame to interpret the left command (⌘) key combined with the 4 key as the left Windows (⊞) key plus the 4 key within the session. This could be helpful for users accessing Windows apps on Frame from a local Mac endpoint. Once you have designated the desired in-session shortcut using the buttons, click "Save."

<figure id="bkmrk-add-a-new-keyboard-m-1">![Add new keyboard mapping](https://docs.difr.com/uploads/images/gallery/2025-10/keyboard-map3.png)

<figcaption>Add a New Keyboard Mapping</figcaption></figure>- **Terminal action:** Select the blue "Switch to Action" link if you would prefer your shortcut be tied to a specific Frame terminal action. For this example, we will use our key mapping to open terminal settings within the Frame session. Once you have selected the desired action from the drop-down menu, click "Save."

<figure id="bkmrk--6">![Add a Terminal Action](https://docs.difr.com/uploads/images/gallery/2025-10/keyboard-map4.png)

<figcaption>  
</figcaption></figure>6. After adding your desired key mappings under the appropriate operating system tabs, click "Add" (if this is a new keyboard profile) or "Save" (if this is an existing keyboard profile) in the bottom right corner of the window to apply the changes to your keyboard profile.

## Delete a Keyboard Mapping

1. To delete an existing keyboard mapping, simply click on the delete (🗑) icon adjacent to the mapping you wish to delete.

<figure id="bkmrk-delete-a-keyboard-ma-1">![Delete a Keyboard Mapping](https://docs.difr.com/uploads/images/gallery/2025-10/keyboard-map-del.png)

<figcaption>Delete a Keyboard Mapping</figcaption></figure>2. Click the "Save" button in the bottom right corner of the window. If you accidentally deleted a keyboard mapping, simply click the

<p class="callout info"> Any changes made to keyboard profiles will take effect after the next session start for end users. Administrators are not required to publish their Sandbox to see changes propagate to end user sessions.</p>

## Edit a Keyboard Mapping

1. To edit a keyboard mapping, simply click on the component of the mapping you wish to change (the client shortcut or the remote shortcut/action) and modify as desired.

<figure id="bkmrk--7">![Edit a Keyboard Mapping](https://docs.difr.com/uploads/images/gallery/2025-10/keyboard-map-edit1.png)

<figcaption>  
</figcaption></figure>2. Click "Save" when you are finished.

<figure id="bkmrk--8">![Saved a Keyboard Mapping](https://docs.difr.com/uploads/images/gallery/2025-10/keyboard-map-edit2.png)

<figcaption>  
</figcaption></figure>3. Click "Save" when you are done editing the Keyboard Profile.

## Troubleshooting

In the event that an administrator has correctly configured a keyboard profile and finds that one or more of their shortcuts is not working in the session, there are some tools available for Windows-based accounts to verify that the shortcut is passing through to the session from the local endpoint. If your Sandbox and workloads are running Windows, consider following the steps below before filing a support case. If you are using a different operating system, please reach out to our support team for help.

1. First, download and run KeyboardStateView for Windows from [NirSoft's website](https://www.nirsoft.net/utils/keyboard_state_view.html). This application displays the current state and virtual key code of every key you press and does not require any installation process or additional files.

<p class="callout info"> Additional  
 LanguagesNirSoft provides instructions and zip files for additional languages on their website. Dutch, French, German, Greek, Japanese, Portuguese, and many other languages are available for testing.</p>

2. KeyboardStateView will display every key that you press in the application's UI, even when the application is not in focus. If you want to view the state of all keys, simply turn off the 'Show Only Keys Pressed In Last seconds' option under the "Options" menu.

You can use this tool to provide more specific information to your Frame support personnel when creating a support case.

# Mouse Modes

Since Frame is accessible from any device with a modern web browser, we've set up multiple mouse modes to navigate a Frame session. While our standard mouse configuration works for most use cases, there are some scenarios where a different mouse mode could be helpful. We'll outline different mouse modes and their corresponding use cases below.

## Enable Mouse Mode Selection

1. Navigate to the "Settings" page in your Dashboard to enable the mouse mode selection option. Click on the "Session" tab and scroll down to the "Advanced options" dialog.

Enter the following string in the "Advanced Terminal Arguments" field:

```powershell
    *features*mouseModes*isEnabled*=true

```

<figure id="bkmrk-enabling-mouse-mode-">![Enabling Mouse Mode Selection](https://docs.difr.com/uploads/images/gallery/2025-10/mouse-mode1.png)

<figcaption>Enabling Mouse Mode Selection</figcaption></figure>If you already have another string in the Advanced Terminal Arguments text area, simply separate the strings with a space. Be sure to click “Save” on this page when you're done to save your addition to the Advanced Terminal Arguments.

## Mouse Mode Selection in Frame Terminal

Once enabled, your users can change their mouse mode in the Frame session by clicking on the Mouse Mode icon on the right side of their Frame status bar.

<figure id="bkmrk-">[![image.png](https://docs.difr.com/uploads/images/gallery/2026-01/scaled-1680-/m6Gimage.png)](https://docs.difr.com/uploads/images/gallery/2026-01/m6Gimage.png)

<figcaption>  
</figcaption></figure>When the Mouse Mode icon is clicked, the Mouse Mode selection dialog window will appear.

<figure id="bkmrk--1">[![image.png](https://docs.difr.com/uploads/images/gallery/2026-01/scaled-1680-/wqeimage.png)](https://docs.difr.com/uploads/images/gallery/2026-01/wqeimage.png)

<figcaption>  
</figcaption></figure>## Types of Mouse Modes

### Standard

By default, a Frame session uses Standard mouse mode. In this mode, you can expect the same functionality and appearance you'd expect when using a regular PC. This mode is meant for normal use with most applications.

Standard mode with a touch-enabled device (such as an iPad) allows you to navigate the session using touch alone. For instance, you can move open windows in your session by holding your finger down on the title bar of the window and dragging it.

### Touchpad

Touchpad mode was created to provide extra precision when accessing a Frame session on touch-enabled devices. With Touchpad mode, you'll see a special gray cursor that you can move by pressing anywhere on the screen and dragging.

<figure id="bkmrk-touchpad-mode-cursor">![Touchpad Mode Cursor](https://docs.difr.com/uploads/images/gallery/2025-10/mouse-mode4.png)

<figcaption>Touchpad Mode Cursor</figcaption></figure>To left-click, tap once anywhere on the screen with the cursor placed in the area you'd like to click. To right-click, tap with two fingers anywhere on the screen. The cursor will show which button-click you are performing. For instance, a left-click in Touchpad mode looks like this:

<figure id="bkmrk-left-click-in-touchp">![Left Click in Touchpad Mode](https://docs.difr.com/uploads/images/gallery/2025-10/mouse-mode5.png)

<figcaption>Left Click in Touchpad Mode</figcaption></figure>### Relative

Relative mouse mode is intended for gaming and 3D world navigation. You'll want to first launch the application you're going to use, and then switch to relative mouse mode when you need to navigate a 3D environment. Once enabled, your cursor will disappear and you will be able to navigate your app like you would with any first-person point-of-view game.

To exit relative mouse mode, hit ESC on your keyboard.

# Multi-language Configuration

Configuring end user experiences for multiple languages in Frame requires careful consideration and planning. Microsoft Windows operating system can be configured to handle different keyboards/characters in addition to multiple display languages. Beyond the operating system, individual applications might require further configuration if the display language is not automatically detected by the application.

Customers who need to deliver a specific display language and keyboard layout on a per-session basis will need to dynamically alter the operating system of a VM before a Frame session is started using [pre-session scripts](https://docs.difr.com/scripting).

## Keyboard Layouts

Support for multiple keyboard layouts allows end users to choose a language to match the keys and characters on their keyboard. Keyboard layouts also determine which on-screen keyboard is used within the Windows environment if physical keyboards cannot be used (for touch displays, tablets, etc).

In a traditional Windows desktop environment, it is fairly easy to switch between multiple keyboard layouts by clicking on the keyboard icon located in the system tray. The keyboard switcher button will be in the bottom right corner of the keyboard.

<figure id="bkmrk-">[![image.png](https://docs.difr.com/uploads/images/gallery/2026-01/scaled-1680-/TBIimage.png)](https://docs.difr.com/uploads/images/gallery/2026-01/TBIimage.png)

<figcaption>  
</figcaption></figure>However, in cases where the end user only has access to individual applications through an Application Launchpad, the Windows system tray will not be visible and the Microsoft Windows keyboard layout switcher (Input Indicator or Language bar) may no longer be available. To accommodate cases where the Windows keyboard layout switcher is not available, Frame has placed a Frame Language swticher on the right side of the Frame status bar.

<figure id="bkmrk--1">[![image.png](https://docs.difr.com/uploads/images/gallery/2026-01/scaled-1680-/EFdimage.png)](https://docs.difr.com/uploads/images/gallery/2026-01/EFdimage.png)

<figcaption>  
</figcaption></figure><p class="callout info"> Note about Keyboard Layouts and Certain Keyboard ShortcutsCertain keyboard shortcuts can conflict with the native Windows keyboard shortcut that switches the current keyboard layout. For example, on macOS device, you can use a keyboard shortcut CMD + SHIFT + 3 to take a screenshot. The key combination to do this sends ALT + SHIFT to the Frame session and will switch the system's keyboard layout to another keyboard layout that is available  
  
 Conflicting shortcuts for OS X that may switch the keyboard layout include:  
 - Screenshot tool: CMD + SHIFT + 3  
 - Screenshot snip tool: CMD + SHIFT + 4  
 - Go to next tab: CMD + SHIFT +   
 - Go to previous tab: CMD + SHIFT + </p>

## Using a Single Language

The most common configuration would be to prepare your account's Sandbox with a default display language and a default keyboard layout other than US English.

You only need to change these settings once within the Sandbox desktop environment to permanently apply the changes to your account. After these adjustments are made and published, all production sessions will use the updated display language and keyboard layout.

## Changing the Default Display Language

The default display language setting can be configured in the "Language" section of the control panel on your Sandbox.

<figure id="bkmrk-windows-server-2016-">![Windows Server 2016 Control Panel - Language](https://docs.difr.com/uploads/images/gallery/2025-10/keyboard3.png)

<figcaption>Windows Server 2016 Control Panel - Language</figcaption></figure>From the “Language” section, you can specify the Windows display language by clicking on the Windows display language dropdown or set the default app language by promoting the specific language to be the first language on the list using the Up arrow.

<figure id="bkmrk-windows-server-2016--1">![Windows Server 2016 Control Panel - Promoting a Language](https://docs.difr.com/uploads/images/gallery/2025-10/keyboard4.png)

<figcaption>Windows Server 2016 Control Panel - Promoting a Language</figcaption></figure>You will then be asked to log off and then log back in to apply the changes.

<p class="callout info"> The above explanation assumes that you have already installed all language keyboards/packs that you require for your applications on the OS.</p>

## Change the Default Keyboard Layout

The default keyboard layout setting can be configured in the "Typing" section of the control panel on your Sandbox.

<figure id="bkmrk-windows-server-2016--2">![Windows Server 2016 Control Panel - Typing](https://docs.difr.com/uploads/images/gallery/2025-10/language1.png)

<figcaption>Windows Server 2016 Control Panel - Typing</figcaption></figure>Scroll down and select "Advanced keyboard settings" and then the keyboard layout from the “Override for default input method” dropdown list.

<figure id="bkmrk-windows-server-2016--3">![Windows Server 2016 Control Panel - Advanced keyboard settings](https://docs.difr.com/uploads/images/gallery/2025-10/language2.png)

<figcaption>Windows Server 2016 Control Panel - Advanced keyboard settings</figcaption></figure><p class="callout info"> The above explanation assumes that you have already installed all language keyboards/packs that you require for your applications on the OS.</p>

# Banners and Classification Labeling

## Custom Terminal Banner

Terminal banners display custom messages across the top of a user's Frame session. Banners can be used as a reminder to the user that they are using a special type of environment. This feature is often used for high security environments such as government, medical, and finance organizations. Administrators can specify the color and text of the banner for their own classification purposes.

1. To enable this feature within your Frame Account, navigate to the **General** tab listed under the **Settings** section of your Dashboard.

<figure id="bkmrk-dashboard-%3E-settings">[![image.png](https://docs.difr.com/uploads/images/gallery/2026-01/scaled-1680-/Zz7image.png)](https://docs.difr.com/uploads/images/gallery/2026-01/Zz7image.png)

<figcaption>Dashboard &gt; Settings &gt; General Settings</figcaption></figure>2. From there, you should see a section titled **Custom Banners**. Under this section, click on the **Enable Custom Terminal Banner** toggle to enable it. A new set of options will appear.
3. Set the banner color and text color by entering hex color codes in each field or clicking on the field to open the color chooser. Specify what you would like your banner to say by entering it in the **Message Text** field. Click **Save** to apply your changes.

<figure id="bkmrk-custom-terminal-bann-1">![Custom Terminal Banner Configuration](https://docs.difr.com/uploads/images/gallery/2025-10/banner2.png)

<figcaption>Custom Terminal Banner Configuration</figcaption></figure>4. Your banner can now be seen at the top of the Frame session.

<figure id="bkmrk-">[![image.png](https://docs.difr.com/uploads/images/gallery/2026-01/scaled-1680-/SXcimage.png)](https://docs.difr.com/uploads/images/gallery/2026-01/SXcimage.png)

<figcaption>  
</figcaption></figure>## Custom Login Banner

From the same section, you can also create a custom login banner for your users. Use the custom login banner to give your users special instructions or an important message if necessary. The end user must "accept" to continue to their Launchpad.

1. To enable this feature within your Frame Account, navigate to the **General** tab listed under the **Settings** section of your Dashboard.
2. From there, you should see a section titled **Custom Banners**. Under the this section, click on the **Enable Custom Login Banner** toggle to enable it. A new set of options will appear.
3. Set the title for your custom login banner and specify what you would want the users to agree to by entering the message in the **Message Text** field. Click **Save** to apply your changes.

<figure id="bkmrk-custom-login-banner-">![Custom Login Banner Configuration](https://docs.difr.com/uploads/images/gallery/2025-10/loginbanner.png)

<figcaption>Custom Login Banner Configuration</figcaption></figure>After your user logs in, they will see a white page displaying your message. They will need to click **I Accept** to be taken to their Launchpad.

<figure id="bkmrk--1">![Custom Login Banner](https://docs.difr.com/uploads/images/gallery/2025-10/loginbanner2.png)

<figcaption>  
</figcaption></figure>## Leveraging the Platform Hierarchy

Administrators with the appropriate role can set a default custom terminal or login banner at the Customer or Organization entity level. The custom terminal and login banner configurations are available on the Admin Console under Settings &gt; Settings at both the Customer or Organization entity levels.

<figure id="bkmrk-custom-login-banner--1">![Custom Login Banner at Customer Entity Level](https://docs.difr.com/uploads/images/gallery/2025-10/terminalbanner2.png)

<figcaption>Custom Login Banner at Customer Entity Level</figcaption></figure>Custom banners set at the Customer entity level will be copied to an Organization entity when the Organization entity is created. A custom banner set at the Organization entity level will be copied to the Frame account settings when a new Frame account is created.

<p class="callout info"> Custom banner definitions are \*\*not\*\* dynamically inherited from higher levels to lower levels of the Frame platform hierarchy. If you wish to leverage a custom banner at a lower level of the platform hierarchy, be sure to configure the custom banner first in the parent entity before creating the child entity.</p>

# Scripting

Frame Guest Agent (FGA) gives customers the ability to tailor the behavior of their workload VMs (e.g., Sandbox, shadow, production, utility server, etc.) to execute scripts at different event-points of a VM and/or user session. These events are defined as “lifecycle hooks.”

Once a Frame account is created, the Frame administrator can place custom scripts (PowerShell for Windows, Bash scripts for Linux) in the Sandbox and then publish the Sandbox to make them available to the workload VMs.

### Custom Script Location

<p class="callout info"> In the context of scripts, spaces are not valid characters. For example `script1.ps1` is a valid script name, while `script 1.ps1` is \*not\* valid.</p>

FGA scripts must be placed into a specific directory. The FGA Users Scripts directory for **Windows** VMs is:

`C:\ProgramData\Nutanix\Frame\FGA\Scripts\User`

Example valid script paths for **Windows**:

- `C:\ProgramData\Nutanix\Frame\FGA\Scripts\User\powershell\my_custom_script.ps1`
- `C:\ProgramData\Nutanix\Frame\FGA\Scripts\User\my_custom_script.ps1`
- `C:\ProgramData\Nutanix\Frame\FGA\Scripts\User\a\b\c\d\my_custom_script.ps1`

For **Linux** VMs, the FGA Users Scripts directory is:

`/opt/nutanix/frame/fga/scripts/user`

Example valid script paths for **Linux**:

- `/opt/nutanix/frame/fga/scripts/user/powershell/my_custom_script.sh`
- `/opt/nutanix/frame/fga/scripts/user/my_custom_script.sh`
- `/opt/nutanix/frame/fga/scripts/user/a/b/c/d/my_custom_script.sh`

### Script Invocation

Invoking or executing custom scripts requires a definition.yml file (case sensitive) to be present in the FGA User Scripts directory. For example, this path for Windows would be `C:\ProgramData\Nutanix\Frame\FGA\Scripts\User\definition.yml`. FGA reads this file at each lifecycle hook and will invoke scripts as defined in this file.

### Definition.yml

The `definition.yml` file describes detailed script context and execution information:

- Script **groups** -- a convenient way to group multiple scripts based on their context.
- Lifecycle hooks or **run-policies** -- phases in Frame's lifecycle of VMs and Sessions.
- Script **paths** and filenames -- only use relative paths (from the FGA Users Script directory) or filenames. Look out for typos!
- **Pool-types** -- specifies which type of Frame VMs you'd like the scripts to execute on (Sandbox, Production, etc.)
- **Error policies** -- specifies the behavior FGA should follow if an error is encountered: [continue or abort](#error-policy).

Below is an example of a definition.yml file.

```yaml
    groups:
    -
      desc: Scripts on first boot
      name: first-boot
      timeout: 30
      run-policy: first-boot
      pool-type:
        - sandbox
        - production
      scripts:
        -
          desc: My script A
          path: A.ps1
          error-policy: continue
          timeout: 10
        -
          desc: My script B
          path: B.ps1
          error-policy: continue
          timeout: 10
    -
      desc: Scripts on each boot
      name: every-boot
      timeout: 30
      run-policy: every-boot
      pool-type:
        - sandbox
        - production
      scripts:
        -
          desc: My script C
          path: C.ps1
          error-policy: continue
          timeout: 10
        -
          desc: My script D
          path: D.ps1
          error-policy: continue
          timeout: 10
    -
      desc: Scripts before session is started
      name: pre-session
      timeout: 30
      run-policy: pre-session
      pool-type:
        - sandbox
        - production
      scripts:
        -
          desc: My script before sessions is started
          path: before-session.ps1
          error-policy: continue
          timeout: 20
    -
      desc: Scripts after session is closed
      name: post-session
      timeout: 30
      run-policy: post-session
      pool-type:
        - sandbox
        - production
      scripts:
        -
          desc: My script after sessions is closed
          path: after-session.ps1
          error-policy: continue
          timeout: 20

```

## Script Execution Order

Order in the definition.yml file is important. When executing the scripts, FGA iterates through the definition.yml file and executes scripts in order from top to bottom. This also applies to Script Groups. If you provide two script groups of the same type (pre-session, post-session, etc), the group that is higher in the YAML file will get executed before any groups that are lower in the file.

In the following definition.yml example, Group 3 will get executed before Group 1 (since Group 3 is higher in the file). Also, `before-session-3.ps1` will get executed prior to `before-session-2.ps1` for the same reason:

```yaml
    groups:
    -
      desc: Group 3 - Scripts before session is started
      name: Group 3 Pre-session
      timeout: 30
      run-policy: pre-session
      pool-type:
        - production
      scripts:
        -
          desc: The 3 pre-session script
          path: before-session-3.ps1
          error-policy: continue
          timeout: 20
        -
          desc: The 2 pre-session script
          path: before-session-2.ps1
          error-policy: continue
          timeout: 20
    -
      desc: Group 1 - Scripts after session is closed
      name: Group 1 pre-session
      timeout: 30
      run-policy: pre-session
      pool-type:
        - production
      scripts:
        -
          desc: My script after sessions is closed
          path: after-session.ps1
          error-policy: continue
          timeout: 20

```

<p class="callout warning"> **Important!**  Each script will need to be fully completed before the next script is executed. (Sequential execution vs. parallel execution)</p>

## Frame Lifecycle Hooks

The following table outlines various Frame Lifecycle Hooks, used as values for run-policy in a definition.yml script group. Each lifecycle hook is optional.

### VM Lifecycle Hooks

<table id="bkmrk-%3Cdiv-style%3D%7B-%7Bwidth%3A"><thead><tr><th>Hook Name</th><th>Description</th><th>Applicable pool groups</th><th>User Context</th></tr></thead><tbody><tr><td>`pre-generalization`</td><td>Executed before Domain-Join generalization process (which includes sysprep) is started.</td><td>shadow, persistent\_desktop\_shadow</td><td>**Frame** user</td></tr><tr><td>`post-generalization`</td><td>Executed after Domain-Join generalization process (which includes sysprep) is finished.</td><td>shadow, persistent\_desktop\_shadow</td><td>**Frame** user</td></tr><tr><td>`first-boot`</td><td>Executed only on the very first boot of the virtual machine, after it is created. This hook is available for all instance types, allowing scripts to make stateful changes right after instances are provisioned/created. For domain joined instances and enterprise profiles, the local user `frameuser` needs to have elevated privileges.</td><td>shadow, production, persistent\_desktop\_shadow, persistent\_desktop\_production</td><td>**Frame** user</td></tr><tr><td>`every-boot`</td><td>Executed upon every system/OS boot. This hook can be used to update the image before non-persistence is enabled (on shadow/production instances).</td><td>shadow, production, sandbox, utility</td><td>**Frame** user</td></tr></tbody></table>

### Session Lifecycle Hooks

<table id="bkmrk-%3Cdiv-style%3D%7B-%7Bwidth%3A-1"><thead><tr><th>Hook Name</th><th>Description</th><th>Applicable pool groups</th><th>User Context</th></tr></thead><tbody><tr><td>`pre-session`</td><td>Executed right before a user session is started.  
 **User Context info:**  
For example, if the workload VM is joined to the domain and the user authenticates to the Windows domain, then the scripts would run in the domain user context. Pre-session scripts are executed after the Windows login screen and before the onboarded application or desktop is displayed. Pre-session scripts never run in SYSTEM context.</td><td>sandbox, production, persistent\_desktop\_production, utility</td><td>**Currently logged in user**</td></tr><tr><td>`on-idle`</td><td>Executed when session goes to idle state (workload stops streaming).</td><td>sandbox, production, persistent\_desktop\_production, utility</td><td>**Currently logged in user**</td></tr><tr><td>`on-active`</td><td>Executed when session goes from idle to active state (workload resumes streaming).</td><td>sandbox, production, persistent\_desktop\_production, utility</td><td>**Currently logged in user**</td></tr><tr><td>`post-session`</td><td>Executed immediately after a session is closed. This occurs after the session has stopped streaming and before both the Windows logoff process and the profile disk unmount process.</td><td>sandbox, production, persistent\_desktop\_production, utility</td><td>**Currently logged in user**</td></tr></tbody></table>

### Script User Context (Windows)

It is important for Frame administrators to know which Windows user is running which script. Refer to the table above to see each lifecycle hook and their associated execution context. Frame's default `Frame` user is a member of the local Windows administrator group.

To determine the user context, you can execute `whoami` within your script and it will print out the current script context.

### Script Group Properties

#### desc

> A detailed description of the group.

#### name

> A descriptive name of the group.

#### timeout

> Integer value in seconds. Defines the maximum amount of time for *all scripts executing within a group*. If the execution time of the scripts exceeds this timeout value, FGA will kill the currently running script and skip any remaining the scripts in the group.

#### run-policy

> Defines the Frame Lifecycle Hook that will execute the scripts.

#### pool-type

> Defines target pool types on which the scripts in the group are going to be applied. If none of the pool types is set, FGA will execute the script on all pool types.
> 
> **Pool types and descriptions**
> 
> - `sandbox` - Scripts are going to be applied only on sandbox VMs
> - `production` - Scripts are going to be applied only on production VMs
> - `shadow` - Scripts are going to be applied only on shadow VMs that are part of the publishing process
> - `utility` - Scripts are going to be applied only on utility VMs
> - `persistent_desktop_production` - Scripts are going to be applied on persistent desktops
> - `persistent_desktop_shadow` - Scripts are going to be applied on freshly provisioned persistent desktops that are not yet assigned

<p class="callout info"> Newly published VMs that have been placed in the production pool will still be marked as `shadow` until they are rebooted.</p>

#### scripts

> Specifies the list of scripts that needs to be executed.

<p class="callout success"> **Did you know?**  A “pool” in Frame's context is a grouping of VMs/instances associated with a Frame account.</p>

### Script Item Properties

#### desc

> Description of the script.

#### path

> Script file location, relative to base user scripts directory.

#### error-policy

> Defines FGA strategies when script fails.
> 
> Follow these three simple steps to get started creating scripts and customizing the VMs on first boot (or every boot) and your Frame sessions.
> 
> **Error-policy values**
> 
> - `continue` - FGA to proceed on even if the script fails.
> - `abort` - FGA to abort the task if script fails; **use with caution.**
>     - For Session Lifecycle hooks, this will immediately end the session for the end-user.
>     - For VM Lifecycle hooks, this can prevent publishes from completing, or spinning up new instances when the pool's capacity is expanded

#### timeout{#script-timeouts}

> Integer value in seconds. Defines the maximum amount of time for the script to run. If the execution time of the script exceeds the timeout value, FGA will kill the running script. **Be sure that your script's combined timeouts are less than or equal to the group's timeout duration.**

## Getting Started

Follow these three simple steps to get started creating scripts and customizing the VMs on first boot (or every boot) and your Frame sessions.

### 1. Create a Simple Script

Create a new PowerShell file (hello-world.ps1) in the FGA Scripts User directory.

```powershell
# Writing a simple text file with warm greeting.
$timestamp = Get-Date -Format "dddd MM/dd/yyyy HH:mm K"
"$timestamp - Hello, World!" | Out-File "C:\ProgramData\Nutanix\Frame\Logs\sandbox_greeting.txt" -Append

```

### 2. Your *definition.yml*

Next, you need to communicate to FGA about this script via a `definition.yml` file to specify which Frame Session Lifecycle hook will trigger this script, timeout settings, the pool type(s), etc.

```yaml
groups:
-
  desc: Simple script example
  name: A very simple pre-session script.
  timeout: 10
  run-policy: pre-session
  pool-type:
    - sandbox
  scripts:
    -
      desc: Frame Hello World Example script!
      path: hello-world.ps1
      error-policy: continue
      timeout: 10

```

The `definition.yml` file specifies that we have one script group that only executes during the pre-session Lifecycle Hook. We also specify that this group should only execute on the sandbox instance *pool*. Next, we specify a single script called `hello-world.ps1`. This script can run for a maximum of 10 seconds before reaching either timeout value, causing FGA to quit waiting and continue on.

### 3. Testing and Debugging

Finally, double-check to make sure the files are saved, named correctly, and are located in the correct locations. Next, quit your sandbox session. Now we're ready to test!

Testing our script is simple. When starting a new Sandbox Session, you should see a file populated at `C:/sandbox_greeting.txt`, showing our execution timestamp and our greeting.

## Logging and Troubleshooting

Logging can be incredibly useful for debugging. However, if you're using non-persistent desktops and trying to debug scripts in production, any logging you do on the VM is wiped out after the session.

### Logging tips for various environments

1. **Sandbox and Persistent Desktops**: Create any text file somewhere on C: with the output of your logs.
2. **Non-persistent Shadow and Production VMs**: External logging service, either on the public internet (like Loggly, Splunk, etc.) or perhaps a service running on an accessible Utility Server.

### Troubleshooting Tips

- Be mindful of about [group](#group-timeouts) and [script](#script-timeouts) timeouts, how they're different, and that your values don't overlap.
- Always take backups before scripting.
- If your scripts reference any file paths, be sure to use absolute filepaths, even for files residing in the FGA User Scripts folder.
- If possible, test by executing the Powershell code in the Sandbox using PowerShell ISE.
- If your scripts contain any sensitive information or credentials, be sure to write a cleanup pre-session script that can execute after your credentials are used and *delete the sensitive script/files* before users are connected to a Session.
- Use identifying elements from Frame environment variables to help understand who and when (if needed).
- You can set and get environment variables or registry entries to help communicate between scripts and lifecycle hooks.
- Avoid using `error-policy: abort` for sandbox scripts, as failing scripts can make the Sandbox inaccessible, requiring a restoration from a backup or termination (and recreation) of the Sandbox.
- If your scripts need to run with Elevated Privilege in Windows 10, make sure that the below registry key value is set to `0`. Otherwise, your scripts will fail due to Microsoft Windows User Account Controls (UAC) preventing the script from executing in an elevated context.
    
    
    - Key: `SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System`
    - Value: "EnableLUA"
    - Type: `REG_DWORD`

### Environment Variables

FGA populates environment variables via registry entries to `HKCU/Environment`. These values are dynamically set for each Frame session and are useful when used with logging.

<table id="bkmrk-env-variable-descrip"><thead><tr><th>Env Variable</th><th>Description</th></tr></thead><tbody><tr><td>`FRAME_VENDOR_ID`</td><td>A unique identifier tied to the Frame Account the VM is associated with.</td></tr><tr><td>`FRAME_VENDOR_NAME`</td><td>The name of the instance's Account.</td></tr><tr><td>`FRAME_USER_EMAIL`</td><td>The current session user's email address.</td></tr><tr><td>`FRAME_SESSION_ID`</td><td>The unique Session ID associated with the current session. Useful for debugging and support purposes.</td></tr><tr><td>`FRAME_SESSION_INFO`</td><td>Provides additional session information represented within a JSON object: `colorspace` (`YUV420` or `YUV444`), `protocol` (`FRP7` or `FRP8`), and `connectionType` (`tcp` or `udp`)</td></tr><tr><td>`FRAME_SESSION_LABEL`</td><td>Custom value set in Session Settings through the [Advanced Server Argument](https://docs.difr.com/platform/session/session-settings#advanced-arguments) `-frame-session-label`</td></tr><tr><td>`FRAME_SESSION_TOKEN`</td><td>Unique token specific to the session. This token can be used to query user assertion/claims data, or base64 decoded to access various user and authentication-related data.</td></tr><tr><td>`FRAME_VENDOR_EMAIL`</td><td>Contrary to the name, this value is the unique GUID associated to the Frame account the VM belongs to.</td></tr><tr><td>`FRAME_MAX_SESSION_DURATION`</td><td>The maximum amount of time (in seconds) the user can be in the session. This value is set in the Account, Launchpad, Sandbox, and Utility Server session settings.</td></tr><tr><td>`FRAME_SESSION_START_TIME`</td><td>The date/time when the session started.</td></tr><tr><td>`FRAME_POOL_GROUP_TYPE`</td><td>Type of pool group the session is currently connected to (`sandbox`, `production`, `test`, `utility`).</td></tr><tr><td>`FRAME_POOL_NAME`</td><td>Name of instance pool the session is currently connected to as defined within *Dashboard* &gt; *Capacity*</td></tr><tr><td>`FRAME_INSTANCE_TYPE`</td><td>The instance type name of the current instance.</td></tr><tr><td>`FRAME_IMAGE_FAMILY`</td><td>Image Family Name that the instance is based off of.</td></tr><tr><td>`FRAME_DATACENTER`</td><td>Name of the datacenter where the instance is located.</td></tr><tr><td>`FRAME_CLOUD_PROVIDER`</td><td>Name of the infrastructure provider (`ahv`, `azure`, `gcp`, `amazon`).</td></tr></tbody></table>

## Frame Script Helper Tool

Frame Script Helper is a tool designed for the creation and maintenance of the ***definition.yml*** file. Frame Script Helper can be found in `C:\ProgamData\Nutanix\Frame\Tools`. Key tool features include the import, validation, editing, and export of definition.yml files.

<p class="callout info"> As this tool was written for Windows, it only supports `.ps1` scripts.</p>

### Import and Validation of the Definition.yml File

Importing the definition.yml file can be accomplished in two ways:

- **Automatically**: When launched the tool will search for a definition.yml file in `C:\ProgramData\Nutanix\Frame\FGA\Scripts\User`
- **Manually**: By using the import section from toolbar menu: Configuration&gt;Import

<p class="callout info"> The file will not be imported until any errors are resolved.</p>

If the tool cannot find a definition.yml file at startup, it will display a prompt; you can still continue using the tool. All changes will be saved afterwards into a new definition.yml file.

### Edit the Definition.yml File

All available Frame Lifecycle hooks ([see above](#-frame-lifecycle-hooks) for hook definitions) are displayed to the left of the tool window.

To begin, select one of the hooks. By default, "first-fga-boot" is selected. Next to the name of the hook are two numbers. The first number represents the number of pool-type groups, the second represents the total number of scripts assigned to that hook.

To attach your scripts to the selected hook, drag scripts files from File Explorer into the drop area at the top of the screen.

<p class="callout info"> Another way to import the scripts is to directly drag their file onto the existing pool-type group.</p>

Next, a prompt will ask you to specify the pool-type groups for your scripts. Check the box next to each desired pool and click “Next” when all desired options are checked.

![Frame Script Helper Tool - Pool Types](https://docs.difr.com/uploads/images/gallery/2025-10/shelper2.png)

### Changing Script Order

To change the order of the scripts, simply drag a script to desired position in the pool-type group.

<p class="callout info"> Scripts can only be moved within the current group, not to another.</p>

### Rearranging the Pool-Type Groups

Order of the pool-types can be also changed. Each of the pool-type group "box" can be dragged over the other group.

### Export the Definition.yml File

After making your changes, you can save your file by clicking “File” and then “Save”, or even export it to a new file from **Configuration &gt; Export**.

![](https://docs.difr.com/uploads/images/gallery/2025-10/shelperconfiguration.png)

## Advanced Scripting

### Update Script (Windows only)

If found, FGA will execute an “update” script right after a VM boots, but *before FGA User scripts are executed*. This allows Frame administrators to create custom update scripts to automated or dynamic maintenance operations on their custom scripts and files before user scripts defined in definition.yml are executed. The update script must be in the following path:

`C:\ProgramData\Nutanix\Frame\FGA\Scripts\User\update.ps1`

Updating the user scripts might include completely new packages of scripts or just a new definition.yml file. The following are best practices when it comes to updating your custom scripts using the Update script feature.

1. Make sure your updated scripts and/or definition.yml are packaged in a bundle.
2. Make sure your workload VMs are able to access and download that bundle.
3. Create an update script that downloads the package and checks if there is a need for the update to be applied. 
    - If not, the "update" script should just exit.
    - If yes, the "update" script should perform the update (it can delete existing definition.yml and all script files and then recreate definition.yml file and/or scripts).
4. Place the update script content inside the update.ps1 (for Windows) and update.sh (for Linux).

When the VM gets into boot phase, FGA is going to search for the "update" script. If it does not find the script, FGA will read the definition.yml file and run the scripts as they are defined in the definition.yml file. If the FGA finds the "update" script, FGA will execute the script first. Once the script is executed, FGA will proceed to execute the custom scripts following the definition.yml file.

If the update script on Windows OS takes more than 10 minutes to execute, FGA will timeout and continue with its startup workflow.

## Example Scripts

Below are some example use cases where a custom script and associated definition.yml file can customize the end user experience.

### Mount a Network Volume

**Scenario**: A Frame administrator would like to mount an existing read-only file share once a user starts a Frame session in either the Sandbox (Frame administrator) or a production workload VM (user).

The following simple PowerShell script "mount-read-only-volume.ps1" is placed in the scripts folder to be executed:

```batch
echo off
net use * /delete /Y
net use K: \\10.0.0.5\Fileshare /user:username password

```

The corresponding **definition.yml** file:

```yaml
groups:
-
  desc: Scripts before session is started in either Sandbox or production workload VMs
  name: pre-session
  timeout: 30
  run-policy: pre-session
  pool-type:
    - sandbox
    - production
  scripts:
    -
      desc: Pre-session script to mount a read-only volume
      path: mount-read-only-volume.ps1
      error-policy: continue
      timeout: 20

```

### Exclusion/Inclusion Rules for Enterprise Profiles

**Scenario**: A Frame administrator wishes to exclude specific folders from persisting and/or include specific folders to persist in users' enterprise profiles. The following PowerShell script “exclude-include-folders.ps1” is placed in the scripts folder to be executed:

```powershell
# Exclude four folders in the %USERPROFILE%
Add-ProfileDiskExclusion -SourcePath $env:USERPROFILE\Downloads -TargetPath C:\_Profile
Add-ProfileDiskExclusion -SourcePath $env:USERPROFILE\Music -TargetPath C:\_Profile
Add-ProfileDiskExclusion -SourcePath $env:LOCALAPPDATA\Autodesk -TargetPath C:\_Profile
Add-ProfileDiskExclusion -SourcePath $env:LOCALAPPDATA\Spotify -TargetPath C:\_Profile

# Include two separate folders C:\MyData and C:\MoreData to the user's enterprise profile.
Add-ProfileDiskInclusion -SourcePath C:\MyData
Add-ProfileDiskInclusion -SourcePath C:\MoreData

```

The corresponding definition.yml file specifies that this PowerShell script should only be executed in the context of production workload VMs where the user's enterprise profile volume is used (in a non-persistent Frame account):

```yaml
groups:
-
  desc: Scripts before session is started in production workload VMs
  name: pre-session
  timeout: 30
  run-policy: pre-session
  pool-type:
    - production
  scripts:
    -
      desc: Pre-session script to include/exclude folders from the user's enterprise profile
      path: exclude-include-folders.ps1
      error-policy: continue
      timeout: 20

```

### Autohide the Windows Task Bar in App Mode 2.0

**Scenario**: A Frame administrator wants to have the Windows Task Bar automatically hidden when using an Application Launchpad with App Mode 2.0. The Windows registry key that controls this behavior is at `HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\StuckRects3`. The following PowerShell script is placed in the scripts folder to be executed:

```powershell
$p='HKCU:SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\StuckRects3';
$v=(Get-ItemProperty -Path $p).Settings;
$v[8]=1;
Set-ItemProperty -Path $p -Name Settings -Value $v;
Stop-Process -f -ProcessName explorer

```

The corresponding definition.yml file specifies that this PowerShell script should only be executed in the context of production workload VMs:

```yaml
groups:
-
  desc: Scripts before session is started in production workload VMs
  name: pre-session
  timeout: 30
  run-policy: pre-session
  pool-type:
    - production
  scripts:
    -
      desc: Pre-session script to autohide the Windows Task Bar
      path: autohide-taskbar.ps1
      error-policy: continue
      timeout: 20

```

If you wish to show the Windows Task Bar, then the PowerShell script can be used:

```powershell
$p='HKCU:SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\StuckRects3';
$v=(Get-ItemProperty -Path $p).Settings;
$v[8]=2;
Set-ItemProperty -Path $p -Name Settings -Value $v;
Stop-Process -f -ProcessName explorer

```

### Add Applications dynamically to the Frame Taskbar in App Mode 2.0

**Scenario**: A Frame administrator needs to dynamically add an application shortcut/launch link to the Frame Taskbar in App Mode 2.0. App Mode 2.0 allows you to dynamically modify the Frame Taskbar to any configuration you need (in real time).

The following PowerShell script should be placed in the scripts folder to be executed. This is designed as a pre-session script that modifies the Frame Taskbar configuration before the session starts. The script will override any of the default Frame Taskbar configuration and show Notepad only (update-taskbar.ps1):

<p class="callout info"> Notice that any URI path requires two backslashes in the path (Within the JSON file only)</p>

```powershell
$jsonFilePath = 'C:\ProgramData\Nutanix\Frame\Config\server_launchpad_override.json'

$jsonOverrideContent = @"
{
    "name": "root",
    "order": 0,
    "applications": [
        {
            "name": "Frame",
            "path": "C:\\Windows\\System32\\notepad.exe",
            "icon_url": "",
            "order": 0,
	    "arguments": ""
        }
    ],
    "folders": []
}
"@

Set-Content -Path $jsonFilePath -Value $jsonOverrideContent

```

The corresponding definition.yml file specifies that this PowerShell script should only be executed in the context of production workload VMs:

```yaml
groups:
-
  desc: Scripts before session is started in production workload VMs
  name: pre-session
  timeout: 30
  run-policy: pre-session
  pool-type:
    - production
  scripts:
    -
      desc: Pre-session script to add Notepad into the Frame Taskbar icon/shortcut list 
      path: update-taskbar.ps1
      error-policy: continue
      timeout: 20

```

## Playing in the Sandbox

In this example, we'll create a few more scripts, each set to execute at common session lifecycle hooks.

<p class="callout info"> Before continuing with any changes to your sandbox, please make a backup first! Sandbox scripts, if improperly configured, can cause undesired behaviors and in some cases can cause the sandbox to become unresponsive, requiring restoration from a backup or a fresh sandbox.</p>

To get started, grab your shovel and connect to your Sandbox. Then, open up your favorite text editor and create the following **five** files in the **FGA User Scripts Directory**.

**Pre-session script: pre-session.ps1**

To test this, the scripts will create or append to a single log file created at `.\logs\sandbox_bucket.txt` with a timestamp and message from the script.

```powershell
$RootPath = "C:\ProgramData\Nutanix\Frame\FGA\Scripts\User"
If (!(test-path "$RootPath\logs")){ New-Item -Path "$RootPath\logs" -Type Directory }
$timestamp = Get-Date -Format "dddd MM/dd/yyyy HH:mm K"
"$timestamp - Hello from pre-session.ps1" | Out-File "$RootPath\logs\sandbox_bucket.txt" -Append

```

**Session Disconnect script: on-idle.ps1**

```powershell
$RootPath = "C:\ProgramData\Nutanix\Frame\FGA\Scripts\User"
If (!(test-path "$RootPath\logs")){ New-Item -Path "$RootPath\logs" -Type Directory }
$timestamp = Get-Date -Format "dddd MM/dd/yyyy HH:mm K"
"$timestamp - Hello from on-idle.ps1" | Out-File "$RootPath\logs\sandbox_bucket.txt" -Append

```

**Session Resume script: on-active.ps1**

```powershell
$RootPath = "C:\ProgramData\Nutanix\Frame\FGA\Scripts\User"
If (!(test-path "$RootPath\logs")){ New-Item -Path "$RootPath\logs" -Type Directory }
$timestamp = Get-Date -Format "dddd MM/dd/yyyy HH:mm K"
"$timestamp - Hello from on-active.ps1" | Out-File "$RootPath\logs\sandbox_bucket.txt" -Append

```

**Post-session script: post-session.ps1**

```powershell
$RootPath = "C:\ProgramData\Nutanix\Frame\FGA\Scripts\User"
If (!(test-path "$RootPath\logs")){ New-Item -Path "$RootPath\logs" -Type Directory }
$timestamp = Get-Date -Format "dddd MM/dd/yyyy HH:mm K"
"$timestamp - Hello from post-session.ps1" | Out-File "$RootPath\logs\sandbox_bucket.txt" -Append

```

Let's walk through each line in these files.

- **Line 1**: This line declares the root path as a variable variable. We could also use `Set-Location`.
- **Line 2**: Creates the log folder inside of the root path if it doesn't exist.
- **Line 3**: Gets a timestamp in a readable format (based on the Sandbox's local time).
- **Line 4**: Writes our timestamp and hello message to the specified "sandbox\_bucket" txt file.

**Defining our scripts: definition.yml**

We'll create four different script *groups* (one for each lifecycle hook). These scripts will only execute on the Sandbox; each will have a total of 5 seconds to execute (timeout); and if these scripts fail for any reason, FGA will continue with the next lifecycle procedures.

```yaml
groups:
-
  desc: Pre-session script
  name: Pre-session script group
  timeout: 5
  run-policy: pre-session
  pool-type:
    - sandbox
  scripts:
    -
      desc: Example sandbox pre-session script.
      path: pre-session.ps1
      error-policy: continue
      timeout: 5
-
  desc: On-idle disconnect script
  name: On-idle script group
  timeout: 5
  run-policy: on-idle
  pool-type:
    - sandbox
  scripts:
    -
      desc: Example sandbox on-idle script.
      path: on-idle.ps1
      error-policy: continue
      timeout: 5
-
  desc: On-active resume script
  name: On-active script group
  timeout: 5
  run-policy: on-active
  pool-type:
    - sandbox
  scripts:
    -
      desc: Example sandbox on-active script.
      path: on-active.ps1
      error-policy: continue
      timeout: 5
-
  desc: Post-session script
  name: Post-session script group
  timeout: 5
  run-policy: post-session
  pool-type:
    - sandbox
  scripts:
    -
      desc: Example sandbox post-session script.
      path: post-session.ps1
      error-policy: continue
      timeout: 5

```

<p class="callout info"> Notice that we're only setting `- sandbox` for each \*\*pool-type\*\*. Publishing this Sandbox configured like this would ensure that these scripts will not execute on any other VM on this account (Shadow, non-persistent Production, Persistent VM instances).</p>

### Testing our Sandbox scripts

You made it this far, you have your scripts and definition.yml file in place on the Sandbox, great! Let's test. Before we do, **changes to the definition.yml are active in real-time**. The Frame Guest Agent (FGA) does a fresh read of the definition.yml at each Session lifecycle hook. This means that if you are in your Sandbox session right now, we can test the disconnect and resume scripts by disconnecting from your Sandbox using the Gear menu at the bottom left corner of the Frame Session. Next, resume the session -- we should see two new log entries in our `/logs/sandbox_bucket.txt` files.

Let's test all four lifecycle hooks.

1. This time, **quit the session** via the Gear menu. Wait for the session to fully close.
2. Once you can, **start a new session**.
3. **Disconnect** from the Gear Menu. This will fire our disconnect or "on-idle" script.
4. **Resume the Session**. This will trigger our resume or "on-active" script.
5. **Close the session**.
6. Finally, **start one more session** to verify our `sandbox_bucket.txt` file contains messages and timestamps in order.

That's it! If you run into any problems, here are a few basic troubleshooting steps before contacting Support:

1. Please ensure that your files are in the correct paths.
2. Please ensure that the file names match in the directory as well as in the definition.yml file.
3. Test your PowerShell scripts manually from the Sandbox.

<p class="callout success"> **Cleanup**  Once you're done with testing these scripts and scenarios, all you need to do is remove the scripts from the definition.yml, delete the files, or customize them to your liking!</p>

## Onboarding Applications via CLI

Onboarding Windows applications to a Sandbox can be automated. If the applications are present on the Sandbox, we have a command-line utility that can be used to onboard a single application, multiple applications, or multiple apps defined in a file.

Introducing ShellHandler! Find and run `ShellHandler.exe` located in `C:\Program Files\Nutanix\Frame\Server\`. Using the command-line arguments listed below, you can onboard applications in a number of ways:

### ShellHandler Arguments

<table id="bkmrk-%3Cdiv-style%3D%7B-%7Bwidth%3A-2"><thead><tr><th>&lt;div style={ {width: "150px"} }&gt;Command-line Argument</th><th>Description</th></tr></thead><tbody><tr><td>`onboard`</td><td>Instructs the ShellHandler that we're onboarding an application or more. onboard must be the first argument and proceeded next by one of the three following onboard options.   
  
**Example:**  
`ShellHandler.exe onboard -i C:\MyApp.exe -s`</td></tr><tr><td>`--item` or `-i`</td><td>Onboard a single application item by filepath.   
  
**Example:**  
`ShellHandler.exe onboard --item C:\MyApp.exe -s`</td></tr><tr><td>`--list` or `-l`</td><td>Onboard multiple applications via a list of application filepaths.   
  
**Example:**  
`ShellHandler.exe onboard --list "C:\MyApp1.exe, C:\MyApp2.exe, C:\MyApp3.exe" -s`</td></tr><tr><td>`--file` or `-f`</td><td>Onboard multiple applications via a file containing a list of application filepaths.   
**C:\\ExampleAppList.txt:**   
C:\\MyApp1.exe   
C:\\MyApp2.exe   
C:\\Program Files\\TestApp\\HelloWorld.exe   
  
**Example:**  
`ShellHandler.exe onboard --file C:\ExampleAppList.txt -s`</td></tr><tr><td>`--silent` or `-s`</td><td>If present, application(s) filepaths will be onboarded without any user prompt.   
  
**Example:**  
`ShellHandler.exe onboard -i C:\MyApp.exe --silent`</td></tr></tbody></table>

# USB Peripheral Support

The **Frame Platform** provides flexible peripheral support to meet diverse enterprise needs through both **browser-based** and **Frame App** deployment options.

For standard office peripherals like keyboards, mice, webcams, and microphones, users can access their devices directly through **browser-based Frame sessions**.

For organizations requiring support for specialized industry devices - common in education, financial services, healthcare, and professional design environments, **Frame App** offers enhanced USB support.

This dual approach ensures organizations can choose the deployment method that best matches their peripheral requirements while maintaining **security and performance**.

# Considerations

Before implementing Frame Platform’s peripheral support, it’s important to assess your organization’s specific needs. Consider the types of devices your users require, their work patterns and any industry-specific requirements.

This discovery process will help determine whether browser-based Frame or Frame App is the most suitable deployment option for your environment.

## Key Questions

- Are your users primarily using standard keyboards, mice, webcams, and microphones?
- Do your users need to connect specialized USB devices (healthcare peripherals, security dongles, CAD controllers)?
- Will users need access to smart card readers or document scanners?
- Is basic browser-based peripheral support sufficient for your workflows?
- Do you require enhanced USB device support beyond standard input/output devices?

**Supported Peripheral Use Cases**

<table border="0" cellpadding="0" cellspacing="3" class="MsoNormalTable" id="bkmrk-user-type-required-p" style="mso-cellspacing: 1.5pt; mso-yfti-tbllook: 1184;"><thead><tr style="mso-yfti-irow: 0; mso-yfti-firstrow: yes;"><td style="padding: .75pt .75pt .75pt .75pt;">**User Type**

</td><td style="padding: .75pt .75pt .75pt .75pt;">**Required Peripherals**

</td><td style="padding: .75pt .75pt .75pt .75pt;">**Recommended Approach**

</td><td style="padding: .75pt .75pt .75pt .75pt;">**Additional Details**

</td></tr></thead><tbody><tr style="mso-yfti-irow: 1;"><td style="padding: .75pt .75pt .75pt .75pt;">**Standard Office User**

</td><td style="padding: .75pt .75pt .75pt .75pt;">• Standard keyboards and mice   
• Webcams   
• Headsets/microphones   
• Basic document scanners

</td><td style="padding: .75pt .75pt .75pt .75pt;">**Frame in browser**

</td><td style="padding: .75pt .75pt .75pt .75pt;">• Provides standard peripheral support through browser APIs   
• Ideal for common office peripherals   
• Simplest deployment option   
• No additional software required

</td></tr><tr style="mso-yfti-irow: 2;"><td style="padding: .75pt .75pt .75pt .75pt;">**CAD/AEC Professional**

</td><td style="padding: .75pt .75pt .75pt .75pt;">• 3D mice/Space mice   
• Drawing tablets   
• Hardware security keys/dongles   
• Professional-grade input devices

</td><td style="padding: .75pt .75pt .75pt .75pt;">**Frame App 7 with Generic USB enabled**

</td><td style="padding: .75pt .75pt .75pt .75pt;">• Required for specialized input devices and security dongles   
• Ensures compatibility with professional design peripherals   
• Supports high-precision input requirements   
• Enables advanced device features

</td></tr><tr style="mso-yfti-irow: 3; mso-yfti-lastrow: yes;"><td style="padding: .75pt .75pt .75pt .75pt;">**Financial Services Professional**

</td><td style="padding: .75pt .75pt .75pt .75pt;">• Smart card readers   
• Security tokens   
• Signature pads   
• Multi-card readers   
• Document scanners

</td><td style="padding: .75pt .75pt .75pt .75pt;">**Frame App 7 with Generic USB enabled**

</td><td style="padding: .75pt .75pt .75pt .75pt;">• Required for secure authentication devices   
• Ensures compliance with financial security requirements   
• Supports specialized financial hardware   
• Enables secure peripheral access

</td></tr></tbody></table>

After determining your peripheral requirements and recommended deployment approach, it’s important to understand the technical capabilities and limitations of each solution.

Browser-based Frame sessions utilize modern web standards, such as WebHID APIs and MediaDevices APIs, to enable peripheral support directly through the browser. In contrast, **Frame App 7** provides enhanced USB device compatibility through its client architecture.

# Understanding Peripheral Support

This section provides a high-level look at how end-user device peripherals communicate with the Frame session when accessing via **Frame App** or a **compatible browser**.  
We’ll review how devices are supported and what to keep in mind when using each environment.

## Frame in a Browser

Frame utilizes several standard browser APIs for peripheral support:

- **WebHID API:** Enables direct communication with Human Interface Devices (HID) such as keyboards, mice, and game controllers.
- **MediaDevices API:** Manages audio and video peripherals like webcams, microphones, and speakers.
- **WebUSB API:** Provides access to certain USB devices in Chromium-based browsers on macOS and Linux.

**Note:**  
Some peripheral features require enabling experimental web platform features in certain browsers. This is particularly relevant for USB and HID device support in Chrome-based browsers.  
Instructions will be provided later in this document.

<table border="0" cellpadding="0" cellspacing="3" class="MsoNormalTable" id="bkmrk-operating-system-chr" style="width: 100%; height: 99.6875px;"><thead><tr style="height: 19.9375px;"><td style="padding: 0.75pt; width: 24.9801%; height: 19.9375px;">**Operating System**

</td><td style="padding: 0.75pt; width: 24.9801%; height: 19.9375px;">**Chrome/Edge**

</td><td style="padding: 0.75pt; width: 24.9801%; height: 19.9375px;">**Firefox**

</td><td style="padding: 0.75pt; width: 24.9801%; height: 19.9375px;">**Safari**

</td></tr></thead><tbody><tr style="height: 19.9375px;"><td style="padding: 0.75pt; width: 24.9801%; height: 19.9375px;">Windows

</td><td style="padding: 0.75pt; width: 24.9801%; height: 19.9375px;">Full peripheral support

</td><td style="padding: 0.75pt; width: 24.9801%; height: 19.9375px;">Basic peripheral support\*

</td><td style="padding: 0.75pt; width: 24.9801%; height: 19.9375px;">Not supported

</td></tr><tr style="height: 19.9375px;"><td style="padding: 0.75pt; width: 24.9801%; height: 19.9375px;">macOS

</td><td style="padding: 0.75pt; width: 24.9801%; height: 19.9375px;">Full peripheral support

</td><td style="padding: 0.75pt; width: 24.9801%; height: 19.9375px;">Basic peripheral support\*

</td><td style="padding: 0.75pt; width: 24.9801%; height: 19.9375px;">Basic peripheral support\*

</td></tr><tr style="height: 19.9375px;"><td style="padding: 0.75pt; width: 24.9801%; height: 19.9375px;">Linux

</td><td style="padding: 0.75pt; width: 24.9801%; height: 19.9375px;">Full peripheral support

</td><td style="padding: 0.75pt; width: 24.9801%; height: 19.9375px;">Basic peripheral support\*

</td><td style="padding: 0.75pt; width: 24.9801%; height: 19.9375px;">Not supported

</td></tr><tr style="height: 19.9375px;"><td style="padding: 0.75pt; width: 24.9801%; height: 19.9375px;">iOS/Android

</td><td style="padding: 0.75pt; width: 24.9801%; height: 19.9375px;">Limited support\*\*

</td><td style="padding: 0.75pt; width: 24.9801%; height: 19.9375px;">Limited support\*\*

</td><td style="padding: 0.75pt; width: 24.9801%; height: 19.9375px;">Limited support\*\*

</td></tr></tbody></table>

\* Basic support includes standard audio/video devices only.  
\*\* Mobile devices support touch input and basic audio/video features.

## Frame App 7

The communication flow between a user's local device and the Frame Workload VM begins with the **Frame App**, where a device type check determines compatibility.

- **WebHID-compatible devices** are routed through **WebHID** or **MediaDevices APIs**.
- Other devices undergo a **WebUSB compatibility check**.
- If compatible, the device connects via **WebUSB API**.
- If incompatible, drivers are replaced with WinUSB.sys on Windows or libUSB on macOS/Linux before routing to WebUSB.

Once connected, the physical USB device communicates with the **VirtualUSB Driver** on the Frame Workload VM, which integrates with the Frame Session to enable optimal peripheral functionality.

This process ensures support for a wide range of peripherals across different devices and operating systems.

<span style="mso-no-proof: yes;">![A green screen with black text

AI-generated content may be incorrect.](https://docs.difr.com/uploads/images/gallery/2025-10/embedded-image-ryiiupdn.png)</span>

# Browser-Based Frame Compatibility

This section provides administrators with a high-level overview of how Frame supports peripherals and workflows in browser-based sessions. By leveraging technologies such as WebUSB and WebHID, Frame enables functionality for printers, scanners, and USB HID devices, alongside secure, browser-native file transfer capabilities. It also outlines limitations tied to operating systems and browsers, offering guidance to help organizations optimize peripheral compatibility for their users.

**NOTE:** Compatibility for peripherals and features in Frame can vary depending on the end user's device, operating system, and the browser used to access Frame. While we strive to provide broad support across platforms, some functionality may be limited or optimized for specific environments.

For assistance in ensuring the best experience for your users or to address specific compatibility questions, we encourage you to work closely with your Dizzion Account Team. They can help you evaluate your needs and recommend the best configurations for your organization.

**Printers**

Frame supports two options for printing from a session:

<span style="mso-no-proof: yes;">![A screenshot of a computer

AI-generated content may be incorrect.](https://docs.difr.com/uploads/images/gallery/2025-10/embedded-image-jaeommcq.png)</span>

Printing within a Frame session

1. **Frame Printer:** When an end user initiates a print from any application, the default option will be the Frame Printer. Frame Printer uses WebUSB technology to enable direct printing from the Frame session through your local browser to your USB-connected printer. The print job is processed locally on your device, similar to a "Print to PDF" workflow. The Frame Printer is automatically installed and configured on all Frame Workload VMs, requiring no additional setup on the VM side. Users simply need a USB or network-connected printer on their local device to utilize this functionality.
2. **Network Printing:** Network printing directly from a VM is possible for accounts leveraging Domain Joined Instances where network printer policies are set by the Windows sytem Admin through their domain controller. Organizations interested in leveraging this option can discuss with their Dizzion Account Team.

## Mass Storage and File Transfer

Frame handles file transfers through native browser-based upload and download capabilities rather than direct mass storage access. For security and data integrity, Frame does not support local disk passthrough or direct access to external storage devices (such as USB drives or external hard drives).

<span style="mso-no-proof: yes;">![A screenshot of a computer

AI-generated content may be incorrect.](https://docs.difr.com/uploads/images/gallery/2025-10/embedded-image-weg5vogm.png)</span>

Users can transfer files efficiently using intuitive browser-based workflows, including drag-and-drop functionality between their local device and Frame sessions. This approach ensures consistent file handling while maintaining data integrity across sessions.

**NOTE:** Frame does not support operations requiring **asynchronous file transfers**. All file operations are handled through direct browser-based upload and download processes.

# HID Device Support

Frame supports **USB Human Interface Devices (HID)**, enabling seamless integration for devices such as keyboards, mice, game controllers, and specialty input devices.

When using **Frame App**, USB HID devices (mouse, keyboard, touchpad, headset, speakers) are supported without requiring users to manually select them.  
Specialized HID devices (joysticks, gamepads, fingerprint scanners, driving and flight simulators) may require manual selection from the menu to enable access and use within the Frame session.

To jump ahead to the high-level compatibility chart, click here. (link missing)

# Frame App Compatibility

Frame App provides robust support for a variety of peripheral devices, offering administrators and end users a reliable and seamless experience. Designed to accommodate the needs of modern enterprise environments, Frame App ensures that USB peripherals integrate effortlessly into virtual sessions with minimal setup. The peripherals listed below require Frame App 7 to connect to a Frame session from the user's local device.

## WIA Scanners

Frame enables seamless integration with document WIA scanners through USB redirection, offering a smooth scanning experience within virtual desktop sessions. Users can connect a scanner to their local device, where the operating system typically detects and installs the necessary drivers automatically. Once in a Frame session, the scanner can be virtually attached using the "Add USB Device" feature in Frame Terminal.

After the scanner is recognized within the virtual session, applications running in the Frame environment can access the scanner as though it were directly connected. This allows users to perform tasks like document scanning without the need for complex configurations or manual driver installations. Supported scanners, such as Fujitsu/Ricoh models, have been successfully used in scenarios involving Frame App and Windows-based sessions.

For tailored recommendations or assistance with scanner compatibility, we encourage you to collaborate with your Dizzion Support Team.

**NOTE:** Scanners that rely on the TWAIN standard are not supported.

# USB to Web Serial Redirection on Frame

The **Web Serial** feature allows end users to connect and redirect serial devices through the browser within a Frame session.  
This enables communication with devices such as sensors, barcode scanners, and industrial controllers directly from within the virtual environment. **Example use case:** A user connects a local COM device to a remote application that requires serial communication.

<span style="mso-no-proof: yes;">![A diagram of a remote work flow

AI-generated content may be incorrect.](https://docs.difr.com/uploads/images/gallery/2025-10/embedded-image-bnuwok6v.png)</span>

## Prerequisites

Before using Web Serial, make sure the environment meets the following requirements:

- Use **Frame Server version 9.4 or higher**, along with **Frame Terminal version 7.0.0.15rc1.1 or newer**.
- **Frame App**<span style="text-indent: -0.25in;"> should be at least </span>**version 7.9**<span style="text-indent: -0.25in;">.</span>
- <span style="text-indent: -0.25in;">Additionally, the </span>**Com0Com driver**<span style="text-indent: -0.25in;"> must be installed on the remote machine. This driver can be downloaded from </span>[https://sourceforge.net/projects/com0com/](https://sourceforge.net/projects/com0com/)<span style="text-indent: -0.25in;">, or — preferably - installed automatically using the </span>**Frame Agent Setup Tool (FAST)**<span style="text-indent: -0.25in;">.</span>

Once these components are in place, you can proceed with configuring Web Serial redirection.

## Setup Guide

#### Step 1 – Create a Virtual Port Pair (Com0Com)

After installing the Com0Com driver, create a **virtual port pair** that links two emulated serial ports - for example, COM4 and COM5.  
These ports will appear automatically in Windows Device Manager under “Ports (COM &amp; LPT).” The paired ports act as two ends of a communication channel, enabling redirection between your local serial device and the remote application running inside the Frame session.

#### Step 2 – Enable Web Serial Redirection

To enable Web Serial, make sure that USB Redirection is turned on. This feature must be active for the serial connection to function correctly within a Frame session.

Next, specific advanced arguments must be configured on both the server and the terminal.  
On the server side, you should include the argument that defines the virtual port name used for redirection. The argument is written as *“-comPortNames”* followed by the name of the virtual port {nameOdVirtualPort}. For example, if your virtual port is COM4, the argument would reference that port.

On the terminal side, two arguments must be added. The first one, *“allowSerialRedirection =true”* enables serial redirection itself. The second one, “*serialPortBaudRate={the desired baud rate}”* specifies the communication speed for the redirected serial device. For most devices, a baud rate of 115200 is commonly used.

<span style="mso-no-proof: yes;">![A screenshot of a computer

AI-generated content may be incorrect.](https://docs.difr.com/uploads/images/gallery/2025-10/embedded-image-faumdssp.png)</span>

Together, these server and terminal arguments instruct the Frame environment which port to use and how quickly to communicate with the device. When properly configured, the remote application inside the Frame session will be able to access and exchange data with the connected serial device through the browser.

#### Step 3 – Additional Server Arguments

If needed, you can fine-tune serial communication by adding the following additional server arguments. Each one adjusts how data is read or written through the serial port.

<table border="0" cellpadding="0" cellspacing="3" class="MsoNormalTable" id="bkmrk-argument-type-descri" style="mso-cellspacing: 1.5pt; mso-yfti-tbllook: 1184;"><thead><tr style="mso-yfti-irow: 0; mso-yfti-firstrow: yes;"><td style="padding: .75pt .75pt .75pt .75pt;">**Argument**

</td><td style="width: 75.3pt; padding: .75pt .75pt .75pt .75pt;" width="100">**Type**

</td><td style="width: 209.0pt; padding: .75pt .75pt .75pt .75pt;" width="279">**Description**

</td></tr></thead><tbody><tr style="mso-yfti-irow: 1;"><td style="padding: .75pt .75pt .75pt .75pt;">-serialReadIntervalTimeout

</td><td style="width: 75.3pt; padding: .75pt .75pt .75pt .75pt;" width="100">int

</td><td style="width: 209.0pt; padding: .75pt .75pt .75pt .75pt;" width="279">Maximum read time in milliseconds between two bytes

</td></tr><tr style="mso-yfti-irow: 2;"><td style="padding: .75pt .75pt .75pt .75pt;">-serialReadTotalTimeoutMultiplier

</td><td style="width: 75.3pt; padding: .75pt .75pt .75pt .75pt;" width="100">int

</td><td style="width: 209.0pt; padding: .75pt .75pt .75pt .75pt;" width="279">Read multiplier

</td></tr><tr style="mso-yfti-irow: 3;"><td style="padding: .75pt .75pt .75pt .75pt;">-serialReadTotalTimeoutConstant

</td><td style="width: 75.3pt; padding: .75pt .75pt .75pt .75pt;" width="100">int

</td><td style="width: 209.0pt; padding: .75pt .75pt .75pt .75pt;" width="279">Total read time in milliseconds

</td></tr><tr style="mso-yfti-irow: 4;"><td style="padding: .75pt .75pt .75pt .75pt;">-serialWriteTotalTimeoutConstant

</td><td style="width: 75.3pt; padding: .75pt .75pt .75pt .75pt;" width="100">int

</td><td style="width: 209.0pt; padding: .75pt .75pt .75pt .75pt;" width="279">Total write time in milliseconds

</td></tr><tr style="mso-yfti-irow: 5; mso-yfti-lastrow: yes;"><td style="padding: .75pt .75pt .75pt .75pt;">-serialWriteTotalTimeoutMultiplier

</td><td style="width: 75.3pt; padding: .75pt .75pt .75pt .75pt;" width="100">int

</td><td style="width: 209.0pt; padding: .75pt .75pt .75pt .75pt;" width="279">Write multiplier

</td></tr></tbody></table>

<span style="mso-spacerun: yes;"> </span>These arguments are optional but can be used to optimize serial performance for specific devices or workloads.

#### Step 4 – Additional Terminal Arguments

You can also define advanced settings for the serial port directly in the terminal arguments.  
The available parameters are:

<table border="0" cellpadding="0" cellspacing="3" class="MsoNormalTable" id="bkmrk-argument-type-descri-1" style="mso-cellspacing: 1.5pt; mso-yfti-tbllook: 1184;"><thead><tr style="mso-yfti-irow: 0; mso-yfti-firstrow: yes;"><td style="width: 107.95pt; padding: .75pt .75pt .75pt .75pt;" width="144">**Argument**

</td><td style="width: 54.55pt; padding: .75pt .75pt .75pt .75pt;" width="73">**Type**

</td><td style="width: 143.15pt; padding: .75pt .75pt .75pt .75pt;" width="191">**Description**

</td></tr></thead><tbody><tr style="mso-yfti-irow: 1;"><td style="width: 107.95pt; padding: .75pt .75pt .75pt .75pt;" width="144">serialPortDataBits

</td><td style="width: 54.55pt; padding: .75pt .75pt .75pt .75pt;" width="73">int

</td><td style="width: 143.15pt; padding: .75pt .75pt .75pt .75pt;" width="191">Default 8

</td></tr><tr style="mso-yfti-irow: 2;"><td style="width: 107.95pt; padding: .75pt .75pt .75pt .75pt;" width="144">serialPortStopBits

</td><td style="width: 54.55pt; padding: .75pt .75pt .75pt .75pt;" width="73">int

</td><td style="width: 143.15pt; padding: .75pt .75pt .75pt .75pt;" width="191">Default 1

</td></tr><tr style="mso-yfti-irow: 3; mso-yfti-lastrow: yes;"><td style="width: 107.95pt; padding: .75pt .75pt .75pt .75pt;" width="144">serialPortParity

</td><td style="width: 54.55pt; padding: .75pt .75pt .75pt .75pt;" width="73">string

</td><td style="width: 143.15pt; padding: .75pt .75pt .75pt .75pt;" width="191">Default ‘none’

</td></tr></tbody></table>

These parameters determine how data is framed and transmitted over the serial connection. The default values are typically suitable for most devices.

#### Step 5 – Connecting the Serial Device

Once everything is configured correctly, an **“Add Serial Device”** option will appear in the USB menu within the Frame session.  
<span style="mso-no-proof: yes;">![A screenshot of a computer

AI-generated content may be incorrect.](https://docs.difr.com/uploads/images/gallery/2025-10/embedded-image-sxsdroy6.png)</span>

When you click **Add Serial Device**, you will be prompted to select a local serial device for redirection.  
The server will use the virtual port defined in its advanced arguments (for example, COM4), while the remote application will connect to the corresponding paired port (for example, COM5). Once connected, your application can communicate directly with the redirected serial device.

## Troubleshooting on Ubuntu Client

If you encounter the error message **“failed to open device with network error”** when connecting from an Ubuntu client, it usually indicates a permission issue.  
To fix this, run the following command in the terminal:

*sudo usermod -a -G dialout $USER*

After executing this command, log out and log back in to apply the permission change.