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
        }
    }
}