Private/New-WingetSnapshot.ps1

function New-WingetSnapshot {
    <#
    .SYNOPSIS
        Save the current installed-package state to ~/.wingetbatch/snapshots.
        Returns the snapshot as a hashtable.
    #>

    [CmdletBinding()]
    param([string]$Label = 'manual')

    $snapshotDir = Join-Path (Get-WingetBatchConfigDir) "snapshots"
    if (-not (Test-Path $snapshotDir)) {
        New-Item -Path $snapshotDir -ItemType Directory -Force | Out-Null
    }

    # Milliseconds keep IDs unique when an auto-snapshot and a manual one land in the same second
    $id = "snap_$(Get-Date -Format 'yyyyMMdd_HHmmss_fff')"
    $packages = @(Microsoft.WinGet.Client\Get-WinGetPackage -ErrorAction SilentlyContinue)

    $snapshot = [ordered]@{
        Id           = $id
        Timestamp    = (Get-Date).ToString('o')
        Label        = $Label
        Hostname     = $env:COMPUTERNAME
        PackageCount = $packages.Count
        Packages     = @($packages | ForEach-Object {
            [ordered]@{ Id = $_.Id; Name = $_.Name; Version = $_.InstalledVersion; Source = $_.Source }
        })
    }

    $filePath = Join-Path $snapshotDir "$id.json"
    $snapshot | ConvertTo-Json -Depth 5 -Compress | Set-Content -Path $filePath -Encoding UTF8
    return $snapshot
}

function Invoke-WingetAutoSnapshot {
    <#
    .SYNOPSIS
        Take a snapshot before a change, if auto-snapshots are enabled
        (Restore-WingetSnapshot -AutoSnapshot $true). Never throws.
    #>

    [CmdletBinding()]
    param([Parameter(Mandatory)][string]$Reason)

    try {
        $autoConfigPath = Join-Path (Get-WingetBatchConfigDir) "snapshot_config.json"
        if (-not (Test-Path $autoConfigPath)) { return }
        $autoConfig = Get-Content $autoConfigPath -Raw | ConvertFrom-Json
        if (-not $autoConfig.AutoSnapshot) { return }

        $snap = New-WingetSnapshot -Label "auto: before $Reason"
        Write-Host " [SNAPSHOT] Saved $($snap.Id) (undo with Restore-WingetSnapshot -UndoLast 1)" -ForegroundColor DarkGray
    }
    catch {
        Write-Verbose "Auto-snapshot skipped: $_"
    }
}