Best Practice for the Active Setup StubPath value

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.

Active Setup StubPath

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 (629 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!

Jeremy Saunders

Jeremy Saunders

Delivering customer success through tech: IT Infrastructure | Citrix | End User Computing | Platform Engineering | DevOps | Full Stack Developer | Technical Architect | Improvisor | Aspiring Comedian | Midlife Adventurer at J House Consulting
Jeremy Saunders is the Problem Terminator; the MacGyver of IT. Views and Intellectual Property (IP) published on this site belong to Jeremy. Please refer to the About page for more information about Jeremy.