Windows 10 is, by its nature of constant updates, a moving target. So far I’ve had a couple of cracks at roaming a full Windows 10 user state between domain-joined machines. Both of them so far proved to be quite intrusive, necessitating in each case the restart of a system service to accomplish anything near to what we were after. This just doesn’t sit well with me – it complicates the tooling required, for one thing – and looks messy. However, as Microsoft release updates to it, bug fixes appear to be included which are making things slightly easier.
UPDATE – with the 1607 release of Windows 10, I’ve done a full recap of this subject which is more up-to-date. Please refer to the new article here.
MUCH BETTER UPDATE – we can now do this with native roaming profiles and a quick Registry change, which will allow them to work perfectly for Windows 10 1607. Watch the video here https://www.youtube.com/watch?v=R4R4QlExLsU&t=3s
This doesn’t, though, address the glaring issue that the Start Tiles settings sit in %LOCALAPPDATA%. If you’re using a standard Microsoft roaming profile, LOCALAPPDATA isn’t included, and can’t be without third-party tools – you can exclude directories from a roaming profile, but not add them, via GPO. Whilst I’ve speculated that this may be by design, with an intention to subsume all of the roaming market into Microsoft’s Azure-based Enterprise State Roaming (when it lands), it still doesn’t help us out. If you’re deploying Windows 10 right now, or in the near future – and bear in mind we’ve had the Threshold release in November 2015, and are now waiting for Redstone in June (effectively SP2) – then you still can’t roam the most glaringly in-your-face part of the new Windows 10 look and feel.
To recap, here’s what we’ve tried before, with varying degrees of success:-
- At logoff, stop the “Tile Data model server” service
- Copy out the %LOCALAPPDATA%\TileDataLayer\Database\* files onto the network
- At logon, copy the files back in from the network to the local folder
This method required elevated privileges to stop the service, and was also a bit hit-and-miss. The privilege elevation could be scripted or tooled around, but reliability was not great, and when it didn’t work, would invariably corrupt the Start Menu.
- At logoff, use the Powershell Export-StartLayout cmdlet to copy the Start Tiles settings out to a file on the network
- At logon, set a GPO that imports the XML file generated at logoff to create the Start Tiles from this
- A short time after logon, “unlock” the Start Tiles for manipulation by resetting the Registry value that locks them, and then restart the “Tile Data model server” service to refresh the Start Tiles
This method was considerably more effective than the previous one, but still required elevated privileges to stop the service, and also needed a “delayed action” after logoff to allow the Start Tiles to be created without unlocking them. This made it more suited to using a tool like AppSense Environment Manager, although not impossible to script your way around.
But there has to be a better way, surely?
Now, there’s a corresponding cmdlet in PowerShell that goes with Export-StartLayout – Import-StartLayout. However, it can only be used to either import layouts to an offline WIM image, or, if you’re like Aaron Parker and just go out and run it on a live OS, you’ll find out it simply works on the default profile. So no good unless you’re creating a new local user profile.
Hmmm…let’s dig under the hood a bit. What does Import-StartLayout actually do?
Process Monitor reveals it simply writes a file called LayoutModification.xml into the C:\Users\Default\AppData\Local\Microsoft\Windows\Shell folder. This file is then read during the logon process, and (I’m assuming) then used to create the Start Tiles in the newly-created local user profile. A succession of writes to the file %LOCALAPPDATA%\TileDataLayer\Database\vedatamodel.edb (that awful database that controls these Tile settings) would lead me to believe that my postulation could well indeed be accurate.
What would happen if we used Export-StartLayout to create a file at logoff in the user’s homedrive called LayoutModification.xml, and then popped this into %LOCALAPPDATA%\Microsoft\Windows\Shell for a user with a roaming profile as they logged in? After all, the Start Tiles have to be created for a roaming profile user – because they don’t have any in their profile.
It works 🙂
However, the key is, the roaming user profile must deleted from the endpoint at logoff. This is something Windows 10 has historically had trouble with, because the damned “Tile Data model layer” service hangs on to the database (I believe this is intended to be fixed in Redstone, but don’t quote me on that). Even with “Delete cached copies of roaming profiles” defined via GPO. But, in the latest preview builds (14279) the deletion of roaming profiles appears a lot more stable (although not 100%, it is a damn sight better than early builds), so I’m sure this is slated for a fix sooner rather than later.
So we can successfully deploy a roaming profile for a Windows 10 domain deployment by using the following steps:-
- Define a roaming profile path for the target user in ADUC
- Ensure that your clients have the “Delete cached copes of roaming profiles” GPO defined
- Set up a GPO Logoff Script to run the command in the next line
- Export-StartLayout -Path \\SERVER\Share\User\LayoutModification.xml
- Set up a Group Policy Preference File Item (see image) to copy the following file to the named destination folder at user logon (or use a script, or third-party tool)
- \\SERVER\Share\User\LayoutModification.xml –> %LOCALAPPDATA%\Microsoft\Windows\Shell
This will then create a new set of Start Tiles with the settings that you exported from your previous session when you log in to a new machine. Finally, smooth roaming without all the complicated hacks!
The key to all of this is the name of the file that you output with Export-StartLayout, and where you put it. Call it LayoutModification.xml, and drop it back in the required folder when the user logs back in, and it will generate a set of Start Tiles based on the layout you exported from.
But the best thing is, it doesn’t lock the Start Tiles in place – the user can edit them to their heart’s content without any of the jiggery-pokery we had to do in Method 2 above. Glorious, no?
Unfortunately, now it’s time for the bad news.
Running Export-StartLayout at logoff (no matter how you trigger it) has problems in some builds of Windows 10. Which means dependent on the build you’re on, the actual export function may or may not work. It works fine when run interactively during the session – it’s only when triggered at logoff that you get the failure. If it doesn’t work, it throws an error like this
This is a major PITA. It appears to be related to some combination of updates why this occurs, because I have 10240 builds that don’t get this error and 10586 builds that do. One thing I have noticed though is 14279 builds – all of them – don’t suffer from the error. So whatever is causing it is slated to be fixed in Redstone. Windows 10’s awful documentation of bug fixes – many builds shipped just with this one sentence “bug fixes and improvements” – mean I have no idea where the fix came in or what possibly causes it to manifest on some builds and not others.
You can tell pretty much straight away if you’re affected by this, because when you log off the LayoutModification.xml file won’t be updated. Running the PowerShell from within the user session will update it fine.
If you’re on one of the affected builds, you have two choices:-
- Wait for the Redstone release in June (deploying preview builds to live machines is probably not an option)
- Set up a Scheduled Task to run the PowerShell Export-StartLayout cmdlet that starts when the user logs on, and continues every few minutes until they log out
- Set up a Scheduled Task that is triggered by a Logoff event (Security event id 4647, if I remember right, and it will need Logoff Auditing configured as well to work)
Doing it via a Scheduled Task makes the whole routine feel rather “hacky” again, but if you’re suffering from this issue, it’s the only way that you can do it short of waiting for the Redstone release. The interval you need to configure depends on your preference, and how your users behave. You may also need to configure your task to run the PowerShell window with the windowstyle -Hidden parameter.
I covered setting up a Scheduled Task using AppSense Environment Manager in a previous post. However, if you’re not in an AppSense environment, you should be able to do it through Group Policy Preferences, or create it in the Task Scheduler and export it out to other machines using an XML file.
An example XML file to import a Scheduled Task is shown here. This points to \\UKSLDC003\FileStore\ExportStartLayout2.ps1 and runs in the context of the user JRR\jrankin, should you choose to edit for your own use
<?xml version=”1.0″ encoding=”UTF-16″?>
<Task version=”1.4″ xmlns=”http://schemas.microsoft.com/windows/2004/02/mit/task”>
<RegistrationInfo>
<Date>2016-03-22T19:06:45.4275818</Date>
<Author>JRR\jrankin</Author>
<URI>\ESL</URI>
</RegistrationInfo>
<Triggers>
<TimeTrigger>
<Repetition>
<Interval>PT1M</Interval>
<Duration>P1D</Duration>
<StopAtDurationEnd>false</StopAtDurationEnd>
</Repetition>
<StartBoundary>2016-03-22T00:00:00</StartBoundary>
<Enabled>true</Enabled>
</TimeTrigger>
</Triggers>
<Principals>
<Principal id=”Author”>
<UserId>S-1-5-21-2950944927-1203068717-1704750700-1114</UserId>
<LogonType>InteractiveToken</LogonType>
<RunLevel>LeastPrivilege</RunLevel>
</Principal>
</Principals>
<Settings>
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
<DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries>
<StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
<AllowHardTerminate>true</AllowHardTerminate>
<StartWhenAvailable>false</StartWhenAvailable>
<RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
<IdleSettings>
<StopOnIdleEnd>true</StopOnIdleEnd>
<RestartOnIdle>false</RestartOnIdle>
</IdleSettings>
<AllowStartOnDemand>true</AllowStartOnDemand>
<Enabled>true</Enabled>
<Hidden>false</Hidden>
<RunOnlyIfIdle>false</RunOnlyIfIdle>
<DisallowStartOnRemoteAppSession>false</DisallowStartOnRemoteAppSession>
<UseUnifiedSchedulingEngine>true</UseUnifiedSchedulingEngine>
<WakeToRun>false</WakeToRun>
<ExecutionTimeLimit>PT72H</ExecutionTimeLimit>
<Priority>7</Priority>
</Settings>
<Actions Context=”Author”>
<Exec>
<Command>powershell.exe</Command>
<Arguments>.\ExportStartLayout2.ps1</Arguments>
<WorkingDirectory>\\UKSLDC003\FileStore</WorkingDirectory>
</Exec>
</Actions>
</Task>
And after all of this, I spotted one more thing. A profile version increment? Interesting…
When you log on with a roaming profile from a machine running build 14279 of Windows 10 and upwards there is an increment to the profile version. That’s right, Windows 10 shipped with a .v5 profile but on version 14279 the profile becomes a .v6. Which means that potentially roaming profiles from pre-14279 builds are incompatible with those on the Redstone build. And what’s more, historically, profile version increments have only occurred on operating system upgrades. Does this mean that June’s update will see us being moved to what is effectively Windows 10.1?
Personally, if I was on one of the builds that can’t manage to run the export command at logoff, I’d be tempted to wait for the Redstone update, unless this was an absolute deal-breaker. The very fact that the profile type has changed leads me to believe that Redstone will provide full roaming profile functionality such as we had in Windows 7 – a year too late maybe, but there nevertheless.
Anyway, I’ve put together a quick video which should hopefully show you this theory in action…hopefully this may help some of you out there!