public/Restore-PSProfileSnapshot.ps1
|
<# .SYNOPSIS Restores the current profile from a specific snapshot. .DESCRIPTION Restores the user's PowerShell profile from a previously saved snapshot. The user can select a snapshot by name or by GUID. The current profile is backed up before restoration in case the restore needs to be undone. .PARAMETER Name The name of the snapshot to restore from. Use Get-PSProfileSnapshot to list available snapshots. If not specified, the most recent snapshot is used by default. Can be piped from Get-PSProfileSnapshot. .PARAMETER GUID The GUID of the snapshot to restore. Used as an alternative to Name for precise snapshot identification. Format: 12345678-1234-1234-1234-123456789abc Can be piped from Get-PSProfileSnapshot. .INPUTS None .OUTPUTS None .EXAMPLE Restore-PSProfileSnapshot Restores the profile from the most recent snapshot. .EXAMPLE Restore-PSProfileSnapshot -Name "before-major-change" Restores the profile from a snapshot with a custom name. .EXAMPLE Get-PSProfileSnapshot | Where-Object Name -EQ "stable-config" | Restore-PSProfileSnapshot Restores profile by piping from Get-PSProfileSnapshot. .NOTES A safety backup of the current profile is created before restoration. If restoration fails, the profile remains unchanged. #> function Restore-PSProfileSnapshot { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] param( [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [Alias('SnapshotName')] [string]$Name, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [Alias('SnapshotGUID')] [guid]$GUID ) try { $profilesPath = Split-Path -Path $profile -Parent # Find the snapshot to restore $snapshotBackupFile = $null if ($GUID) { # Search by GUID $snapshotBackupFile = Get-ChildItem -Path $profilesPath -Filter "*_$($GUID).backup" -ErrorAction Stop | Select-Object -First 1 if (-not $snapshotBackupFile) { Write-Error "❌ No snapshot found with GUID: $GUID" return } } elseif ($Name) { # Search by name (custom name from metadata or timestamp) $backupFiles = Get-ChildItem -Path $profilesPath -Filter "*.backup" -ErrorAction Stop foreach ($backupFile in $backupFiles) { $guid = $backupFile.BaseName -replace '^.*_([a-f0-9\-]+)$', '$1' $metadataFileName = "$($profile)_$($guid).metadata" # Check metadata first for custom name if (Test-Path -Path $metadataFileName -ErrorAction SilentlyContinue) { $metadata = Get-Content -Path $metadataFileName -Raw | ConvertFrom-Json -ErrorAction SilentlyContinue if ($metadata.Name -eq $Name) { $snapshotBackupFile = $backupFile break } } # Also check if name matches the timestamp format of CreatedTime $timestampName = $backupFile.CreationTime.ToString("yyyy-MM-dd HH:mm:ss") if ($timestampName -eq $Name) { $snapshotBackupFile = $backupFile break } } if (-not $snapshotBackupFile) { Write-Error "❌ No snapshot found with name: $Name" return } } else { # Use most recent snapshot $snapshotBackupFile = Get-ChildItem -Path $profilesPath -Filter "*.backup" -ErrorAction Stop | Sort-Object -Property CreationTime | Select-Object -Last 1 if (-not $snapshotBackupFile) { Write-Error "❌ No snapshots available to restore from." return } } # Create a pre-restoration backup as safety measure $safetyBackupGUID = [guid]::NewGuid() $safetyBackupFile = "$($profile)_$($safetyBackupGUID).backup.pre-restore" $actionTarget = "profile from snapshot: $($snapshotBackupFile.Name)" if ($PSCmdlet.ShouldProcess($actionTarget, 'Restore')) { try { # Create safety backup Copy-Item -Path $profile -Destination $safetyBackupFile -Force -ErrorAction Stop # Restore from snapshot Copy-Item -Path $snapshotBackupFile.FullName -Destination $profile -Force -ErrorAction Stop Write-Host "✅ Profile restored successfully from snapshot: $($snapshotBackupFile.Name)" -ForegroundColor Green Write-Host "ℹ️ A safety backup was created at: $safetyBackupFile" -ForegroundColor Cyan } catch { Write-Error "❌ Could not restore profile from snapshot." # Clean up safety backup if restoration failed if (Test-Path -Path $safetyBackupFile -ErrorAction SilentlyContinue) { Remove-Item -Path $safetyBackupFile -Force -ErrorAction SilentlyContinue } throw $_.Exception.Message } } } catch { Write-Error "❌ An error occurred during snapshot restoration." throw $_.Exception.Message } } |