The ultimate guide to Windows logon time optimizations, part #7

Everything you need to know about Windows logons in one blog series continues here!

I have threatened on several occasions now to do a follow-up to my previous article on Windows logon times which incorporates the findings from my “logon times masterclass” that I have presented at a few events. The time has come for me to turn these threats into reality, so this series of articles and accompanying videos will explore every trick we know on how to improve your Windows logon times. As many of you know, I work predominantly in Remote Desktop Session Host (RDSH) environments such as Citrix Virtual Apps and Desktops, VMware Horizon, Windows Virtual Desktop, Amazon Workspaces, Parallels RAS, and the like, so a lot of the optimizations discussed here will be aligned to those sorts of end-user computing areas…but even if you are managing a purely physical Windows estate, there should be plenty of material here for you to use. The aim of this is to provide a proper statistical breakdown of what differences optimizations can make to your key performance indicators such as logon time.

This series of articles is being sponsored by uberAgent, because the most important point to make about logon times is that if you can’t measure them effectively, then you will never be able to improve them! uberAgent is my current tool of choice for measuring not just logons (which it breaks down into handy sections that we are going to use widely during this series) but every other aspect of the user’s experience. All of the measurements in this series are going to be done via uberAgent, and as it comes with free, fully-featured community and consultants’ editions, there’s absolutely no reason that you can’t download it and start using it straight away to assess your own performance metrics. I’ve written plenty about uberAgent on this blog before, and I stand by it as the best monitoring tool out there for creating customized, granular, bespoke consoles that can be used right across the business. I’ve recently deployed it into my largest current client, so you can be sure I am putting my money where my mouth is – if it didn’t do the job, I wouldn’t have used it for my customers, simple as. It now features full Citrix Cloud integration and a “user experience” score to tell you where your users are having issues, so go and try uberAgent right now – you won’t regret it!

Part #7 – Active Setup

We are getting pretty down into the weeds now, so we’ve moved on to Active Setup. Some caveats around Active Setup – it only applies to desktops, so if you’re doing pure published remote applications there’s nothing much of use here, and it also applies to the user’s first logon only, so once they’ve saved a profile you won’t see it again (unless you’re using mandatory/hybrid or some other mechanism that reparses the entries at each logon). It did used to be quite intrusive for that first logon, but let’s see what the numbers look like today.

Active Setup Setup is a mechanism for executing commands once per user early during logon. Active Setup is used by some operating system components like Internet Explorer to set up an initial configuration for new users logging on for the first time. It is a way of hard-coding user-specific data, and you can usually tell it is in play by spotting these tell-tale pop-ups similar to those shown below

Active Setup always runs before the desktop appears, usually as part of the profile or shell phases. Commands that are initiated by Active Setup run synchronously, blocking the logon while they are executing. Active Setup doesn’t use a timeout nor any other mechanism to determine if a process it started is still alive, so if it hangs, the entire logon will stop. If they do fail, they will leave the user at a black screen. If you’ve ever had to press Ctrl Alt Del, pull up Task Manager, and then run explorer.exe from the New Task command after a user’s logon has stopped at a blank screen, that’s probably a failed Active Setup command you’ve encountered. They are referred to as StubPaths because they are controlled by entries called StubPath in the Registry.

An Active Setup entry in the Registry – this one is from Google Chrome

I normally remove as many of the StubPath entries as possible (which usually means all of them). They sit in the Registry within [GUID] subkeys of these Registry keys

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Active Setup\Installed Components and HKEY_LOCAL_MACHINE\Wow6432Node\SOFTWARE\Microsoft\Active Setup\Installed Components

Sometimes people ask me whether it is safe to remove these StubPath entries. In my experience, yes. Most of them deal with old Windows components (Microsoft Mail, for instance), and some of them are placed by software like Google Chrome or Adobe Reader to spit out shortcuts onto the user’s desktop which is an annoyance in its own right when you’re trying to keep the UX clean and tidy. Occasionally I hear rumours that they are needed to get .Net to work properly or pin particular items, but I can safely say that in all the deployments I’ve done, like I do with UWP apps, I just kill them with fire and never see any oddness resulting from it. Needless to say though – test your functionality both before and after to make sure.

Baseline – before we remove the Active Setup entries

Firstly, let’s do our usual and take some fresh Packer builds of both Windows Server and Windows 10 21H1, and measure their logon times. Because we are looking to measure the Active Setup impact, we are removing the profile between logons (by converting the state to mandatory at logoff and letting the OS purge it).

Server 2019 baselines at around 35 seconds

All data courtesy of uberAgent
All data courtesy of uberAgent

Strangely, though, Windows 10 baselines at 33 seconds, which is unusual for it to be quicker than 2019 RDSH. I’m not sure if this is because I got my 12-year old son who has been sent home from school again to do the Windows 10 data gathering, but it will teach him and his friends to stop running PCR tests on lemons so they can claim they’ve got COVID and get a week off school. Regardless – let’s take the numbers and move onwards.

All data courtesy of uberAgent
All data courtesy of uberAgent

Right, so we’ve established our baselines, now let’s remove the Active Setup entries.

Removal

