MSEndpointMgr

Building lock down device – Part 2 (Shell Launcher)

In Building lock down device – Part 1 – (Keyboard Filter) , we introduce Windows Feature device lockdown. One of the device lockdown feature is Shell Launcher. Requirement is same as Keyboard Filter, you will need Windows 10 Enterprise or Windows 10 Education

In a normal Windows 10, we see desktop when log on Windows. By using shell launcher, you can replace the default Windows launcher with any applications or executable as your custom shell.

Come back to why would I want to use Shell Launcher in the first place. As you know, in Europe, we have GDPR regulation, I consider it would be necessary to have full screen “popup window” to tell people about teams of using this device when user logon to a Kiosk machine. Or maybe, there is scenario that you only allow user to use one application in this kiosk device, and you want the application restart again if user closes this application. In the case Shell Launcher is very useful feature.

Shell launcher is not startup application, when use Shell launcher to launch an application, that application is the only app you will see when log on to Windows, you won’t be able access to desktop or anything else.

These are important notes from the official Microsoft documents, I quote them in here as well:

There are a few exceptions to the applications and executable you can use as a custom shell:

  • You cannot use the following executable as a custom shell: C:\\Windows\\System32\\Eshell.exe. Using Eshell.exe as the default shell will result in a blank screen after user signs in.
  • You cannot use a Universal Windows app as a custom shell.
  • You cannot use a custom shell to launch Universal Windows apps, for example, the Settings app.
  • You cannot use an application that launches a different process and exits as a custom shell. 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, and restart the custom shell.
  • You cannot configure both Shell Launcher and assigned access on the same system.

First we need to enable Shell Launcher feature, it does not required restart. Here is PowerShell example:

#Event log source
$LogSource = "SCConfigMgr"
New-EventLog -LogName Application -Source $LogSource -ErrorAction Ignore

#Enable Shell launcher feature		
try
{
    #Write event log
    Write-EventLog -LogName Application -Source $LogSource -EntryType Info -EventId 1000 -Message "Start enable Shell Launcher Feature"

    #Enable Shell launcher feature without restart		
    Enable-WindowsOptionalFeature -Online -FeatureName Client-EmbeddedShellLauncher -All -NoRestart -OutVariable result		
}
catch
{
    # Something went wrong, display the error details and write an error to the event log
    Write-EventLog -LogName Application -Source $LogSource -EntryType Warning -EventId 1001 -Message "$_.Exception.Message"
}

Here is example I configure default shell is explorer.exe, so that by default users will see the normal desktop when log on to Windows 10. Then I configure Internet Explorer as custom shell for local user name “KioskUser“, it will launch Internet Explorer when user “KioskUser” log on Windows, and it will restart Internet Explorer if user closes it.

You can configure four actions when shell exits: Restart Shell, Restart Device, Shutdown Device or Do nothing. But of course, if you develop your own application, you can configure more actions, just configure shell exits action as “Do nothing”, but configure in your app that what actions will continue if user close your app.

#Event log source
$LogSource = "SCConfigMgr"
New-EventLog -LogName Application -Source $LogSource -ErrorAction Ignore

# 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)
  try
  {
    $NTUserSID = $NTUserObject.Translate([System.Security.Principal.SecurityIdentifier])
    return $NTUserSID.Value
  }
  catch
  {
    $ErrorMessage = $_.Exception.Message
    Write-Error $ErrorMessage -Verbose
  }
}
    
# Get the SID for a user account named "Cashier". Rename "Cashier" to an existing account on your system to test this script.
    
$KioskUser_SID = Get-UsernameSID("KioskUser")
    
$COMPUTER = "localhost"
$NAMESPACE = "root\standardcimv2\embedded"
    
# Create a handle to the class instance so we can call the static methods.
try
{
  Write-EventLog -LogName Application -Source $LogSource -EntryType Info -EventId 1001 -Message "Create a handle to the class instance"
  $ShellLauncherClass = [wmiclass]"\\$COMPUTER\${NAMESPACE}:WESL_UserSetting"
}
catch [Exception] {
  Write-Error $_.Exception.Message -Verbose
}
    
# Define actions to take when the shell program exits.
    
$restart_shell = 0
$restart_device = 1
$shutdown_device = 2
$do_nothing = 3
    
try
{
  # Remove the old custom shells.
  $ShellLauncherClass.RemoveCustomShell($KioskUser_SID)
}
catch [Exception] {
  Write-Error $_.Exception.Message -Verbose
  Write-EventLog -LogName Application -Source $LogSource -EntryType Warning -EventId 1001 -Message "$_.Exception.Message"
}
    
try
{
      
  # Examples. You can change these examples to use the program that you want to use as the shell.
  $ShellLauncherClass.SetDefaultShell("explorer.exe", $do_nothing)
      
  # Display the default shell to verify that it was added correctly.
  $DefaultShellObject = $ShellLauncherClass.GetDefaultShell()
  Write-Error "Default Shell is set to $DefaultShellObject.Shell,and the default action is set to $DefaultShellObject.defaultaction" -Verbose
      
      
  # Set Autologon as the shell for "KIOSKI"
  $ShellLauncherClass.SetCustomShell($KioskUser_SID, "c:\program files\internet explorer\iexplore.exe www.microsoft.com", ($null), ($null), $restart_shell)
      
  # Enable Shell Launcher
  $ShellLauncherClass.SetEnabled($TRUE)
  $IsShellLauncherEnabled = $ShellLauncherClass.IsEnabled()
      
  Write-EventLog -LogName Application -Source $LogSource -EntryType info -EventId 1000 -Message "Custom Shell Launcher Feature enabled"
}
catch [Exception]
{
  $ErrorMessage = $_.Exception.Message
  Write-Error $ErrorMessage -Verbose
  Write-EventLog -LogName Application -Source $LogSource -EntryType Warning -EventId 1001 -Message "Failed to Add custom Shell Launcher $($ErrorMessage)"
}

Notes:

  • Make sure the user exist before configure Shell Launcher to the user
  • Make sure the application exist, other wise you will get a totally black screen.

For more information and script samples, see https://docs.microsoft.com/en-us/windows-hardware/customize/enterprise/shell-launcher

Next part. Building lock down device – Part 3 (Shared PC mode)

Sandy Zeng

Sandy is an Enterprise Mobility MVP since 2018. She is an experienced Information Technology Specialist for over 10 years. Skilled in Microsoft Endpoint Manager (ConfigMgr and Intune), Windows 10 and security. Sandy's interests are mostly related to Microsoft Technologies, she has passions learning new skill sets to improve her professional career and also as her hobbies. She uses her expertise to help customers achieve their goals and solve their issues.

Sandy founded the https://sandyzeng.com blog and is now a blogger on MSEndPointMgr.

5 comments

  • Hi Sandy,

    I cannot appreciate enough of this invaluable article as I am currently involved in setting up a kiosk for a client. In the normal PC, what is the name of the log source?

    Thank’s heaps again.

  • Thank you Sandy, please suggest what do you mean by Make sure the user exist before configure Shell Launcher to the user

    • if you are configuring Shell Launcher to launch for a local user example “Sandy”, you will need create this local user “Sandy” first.

  • Hi there,

    Realise it’s a while since you posted this, but wondered why I’d get a exception when calling for setcustomshell and it saying that the object or property already exists.

Sponsors

Categories

MSEndpointMgr.com use cookies to ensure that we give you the best experience on our website.