-
Notifications
You must be signed in to change notification settings - Fork 0
Deployment At Scale
Everything TaskbarUtil does is per-user and local. There is no server, no agent, no scheduled task and no inventory. Deploying a taskbar layout across a fleet therefore means deciding two things: which file becomes the layout, and in whose session the tool runs. This page covers what an administrator actually runs, and when, grounded in what the tool supports.
| Point | Reaches | Runs as | Shell restart |
|---|---|---|---|
| Image time / provisioning | Every profile created afterwards | SYSTEM or admin | none needed |
| Login script | The user logging in | that user | one, at logon |
| Ad-hoc / remediation | The users currently signed in | admin or SYSTEM | one per session |
A complete rollout usually needs the first two. The third is how you fix a machine that missed both.
The layout that new users get comes from
C:\Users\Default\AppData\Local\Microsoft\Windows\Shell\LayoutModification.xml. Windows
copies the Default profile when it creates a new one, so a layout staged there is
inherited by every profile created from that moment on, with no login script, no policy
key and no shell restart.
apply --allhomes writes that file as part of its work. On a reference image with a single
build account, that is the whole job:
taskbarutil add "File Explorer"
taskbarutil add "Microsoft Edge"
taskbarutil add "Outlook"
taskbarutil add "Microsoft Teams"
taskbarutil apply --allhomesRun elevated. --allhomes also copies the layout to
C:\ProgramData\TaskbarUtil\LayoutModification.xml and points the build account's own
policy at it, which is harmless on an image.
If you would rather not modify the build account at all, build the config, then place the
XML yourself. taskbarutil show prints exactly what to copy:
taskbarutil showNew-Item -ItemType Directory -Force -Path "C:\Users\Default\AppData\Local\Microsoft\Windows\Shell"
Copy-Item "$env:LOCALAPPDATA\TaskbarUtil\LayoutModification.xml" "C:\Users\Default\AppData\Local\Microsoft\Windows\Shell\LayoutModification.xml"The Default profile route reaches only profiles created after it. Existing profiles need one of the routes below.
For existing users, the layout has to be installed into their own HKCU or their own
Shell directory, which means running as that user. A login script or a per-user scheduled
task is the delivery vehicle.
The safest login-time shape reuses the machine-wide layout rather than rebuilding it in each session, and does the least possible work when nothing has changed. TaskbarUtil has no built-in idempotency check, so write one:
$shared = 'C:\ProgramData\TaskbarUtil\LayoutModification.xml'
$config = Join-Path $env:LOCALAPPDATA 'TaskbarUtil\LayoutModification.xml'
$applied = (Get-ItemProperty 'HKCU:\Software\Policies\Microsoft\Windows\Explorer' -Name LockedStartLayout -ErrorAction SilentlyContinue).LockedStartLayout
if ((Test-Path $shared) -and (-not (Test-Path $config) -or (Get-FileHash $shared).Hash -ne (Get-FileHash $config).Hash -or $applied -ne 1)) {
New-Item -ItemType Directory -Force -Path (Split-Path $config) | Out-Null
Copy-Item $shared $config -Force
& taskbarutil apply
}Without a guard like that, every logon tears down and rebuilds the shell — which is visible, slow, and takes the user's own pins with it each time.
The PinGeneration note matters here: the layout the tool writes by default does not let
users keep their own pins, and re-applying at every logon means anything they pin is gone
by the next one. If that is not the intent, either apply once and record it, or hand-edit
PinGeneration="1" into the XML — see
Layout XML Reference.
The examples/ scripts in the repository take the simpler approach of constructing the
layout from scratch in each session:
taskbarutil reset --no-restart
taskbarutil add "File Explorer"
taskbarutil add "Google Chrome"
taskbarutil add "Windows Terminal"
taskbarutil add "Visual Studio Code"
taskbarutil applyThis is readable and self-contained, and it is fine for a lab or a small fleet. Two costs
to know about. Each add that is not a known-app entry scans both Start Menu trees and
opens shortcuts through COM, so a layout of a dozen third-party apps is not instant. And
reset --no-restart plus apply means the shell is rebuilt on every logon.
A login script that pops a console window on a shared or lab machine is its own problem. Deliver the script through whatever mechanism you already use for per-user logon work (Group Policy logon scripts, a per-user scheduled task with a hidden window, or your management agent's user-context runner) rather than a Run key. TaskbarUtil itself does nothing to hide a console — it is an ordinary console application.
apply --allhomes run elevated on a live machine writes the policy into every profile
whose hive is currently loaded in HKEY_USERS. In practice that is the signed-in users
and no one else. It reports the count:
taskbarutil apply --allhomesRead that count. "Policy set for 1 user profile(s)" on a machine with 40 profiles is not a
failure — it is --allhomes telling you the other 39 hives were not loaded.
Note also what --allhomes does per profile: it writes StartLayoutFile and
LockedStartLayout into HKEY_USERS\<SID>, deletes that profile's start2.bin, and
deletes that profile's Taskband subtree. It does not restart the shell for other
users' sessions, so their taskbars converge on the layout when their shell next starts.
The Explorer restart that apply performs happens only in the session running the
command.
| Situation | Pattern |
|---|---|
| New image, one standard layout | Seed the Default profile at image time |
| Existing fleet, one standard layout | Seed the Default profile and run a guarded login script for existing users |
| Different layouts per machine role | Stage a different C:\ProgramData\TaskbarUtil\LayoutModification.xml per role, with the same login script everywhere |
| Kiosk or lab where the layout must not drift | Re-apply on every logon and accept the shell restart; do not set PinGeneration
|
| Users may customise, you set the starting point | Seed the Default profile only; never apply at logon |
The last two rows are the real decision. Once you understand that Replace plus a
Taskband wipe means an apply is destructive to user customisation, the choice of when to
apply becomes the whole deployment design.
Install taskbarutil.exe machine-wide before anything needs it. The MSI puts it in
C:\Program Files\sbin and adds that to the machine PATH; that directory is where the
login script should expect to find it. Because PATH is set at machine scope in
postinstall, a session that started before installation will not see it — call the full
path in scripts that might run early:
& 'C:\Program Files\sbin\taskbarutil.exe' applyReleased binaries are unsigned. Sign them with your own certificate before fleet distribution — see Installation.
There is no reporting built in, so verification is reading state. On a single machine:
taskbarutil listAcross a fleet, the two facts worth collecting are whether the policy is set and whether the layout matches what you shipped:
Get-ItemProperty 'HKCU:\Software\Policies\Microsoft\Windows\Explorer' -Name StartLayoutFile,LockedStartLayout -ErrorAction SilentlyContinue(Get-FileHash 'C:\ProgramData\TaskbarUtil\LayoutModification.xml').HashThe file log is the per-machine audit trail. Every apply, reset, pin and unpin lands in
C:\ProgramData\ManagedUtilities\logs\taskbarutil.log with its outcome, which is the
right thing to collect when a rollout looks partial:
Get-Content 'C:\ProgramData\ManagedUtilities\logs\taskbarutil.log' -Tail 40Note that an unelevated user's run may have logged to
%LOCALAPPDATA%\TaskbarUtil\logs\taskbarutil.log instead. Check both.
reset is per-user and has no --allhomes. Rolling back a fleet means either running
reset in each user's session — the same delivery problem as applying — or removing the
policy values directly and letting Explorer rebuild.
taskbarutil resetTo stop new profiles inheriting the layout, delete the Default-profile copy:
Remove-Item 'C:\Users\Default\AppData\Local\Microsoft\Windows\Shell\LayoutModification.xml' -ForceRemoving C:\ProgramData\TaskbarUtil\LayoutModification.xml while profiles still point
their StartLayoutFile at it leaves those users with a policy pointing at a missing file.
Clear the policy values first, then the shared file.
TaskbarUtil — Apache-2.0 — github.com/windowsadmins/taskbarutil
Getting started
Reference
Operating it
Internals