It’s been a best practice for a long time to clear the Active Setup StubPath value per application to avoid the Active Setup processes from running at logon, impacting the user experience. This is a challenge we constantly have with Vendors and packaging teams. But blindly clearing the StubPath value could lead to application issues. So what happens when you need to go back and troubleshoot an issue with an application that may be related to what “should have” run via the Active Setup process. How do you know what the StubPath value was originally set to? Do you record it somewhere?
I’ve been running a script for years over my builds that simply renames the existing StubPath value to StubPath.Backup and time stamps it. This way you can always review what it should be, and make the necessary changes to allow for this.
The following screen shot shows what the Microsoft Edge StubPath looks like once the script has run.
Notice how the real StubPath value is blank as per best practice, but a second value exists that is a point in time backup of the value? So in this case should we experience issues with Microsoft Edge, I can easily review what the expected value was set to in order to understand if this is the cause of the issue. With this in place there is no stress.
The script enumerates all subkeys from the following keys to process all StubPath values:
- HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Active Setup\Installed Components
- HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Active Setup\Installed Components
I run this as a once of task after all the applications are patches are installed before a build completes, but you can also run it as a computer startup script.
Here is the Active Setup StubPath (184 downloads) script:
<# This script will clear the Active Setup Stubpath values. However, instead of just clearing them, it creates a backup of the Stubpath with the time stamp for future reference and troublshooting requirements. Script name: ClearActiveSetup.ps1 Release 1.2 Written by Jeremy Saunders (jeremy@jhouseconsulting.com) 19th September 2017 Modified by Jeremy Saunders (jeremy@jhouseconsulting.com) 25th September 2023 #> #------------------------------------------------------------- # Set Powershell Compatibility Mode Set-StrictMode -Version 2.0 # Enable verbose, warning and error mode $VerbosePreference = 'Continue' $WarningPreference = 'Continue' $ErrorPreference = 'Continue' #------------------------------------------------------------- $StartDTM = (Get-Date) # Get the TEMP path $logPath = [System.IO.Path]::GetTempPath() $logPath = $logPath.Substring(0,$logPath.Length-1) # Set the logpath to C:\Windows\Temp $logPath = "${env:SystemRoot}" + "\Temp" # Get the script name $ScriptName = [System.IO.Path]::GetFilenameWithoutExtension($MyInvocation.MyCommand.Path.ToString()) $logFile = "$logPath\$ScriptName.log" # Start the transcript try { Start-Transcript "$logFile" } catch { Write-Verbose "$(Get-Date -format "dd/MM/yyyy HH:mm:ss"): This host does not support transcription" } #------------------------------------ # Add strings to this array that may be in StubPaths that you want to be excluded from being cleared. $Excludes = @() $ParentPaths = @("HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components","HKLM:\SOFTWARE\WOW6432Node\Microsoft\Active Setup\Installed Components") $Value = "StubPath" $BackupValue = "StubPath.Backup-$(Get-Date -format "dd/MM/yyyy HH:mm:ss")" ForEach ($ParentPath in $ParentPaths) { Get-Childitem "$ParentPath" -Recurse -ErrorAction SilentlyContinue | % { $ValueExist = $False $ErrorActionPreference = "stop" Try { If ((Get-ItemProperty -Path "$ParentPath\$($_.PSChildName)" | Select-Object -ExpandProperty "$Value") -ne $null) { $ValueExist = $True } } Catch [System.Exception] { #$($_.Exception.Message) } $ErrorActionPreference = "Continue" If ($ValueExist) { Write-Verbose "`"$Value`" found under `"$ParentPath\$($_.PSChildName)`"" -verbose $BackupValueExist = $False $ErrorActionPreference = "stop" Try { If ((Get-ItemProperty -Path "$ParentPath\$($_.PSChildName)" | Select-Object -ExpandProperty "$BackupValue") -ne $null) { $BackupValueExist = $True } } Catch [System.Exception] { #$($_.Exception.Message) } $ErrorActionPreference = "Continue" If ($BackupValueExist -eq $False) { $ParentKey = Get-Item -Path "$ParentPath\$($_.PSChildName)" $PropertyValue = $ParentKey.GetValue("$Value") If ($PropertyValue -ne "") { Write-Verbose "- Value: $PropertyValue" -verbose $PropertyType = $ParentKey.GetValueKind("$Value") $Skip = $False ForEach ($Exlude in $Excludes) { If ($PropertyValue -Like "*$Exlude*") { $Skip = $True Break } } If ($Skip -eq $False) { Write-Verbose "- Type: $PropertyType" -verbose Write-Verbose "- Renaming to `"$BackupValue`"..." -verbose Rename-ItemProperty -Path "$ParentPath\$($_.PSChildName)" -Name "$Value" -NewName "$BackupValue" Write-Verbose "- Creating an empty `"$Value`" value with property type of `"$PropertyType`"..." -verbose New-ItemProperty -Path "$ParentPath\$($_.PSChildName)" -Name "$Value" -PropertyType $PropertyType -Value "" Force | Out-Null } Else { Write-Verbose "- This $Value value has been excluded. No action will be taken." -verbose } } Else { Write-Verbose "- The value is empty. No action will be taken." -verbose } } Else { Write-Verbose "- The `"$BackupValue`" value already exists." -verbose } } } } #------------------------------------ Write-Verbose "Stop logging" -Verbose $EndDTM = (Get-Date) Write-Verbose "Elapsed Time: $(($EndDTM-$StartDTM).TotalSeconds) Seconds" -Verbose Write-Verbose "Elapsed Time: $(($EndDTM-$StartDTM).TotalMinutes) Minutes" -Verbose # Stop the transcript try { Stop-Transcript } catch { Write-Verbose "$(Get-Date -format "dd/MM/yyyy HH:mm:ss"): This host does not support transcription" }
Enjoy!