Public/Backup-Path.ps1

function Backup-Path {
    <#
    .SYNOPSIS
        Creates a backup of the current PATH environment variable.
         
    .DESCRIPTION
        Saves the current PATH to a timestamped JSON file in the backup directory.
         
    .PARAMETER Target
        Which PATH to backup: User, Machine, or Both. Default is Both.
         
    .EXAMPLE
        Backup-Path
         
    .EXAMPLE
        Backup-Path -Target Machine
    #>

    [CmdletBinding()]
    [OutputType([PSCustomObject])]
    param(
        [ValidateSet('User', 'Machine', 'Both')]
        [string]$Target = 'Both'
    )

    $timestamp = Get-Date -Format 'yyyy-MM-dd_HH-mm-ss'
    $backupFile = Join-Path $script:BackupPath "path-backup_$timestamp.json"
    
    $backup = @{
        Timestamp = (Get-Date).ToString('o')
        Target    = $Target
        Hostname  = $env:COMPUTERNAME
        Username  = $env:USERNAME
        Paths     = @{}
    }

    if ($Target -eq 'User' -or $Target -eq 'Both') {
        $backup.Paths.User = [Environment]::GetEnvironmentVariable('PATH', 'User')
    }

    if ($Target -eq 'Machine' -or $Target -eq 'Both') {
        $backup.Paths.Machine = [Environment]::GetEnvironmentVariable('PATH', 'Machine')
    }

    $backup | ConvertTo-Json -Depth 10 | Out-File -FilePath $backupFile -Encoding UTF8

    Write-Verbose "Backup created: $backupFile"

    return [PSCustomObject]@{
        BackupFile = $backupFile
        Timestamp  = $backup.Timestamp
        Target     = $Target
    }
}

function Restore-Path {
    <#
    .SYNOPSIS
        Restores PATH from a backup file.
         
    .DESCRIPTION
        Reads a backup JSON file and restores the PATH environment variable.
         
    .PARAMETER BackupFile
        Path to the backup file to restore from.
         
    .PARAMETER Target
        Which PATH to restore: User, Machine, or Both. Default is Both.
         
    .PARAMETER Force
        Skips confirmation prompt.
         
    .EXAMPLE
        Restore-Path -BackupFile "C:\Users\user\.config\winpath-clean\backups\path-backup_2024-01-01.json"
         
    .EXAMPLE
        Get-ChildItem ~/.config/winpath-clean/backups | Select-Object -First 1 | Restore-Path
    #>

    [CmdletBinding(SupportsShouldProcess)]
    [OutputType([PSCustomObject])]
    param(
        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [Alias('FullName')]
        [string]$BackupFile,
        
        [ValidateSet('User', 'Machine', 'Both')]
        [string]$Target = 'Both',
        
        [switch]$Force
    )

    process {
        if (-not (Test-Path $BackupFile)) {
            Write-Error "Backup file not found: $BackupFile"
            return
        }

        $backup = Get-Content $BackupFile | ConvertFrom-Json

        Write-Host
        Write-Host " Restore PATH from Backup" -ForegroundColor Cyan
        Write-Host " ════════════════════════════════════" -ForegroundColor DarkGray
        Write-Host " Backup file: $BackupFile" -ForegroundColor White
        Write-Host " Created: $($backup.Timestamp)" -ForegroundColor White
        Write-Host " Computer: $($backup.Hostname)" -ForegroundColor White
        Write-Host

        if (-not $Force) {
            $confirm = Read-Host " Restore this backup? (Y/N)"
            if ($confirm -ne 'Y' -and $confirm -ne 'y') {
                Write-Host " Restore cancelled." -ForegroundColor Gray
                return
            }
        }

        # Create a backup of current state before restoring
        $preRestoreBackup = Backup-Path -Target $Target
        Write-Host " Pre-restore backup created: $($preRestoreBackup.BackupFile)" -ForegroundColor DarkGray

        try {
            if (($Target -eq 'User' -or $Target -eq 'Both') -and $backup.Paths.User) {
                [Environment]::SetEnvironmentVariable('PATH', $backup.Paths.User, 'User')
                Write-Host " ✓ User PATH restored" -ForegroundColor Green
            }

            if (($Target -eq 'Machine' -or $Target -eq 'Both') -and $backup.Paths.Machine) {
                $isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
                if (-not $isAdmin) {
                    Write-Warning "Administrator privileges required to restore Machine PATH. Skipping."
                }
                else {
                    [Environment]::SetEnvironmentVariable('PATH', $backup.Paths.Machine, 'Machine')
                    Write-Host " ✓ Machine PATH restored" -ForegroundColor Green
                }
            }

            Write-Host
            Write-Host " PATH restored successfully!" -ForegroundColor Green

            return [PSCustomObject]@{
                Success          = $true
                RestoredFrom     = $BackupFile
                PreRestoreBackup = $preRestoreBackup.BackupFile
            }
        }
        catch {
            Write-Error "Failed to restore PATH: $_"
            return [PSCustomObject]@{
                Success = $false
                Error   = $_.Exception.Message
            }
        }
    }
}

function Get-PathBackups {
    <#
    .SYNOPSIS
        Lists all available PATH backups.
         
    .EXAMPLE
        Get-PathBackups
    #>

    [CmdletBinding()]
    [OutputType([PSCustomObject[]])]
    param()

    $backups = Get-ChildItem -Path $script:BackupPath -Filter '*.json' -ErrorAction SilentlyContinue |
    Sort-Object LastWriteTime -Descending |
    ForEach-Object {
        $content = Get-Content $_.FullName | ConvertFrom-Json
        [PSCustomObject]@{
            FileName = $_.Name
            FullName = $_.FullName
            Created  = $content.Timestamp
            Target   = $content.Target
            Computer = $content.Hostname
        }
    }

    return $backups
}