There’s a number of ways you could do this. You can delete the entries direct from the Registry, you can use a tool like SysInternals AutoRuns to spot the entries and disable them, or you can script it. I always go for a scripted method, and I generally run this shell script as one of the tasks in my Packer build.

echo Querying and deleting 32bit STUB paths...
setlocal EnableDelayedExpansion
:: Queries the registry and searches for specific strings. In this case 'STUBPATH'
set KEY="HKEY_LOCAL_MACHINE\Software\Microsoft\Active Setup\Installed Components"
set FND=find /i %KEY%
for /f "tokens=*" %%a in ('reg query %KEY% /s^|%FND%') do (
set SP=N
for /f "tokens=*" %%b in ('reg query "%%a"^|find /i " STUBPATH"^|find "REG_"') do (
set SP=Y
)
:: Runs an if statement, stating that if a key matching 'STUBPATH' is true, it should be deleted. 
if "!SP!" EQU "Y" reg delete "%%a" /V STUBPATH /F
)
echo Querying and deleting 64bit STUB paths...
endlocal
setlocal EnableDelayedExpansion
:: Queries the registry and searches for specific strings. In this case 'STUBPATH'
set KEY="HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Active Setup\Installed Components"
set FND=find /i %KEY%
for /f "Tokens=*" %%a in ('reg query %KEY% /s^|%FND%') do (
set SP=N
for /f "tokens=*" %%b in ('reg query "%%a"^|find /i " STUBPATH"^|find "REG_"') do (
set SP=Y
)
:: Runs an if statement, stating that if a key matching 'STUBPATH' is found, it should be deleted. 
if "!SP!" EQU "Y" reg delete "%%a" /V STUBPATH /F
)
endlocal

Once this is done, we can now repeat the tests.

After we remove the Active Setup entries

Now let’s see what we can see in terms of difference. Let’s do Server 2019 first

All data courtesy of uberAgent
All data courtesy of uberAgent

Yes, a definite big improvement here. Server 2019, with the StubPath entries removed, shows about 8 seconds shaved from that first logon time. Nice!

Let’s follow up with Windows 10

All data courtesy of uberAgent
All data courtesy of uberAgent

Windows 10 has improved, but not as starkly. We’ve managed to take about 3 seconds off the first logon time, which while it’s not to be sniffed at, isn’t as much as we managed on RDSH. It’s still an improvement, though, which is the whole reason we are here, so there is a net positive effect and that’s good.

Summary

I can remember the early days of Active Setup entries and they could make quite a sizeable dent in first logon times. Based around the testing we’ve done today, that is no longer as stark on Windows 10, but still quite noticeable on Server 2019.

It is worth pointing out that the images I built (which were identical in application set terms) don’t include software like Chrome that has a habit of putting in their own StubPath entries as well, so you may well get a better increase in your own environments. Which is why it is important to remove the Active Setup entries after all software installations have finished (and is another reason why I hate using stuff like SCCM/MECM to build targets). It’s also very important that you have a monitoring tool like uberAgent in place, so you can effectively measure the improvement of each change you put in!

So in summary – there’s a positive effect to be had on your logon KPIs here for desktops only, and it’s possibly more noticeable on RDSH than pure client Windows.

Stay tuned for the next part of this series where we will be digging into the subject of application preloading.

Loading

3 comments

  1. In May of 2023, this is still a good article. Time to convert the script to Powershell:

    $RegKeyPrefix = @(
    “HKLM:\SOFTWARE\Wow6432Node\Microsoft\Active Setup\Installed Components”
    “HKLM:\Software\Microsoft\Active Setup\Installed Components”
    )

    $RegKeyPrefix.ForEach({
    ( Get-ChildItem $_ ).ForEach({
    $props = Get-ItemProperty ( $_.Name ).Replace( “HKEY_LOCAL_MACHINE”, “HKLM:” )
    if ( $props.StubPath ) {
    # Save StubPath to NoRunStubPath
    Set-ItemProperty $props.PSPath -Name “NoRunStubPath” -Value $props.StubPath -Force
    # Remove StubPath
    Remove-ItemProperty $props.PSPath -Name “StubPath” -Force
    }
    })
    })

  2. <#
    Name: DisableActiveSetup.ps1

    Purpose: Script to disable ActiveSetup StubPath registry values that can increase logon times.

    Notes:
    This is a powershell port of a command line script taken from this article:
    https://james-rankin.com/features/the-ultimate-guide-to-windows-logon-time-optimizations-part-7/
    #>

    $RegKeyPrefix = @(
    "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Active Setup\Installed Components"
    "HKLM:\Software\Microsoft\Active Setup\Installed Components"
    )

    $RegKeyPrefix.ForEach({
    ( Get-ChildItem $_ ).ForEach({
    $props = Get-ItemProperty ( $_.Name ).Replace( "HKEY_LOCAL_MACHINE", "HKLM:" )
    if ( $props.StubPath ) {
    # Save StubPath to NoRunStubPath
    Set-ItemProperty $props.PSPath -Name "NoRunStubPath" -Value $props.StubPath -Force
    # Remove StubPath
    Remove-ItemProperty $props.PSPath -Name "StubPath" -Force
    }
    })
    })

Leave a Reply to Rex Cancel reply

Your email address will not be published. Required fields are marked *