Problem:
Users may encounter duplicate or "ghost" folders within their Windows Start Menu. This can happen if you are attempting to delete all shortcuts in a configuration. This is to remove anything leftover from a prior session, or just to clean it up completely.
Common "ghost folder" examples include localized versions of the "Programs" folder such as "Programmes", "Programme", or "Programas" appearing alongside the standard English directory. Additionally, unwanted "Java" folders containing update and configuration shortcuts frequently appear in both the global and user-specific Start Menu areas. These folders clutter the workspace and can cause confusion for end-users in VDI and physical desktop environments.
Cause
This behavior is primarily seen on Windows 10 or Windows 11 systems running non-English OS versions, language packs or system updates.
- Localized Junctions: Windows creates Junction Points (Reparse Points) for legacy compatibility. These act as redirects so that installers looking for a localized path (e.g., a German installer looking for ...\Programme) are pointed to the correct system location.
- Java Shortcuts: The Java Runtime Environment (JRE) automatically creates a "Java" folder in the Start Menu during installation or update to provide users with configuration tools.
- Profile Persistence: ProfileUnity may capture these junctions or shortcuts during the profile orchestration process, causing them to persist or reappear even after manual deletion.
Solution:
1. Permanent Fix
This behavior is scheduled to be addressed natively in ProfileUnity Client version 6.9.5 and higher. The updated client will include logic to automatically identify and suppress these localized junction points during the logon process.
2. Immediate Workaround (For versions below 6.9.5)
Administrators can deploy a cleanup script using the Application Launcher module to remove these items at logon.
The Cleanup Script:
Save the following as StartMenuCleanup.ps1 on a network share accessible by your users (e.g., Netlogon):
<#
.SYNOPSIS
ProfileUnity Cleanup Script: Localized Start Menu junctions & Java folder cleanup
.DESCRIPTION
Cleans up localized Start Menu junction folders (commonly created by some builds/languages)
and removes the "Programs\Java" Start Menu folder if present.
Targets:
- C:\ProgramData\Microsoft\Windows\Start Menu
- %AppData%\Microsoft\Windows\Start Menu
Logging:
- Writes to %TEMP%\StartMenuCleanup.log
.NOTES
- Junction detection is done via the ReparsePoint attribute.
- Junctions are removed using rmdir (cmd) to avoid issues removing reparse points with Remove-Item.
- Java folder removal uses Remove-Item -Recurse -Force.
#>
$ErrorActionPreference = 'Stop'
# Log file setup - using UTF8 encoding for better compatibility with localized folder names
$logFile = Join-Path -Path $env:TEMP -ChildPath 'StartMenuCleanup.log'
"--- Cleanup started at $(Get-Date) ---" | Out-File -FilePath $logFile -Encoding UTF8
# List of localized "Programs" folder names to check for junctions
# Note: It is safe to leave them all here as the script will only remove those that exist and are junctions.
# Any non-junction folders will be skipped.
$localizedFolders = @(
"Programma's",
"Programme",
"Programmes",
"Programas",
"Programmi"
)
# Paths to check for localized "Programs" junctions, including both the common Start Menu and the user-specific Start Menu
$pathsToClean = @(
'C:\ProgramData\Microsoft\Windows\Start Menu',
(Join-Path -Path $env:AppData -ChildPath 'Microsoft\Windows\Start Menu')
)
# Process each base path and check for the presence of localized "Programs" folders. If found and they are junctions, remove them.
foreach ($basePath in $pathsToClean) {
if (-not (Test-Path -LiteralPath $basePath)) {
"Path not found: $basePath" | Out-File -FilePath $logFile -Append -Encoding UTF8
continue
}
"Checking path: $basePath" | Out-File -FilePath $logFile -Append -Encoding UTF8
foreach ($folder in $localizedFolders) {
$fullPath = Join-Path -Path $basePath -ChildPath $folder
if (-not (Test-Path -LiteralPath $fullPath)) {
continue
}
try {
$item = Get-Item -LiteralPath $fullPath -Force -ErrorAction Stop
if (($item.Attributes -band [System.IO.FileAttributes]::ReparsePoint) -ne 0) {
"Removing junction: $fullPath" | Out-File -FilePath $logFile -Append -Encoding UTF8
cmd.exe /c rmdir "$fullPath" 2>> $logFile
} else {
"Found folder (not a junction): $fullPath (skipping)" | Out-File -FilePath $logFile -Append -Encoding UTF8
}
} catch {
"ERROR inspecting/removing: $fullPath :: $($_.Exception.Message)" | Out-File -FilePath $logFile -Append -Encoding UTF8
}
}
# Additionally, check for the "Programs\Java" folder and remove it if it exists, as some builds may create a shortcut there.
$javaPath = Join-Path -Path $basePath -ChildPath 'Programs\Java'
if (Test-Path -LiteralPath $javaPath) {
"Removing Java shortcut folder: $javaPath" | Out-File -FilePath $logFile -Append -Encoding UTF8
try {
Remove-Item -LiteralPath $javaPath -Recurse -Force -ErrorAction Stop
}
catch {
"ERROR removing Java folder: $javaPath :: $($_.Exception.Message)" | Out-File -FilePath $logFile -Append -Encoding UTF8
}
}
}
# Overwrite any older log file, and end with a final message indicating cleanup completion, using UTF8 encoding for consistency.
"--- Cleanup finished at $(Get-Date) ---" | Out-File -FilePath $logFile -Overwrite -Encoding UTF8
Setup a new Rule in the "Application Launcher" module with these settings to execute the script:
- Filter: Delete_Shortcuts (This is just an example, so can be adjusted to what you choose).
- Filespec: powershell.exe
- Arguments: -ExecutionPolicy Bypass -WindowStyle Hidden -File "\\YourPath\StartMenuCleanup.ps1"
- Timing: After Configuration Execution
- Hide Progress During Execution: Checked
- Execute without Elevation: Unchecked (This is required to allow the script to modify the protected C:\ProgramData directory)
Product: ProfileUnity
Product Version: 6.8.x and above