Use Shell Launcher to create a Windows client kiosk

Applies to

  • Windows 10 Ent, Edu
  • Windows 11

Using Shell Launcher, you can configure a device that runs an application as the user interface, replacing the default shell (explorer.exe). In Shell Launcher v1, available in Windows client, you can only specify a Windows desktop application as the replacement shell. In Shell Launcher v2, available in Windows 10 version 1809+ / Windows 11, you can also specify a UWP app as the replacement shell. To use Shell Launcher v2 in Windows 10 version 1809, you need to install the KB4551853 update.


Shell Launcher controls which application the user sees as the shell after sign-in. It does not prevent the user from accessing other desktop applications and system components.

Methods of controlling access to other desktop applications and system components can be used in addition to using the Shell Launcher. These methods include, but are not limited to:

You can apply a custom shell through Shell Launcher by using PowerShell. Starting with Windows 10 version 1803+, you can also use mobile device management (MDM) to apply a custom shell through Shell Launcher.

Differences between Shell Launcher v1 and Shell Launcher v2

Shell Launcher v1 replaces explorer.exe, the default shell, with eshell.exe which can launch a Windows desktop application.

Shell Launcher v2 replaces explorer.exe with customshellhost.exe. This new executable file can launch a Windows desktop application or a UWP app.

In addition to allowing you to use a UWP app for your replacement shell, Shell Launcher v2 offers additional enhancements:

  • You can use a custom Windows desktop application that can then launch UWP apps, such as Settings and Touch Keyboard.
  • From a custom UWP shell, you can launch secondary views and run on multiple monitors.
  • The custom shell app runs in full screen, and can run other apps in full screen on user’s demand.

For sample XML configurations for the different app combinations, see Samples for Shell Launcher v2.



  • Windows 10 doesn’t support setting a custom shell prior to OOBE. If you do, you won’t be able to deploy the resulting image.

  • Shell Launcher doesn't support a custom shell with an application that launches a different process and exits. For example, you cannot specify write.exe in Shell Launcher. Shell Launcher launches a custom shell and monitors the process to identify when the custom shell exits. Write.exe creates a 32-bit wordpad.exe process and exits. Because Shell Launcher is not aware of the newly created wordpad.exe process, Shell Launcher will take action based on the exit code of Write.exe, such as restarting the custom shell.

  • A domain, Azure Active Directory, or local user account.

  • A Windows application that is installed for that account. The app can be your own company application or a common app like Internet Explorer.

See the technical reference for the shell launcher component.

Enable Shell Launcher feature

To set a custom shell, you first turn on the Shell Launcher feature, and then you can set your custom shell as the default using PowerShell or MDM.

To turn on Shell Launcher in Windows features

  1. Go to Control Panel > Programs and features > Turn Windows features on or off.

  2. Expand Device Lockdown.

  3. Select Shell Launcher and OK.

Alternatively, you can turn on Shell Launcher using Windows Configuration Designer in a provisioning package, using SMISettings > ShellLauncher, or you can use the Deployment Image Servicing and Management (DISM.exe) tool.

To turn on Shell Launcher using DISM

  1. Open a command prompt as an administrator.

  2. Enter the following command.

    Dism /online /Enable-Feature /all /FeatureName:Client-EmbeddedShellLauncher

Configure a custom shell in MDM

You can use XML and a custom OMA-URI setting to configure Shell Launcher in MDM.

XML for Shell Launcher configuration

The following XML sample works for Shell Launcher v1:

<?xml version="1.0" encoding="utf-8"?> 
<ShellLauncherConfiguration xmlns=""> 
    <Profile ID="{24A7309204F3F-44CC-8375-53F13FE213F7}"> 
      <Shell Shell="%ProgramFiles%\Internet Explorer\iexplore.exe -k" /> 
    <!--local account-->
    <Account Name="ShellLauncherUser"/>
    <Profile ID="{24A7309204F3F-44CC-8375-53F13FE213F7}"/>

For Shell Launcher v2, you can use UWP app type for Shell by specifying the v2 namespace, and use v2:AppType to specify the type, as shown in the following example. If v2:AppType is not specified, it implies the shell is Win32 app.

<?xml version="1.0" encoding="utf-8"?> 
<ShellLauncherConfiguration xmlns="" 
      <Shell Shell="ShellLauncherV2DemoUwp_5d7tap497jwe8!App" v2:AppType="UWP" v2:AllAppsFullScreen="true"> 
        <DefaultAction Action="RestartShell"/> 


In the XML for Shell Launcher v2, note the AllAppsFullScreen attribute. When set to True, Shell Launcher will run every app in full screen, or maximized for desktop apps. When this attribute is set to False or not set, only the custom shell app runs in full screen; other apps launched by the user will run in windowed mode.

Get XML examples for different Shell Launcher v2 configurations.

Custom OMA-URI setting

In your MDM service, you can create a custom OMA-URI setting to configure Shell Launcher v1 or v2. (The XML that you use for your setting will determine whether you apply Shell Launcher v1 or v2.)

The OMA-URI path is ./Device/Vendor/MSFT/AssignedAccess/ShellLauncher.

For the value, you can select data type String and paste the desired configuration file content into the value box. If you wish to upload the xml instead of pasting the content, choose data type String (XML file).

Screenshot of custom OMA-URI settings.

