Windows 10 IoT Enterprise 2019 β€” kiosk mode

Introduction

Windows 10 IoT Enterprise 2019 is the marketing name for the latest release of Windows 10. This version was announced in September 2018, therefore it has version 1809, where 18 represents the year and 09 represents the month. Many articles have been written about the new Windows 10 1809 release, but most of them focus on various 'aesthetics', features that are in demand for home use.
This article will discuss only the features that may be relevant to manufacturers of fixed-purpose devices. Specifically, it will address the new capabilities of the 'Kiosk' mode. The topic of renaming the servicing schemes for enterprise editions of Windows will also be touched upon.

Old servicing scheme with a new name

I will begin with a brief explanation that in the corporate segment of Windows editions, there are two servicing schemes according to which Windows receives updates. The servicing schemes have a letter designation. Currently, these servicing branches are called LTSC and SAC.

LTSC stands for Long Term Servicing Channel (with long-term servicing). Previously, this channel was called LTSB – Long Term Servicing Branch; Microsoft simply changed the name of the servicing channel, while the servicing itself remained the same.

Microsoft also changed the name of the servicing branch CBB – Current Branch for Business; now this servicing branch is called SAC – Semi-Annual Channel. Again, only the name has changed.

However, it should be noted that different Windows distributions are used for the LTSC and SAC servicing branches.

A bit about the new kiosk mode in SAC

As I mentioned, LTSC and SAC have different distributions. LTSC does not have standard universal applications and the app store, while SAC does. Accordingly, LTSC does not include the Edge browser, but it is present in SAC. If you choose the Edge browser during the kiosk setup, there are now two available modes:

  1. As a digital sign or interactive display
  2. As a public web browser

I won't dwell on the setup of these modes, as the setup is very simple and performed through a graphical interface. Just create a user who is not part of the 'Administrators' group, enable the kiosk mode using EDGE, and observe the operation of these modes.

Kiosk with multiple applications

Some people think that the licensed use of Windows 10 IoT Enterprise implies that only one application should run on the device, but that’s not the case. The device should be intended for performing one business task, and the user should not have access to the desktop. Microsoft itself has now provided a tool for using multiple applications. This mode is called 'multi-app kiosk,' and for brevity, I will refer to it as 'kiosk mode' hereafter. In this article, we will examine the configuration of this mode using the provisioning package and some features of this mode.

A Bit About the 'Kiosk Mode'

When logging into a user account configured for kiosk mode, the system will operate in tablet mode. The Start Menu will be expanded to full screen, displaying application tiles.

List of Main Settings and Features of the Mode:

  1. Configuration for Multiple Users or Groups
  2. Individual settings can be assigned to each user or group
  3. Ability to use Universal and Classic Applications
  4. Ability to automatically launch one of the applications upon user login
  5. Application Whitelisting
  6. Folder Access Whitelisting

Attention should be paid to point 5. By default, only the applications necessary for system operation will be allowed; other applications need to be added to the allowed list. That is, it is no longer necessary to configure AppLocker separately. By the way, to avoid conflicts with AppLocker settings, all configured AppLocker rules will not apply in kiosk mode.

Point 6 highlights a good opportunity, but currently, it is only possible to allow write access for the 'Downloads' folder. The mode allows the use of both Universal and Classic applications. All mode settings are specified in the XML file, where settings for a single-application kiosk can also be defined.

Now let’s try to set all this up…

What We Need...

  1. First of all, we need the system that supports kiosk mode. Here you can download the demo version
  2. Instructions for Setting Up Kiosk Mode
  3. Any XML editor
  4. To apply the settings for kiosk mode:
    1. For method #1 β€” ICD, which is part of ADK. ADK can be here
    2. For method #2 – the PsExec utility. The utility can be here

He said – "Let's go!"

I will conduct all experiments on Windows 10 IoT Enterprise 1809 LTSC x32 commercial version, not the demo version. The system will be unactivated since lack of activation does not affect the system's functionality. I chose 32-bit only because it takes up less space and working with system images will be faster.

Step 1 – installation

The installation of Win 10 IoT Enterprise is no different from that of Win 10 Enterprise, so I won't describe the entire installation process, only a few nuances.

Just to remind you, do not install the system over an already installed one. When the installer asks for the installation location, delete all partitions on the future system disk and specify the unallocated disk.

We will install the system without an internet connection, so that the system doesn’t pull anything unnecessary.

Since we will be creating system backups and sealing it in audit mode, we can save some time by booting the system in audit mode immediately after installation. For this, when the system asks you to select a region, "Let’s start with region. Is this right," simply press "Ctrl+Shift+F3."

Step 2 – creating a system image

Since we will be experimenting with the system and trying various new settings, it’s possible that something might go wrong and we will need to restore the system to its original state. To quickly revert to the original state, we need to create a system image. The only thing I will do is copy the "gentleman's set" – the script and the answer file. All files are located in the "Sysprep" folder, which I will copy to the root of the system disk. And of course, I will share this "gentleman's set" with you.

Sysprep.bat – for sealing the system.

@echo off
chcp 1251>nul

net session>nul 2>nul
if %errorLevel% neq 0 (powershell -command "Start-Process "%~s0" -Verb RunAs"&exit)

tasklist /fi "ImageName eq sysprep.exe" | find /i "sysprep.exe"
if %errorlevel% lss 1 (taskkill /im sysprep.exe)

set AdminName=Admin
net user minName%>nul 2>nul
if %errorLevel% neq 0 (call :AddAdmin "minName%")
if %errorLevel% neq 0 (call :ShowMessage "Error creating new administrator account "minName%". Press any key to exit the script"&pause>nul&exit)

