Shell 启动程序

使用 Shell 启动器,可以将展台设备配置为使用几乎任何应用程序或可执行文件作为自定义 shell。 你指定的应用程序将替换通常在用户登录时运行的默认 Shell (explorer.exe)。

还可以将 Shell 启动器配置为为不同的用户或用户组启动不同的 shell 应用程序。

可以用作自定义 shell 的应用程序和可执行文件有一些例外:

  • 不能将以下可执行文件用作自定义 shell: C:\\Windows\\System32\\Eshell.exe。 使用 Eshell.exe 作为默认 shell 将导致用户登录后出现空白屏幕。
  • 不能将通用 Windows 应用用作自定义 shell。
  • 不能使用自定义 shell 启动通用 Windows 应用,例如“设置”应用。
  • 不能使用启动其他进程并作为自定义 shell 退出的应用程序。 例如,无法在 Shell 启动器中指定 write.exe 。 Shell 启动程序启动自定义 shell 并监视进程以识别自定义 shell 何时退出。 Write.exe 创建 32 位 wordpad.exe 进程并退出。 由于 Shell 启动器不知道新创建的 wordpad.exe 进程,因此 Shell 启动器会根据 Write.exe的退出代码执行操作,并重启自定义 shell。
  • 无法阻止系统关闭。 对于 Shell 启动器 V1 和 V2,在图形应用程序中收到WM_QUERYENDSESSION消息时返回 FALSE,或者在控制台应用程序中通过 SetConsoleCtrlHandler 函数添加的处理程序例程中返回 FALSE 来阻止会话结束。

注意

不能在同一系统上同时配置 Shell 启动器和分配的访问权限。

使用 Shell 启动器 V2,可以将通用 Windows 应用指定为自定义 shell。 检查使用 Shell 启动器创建Windows 10展台,了解 Shell 启动器 v1 和 Shell 启动器 V2 之间的差异。

Shell 启动器在启动自定义 shell 之前处理 RunRunOnce 注册表项,因此自定义 shell 不需要处理其他应用程序和服务的自动启动。

Shell 启动器还会处理自定义 shell 退出时系统的行为。 如果默认行为不满足需求,可以配置 shell 退出行为。

除了使用 Shell 启动器(例如、组策略AppLockerMobile 设备管理)之外,还可以使用控制对其他桌面应用程序和系统组件的访问的方法

注意

在 Windows 10 中提供的 Shell 启动器 v1 中,只能将 Windows 桌面应用程序指定为替换 shell。 在 Windows 10 版本 1809 及更高版本中提供的 Shell 启动器 v2 中,还可以将 UWP 应用指定为替换 shell。

若要在版本 1809 中使用 Shell Launcher v2,需要安装 KB4551853更新

Shell Launcher v1 和 Shell Launcher v2 之间的差异

Shell Launcher v1 将 explorer.exe默认 shell 替换为 eshell.exe,后者可以启动 Windows 桌面应用程序。 Shell 启动器 v2 将 explorer.exe 替换为 customshellhost.exe。 此新的可执行文件可以启动 Windows 桌面应用程序或 UWP 应用。 除了允许你将 UWP 应用用于替换 shell 之外,Shell 启动器 v2 还提供了更多增强功能:

  • 可以使用自定义 Windows 桌面应用程序,该应用程序随后可以启动 UWP 应用,例如“设置”和“触摸键盘”。
  • 从自定义 UWP shell 中,可以启动辅助视图并在多个监视器上运行。
  • 自定义 shell 应用以全屏方式运行,并且可以根据用户的需求全屏运行其他应用。 有关不同应用组合的示例 XML 配置,请参阅 Shell 启动器 v2 的示例

要求

Windows 10 企业版或Windows 10 教育版。

术语

  • 打开,启用: 使设置可用于设备,并选择性地将设置应用于设备。
  • 配置: 自定义设置或子设置。
  • 嵌入式 Shell 启动器:此功能在 Windows 10 版本 1511 中称为 Embedded Shell Launcher。
  • 自定义 Shell 启动器:此功能在 Windows 10 版本 1607 及更高版本中称为 Shell 启动器。

打开 Shell 启动器

