private/RestorePoint.ps1
|
function New-OctaRestorePoint { <# Constitution Principle I: attempts a System Restore Point before the first applied category each run. Checkpoint-Computer silently no-ops when throttled by Windows' 24h SystemRestorePointCreationFrequency, so the only reliable way to know whether a *new* point actually appeared is to compare Get-ComputerRestorePoint before/after (see research.md). Never throws - always returns a status the caller can act on. #> [CmdletBinding()] param( [switch]$NoRestorePoint, [string]$Description = 'Octa debloat run' ) if ($NoRestorePoint) { return [pscustomobject]@{ Status = 'SkippedByUser'; SequenceNumber = $null } } $before = @(Get-ComputerRestorePoint -ErrorAction SilentlyContinue | Select-Object -ExpandProperty SequenceNumber) try { Checkpoint-Computer -Description $Description -RestorePointType MODIFY_SETTINGS -ErrorAction Stop } catch { # Checkpoint-Computer throws when System Protection is off for the target volume. return [pscustomobject]@{ Status = 'SkippedProtectionDisabled'; SequenceNumber = $null } } $after = @(Get-ComputerRestorePoint -ErrorAction SilentlyContinue) $newPoint = $after | Where-Object { $_.SequenceNumber -notin $before } | Select-Object -Last 1 if ($newPoint) { return [pscustomobject]@{ Status = 'Created'; SequenceNumber = $newPoint.SequenceNumber } } # No error, but no new point appeared -> the 24h creation-frequency throttle suppressed it. return [pscustomobject]@{ Status = 'SkippedThrottled'; SequenceNumber = $null } } function Invoke-OctaSessionRestorePointGate { <# 010: centralizes the restore-point decision to once per Invoke-Octa session, immediately after language resolves and before the main menu first renders - instead of once per applied category (Invoke-OctaCategory's own restore-point block, still used by non-interactive callers per spec FR-009). Windows' own 24h SystemRestorePointCreationFrequency already makes a second same-day attempt a harmless no-op, so re-prompting "proceed without a restore point?" for every category in the same session was pure repeated friction with no new information - see specs/010-quick-assist-restore-point/research.md. Returns $true if the interactive session should proceed to the main menu, $false if the user declined to continue without a fresh restore point. #> [CmdletBinding()] param( [Parameter(Mandatory)]$Strings ) Write-Host $Strings.restorePointSessionIntro $restorePoint = New-OctaRestorePoint -Description 'Octa session' $warningShown = $false if ($restorePoint.Status -eq 'SkippedProtectionDisabled') { Write-Host $Strings.restorePointSkippedProtectionDisabled $warningShown = $true if (Test-OctaInteractiveConsole) { $enableResponse = Read-Host 'Enable System Protection and create a restore point now? (y/N)' if ($enableResponse -in @('y', 'Y', 's', 'S')) { try { Enable-ComputerRestore -Drive "$env:SystemDrive\" -ErrorAction Stop $restorePoint = New-OctaRestorePoint -Description 'Octa session' } catch { Write-Host "Could not enable System Protection automatically: $($_.Exception.Message)" } } } } elseif ($restorePoint.Status -eq 'Created') { Write-Host $Strings.restorePointCreated } if ($restorePoint.Status -in @('SkippedThrottled', 'SkippedProtectionDisabled')) { if (-not $warningShown) { Write-Host $Strings.restorePointSkippedThrottled } if (-not (Test-OctaInteractiveConsole)) { return $true } $proceedResponse = Read-Host $Strings.confirmPrompt return ($proceedResponse -in @('y', 'Y', 's', 'S')) } return $true } |