DisplaySync

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.

PIN-protecting the config overlay

The desktop sign supports a 4-digit PIN that gates the Ctrl+Shift+C config overlay. When set, anyone pressing the hotkey on the kiosk gets a PIN-entry window before the URL editor / kiosk-mode toggle / Exit-for-Maintenance controls become accessible.

When to set a PIN:

  • Multi-tenant deployments where the venue's onsite staff may have keyboard access to a kiosk that belongs to a different tenant
  • Public-venue kiosks where curious guests might press shortcuts to "see what happens"
  • Customer-managed fleets where techs (your team) and operators (the customer) need different surfaces — operators get the dashboard; techs get the PIN

When not to: for single-tenant fleets where the same crew owns both keyboard access and the dashboard, the dashboard's RBAC is already the gate. PINs add friction without changing the threat model.

How to set a PIN: there is no first-class UI for this in V1. The PIN is stored salted-SHA-256 in the pinHash field of sign-config.json (see File locations). Setting it during image prep means writing this field directly before Sysprep capture, or relying on a deployment-time provisioning step.

Recovery story: there is no in-app reset path. If the PIN is lost, recovery is via:

  • USB recovery with freshConfig: true — wipes the entire config (including identity). See USB recovery → Setup script.
  • Direct file edit if you have RDP/VNC access — delete or zero pinHash in the config file. See File locations for the path.

Both are destructive enough that "set a PIN" is a real commitment. Plan accordingly.

Monitoring mode at deployment time

sign-config.json carries a monitoringMode boolean that determines whether the sign cold-boots in monitoring mode (display hidden, audio muted, telemetry only) or in normal active mode.

Almost always: leave it false in the image. A sign with monitoringMode: true baked in will come up silent on every kiosk cloned from that image — operators won't see anything on the wall and won't necessarily know why.

The narrow case where pre-baked monitoring makes sense: a fleet that ships to venues days before showtime and you want every wall dark on arrival, then a single dashboard "Exit Monitoring" sweep activates them at the right moment. Even then, individual operators forgetting to flip later is a real risk.

For more on what monitoring mode does at runtime, see Remote control → Monitoring mode and Hotkeys → Ctrl+Shift+M.

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.)