After you configure the profile containing the custom Shell Launcher setting, select All Devices or selected groups of devices to apply the profile to. Don't assign the profile to users or user groups.

Configure a custom shell using PowerShell

For scripts for Shell Launcher v2, see Shell Launcher v2 Bridge WMI sample scripts.

For Shell Launcher v1, modify the following PowerShell script as appropriate. The comments in the sample script explain the purpose of each section and tell you where you will want to change the script for your purposes. Save your script with the extension .ps1, open Windows PowerShell as administrator, and run the script on the kiosk device.

# Check if shell launcher license is enabled
function Check-ShellLauncherLicenseEnabled
    [string]$source = @"
using System;
using System.Runtime.InteropServices;

static class CheckShellLauncherLicense
    const int S_OK = 0;

    public static bool IsShellLauncherLicenseEnabled()
        int enabled = 0;

        if (NativeMethods.SLGetWindowsInformationDWORD("EmbeddedFeature-ShellLauncher-Enabled", out enabled) != S_OK) {
            enabled = 0;
        return (enabled != 0);

    static class NativeMethods
        internal static extern int SLGetWindowsInformationDWORD([MarshalAs(UnmanagedType.LPWStr)]string valueName, out int value);


    $type = Add-Type -TypeDefinition $source -PassThru

    return $type[0]::IsShellLauncherLicenseEnabled()

[bool]$result = $false

$result = Check-ShellLauncherLicenseEnabled
"`nShell Launcher license enabled is set to " + $result
if (-not($result))
    "`nThis device doesn't have required license to use Shell Launcher"

$COMPUTER = "localhost"
$NAMESPACE = "root\standardcimv2\embedded"

# Create a handle to the class instance so we can call the static methods.
try {
    $ShellLauncherClass = [wmiclass]"\\$COMPUTER\${NAMESPACE}:WESL_UserSetting"
    } catch [Exception] {
    write-host $_.Exception.Message; 
    write-host "Make sure Shell Launcher feature is enabled"

# This well-known security identifier (SID) corresponds to the BUILTIN\Administrators group.

$Admins_SID = "S-1-5-32-544"

# Create a function to retrieve the SID for a user account on a machine.

function Get-UsernameSID($AccountName) {

    $NTUserObject = New-Object System.Security.Principal.NTAccount($AccountName)
    $NTUserSID = $NTUserObject.Translate([System.Security.Principal.SecurityIdentifier])

    return $NTUserSID.Value

# Get the SID for a user account named "Cashier". Rename "Cashier" to an existing account on your system to test this script.

$Cashier_SID = Get-UsernameSID("Cashier")

# Define actions to take when the shell program exits.

$restart_shell = 0
$restart_device = 1
$shutdown_device = 2

# Examples. You can change these examples to use the program that you want to use as the shell.

# This example sets the command prompt as the default shell, and restarts the device if the command prompt is closed. 

$ShellLauncherClass.SetDefaultShell("cmd.exe", $restart_device)

# Display the default shell to verify that it was added correctly.

$DefaultShellObject = $ShellLauncherClass.GetDefaultShell()

"`nDefault Shell is set to " + $DefaultShellObject.Shell + " and the default action is set to " + $DefaultShellObject.defaultaction

# Set Internet Explorer as the shell for "Cashier", and restart the machine if Internet Explorer is closed.

$ShellLauncherClass.SetCustomShell($Cashier_SID, "c:\program files\internet explorer\iexplore.exe", ($null), ($null), $restart_shell)

# Set Explorer as the shell for administrators.

$ShellLauncherClass.SetCustomShell($Admins_SID, "explorer.exe")

# View all the custom shells defined.

"`nCurrent settings for custom shells:"
Get-WmiObject -namespace $NAMESPACE -computer $COMPUTER -class WESL_UserSetting | Select Sid, Shell, DefaultAction

# Enable Shell Launcher


$IsShellLauncherEnabled = $ShellLauncherClass.IsEnabled()

"`nEnabled is set to " + $IsShellLauncherEnabled.Enabled

# Remove the new custom shells.



# Disable Shell Launcher


$IsShellLauncherEnabled = $ShellLauncherClass.IsEnabled()

"`nEnabled is set to " + $IsShellLauncherEnabled.Enabled

default action, custom action, exit code

Shell launcher defines 4 actions to handle app exits, you can customize shell launcher and use these actions based on different exit code.

Value Description
0 Restart the shell
1 Restart the device
2 Shut down the device
3 Do nothing

These action can be used as default action, or can be mapped to a specific exit code. Refer to Shell Launcher to see how these codes with Shell Launcher WMI.

To configure these action with Shell Launcher CSP, use below syntax in the shell launcher configuration xml. You can specify at most 4 custom actions mapping to 4 exit codes, and one default action for all other exit codes. When app exits and if the exit code is not found in the custom action mapping, or there is no default action defined, it will be no-op, i.e. nothing happens. So it's recommended to at least define DefaultAction. Get XML examples for different Shell Launcher v2 configurations.

    <ReturnCodeAction ReturnCode="0" Action="RestartShell"/>
    <ReturnCodeAction ReturnCode="-1" Action="RestartDevice"/>
    <ReturnCodeAction ReturnCode="255" Action="ShutdownDevice"/>
    <ReturnCodeAction ReturnCode="1" Action="DoNothing"/>
<DefaultAction Action="RestartDevice"/>