public/Test-PSProfileSnapshot.ps1
|
function Test-PSProfileSnapshot { <# .SYNOPSIS Test the current user's profile against the latest snapshot .DESCRIPTION Test the current user's profile against the latest snapshot. This function is designed to be called at the beginning of your PowerShell profile to detect if the profile file has been modified since the last snapshot export. If a mismatch is detected, the user is presented with options to: - Accept the new profile and update the snapshot - Revert to the last known-good snapshot - View the full diff - Abort profile loading .INPUTS None .OUTPUTS System.Boolean Returns $true if the profile hash matches the latest snapshot, $false otherwise. .EXAMPLE Test-PSProfileSnapshot Compares the current profile's hash against the most recently saved snapshot. .NOTES None #> try { $profilesPath = Split-Path -Path $profile -Parent $latestHashFile = Get-ChildItem -Path $profilesPath -Filter "*.hash" -ErrorAction Stop | Sort-Object -Property CreationTime | Select-Object -Last 1 if (-not $latestHashFile) { Write-Warning "⚠️ No profile snapshot found. Run 'New-PSProfileSnapshot' first." return $false } $lastProfileHash = Get-Content -Path $latestHashFile.FullName -ErrorAction Stop } catch { Write-Error "❌ Could not read stored snapshot hash." throw $_.Exception.Message } try { $currentProfileHash = Get-FileHash -Path $profile -Algorithm SHA256 -ErrorAction Stop | Select-Object -ExpandProperty Hash } catch { Write-Error "❌ Could not calculate current profile hash." throw $_.Exception.Message } if ($lastProfileHash -eq $currentProfileHash) { Write-Host "✅ Profile snapshot matches." -ForegroundColor Green return $true } else { try { Write-Host @" ██████╗ ███████╗██████╗ ██╗ ██╗ ██╔══██╗██╔════╝██╔══██╗██║ ██║ ██████╔╝███████╗██████╔╝██║ █╗ ██║ ██╔═══╝ ╚════██║██╔═══╝ ██║███╗██║ ██║ ███████║██║ ╚███╔███╔╝ ╚═╝ ╚══════╝╚═╝ ╚══╝╚══╝ "@ # Get snapshot metadata $snapshotMetadataFile = $latestHashFile.FullName -replace '\.hash$', '.metadata' $snapshotDate = $latestHashFile.CreationTime Write-Host "`n⚠️ PROFILE MISMATCH DETECTED" -ForegroundColor Yellow Write-Host "Last snapshot: $($snapshotDate.ToString('yyyy-MM-dd HH:mm:ss'))" -ForegroundColor Yellow # Get backup and current content for diff $latestBackupFile = Get-ChildItem -Path $profilesPath -Filter "*.backup" -ErrorAction Stop | Sort-Object -Property CreationTime | Select-Object -Last 1 $diffAvailable = $false if ($latestBackupFile) { $lastProfileContent = Get-Content -Path $latestBackupFile.FullName -ErrorAction Stop $currentProfileContent = Get-Content -Path $profile -ErrorAction Stop $diffAvailable = $true # Show summary of changes $diffSummary = Compare-Object -ReferenceObject $lastProfileContent -DifferenceObject $currentProfileContent $additions = @($diffSummary | Where-Object { $_.SideIndicator -eq '=>' }).Count $removals = @($diffSummary | Where-Object { $_.SideIndicator -eq '<=' }).Count Write-Host "`nChanges: +$additions lines, -$removals lines" -ForegroundColor Yellow } # Interactive menu $validInput = $false while (-not $validInput) { Write-Host "`nWhat would you like to do?" Write-Host " [A] Accept new profile (run New-PSProfileSnapshot)" Write-Host " [R] Revert to last snapshot (run Restore-PSProfileSnapshot)" if ($diffAvailable) { Write-Host " [V] View full diff" } Write-Host " [Q] Quit (abort profile load)" $userInput = Read-Host "`nEnter choice (A/R/$(if ($diffAvailable) { 'V/' })Q)" $userInput = $userInput.ToUpper() switch ($userInput) { 'A' { Write-Host "`nAccepting new profile and creating snapshot..." -ForegroundColor Green New-PSProfileSnapshot | Out-Null Write-Host "✅ Snapshot updated successfully." -ForegroundColor Green $validInput = $true return $true } 'R' { Write-Host "`nAbout to revert profile to snapshot from $($snapshotDate.ToString('yyyy-MM-dd HH:mm:ss'))" -ForegroundColor Yellow $confirmRevert = Read-Host "Continue? (y/N)" if ($confirmRevert -eq 'y' -or $confirmRevert -eq 'Y') { Write-Host "Reverting to snapshot..." -ForegroundColor Green # Extract GUID from the hash file name (format: profile_GUID.hash) $snapshotGUID = $latestHashFile.BaseName -replace '^.*_([a-f0-9\-]+)$', '$1' Restore-PSProfileSnapshot -SnapshotGUID $snapshotGUID -ErrorAction Stop Write-Host "✅ Profile reverted successfully." -ForegroundColor Green Write-Host "`nExiting session to reload the restored profile..." -ForegroundColor Cyan exit 0 } else { Write-Host "Revert cancelled." -ForegroundColor Yellow } } 'V' { if ($diffAvailable) { Write-Host "`n----- Full Profile Diff -----" -ForegroundColor Cyan Compare-Object -ReferenceObject $lastProfileContent -DifferenceObject $currentProfileContent | Format-Table -AutoSize @{ Label = "Type"; Expression = { if ($_.SideIndicator -eq '=>') { "NEW" } else { "OLD" } } }, InputObject -Wrap | Out-String | Write-Host Write-Host "----- End Diff -----`n" -ForegroundColor Cyan } else { Write-Host "No diff available." -ForegroundColor Yellow } } 'Q' { Write-Host "Aborting profile load." -ForegroundColor Red exit } default { Write-Host "Invalid input. Please enter A, R, $(if ($diffAvailable) { 'V, ' })or Q." -ForegroundColor Red } } } } catch { Write-Warning "⚠️ Could not display profile differences: $($_.Exception.Message)" return $false } } } |