Shell 启动器是一个可选组件,在 Windows 10 中默认未打开。 在配置之前,必须打开它。 如果尚未安装Microsoft Windows,可以在自定义Windows 10映像 (.wim) 中打开和配置 Shell 启动器。 如果已安装 Windows,则必须在应用预配包来配置 Shell 启动器之前打开 Shell 启动器。

使用 控制面板 启用 Shell 启动器

  1. “搜索 Web 和 Windows ”字段中,键入 “程序和功能 ”,然后按 Enter 或点击或选择“ 程序和功能 ”将其打开。
  2. “程序和功能 ”窗口中,选择“ 打开或关闭 Windows 功能”。
  3. “Windows 功能 ”窗口中,展开“ 设备锁定 ”节点,选中或清除 Shell 启动器的复选框,然后选择“ 确定”。
  4. Windows 功能窗口指示 Windows 正在搜索所需的文件并显示进度栏。 找到后,窗口指示 Windows 正在应用更改。 完成后,窗口指示请求的更改已完成。
  5. 选择“ 关闭 ”以关闭 “Windows 功能 ”窗口。

注意

打开 Shell 启动器不需要重启设备。

通过调用 WESL_UserSetting 启用 Shell 启动器

  1. 通过在 Windows Management Instrumentation (WMI) 类WESL_UserSetting调用 WESL_UserSetting.SetEnabled 函数来启用或禁用 Shell 启动器。
  2. 如果使用 WESL_UserSetting 启用或禁用 Shell 启动器,则更改不会影响当前登录的任何会话;必须注销并重新登录。

