Public/Set-CleanPath.ps1
|
function Set-CleanPath { <# .SYNOPSIS Applies a cleaned PATH by removing duplicates and obsolete entries. .DESCRIPTION Removes duplicate and non-existent paths from the specified PATH environment variable. Optionally reorders entries by priority. Creates a backup before making changes. .PARAMETER Target Which PATH to clean: User or Machine. Default is User. .PARAMETER OptimizeOrder If specified, also reorders PATH entries by priority category after cleaning. Priority order: System Critical > PowerShell > Dev Tools > Languages > Apps .PARAMETER RemoveDuplicates If specified, removes duplicate entries. Default is true. .PARAMETER RemoveObsolete If specified, removes paths that don't exist. Default is true. .PARAMETER WhatIf Shows what changes would be made without applying them. .PARAMETER Force Skips confirmation prompt. .EXAMPLE Set-CleanPath -Target User -WhatIf .EXAMPLE Set-CleanPath -Target User -OptimizeOrder .EXAMPLE Set-CleanPath -Target Machine -Force #> [CmdletBinding(SupportsShouldProcess)] param( [ValidateSet('User', 'Machine')] [string]$Target = 'User', [switch]$OptimizeOrder, [switch]$RemoveDuplicates = $true, [switch]$RemoveObsolete = $true, [switch]$Force ) # Check for admin rights if targeting Machine if ($Target -eq 'Machine') { $isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) if (-not $isAdmin) { Write-Error "Administrator privileges required to modify the Machine PATH. Please run PowerShell as Administrator." return } } # Get current analysis $analysis = Get-PathAnalysis -Target $Target $currentPath = [Environment]::GetEnvironmentVariable('PATH', $Target) # Filter paths to keep $pathsToKeep = @() $pathsToRemove = @() $seenPaths = @{} foreach ($entry in $analysis) { $normalizedPath = $entry.ExpandedPath.TrimEnd('\').ToLowerInvariant() $shouldKeep = $true $reason = '' # Check for duplicates if ($RemoveDuplicates -and $seenPaths.ContainsKey($normalizedPath)) { $shouldKeep = $false $reason = 'Duplicate' } else { $seenPaths[$normalizedPath] = $true } # Check for obsolete if ($RemoveObsolete -and -not $entry.Exists) { $shouldKeep = $false $reason = 'Does not exist' } if ($shouldKeep) { $pathsToKeep += $entry.Path } else { $pathsToRemove += @{ Path = $entry.Path Reason = $reason } } } # Apply order optimization if requested if ($OptimizeOrder -and $pathsToKeep.Count -gt 0) { Write-Host " 🔄 Optimizing path order..." -ForegroundColor DarkCyan $pathsToKeep = Get-OptimizedPathOrder -Paths $pathsToKeep } # Build new PATH $newPath = $pathsToKeep -join ';' $savedChars = $currentPath.Length - $newPath.Length # Display summary Write-Host Write-Host " PATH Cleanup Summary for [$Target]" -ForegroundColor Cyan Write-Host " ═══════════════════════════════════════" -ForegroundColor DarkGray Write-Host Write-Host " Current entries : $($analysis.Count)" -ForegroundColor White Write-Host " Entries to keep : $($pathsToKeep.Count)" -ForegroundColor Green Write-Host " Entries to remove: $($pathsToRemove.Count)" -ForegroundColor Yellow Write-Host Write-Host " Current length : $($currentPath.Length) characters" -ForegroundColor White Write-Host " New length : $($newPath.Length) characters" -ForegroundColor Green Write-Host " Characters saved: $savedChars characters" -ForegroundColor Cyan Write-Host if ($pathsToRemove.Count -gt 0) { Write-Host " Entries to be removed:" -ForegroundColor Yellow foreach ($item in $pathsToRemove) { Write-Host " ✗ $($item.Path) [$($item.Reason)]" -ForegroundColor DarkYellow } Write-Host } # Apply changes if ($WhatIfPreference) { Write-Host " [WhatIf] Would apply the cleaned PATH to $Target scope." -ForegroundColor Magenta return } if (-not $Force) { $confirm = Read-Host " Apply changes? (Y/N)" if ($confirm -ne 'Y' -and $confirm -ne 'y') { Write-Host " Operation cancelled." -ForegroundColor Gray return } } # Create backup first $backupResult = Backup-Path -Target $Target Write-Host " Backup created: $($backupResult.BackupFile)" -ForegroundColor Green # Apply the new PATH try { [Environment]::SetEnvironmentVariable('PATH', $newPath, $Target) Write-Host Write-Host " ✓ PATH successfully updated!" -ForegroundColor Green Write-Host " Note: You may need to restart your terminal for changes to take effect." -ForegroundColor DarkGray return [PSCustomObject]@{ Success = $true Target = $Target EntriesRemoved = $pathsToRemove.Count CharactersSaved = $savedChars BackupFile = $backupResult.BackupFile NewPath = $newPath } } catch { Write-Error "Failed to update PATH: $_" return [PSCustomObject]@{ Success = $false Error = $_.Exception.Message } } } |