Public/Remove-SafePath.ps1
|
function Remove-SafePath { <# .SYNOPSIS Removes a path entry safely, with validation and backup. .DESCRIPTION Removes a path from the PATH environment variable after verifying: - The path exists in PATH - Creates a backup before removing .PARAMETER Path The path to remove from the PATH environment variable. .PARAMETER Target Which PATH to modify: User or Machine. Default is User. .PARAMETER Force Skips confirmation prompt. .PARAMETER WhatIf Shows what would happen without making changes. .EXAMPLE Remove-SafePath -Path "C:\MyApp\bin" .EXAMPLE Remove-SafePath -Path "C:\Tools" -Target Machine .EXAMPLE Remove-SafePath -Path "C:\OldTool\bin" -WhatIf #> [CmdletBinding(SupportsShouldProcess)] param( [Parameter(Mandatory, Position = 0)] [string]$Path, [ValidateSet('User', 'Machine')] [string]$Target = 'User', [switch]$Force ) # Normalize the path $Path = $Path.TrimEnd('\') # 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 } } Write-Host Write-Host " Remove Path from [$Target] PATH" -ForegroundColor Cyan Write-Host " ═══════════════════════════════════════" -ForegroundColor DarkGray Write-Host Write-Host " Path to remove: " -NoNewline -ForegroundColor White Write-Host $Path -ForegroundColor Yellow Write-Host # Get current PATH $currentPath = [Environment]::GetEnvironmentVariable('PATH', $Target) $currentPaths = @($currentPath -split ';' | Where-Object { $_ -ne '' }) # Find the path to remove (case-insensitive comparison) $expandedPath = [Environment]::ExpandEnvironmentVariables($Path) $normalizedSearch = $expandedPath.TrimEnd('\').ToLowerInvariant() $foundIndex = -1 $foundEntry = $null for ($i = 0; $i -lt $currentPaths.Count; $i++) { $normalizedExisting = [Environment]::ExpandEnvironmentVariables($currentPaths[$i]).TrimEnd('\').ToLowerInvariant() if ($normalizedExisting -eq $normalizedSearch) { $foundIndex = $i $foundEntry = $currentPaths[$i] break } } if ($foundIndex -eq -1) { Write-Host " ✗ Path not found in $Target PATH" -ForegroundColor Red Write-Host return [PSCustomObject]@{ Success = $false Reason = 'Path not found in PATH' Path = $Path Target = $Target } } Write-Host " ✓ Path found at position $($foundIndex + 1) of $($currentPaths.Count)" -ForegroundColor Green Write-Host " Entry: $foundEntry" -ForegroundColor DarkGray Write-Host # Check if path exists on filesystem $pathCheck = Test-PathEntry -Path $expandedPath if (-not $pathCheck.Exists) { if ($pathCheck.AccessDenied) { Write-Host " ⚠ Note: Path does not exist or no access (may require elevated privileges)" -ForegroundColor Yellow } else { Write-Host " ⚠ Note: Path does not exist on filesystem (already deleted or obsolete)" -ForegroundColor Yellow } } Write-Host # Build new PATH without the removed entry $newPaths = [System.Collections.ArrayList]::new() for ($i = 0; $i -lt $currentPaths.Count; $i++) { if ($i -ne $foundIndex) { $newPaths.Add($currentPaths[$i]) | Out-Null } } $newPath = $newPaths -join ';' # WhatIf handling if ($WhatIfPreference) { Write-Host " [WhatIf] Would remove path from $Target PATH at position $($foundIndex + 1)" -ForegroundColor Magenta Write-Host " [WhatIf] PATH entries would go from $($currentPaths.Count) to $($newPaths.Count)" -ForegroundColor Magenta return [PSCustomObject]@{ Success = $true WhatIf = $true Path = $Path Position = $foundIndex + 1 Target = $Target } } # Confirmation if (-not $Force) { $confirm = Read-Host " Remove this path? (Y/N)" if ($confirm -ne 'Y' -and $confirm -ne 'y') { Write-Host " Operation cancelled." -ForegroundColor Gray return [PSCustomObject]@{ Success = $false Cancelled = $true } } } # Create backup $backup = Backup-Path -Target $Target Write-Host " ✓ Backup created: $($backup.BackupFile)" -ForegroundColor Green # Apply the change if ($PSCmdlet.ShouldProcess("$Target PATH", "Remove path '$foundEntry'")) { try { [Environment]::SetEnvironmentVariable('PATH', $newPath, $Target) Write-Host Write-Host " ✓ Path removed successfully!" -ForegroundColor Green Write-Host " Note: Restart your terminal for changes to take effect." -ForegroundColor DarkGray Write-Host return [PSCustomObject]@{ Success = $true Path = $Path RemovedEntry = $foundEntry Target = $Target Position = $foundIndex + 1 RemainingEntries = $newPaths.Count BackupFile = $backup.BackupFile } } catch { Write-Error "Failed to update PATH: $_" return [PSCustomObject]@{ Success = $false Error = $_.Exception.Message } } } else { return [PSCustomObject]@{ Success = $false Cancelled = $true } } } |