pushd "%~dp0"

cls
call :ShowMessage 

echo 1 - Seal the system in audit mode
echo 2 - Seal the system in welcome mode
:Select
set /p Choice="Enter menu item number: "
if "%Choice%"=="1" (goto Audit)
if "%Choice%"=="2" (goto OOBE)
echo.&echo Invalid value selected.&goto Select

exit

:Audit
 call :ShowMessage "Sealing the system in audit mode"
 reg add HKLMSoftwareMicrosoftWindowsCurrentVersionRun /v KillSysprep /t REG_SZ /d "taskkill /im sysprep.exe" /f
 %SYSTEMROOT%System32Sysprepsysprep.exe /audit /generalize /shutdown /quiet
goto :eof

:OOBE
 call :ShowMessage "Sealing the system in welcome mode"
 reg delete HKLMSoftwareMicrosoftWindowsCurrentVersionRun /v KillSysprep /f
 powershell -command "(Get-Content -path 'Unattend.xml' -Raw).Trim() -replace 'Architecture=""".+?"""','Architecture="""%PROCESSOR_ARCHITECTURE%"""' | Set-Content -path 'Unattend.xml'"
 %SYSTEMROOT%System32Sysprepsysprep.exe /oobe /generalize /shutdown /quiet /unattend:Unattend.xml
goto :eof

:AddAdmin
 setlocal
 set UserName=%~1
 if not defined UserName (echo No username specified&endlocal&exit /b 1)

 call :GetGroupName "S-1-5-32-544" AdminGroup
 if not defined AdminGroup (endlocal&exit /b 2)

 call :GetGroupName "S-1-5-32-545" UserGroup
 if not defined UserGroup (endlocal&exit /b 3)

 net user %UserName% /add
 wmic useraccount where "Name='%UserName%'" set PasswordExpires=False>nul
 net localgroup minGroup% %UserName% /add
 net localgroup %UserGroup% %UserName% /delete
 endlocal&exit /b 0
goto :eof

:GetGroupName
 if "%~1"=="" (echo Group SID not specified&goto :eof)
 set %2=
 for /f "tokens=2 delims= " %%i in ('whoami /groups /fo table^|find "%~1"') do set %2=%%i
 if not defined %2 (echo Error determining group name from SID "%~1")
goto :eof

:ShowMessage
 setlocal enabledelayedexpansion
 set String=%~1
 if not defined String (echo.&setlocal disabledelayedexpansion&goto :eof)
 set /a ConCols=120 & set /a Num=1
 set "String[!Num!].str=%String:=" & set /a Num+=1 & set "String[!Num!].str=%"
 for /l %%a in (1,1,%Num%) do (
 for /l %%b in (0,1,%ConCols%) do if "!String[%%a].str:~%%b!" == "" (set "String[%%a].str= !String[%%a].str! "&set /a String[%%a].len-=1) else (set /a String[%%a].len+=0||set /a String[%%a].len=0)
 if not defined String[%%a].str (set String[%%a].str= )
 if not !String[%%a].len! equ 0 (call set String[%%a].str=%%String[%%a].str:~,!String[%%a].len!%%)
 if "!String[%%a].str: =!"=="" (echo.) else (echo !String[%%a].str!))
 setlocal disabledelayedexpansion
goto :eof

When the script is run, it will check for the presence of the account 'Admin' and create it if it doesn't exist. The account will be added to the 'Administrators' group.

Unattend.xml – response file for sysprep.

reg add HKLM\

When sealing in audit mode, the script will add a command to the registry to terminate the 'sysprep.exe' process so that you don't have to manually close the sysprep window every time. When sealing in welcome mode, the script will remove the command from the registry to close the window and will change the architecture value in the answer file to the current one. The answer file contains parameters for booting the system without user involvement and a command to delete the 'Sysprep' folder at the root of the system drive.

Now I will seal the system in audit mode using 'Sysprep.bat' and capture the system image. I will capture the image using DISM and will only capture the system volume. If you are capturing the image only of the system volume and not the entire disk, don't forget to copy the contents of the 'WindowsSystem32Recovery' directory to the 'RecoveryWindowsRE' folder on the first volume after deploying the system. This needs to be done before booting the OS because after booting the OS, the 'WindowsSystem32Recovery' directory will already be empty.

Step 3 – Localization of the system

The language pack can be installed without an internet connection if you have the pack. If not, the system will download it from the internet when you add the language in the settings. Just be sure not to take the language pack from previous versions of the OS. For Windows 10 1809, the language pack must be specifically for Windows 10 1809.

Microsoft is following its plan – gradually moving settings from the classic menu to the new one, so you will no longer find settings to change the language or install the language pack in the classic control panel. These settings are now only in the system settings.

In audit mode, you may encounter a problem opening system settings from the 'Start' menu. To open system settings, execute the command – 'ms-settings:', note the colon at the end of the command; without it, the command will not work. After you open system settings once using this command, you will then be able to open it using the graphical menu.

However, in system settings, you can install the language pack if the system is connected to the internet; there is no option to choose to install the language pack from a local file.

I won't describe the localization process as it would significantly lengthen the article, especially since the localization process is detailed here. However, I would like to draw your attention to the particularity of changing the system language after installing the language pack via the console. This feature is described in the same wiki to which I provided a link earlier, in the subsection "Adding a Language to the List of Languages".

I will install the language pack without an internet connection.

After fully localizing the system, be sure to create a system image.

Step 4 – Installing Necessary Applications

Since the LTSB and LTSC systems do not have an app store, installing applications from the 'Microsoft Store' poses certain difficulties, namely – downloading the application. To facilitate downloading applications, 'Adguard' created a very convenient service – "Adguard Store", which provides temporary links for downloading applications and their components.

To install the application, you will need files with the extensions 'Appx' and 'AppxBundle'. Before installing the application itself, its components must be installed. Usually, the components of an application can be intuitively distinguished by the file name.

To avoid making the article too lengthy, I won't go into detail about the application installation process, especially since there is a detailed guide. However, I will add another method for installing applications in the current user account. Applications can be installed using the "App Installer", but an internet connection will be required to install the applications; however, applications can be installed with a double-click, and you won't need their components, as all necessary components will be downloaded and installed "App Installer".

And a small reminder, when installing an application in the current user account, the system cannot be sealed. To install applications allowing the system to be sealed, refer to the aforementioned guide. For checking the operation of the multi-kiosk, the already available applications will suffice.

Step 5 – Creating the Configuration File for the Multi-Kiosk

Now we have reached the most interesting part – setting up the kiosk mode. Let's refer to the guide on configuration and see. First of all, we need to create a configuration XML file, a complete example of which can be found be viewed here.

Let's start by setting up the tile layout. The easiest way to create an XML configuration for tile settings is to export their current state..

First, let's add the tiles of the applications we need to the Start menu. Invoke search with 'Win+s', find the desired application, right-click on it, and select 'Pin to Start'.

I pinned the following applications:

  • Notepad
  • Calculator
  • Internet Explorer
  • Paint
  • WordPad
  • Parameters
  • Windows Security

The last two applications were pinned because there are no other universal apps available in the standard LTSC package. Note that the tiles of classic applications link to shortcuts. Now, by moving the tiles directly in the Start menu, I will separate the pinned tiles into two groups. To create a new group of tiles, drag a tile significantly above or below other tiles, and an intuitive divider will appear. You can name the groups as you wish; to do this, place the cursor over the group, and when the prompt 'Name Group' appears, click the left mouse button. I will name the first group 'Settings', which will include the 'Settings' and 'Windows Security' tiles. The second group will be named 'Office Applications', which will include all the other tiles. By the way, entire groups of tiles can be moved by dragging them by the two stripes located at the top right of the group title.

Since the name on the 'Windows Security' tile does not fit completely, I will change its size to 'Wide'. To change the tile size, right-click on the tile and select 'Resize'.

After configuring, we will export the current state by running the command in PowerShell – 'Export-StartLayout – path C:SysprepStartLayout.xml'.

Next, it's easiest not to create the settings file yourself, but to take a sample file from here. Settings – click the 'Copy' button, paste the contents into a text editor, and save it as 'MultiAppKiosk.xml'. Now change the settings to your own. To modify the settings of the pinned tiles, copy the entire 'StartLayoutCollection' block from 'StartLayout.xml' into 'MultiAppKiosk.xml'. To add applications to the allowed list, you need to insert the identifiers of the universal applications in the 'AllowedApps' section, and in this same block, add the full path to the executable files of classic applications, which is specified in the properties of the shortcuts referenced by the tiles. For quick access to the shortcut, right-click on the pinned tile and go through the menu 'More > Open file location'. Please note, to specify the ID of the universal application, use the 'AppUserModelId' parameter, and to specify the full path to the classic application, use the 'DesktopAppPath' parameter. One more small nuance, if you plan to use IE on an x64 system, you need to specify two paths for the executable file in the list of allowed applications: 'Program FilesInternet Exploreriexplore.exe' and 'Program Files (x86)Internet Exploreriexplore.exe'.

I will not provide access to the folders, so I am removing the 'FileExplorerNamespaceRestrictions' section.

Displaying the taskbar will not hinder me, so I will leave everything as is in the 'Taskbar' section.

The example includes two profiles, but I will only have one profile, so the section with the second profile can be removed. Before deleting, take note of the application auto-start example with arguments.

In the 'Configs' section, accounts are linked to profiles. Note that multiple accounts can be linked to a single profile. However, since I am only concerned with one account, I will delete all links except for the first one – the 'Config' blocks. In the remaining link, I will enter the username 'User'.

I ended up with a file like this with parameters

MultiAppKiosk.xml

<![CDATA[
                    
                    
                      
                        
                          
                            
                            
                          
                          
                            
                            
                            
                            
                            
                          
                        
                      
                    
                  
              ]]>
          
          
      
  
  
      
          User

When creating your XML configuration files, remember that each profile must have a unique ID, not only within a single XML file, but across an entire OS. Ideally, to avoid confusion, you can generate a new identifier every time, which can be done in PowerShell using the command "[guid]::NewGuid()". And make sure to save the file in "UTF-8" encoding; if the file is saved in "ANSI" encoding, you will encounter an error during package preparation if there is Cyrillic in the XML file.

Step 6 – Applying Kiosk Settings

Let's consider two methods for applying the settings described in the configuration file. The first is using the preparation package, which needs to be created in ICD. For some, this method may be more familiar. The second is using the "MDM Bridge WMI Provider", which I found to be more convenient.

Method No. 1

For those without ICD, download ADK and install it. The installation of ADK is very straightforward, and you can keep the default component set.

Launch ICD, click on the "Additional Preparation" tile, specify the project name and folder, and click "Next". In the next window, select "All Windows releases for desktop computers" and click "Next". You can skip importing the preparation package, click "Finish".

Expand the "Runtime Options" dropdown menu, then expand the "AssignedAccess" submenu and select "MultiAppAssignedAccessSettings". In the upper part of the middle section of the ICD window, click the "Browse" button and specify the location of the XML file with the settings. As a precaution, you can save the project by pressing "Ctrl+s". In the upper left corner of ICD, select "Export" from the dropdown menu and choose "Preparation Package". For the owner, select "IT Administrator"; you can skip the remaining questions by clicking "Next", then click "Build" and "Finish".

In the installed system, do not forget to create a user named "User"; do not add it to the "Administrators" group, otherwise the kiosk will not function. I created the user in the "Computer Management" snap-in with an unlimited password expiration.

Now we launch the preparation package in the previously installed system. After applying the preparation package, the Start menu and the administrator will change. The buttons: "Documents", "Images", "Settings" should disappear from the left column of the Start menu. If the Start menu has not changed, something went wrong. The installed package can be removed by opening the "Settings > Accounts > Access to work or school account > Add or remove the preparation package" window.

If the Start menu has changed, the settings have been applied to the system. Log in as the user for whom the MultiKiosk is configured and see the result.

Method #2

Applying settings using the "MDM Bridge WMI Provider" described here. The convenience of this method lies in its flexibility and the ability to eliminate many manual operations required to create a preparation package. Here, everyone can create a solution that suits them. I created a couple of scripts for myself.

MiltiKiosk.bat – script for launch

@echo off
chcp 1251>nul

if not exist "%~dp0psexec.exe" call :ShowMessage "‑‑‑‑‑‑‑‑‑‑‑‑‑The script requires the file psexec.exe‑‑Press any key to exit the script"&pause>nul&exit

net session>nul 2>nul
if %errorLevel% neq 0 (powershell -command "Start-Process "%~s0" -Verb RunAs"&exit)

for /f "tokens=2 delims==" %%i in ('wmic useraccount where "Name='%UserName%'" get SID /value^|find "SID"') do set SID=%%i
reg add HKU%SID%SoftwareSysinternalsPsExec /v EulaAccepted /t REG_DWORD /d 1 /f

for /f %%i in ('dir "%~dp0%~n0*.ps1" /b /o:n') do set PSFilePath=%~dp0%%i
if not defined PSFilePath (echo No PS files found starting with - "%~n0"&pause&exit)
set PSFilePath=%PSFilePath: =` %
"%~dp0psexec.exe" -i -s powershell -command "Start-Process powershell.exe -ArgumentList '-ExecutionPolicy Unrestricted -Command %PSFilePath%'"

exit

:ShowMessage
    setlocal enabledelayedexpansion
    set String=%~1
    if not defined String (echo.&setlocal disabledelayedexpansion&goto :eof)
    set /a ConCols=120 & set /a Num=1
    set "String[!Num!].str=%String:‑=" & set /a Num+=1 & set "String[!Num!].str=%"
    for /l %%a in (1,1,%Num%) do (
        for /l %%b in (0,1,%ConCols%) do if "!String[%%a].str:~%%b!" == "" (set "String[%%a].str= !String[%%a].str! "&set /a String[%%a].len-=1) else (set /a String[%%a].len+=0||set /a String[%%a].len=0)
        if not defined String[%%a].str (set String[%%a].str= )
        if not !String[%%a].len! equ 0 (call set String[%%a].str=%%String[%%a].str:~,!String[%%a].len!%%)
        if "!String[%%a].str: =!"=="" (echo.) else (echo !String[%%a].str!))
    setlocal disabledelayedexpansion
goto :eof

MiltiKiosk_Ver.12.ps1 – main script

Function ConvertEncoding ([string]$From, [string]$To) {
    Begin{$encFrom = [System.Text.Encoding]::GetEncoding($From);$encTo = [System.Text.Encoding]::GetEncoding($To)}
    Process{$bytes = $encTo.GetBytes($_);$bytes = [System.Text.Encoding]::Convert($encFrom, $encTo, $bytes);$encTo.GetString($bytes) -replace [char]0, ''}
}

Function ShowMessage ($Message='', $Align=0) {
    Try {$Align = [decimal]$Align} Catch {Return 'For the Align parameter, only a number can be specified' | ConvertEncoding 'windows-1251' -To 'UTF-16'}
    if ($Message -is [int]) {for ($i=1; $i -le $Message; $i++) {Write-Host}; Return}
    if ([System.Text.Encoding]::Default.WindowsCodePage -eq 1252) {$Message = $Message | ConvertEncoding 'windows-1251' -To 'UTF-16'}
    if ($Message -is [string]) {[array] $Message = $Message}
    foreach ($String in $Message) {
        Try {$String = [int]$String} Catch {}
        if ($String -is [int]) {for ($i=1; $i -le $String; $i++) {Write-Host}; continue}
        if ($Host.UI.RawUI.BufferSize.Width -gt $String.Length) {
            if ($Align -eq 0) {Write-Host $String
            } else {Write-Host ("{0}{1}" -f (' ' * (([Math]::Max(0, $Host.UI.RawUI.BufferSize.Width / $Align) - [Math]::Floor($String.Length / $Align)))), $String)}
        } else {Write-Host $String}
    } 
}

$script:NameSpace="rootcimv2mdmdmmap"
$script:ClassName="MDM_AssignedAccess"
$script:MultiAppKiosk = Get-CimInstance -Namespace $NameSpace -ClassName $ClassName
if (-not $MultiAppKiosk) {ShowMessage -Message (3, 'Error retrieving the configuration object', 2, 'Press "Enter" to exit the script') -Align 2; Read-Host; Exit}

Function MainMenu() {
    ShowMessage (13, ' 0 - Exit', ' 1 - Select XML file for installation', ' 2 - Show current multi-kiosk configuration', ' 3 - Remove multi-kiosk settings', 1)
    $local:PromptText = 'Select an action'
    if ([System.Text.Encoding]::Default.WindowsCodePage -eq 1252) {$PromptText = $PromptText | ConvertEncoding 'windows-1251' -To 'UTF-16'}

    $local:Selections = 1..2
    While ($true) {
        $Select = Read-Host -Prompt $PromptText
        Switch ($Select) {
            0 {exit}
            1 {XMLSelection}
            2 {ShowMessage -Message (1, 'Configuration process starting') -Align 2; Write-Host $MultiAppKiosk.Configuration; ShowMessage -Message ('End of configuration', 1, 'Press "Enter" to return to the menu', 1) -Align 2; Read-Host}
            3 {$MultiAppKiosk.Configuration = $Null; Set-CimInstance -CimInstance $MultiAppKiosk; ShowMessage -Message (1, 'Settings removal command executed', 1) -Align 2}
            DEFAULT {ShowMessage 'Invalid selection'}
        }
        if ($Selections -contains $Select) {Clear-Host; ShowMessage (15, ' 0 - Exit', ' 1 - Select XML file for installation', ' 2 - Show current multi-kiosk configuration', ' 3 - Remove multi-kiosk settings', 1)}
    }
}

Function XMLSelection() {
    Clear-Host

    if (!(Test-Path -Path $PSScriptRoot'XML')) {ShowMessage -Message (13, 'Directory not found', $('"'+$PSScriptRoot+'XML"'), 1, 'Press "Enter" to return to the previous menu') -Align 2; Read-Host; Return}

    $local:XMLList = @()
    $XMLList += Get-ChildItem -Path $PSScriptRoot'XML' -name -filter '*.xml'
    if ($XMLList.Count -eq  0) {ShowMessage -Message (13, 'No XML files found in the directory', $('"'+$PSScriptRoot+'XML"'), 1, 'Press "Enter" to return to the previous menu') -Align 2; Read-Host; Return}

    [int]$local:Indent = 13 - $XMLList.Count / 2; if ($Indent -lt 1) {$Indent = 1}
    ShowMessage ($Indent, ' 0 - Return to the previous menu')
    for ($i=0; $i -le $XMLList.GetUpperBound(0); $i++) {Write-Host $(' '+($i+1)+' - '+$XMLList[$i])}
    Write-Host
    $local:PromptText = 'Select file for installation'
    if ([System.Text.Encoding]::Default.WindowsCodePage -eq 1252) {$PromptText = $PromptText | ConvertEncoding 'windows-1251' -To 'UTF-16'}

    $local:Selections = 1..$XMLList.Count
    $local:BackToPrevMenu = 0
    While ($BackToPrevMenu -eq 0) {
        $Select = Read-Host -Prompt $PromptText
        Switch ($Select) {
            0 {$BackToPrevMenu = 1}
            {$Selections -contains $Select} {ShowMessage $('This command is for applying settings from the file '+$XMLList[$Select-1]);
                $local:Config = (Get-Content -encoding UTF8 -path $($PSScriptRoot+'XML'+$XMLList[$Select-1]) -Raw).Trim()
                $local:GUIDs = [regex]::matches($Config, '{.+?}') | select -ExpandProperty Value | Get-Unique
                foreach ($GUID in $GUIDs) {$Config = $Config -replace $(''+$GUID),$('{'+[guid]::NewGuid()+'}')}
                $Config = $Config -replace '&','&' -replace '<','<' -replace '>','>' -replace "'",''' -replace '"','"'
                $MultiAppKiosk.Configuration = $Config
                Set-CimInstance -CimInstance $MultiAppKiosk
            }
            DEFAULT {ShowMessage ('Invalid selection')} 
        }
    }
}

MainMenu

If you want to use my solution, save the above scripts in a folder with their original names and place the file "PsExec.exe" in the same folder. In this folder, create a folder named "XML" and copy the XML files for configuring the multi-kiosk into it. I will use the same file as in the first method.

MultiAppKiosk.xml

<![CDATA[
                    
                    
                      
                        
                          
                            
                            
                          
                          
                            
                            
                            
                            
                            
                          
                        
                      
                    
                  
              ]]>
          
          
      
  
  
      
          User

A bit about the script's features. The script is designed to use XML files with "UTF8" encoding; if you want to use "ANSI" encoding, remove the parameter "encoding UTF8" from the file reading parameter. XML files must be placed in the "XML" folder without character replacement; the script will automatically replace special characters with the corresponding symbols. To avoid confusion with the user GUIDs linked to profiles, you can simply specify the user number or name in curly braces; all content in curly braces will be replaced with GUIDs.

Using the script is very simple; just run it and select the required option. You do not need to delete the current configuration to change it to a new one; it will be overwritten. Don't forget to create users that are specified in the configuration file.

When viewing the current configuration of the multi-kiosk in the same session where it was applied, replacement symbols will be displayed instead of special characters. After changing sessions (restarting the script), all special characters will be displayed in their original form.

Step 7 – sealing the system

The multi-kiosk is working, and that's it, it seems...

If everything is going according to plan, then you may not be noticing something.

Let's not forget that we also need to switch the system from audit mode to welcome mode. Well, we are ready for this; we run "Sysprep.bat", select option 2, the system seals. We turn on the device, the system boots, we log into the user account for which the multi-kiosk is set up, and cannot log in. After the "Welcome" message, the message "Signing Out" appears.

Initially, I wanted to describe only the solution to the problem, but later I decided to outline the steps for identifying the problem and finding the simplest solution, as many readers might have lingering doubts – "What if it’s like this...?" I believe that detailing various experiments will save you a significant amount of time if you wish to find an alternative solution. To ensure the information is as accurate as possible, and to double-check for any errors, I will describe the experiments in the format of "did – recorded." That is, I will repeat the described experiments.

Experiments

So, what do we have? The system has two accounts:

"Admin" – in the "Administrators" group
"User" – in the "Users" group
In audit mode, the kiosk mode worked; once sealed – it does not.

Experiment 1

We remove the installed provisioning package, in the "Computer Management" snap-in we delete the user "User" and create a new user named "User," apply the provisioning package, log in to the "User" account – it does not work. We log in as "Admin," remove the user "User" from the "Users" group, add it to the "Administrators" group, log in as "User" – it does not work. We log in as "Admin," remove the provisioning package with the kiosk mode, log in as "User" – managed to log in, but of course, kiosk mode does not work since the provisioning package was deleted.

Experiment 2

We upload the system image – localized in audit mode.

The OS has booted up. We press 'Win+r' since the sysprep window closed automatically. We execute the command 'sysprep', and in the opened window, we start 'sysprep'. The sysprep settings in the window are: 'OOBE transition', 'Preparation for use', 'Restart'. We press 'OK' and wait for the OS greeting. We answer the questions during the first system load: 'Continue in selected language?' – 'English'; region – United States; keyboard layout – English; add a second keyboard layout – skip; 'Let’s connect you to a network' – 'Skip for now'; connect to the internet – no; license agreement – accept; 'Who will use this computer?' – 'Test'; password creation – leave the field blank; comfortable use on different devices – no; privacy settings – accept. The OS has booted, and in the 'Computer Management' console, we create a user named 'User' and add the preparation package. Result – it does not work.

Experiment 3

We upload the system image – localized in audit mode.

The OS has booted up, we connect the system to the internet, execute the command 'gpedit.msc' and in the 'Windows Update Center' section, we enable the setting 'Turn on recommended updates through automatic updates'. Just in case, we restart. In the update center, we click 'Check for updates' and restart until all updates are installed. We disconnect the system from the internet. We launch 'sysprep' in graphical mode and repeat all the actions described in the previous step of launching the 'sysprep' utility up to the addition of the preparation package. Result – it does not work.

Experiment 4

Uploading the system image – English version in audit mode.

We launch 'sysprep' in graphical mode, sealing the OS with the same parameters as in Experiment 2. During the initial system boot, we select the same parameters as in Experiment 2, except for regional and language settings since there is no Russian language. We create the user 'User' the same way and add the preparation package. Result – it works. That is, the problem is related to localization.

Experiment 5

We upload the system image – localized in audit mode.

In the 'Computer Management' console, we create the user 'User', add the preparation package, log into the 'User' account, the multi-user kiosk works.

Log out from the account, log in with the account "Admin". Launch PowerShell with administrator rights, execute the command "Dism /online /Get-Intl" and see "Default UI language: en-US."

Boot from the flash drive into WinPE, my deployed OS is on drive E. Execute the command "Dism /image:E: /Set-UILang:ru-ru". Check the result, execute "Dism /image:E: /Get-Intl" and see "Default system UI language: ru-RU."

Boot into the system, log in with the account "User", the multi-kiosk is not working.

To clearly capture the cause-and-effect relationship of the problem's emergence, let's try to make the multi-kiosk work and not work once again.

Boot from the flash drive into WinPE, my deployed OS is on drive E. Execute the command "Dism /image:E: /Set-UILang:en-us". Check the result, execute "Dism /image:E: /Get-Intl" and see "Default system UI language: en-US."

Boot into the system, log in with the account "User", the multi-kiosk is working.

Boot from the flash drive into WinPE, my deployed OS is on drive E. Execute the command "Dism /image:E: /Set-UILang:ru-ru". Check the result, execute "Dism /image:E: /Get-Intl" and see "Default system UI language: ru-RU."

Boot into the system, log in with the account "User", the multi-kiosk is not working.

That is, one can see a clear dependency of the kiosk's functionality on the value of the default UI language. Are there any other factors that might affect the functionality of the multi-kiosk?

Experiment 6

For the purity of the experiment, we will reinstall the system. We will upload the system image - localized in audit mode.

Run "sysprep" in graphical mode, seal the OS with the same parameters as in experiment 2. Wait for the OS welcome and answer the questions: "Continue in selected language?" – "English (United States)"; region – Russia; keyboard layout – Russian. All other parameters are selected as in experiment 2.

Check the parameters of the default UI language. Execute the command "Dism /online /Get-Intl" and see "Default system UI language: en-US." In the "Computer Management" console, create a user "User", add a preparation package, log in to the account "User", the multi-kiosk is working.

We will try to break the kiosk by changing the default UI language. Log into the user "Test", which was created during the first system boot, and enable automatic login for it so the system does not load into the account "User" immediately. Execute "netplwiz", select the user "Test", uncheck the box "Require user name and password", and apply the settings.

Booting from USB into WinPE. Execute the command "Dism /image:E: /Set-UILang:en-US". Check the result, run "Dism /image:E: /Get-Intl" and see "Default system UI language: en-US".

Booting into the system, trying to log in to the account "User", multi-kiosk is working. That is, it cannot be broken. But can it be forced to work like this?

Experiment 7

We upload the system image – localized in audit mode.

Running "Sysprep.bat", selecting item 2. Booting into the system, in the "Computer Management" snap-in, create the user "User", add the preparation package, log into the account "User", multi-kiosk is not working.

Booting from USB into WinPE. Execute the command "Dism /image:E: /Set-UILang:en-US". Check the result, run "Dism /image:E: /Get-Intl" and see "Default system UI language: en-US".

Booting into the system, trying to log in to the account "User", multi-kiosk is not working.

It turns out that by changing the default user interface language setting, the functionality of the multi-kiosk can only be affected when the system is in audit mode or upon the first boot after sealing the system. This means that the system will have to be sealed with an answer file that selects the system language as English, and then change the system settings to make the interface Russian. Not a very good solution. Maybe the problem can be resolved by installing a language pack or installing additional language packs?

Experiment 8

Uploading the system image – English version in audit mode.

Connect to the internet, go to the system settings, in the "Language" section select "Add language", choose the language "Russian", click "Next", leave the installation options as default, click "Install", after installing the language pack restart the system, now it is localized. Disconnect the system from the internet, run "Sysprep.bat", selecting item 2.

After booting the system in the "Computer Management" snap-in, create the user "User", add the preparation package, log into the account "User", multi-kiosk is not working.

Experiment 9

Let's try localizing the system before installation, in offline mode. Meanwhile, it will be a brief tutorial on localizing the distribution.

I take a flash drive with a clean original distribution – X21-96381. It will be disk "E". To mount the images, I create folders: "c:MountInstall", "c:MountWinre", "c:MountBoot". I take the localization package set – X21-87814. And I copy the following packages into the "c:Mount" folder: "Microsoft-Windows-Client-Language-Pack_x86_ru-ru.cab", "lp.cab", "WinPE-Setup_ru-ru.cab". I launch the console with administrator rights. I believe the further commands will be understandable without comments.

Localization Commands

cd c:mount
dism /Mount-Wim /WimFile:e:sourcesinstall.wim /index:1 /MountDir:Installcode
dism /Image:Install /Add-Package /PackagePath:Microsoft-Windows-Client-Language-Pack_x86_ru-ru.cabcode
dism /Image:Installcode /Set-AllIntl:ru-ru
dism /Image:Install /Set-TimeZone:"Russian Standard Time"code

dism /Mount-Wim /WimFile:InstallWindowsSystem32RecoveryWinre.wim /index:1 /MountDir:Winrecode
dism /Image:Winre /Add-Package /PackagePath:lp.cabcode
dism /Image:Winrecode /Set-AllIntl:ru-ru
dism /Image:Winre /Set-TimeZone:"Russian Standard Time"code
dism /Unmount-Image /MountDir:Winre /Commitcode

dism /Image:Install /Gen-LangINI /distribution:E: /Set-AllIntl:ru-RUcode
dism /image:Install /Set-SetupUILang:RU-ru /distribution:E:code
dism /Unmount-Image /MountDir:Install /Commitcode

dism /mount-wim /wimfile:e:sourcesboot.wim /index:1 /mountdir:Bootcode
dism /Image:Boot /Add-Package /PackagePath:lp.cabcode
dism /Image:Bootcode /Set-AllIntl:ru-ru
copy e:sourceslang.ini Bootsourceslang.inicode
dism /Unmount-Image /MountDir:Boot /Commitcode

dism /mount-wim /wimfile:e:sourcesboot.wim /index:2 /mountdir:Bootcode
dism /Image:Boot /Add-Package /PackagePath:lp.cabcode
dism /Image:Boot /Add-Package /PackagePath:WinPE-Setup_ru-ru.cabcode
dism /Image:Bootcode /Set-AllIntl:ru-ru
copy e:sourceslang.ini Bootsourceslang.ini /ycode
dism /Unmount-Image /MountDir:Boot /Commit

We boot from the flash drive, select Russian as the language, and install the system on a clean disk. When the system asks to select a region, we press "Ctrl+Shift+F3". In the "Computer Management" snap-in, we create the user "User", add the preparation package, log into the "User" account, and the multimedia kiosk does not work.

We boot from the flash drive into WinPE. We execute the command "Dism /image:E: /Set-UILang:en-us".

We boot into the system, try to enter the "User" account, and the multimedia kiosk works.

Apparently, the issue is not with the package addition methods; let's try adding additional packages.

Experiment 10

We take the flash drive that we prepared in the previous step.

We take the "Feat on Demand" package – X21-87815. I copy the following packages into the "c:Mount" folder: "Microsoft-Windows-LanguageFeatures-Basic-ru-ru-Package~31bf3856ad364e35~x86~~.cab", "Microsoft-Windows-LanguageFeatures-OCR-ru-ru-Package~31bf3856ad364e35~x86~~.cab", "Microsoft-Windows-LanguageFeatures-Handwriting-ru-ru-Package~31bf3856ad364e35~x86~~.cab", "Microsoft-Windows-LanguageFeatures-TextToSpeech-ru-ru-Package~31bf3856ad364e35~x86~~.cab".

We take the package "Feat on Demand RDX Updt" – X21-99781. I copy from it to the folder "c:Mount": "Microsoft-Windows-RetailDemo-OfflineContent-Content-Package~31bf3856ad364e35~x86~~.cab", "Microsoft-Windows-RetailDemo-OfflineContent-Content-ru-ru-Package~31bf3856ad364e35~x86~~.cab".

We launch the console with administrator rights and execute the commands:

Commands

cd c:mount
dism /Mount-Wim /WimFile:e:sourcesinstall.wim /index:1 /MountDir:Install
dism /Add-Package /Image:Install /PackagePath:Microsoft-Windows-LanguageFeatures-Basic-ru-ru-Package~31bf3856ad364e35~x86~~.cab
dism /Add-Package /Image:Install /PackagePath:Microsoft-Windows-LanguageFeatures-OCR-ru-ru-Package~31bf3856ad364e35~x86~~.cab
dism /Add-Package /Image:Install /PackagePath:Microsoft-Windows-LanguageFeatures-Handwriting-ru-ru-Package~31bf3856ad364e35~x86~~.cab
dism /Add-Package /Image:Install /PackagePath:Microsoft-Windows-LanguageFeatures-TextToSpeech-ru-ru-Package~31bf3856ad364e35~x86~~.cab
dism /Add-Package /Image:Install /PackagePath:Microsoft-Windows-RetailDemo-OfflineContent-Content-Package~31bf3856ad364e35~x86~~.cab
dism /Add-Package /Image:Install /PackagePath:Microsoft-Windows-RetailDemo-OfflineContent-Content-ru-ru-Package~31bf3856ad364e35~x86~~.cab
dism /Unmount-Image /MountDir:Install /Commit

We boot from the flash drive, select Russian language, and install the system on a clean disk. When the system asks to choose a region, we press "Ctrl+Shift+F3". In the "Computer Management" snap-in, we create a user called "User", add the preparation package, and log in to the account "User". I got a black screen that hung for a long time, so I performed a hot reboot of the system.

We remove the preparation package, log in as "User", reboot the system, add the preparation package, the multimedia kiosk is not working.

We boot from the flash drive into WinPE. We execute the command "Dism /image:E: /Set-UILang:en-us".

We boot into the system, try to enter the "User" account, and the multimedia kiosk works.

Bypassing the issue

Normal heroes always find a way around!

Various methods of installing localization packages did not solve the problem, so we will have to set the language to "en-us" upon first boot after sealing, and then change the language settings after the first boot.

We upload the system image – localized in audit mode.

In the file "Unattend.xml", we enter "en-US" in the parameter, run "Sysprep.bat", select option 2, and see what we got. The welcome screen is in English, the multimedia kiosk works. So we need to add a command to "Unattend.xml" to change the welcome language. For this, it is necessary to execute the command "control intl.cpl,,/f:" with the configuration file specified, in which the copying of current settings to the welcome screen will be written. The content of the configuration file will look like this.

Since we will be copying the settings of the current user, the command needs to be executed after the user logs into the system, which means we will need to. There is one small catch: the execution will be after the user logs in with administrator rights. I would prefer not to create an additional file that would be necessary for successfully executing the command. It's better to implement the entire solution in a single file β€” 'Unattend.xml'. To do this, we just need to run the command that creates the configuration file. I think I will create the configuration file using the 'echo' command in the 'cmd' environment, but in it, we need to escape angle brackets with a caret. Thus, to create the configuration file, the command will look like this.

echo ^^^^^ >>Config.xml

But we need to place this command in XML, which has its own requirements for the use of special symbols:

Special symbol
Placeholder value

>
>

<
<

&
&

β€˜
'

β€œ
"

As a result, the command to create the configuration file turned out to be like this for 'FirstLogonCommands'.

cmd.exe /c echo ^<gs:GlobalizationServices xmlns:gs="urn:longhornGlobalizationUnattend"^>^<gs:UserList^>^<gs:User UserID="Current" CopySettingsToSystemAcct="true"/^>^</gs:UserList^>^</gs:GlobalizationServices^>>"%TMP%Config.xml"

Next, we execute the command using the configuration file.

control intl.cpl,,/f:"%TMP%Config.xml"

Then, we delete the previously created file and restart the system since the changes will take effect after the reboot.

cmd.exe /c del "%TMP%Config.xml" /q&&shutdown /r /f /t 00

As a result, I ended up with this answer file for sysprep.

Unattend.xml

reg add HKLMSoftwareMicrosoftWindowsCurrentVersionSetupOOBE /v SetupDisplayedProductKey /t REG_DWORD /d 1 /f
                    1
                    Don't show key page
                
                
                    reg add HKLMSoftwareMicrosoftWindowsCurrentVersionSetupOOBE /v UnattendCreatedUser /t REG_DWORD /d 1 /f
                    2
                    Don't create account
                
                
                    cmd.exe /c rd %systemdrive%Sysprep /s /q
                    3
                    Delete Folder
                
            
        
        
            
                true
                Admin
            
        
    
    
        
            en-US; ru-RU
            ru-RU
            en-US
            
            ru-RU
        
        
            
                true
                true
                true
                true
                true
                1
            
            
                
                    cmd.exe /c echo ^<gs:GlobalizationServices xmlns:gs="urn:longhornGlobalizationUnattend"^>^<gs:UserList^>^<gs:User UserID="Current" CopySettingsToSystemAcct="true" /^>^</gs:UserList^>^</gs:GlobalizationServices^>>"%TMP%Config.xml"
                    CreateConfig
                    1
                
                
                    control intl.cpl,,/f:"%TMP%Config.xml"
                    UseConfig
                    2
                
                
                    cmd.exe /c del "%TMP%Config.xml" /q&shutdown /r /f /t 00
                    DeleteConfig
                    3

Checking…

We upload the system image – localized in audit mode.

We replace the Unattend.xml file with the new one, run 'Sysprep.bat', select option 2, and see what we get. On first boot, the welcome screen is in English, the system reboots. The welcome screen in Russian, the multi-kiosk works.

If you have any questions regarding the setup and licensing of Windows 10 IoT Enterprise, please contact mse@quinta.ru or visit the website quinta-embedded.ru.
You can find answers to some questions in our wiki or on our the YouTube channel

Article by: Borisenkov Vladimir, technical expert at Quarta Technologies.

Source: habr.com

Buy reliable website hosting with DDoS protection, VPS VDS servers πŸ”₯ Buy reliable website hosting with DDoS protection, VPS VDS servers | ProHoster