此示例使用名为 install.wim 的 Windows 映像,但你可以使用相同的过程来应用预配包 (有关 DISM 的详细信息,请参阅 什么是部署映像服务和管理

使用 DISM 启用 Shell 启动器

  1. 使用管理员权限打开命令提示符。

  2. 在以下步骤中,将 install.wim 复制到硬盘驱动器 (上的临时文件夹,假设它名为 C:\wim) 。

  3. 创建新目录。

    md c:\wim
    
  4. 装载映像

    dism /mount-wim /wimfile:c:\bootmedia\sources\install.wim /index:1 /MountDir:c:\wim
    
  5. 启用该功能。

    dism /image:c:\wim /enable-feature /all /featureName:Client-EmbeddedShellLauncher
    
  6. 提交更改。

    dism /unmount-wim /MountDir:c:\wim /Commit
    

使用 Windows 配置Designer启用 Shell 启动器

Shell 启动器设置也作为 Windows 预配设置提供,因此你可以配置这些设置以在映像运行时期间应用。 通过使用 Windows 配置Designer创建预配包,然后在映像部署时间或运行时应用预配包,可以设置一个或所有 Shell 启动程序设置。 如果尚未安装 Windows,并且你正在使用 Windows 配置Designer创建安装媒体,并且映像中包含 Shell 启动器设置,或者在安装过程中应用预配包,则必须在安装媒体上使用 DISM 启用 Shell Launcher,才能成功应用预配包。

使用以下步骤创建包含 ShellLauncher 设置的预配包。

  1. 按照为Windows 10创建预配包中的说明,在 Windows 配置Designer生成预配包
  2. “可用自定义项 ”页中,选择“ 运行时设置>SMISettings>ShellLauncher”。
  3. “启用” 的值设置为 ENABLE。 将显示更多用于配置 Shell 启动器的选项,你可以根据需要设置值。
  4. 完成设置配置并创建预配包后,可以将包应用到映像部署时间或运行时。 有关详细信息,请参阅 应用预配包 。 将包应用于Windows 10 企业版映像的过程是相同的。

配置 Shell 启动器

可通过两种方式配置 Shell 启动器:

  1. 在 Windows 10 版本 1803 中,可以使用分配的访问配置服务提供程序的 ShellLauncher 节点 (CSP) 配置 Shell 启动器。 有关详细信息 ,请参阅 AssignedAccess CSP 。 使用此方法配置 Shell 启动器还会在设备上自动启用 Shell 启动器(如果设备支持)。
  2. 直接在 PowerShell 脚本或应用程序中使用 Shell 启动器 WMI 提供程序。

可以为 Shell 启动器配置以下选项:

  • 启用或禁用 Shell 启动器。
  • 指定特定用户或组的 shell 配置。
  • 删除特定用户或组的 shell 配置。
  • 更改默认 shell 配置。
  • 获取有关特定用户或组的 shell 配置的信息。

任何更改在用户登录之前才会生效。

为不同的用户帐户启动不同的 shell

默认情况下,Shell 启动器运行默认 shell,这是在设计时创建 OS 映像时指定的。 默认 shell 设置为 Cmd.exe,但你可以将任何可执行文件指定为默认 shell。

如果不想运行默认 shell,可以将 Shell 启动器配置为针对特定用户或组启动其他 shell。 例如,你可以将设备配置为为来宾帐户运行自定义应用程序 shell,但为管理员帐户运行标准 Windows 资源管理器 shell,以便为设备提供服务。

如果在运行时使用 WMI 提供程序为用户或组配置 Shell 启动器,则必须使用该用户或组的安全标识符 (SID) ;不能使用用户名或组名称。

有关常见安全标识符的详细信息,请参阅 已知 SID

当当前登录的帐户属于两个或更多组,这些组具有为每个组定义的不同配置时,Shell 启动器将使用它找到的第一个配置。 搜索顺序未定义,因此建议避免将用户分配到具有不同 Shell 启动器配置的多个组。

在 shell 退出时执行操作

当自定义 shell 退出时,Shell 启动器可以执行以下四项操作之一:

操作 描述
0 重启 shell。
1 重启设备。
2 关闭设备。
3 不执行任何操作。

重要提示

请确保 Shell 应用程序不会自动退出,也不会被对话框筛选器等任何功能自动关闭,因为这样可能会导致退出和重启的无限循环,除非返回代码操作设置为不执行任何操作。

默认返回代码操作

可以使用 DefaultReturnCodeAction 设置为 Shell 启动器定义默认返回代码操作。 如果不更改初始值,则默认返回代码操作将设置为 0 (零) ,这表示 Shell 启动器在 shell 退出时重启 shell。

将退出代码映射到 Shell 启动器操作

Shell 启动器可以根据 shell 返回的退出代码执行特定操作。 对于 shell 返回的任何给定退出代码,可以通过将该退出代码映射到 shell 退出操作之一来配置 Shell 启动程序执行的操作。

如果退出代码与定义的值不匹配,Shell 启动器将执行默认返回代码操作。

例如,shell 可能会返回 -1、0、1 或 255 的退出代码值,具体取决于 shell 退出的方式。 可以将 Shell 启动器配置为:

  • 当 shell 返回值 -1 的退出代码时, (1) 重启设备
  • 当 shell 返回值 0 的退出代码时,重启 shell (0)
  • 当 shell 返回值 1 的退出代码时, (3) 不执行任何操作
  • 当 shell 返回值 255 的退出代码时, (2) 关闭设备

自定义返回代码操作映射如下所示:

退出代码 操作
-1 1 (重启设备)
0 0 (重启 shell)
1 3 (不执行任何)
255 2 (关闭设备)

设置自定义 shell

根据需要修改以下 PowerShell 脚本,并在设备上运行该脚本。

# 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
    {
        [DllImport("Slc.dll")]
        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"
    exit
}

$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"
    exit
    }


# 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
$do_nothing = 3

# 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 www.microsoft.com", ($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

$ShellLauncherClass.SetEnabled($TRUE)

$IsShellLauncherEnabled = $ShellLauncherClass.IsEnabled()

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

# Remove the new custom shells.

$ShellLauncherClass.RemoveCustomShell($Admins_SID)

$ShellLauncherClass.RemoveCustomShell($Cashier_SID)

# Disable Shell Launcher

$ShellLauncherClass.SetEnabled($FALSE)

$IsShellLauncherEnabled = $ShellLauncherClass.IsEnabled()

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

注意

前面的脚本包含多个配置选项的示例,包括删除自定义 shell 和禁用 Shell 启动器。 它不应按原样运行。

Shell 启动器用户权限

自定义 shell 使用所登录帐户的用户权限的相同级别启动。 这意味着,具有管理员权限的用户可以执行需要管理员权限的任何系统操作,包括启动具有管理员权限的其他应用程序,而没有管理员权限的用户则不能。

警告

如果 shell 应用程序需要管理员权限并且需要提升,并且设备上存在用户帐户控制 (UAC) ,则必须禁用 UAC 才能让 Shell 启动器启动 shell 应用程序。