DisplaySync/ docs

Kiosk configuration

This page is the lock-down step. After Base Windows setup you have a fully-patched Windows 11 Pro device with venue networking pre-staged. Now we turn it into a kiosk: a dedicated low-privilege user that auto-logs in at boot, the DisplaySync sign app set up to launch automatically, never any monitor sleep, and Windows shell features (lock screen, Cortana, Action Center, etc.) disabled.

Almost all of this is automated by provision-windows.ps1, which ships in the desktop-sign repo. This page documents what the provisioner does and why, so you can audit, troubleshoot, or replicate it manually if needed.

If you just want to run the script

Skip ahead to Installing DisplaySync — that page covers running provision-windows.ps1, which does everything on this page in one command. Come back here when you need to understand or modify a specific concern.

The kiosk user

The image runs the sign app under a dedicated non-administrator local account named DisplaySync. Reasons to keep it isolated from the image-builder admin (imgadmin):

  • Limits blast radius if anything compromises the kiosk runtime
  • Lets us scope file/registry permissions narrowly
  • Auto-login credentials live in the registry in plaintext (Microsoft's design, not ours) — better that's a low-privilege account than the admin

Create it:

$securePassword = ConvertTo-SecureString "<random-password>" -AsPlainText -Force
New-LocalUser -Name "DisplaySync" `
  -Password $securePassword `
  -FullName "DisplaySync Kiosk" `
  -Description "Dedicated kiosk user for DisplaySync Sign" `
  -PasswordNeverExpires `
  -UserMayNotChangePassword
Add-LocalGroupMember -Group "Users" -Member "DisplaySync"

Generate a long random password (16+ chars). The provisioner generates and prints one once on completion — capture it then; you won't see it again without re-reading the registry.

The kiosk user also needs shutdown privilege so the dashboard's remote-reboot command works without invoking UAC. Grant it via secedit (the provisioner does this; the manual approach is to add the user to SeShutdownPrivilege in secedit /export → edit → secedit /configure).

Auto-login

Auto-login lives in three Winlogon registry values:

HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon
  AutoAdminLogon   = "1"
  DefaultUserName  = "DisplaySync"
  DefaultPassword  = "<the password from above>"
  DefaultDomainName = "<computername>"
$winlogon = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
Set-ItemProperty -Path $winlogon -Name "AutoAdminLogon"  -Value "1"
Set-ItemProperty -Path $winlogon -Name "DefaultUserName" -Value "DisplaySync"
Set-ItemProperty -Path $winlogon -Name "DefaultPassword" -Value $KioskPassword
Set-ItemProperty -Path $winlogon -Name "DefaultDomainName" -Value $env:COMPUTERNAME

Disable Fast Startup

Windows' Fast Startup feature (a hybrid hibernate-on-shutdown) interferes with reliable auto-login on cold boot. Disable it:

Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Power" `
  -Name "HiberbootEnabled" -Value 0

Without this, you'll see intermittent "DefaultUserName not auto-logged in" boots that look like flaky hardware.

Auto-start the sign app

The sign app launches via a Scheduled Task triggered at the kiosk user's logon. Scheduled Task vs. a Startup-folder shortcut matters: the task supports RestartCount/RestartInterval, so if the app crashes it relaunches automatically. (Crash recovery covers the watchdog details.)

$exePath  = "C:\Program Files\DisplaySync Sign\DisplaySync Sign.exe"
$action   = New-ScheduledTaskAction -Execute $exePath
$trigger  = New-ScheduledTaskTrigger -AtLogOn -User "DisplaySync"
$settings = New-ScheduledTaskSettingsSet `
  -AllowStartIfOnBatteries `
  -DontStopIfGoingOnBatteries `
  -RestartCount 3 `
  -RestartInterval (New-TimeSpan -Minutes 1) `
  -ExecutionTimeLimit (New-TimeSpan -Hours 0)

Register-ScheduledTask `
  -TaskName "DisplaySync Sign" `
  -Action $action `
  -Trigger $trigger `
  -Settings $settings `
  -User "DisplaySync" `
  -RunLevel Limited `
  -Description "Start DisplaySync Sign on kiosk user login" `
  -Force

RunLevel Limited is intentional — the sign app does not need elevation, and running it as a regular user is part of the lock-down posture.

Power management

A kiosk should never sleep, dim, or hibernate. Apply the High Performance plan and zero out every timeout:

# Activate High Performance plan
$highPerf = (powercfg /list | Select-String "High performance") -match "([0-9a-f-]{36})"
powercfg /setactive $Matches[1]

# Disable monitor + sleep + hibernate (AC and DC)
powercfg /change monitor-timeout-ac 0
powercfg /change monitor-timeout-dc 0
powercfg /change standby-timeout-ac 0
powercfg /change standby-timeout-dc 0
powercfg /change hibernate-timeout-ac 0
powercfg /change hibernate-timeout-dc 0
powercfg /hibernate off

Disabling hibernate also reclaims hiberfil.sys (typically a few GB) — useful on small SSDs.

Disable Windows shell distractions

The kiosk needs the screen and the screen alone — no lock screen, Cortana, Action Center, "tip of the day" toasts, or first-run animations. Each is one or two registry values:

# Lock screen off
$lock = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Personalization"
New-Item -Path $lock -Force | Out-Null
Set-ItemProperty -Path $lock -Name "NoLockScreen" -Value 1

# Cortana off
$cortana = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Windows Search"
New-Item -Path $cortana -Force | Out-Null
Set-ItemProperty -Path $cortana -Name "AllowCortana" -Value 0

# Action Center / notification center off
$action = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Explorer"
New-Item -Path $action -Force | Out-Null
Set-ItemProperty -Path $action -Name "DisableNotificationCenter" -Value 1

# Consumer features, soft-landing tips, tailored experiences off
$cloud = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\CloudContent"
New-Item -Path $cloud -Force | Out-Null
Set-ItemProperty -Path $cloud -Name "DisableWindowsConsumerFeatures" -Value 1
Set-ItemProperty -Path $cloud -Name "DisableSoftLanding" -Value 1
Set-ItemProperty -Path $cloud -Name "DisableTailoredExperiencesWithDiagnosticData" -Value 1

# Allow shutdown without an interactive logon (for remote reboot)
$sys = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"
Set-ItemProperty -Path $sys -Name "ShutdownWithoutLogon" -Value 1

You can verify a value with Get-ItemProperty -Path <key> -Name <value>.

Windows Update active hours

Default Windows behavior is to install cumulative updates and reboot the device whenever it feels like it. That is unacceptable mid-show. Constrain updates to a quiet window — by default, the provisioner uses 6 AM to 11 PM as "active hours" (no reboots), and schedules installs for 3 AM:

$ux = "HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings"
New-Item -Path $ux -Force | Out-Null
Set-ItemProperty -Path $ux -Name "ActiveHoursStart" -Value 6
Set-ItemProperty -Path $ux -Name "ActiveHoursEnd"   -Value 23

$au = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU"
New-Item -Path $au -Force | Out-Null
Set-ItemProperty -Path $au -Name "AUOptions" -Value 4              # auto-download + scheduled install
Set-ItemProperty -Path $au -Name "ScheduledInstallTime" -Value 3   # 3 AM

For events with overnight programming, narrow the window further or pause updates entirely during the freeze window — see Stability over features.

Optional: Shell Launcher (IoT Enterprise)

If you build on Windows 11 IoT Enterprise, you can replace the Explorer shell entirely with the DisplaySync sign app. There's no Start menu, no taskbar, no desktop — the app is the shell. This is the strictest lock-down available:

Enable-WindowsOptionalFeature -Online -FeatureName "Client-EmbeddedShellLauncher"

$shellLauncher = [wmiclass]"\\.\root\standardcimv2\embedded:WESL_UserSetting"
$shellLauncher.SetCustomShell(
  "$env:COMPUTERNAME\DisplaySync",
  "C:\Program Files\DisplaySync Sign\DisplaySync Sign.exe",
  $null, $null, 1
)
$shellLauncher.SetEnabled($true)

Pro edition does not support Shell Launcher — the auto-login + scheduled task + lock-down policies above produce a "good enough" kiosk on Pro. Reach for IoT Enterprise when you need belt-and-braces, e.g., regulated industries or signage that runs unattended for months.

Verify

Once everything is applied, sign out of imgadmin and let the device reboot. It should:

  1. Cold-boot to the Winlogon screen
  2. Auto-login as DisplaySync without prompting
  3. Launch the sign app within ~5 seconds (you'll likely see a blank desktop briefly — that's expected on Pro; IoT Enterprise hides this entirely)
  4. Display the QR setup screen full-screen if not yet claimed, or the assigned content if already claimed

If any step fails, the most common causes:

SymptomLikely cause
Stops at Winlogon screenAutoAdminLogon not set, or wrong DefaultPassword
Auto-login but no sign appScheduled Task not registered, or kiosk user lacks read access to the install dir
App launches then closes immediatelyMissing .env config — see Installing DisplaySync
Lock screen appears on idleLock screen policy didn't apply; re-run the relevant Set-ItemProperty

Once auto-login + auto-start + lock-down are all working, move to Installing DisplaySync for the actual app install and configuration. (If you ran provision-windows.ps1, that's already done — and you can skip ahead to Tailscale integration.)