Public/Backup-LedgerJournal.ps1
|
<# .SYNOPSIS Creates a timestamped zip backup of a PSLedger journal. .DESCRIPTION Compresses an entire journal directory (.ledger) into a single timestamped zip archive named '<JournalName>_yyyy-MM-dd_HHmmss.zip'. Backups are written to a destination directory (by default a 'backups' folder next to the journal) which is created if it does not exist. By default the five most recent backups of the same journal are retained and any older ones are removed. Use -KeepCount to change the retention count, or -KeepCount 0 to keep every backup. The journal schema version is not enforced, so a backup can always be taken — for example just before running Update-LedgerJournal. .PARAMETER JournalPath The path to an existing journal directory. If omitted, the current session journal (set via Set-LedgerCurrentJournal) is used. .PARAMETER DestinationPath The directory where the backup archive is written. Defaults to a 'backups' folder located next to the journal directory. Created if it does not exist. .PARAMETER KeepCount How many of the most recent backups of this journal to keep. Older backups are removed after the new one is created. Defaults to 5. Use 0 to keep all backups. .EXAMPLE Backup-LedgerJournal -JournalPath .\MinFirma.ledger Creates .\backups\MinFirma_2026-07-03_095752.zip and keeps the five most recent backups. .EXAMPLE Set-LedgerCurrentJournal -Path .\Konsult.ledger Backup-LedgerJournal -DestinationPath D:\Backuper -KeepCount 10 Backs up the current session journal to D:\Backuper and retains the ten most recent archives. #> function Backup-LedgerJournal { [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')] param ( [Parameter()] [string]$JournalPath, [Parameter()] [string]$DestinationPath, [Parameter()] [ValidateRange(0, [int]::MaxValue)] [int]$KeepCount = 5 ) $JournalPath = Resolve-LedgerJournalPath -JournalPath $JournalPath -SchemaCheck None if (-not (Test-Path $JournalPath -PathType Container)) { throw "Journal not found: $JournalPath" } if (-not (Test-Path (Join-Path $JournalPath 'journal.txt') -PathType Leaf)) { throw "Invalid journal - journal.txt not found in: $JournalPath" } $JournalDir = (Resolve-Path $JournalPath).Path.TrimEnd('\', '/') $BaseName = [System.IO.Path]::GetFileNameWithoutExtension($JournalDir) if (-not $DestinationPath) { $DestinationPath = Join-Path (Split-Path $JournalDir -Parent) 'backups' } if (-not (Test-Path $DestinationPath -PathType Container)) { if ($PSCmdlet.ShouldProcess($DestinationPath, 'Create backup directory')) { New-Item -ItemType Directory -Path $DestinationPath -Force | Out-Null } } $Timestamp = Get-Date -Format 'yyyy-MM-dd_HHmmss' $ArchiveName = "${BaseName}_${Timestamp}.zip" $ArchivePath = Join-Path $DestinationPath $ArchiveName if ($PSCmdlet.ShouldProcess($ArchivePath, "Back up journal '$BaseName'")) { Compress-Archive -Path $JournalDir -DestinationPath $ArchivePath -Force } if ($KeepCount -gt 0 -and (Test-Path $DestinationPath -PathType Container)) { $Existing = @(Get-ChildItem -Path $DestinationPath -Filter "${BaseName}_*.zip" -File | Sort-Object Name -Descending) if ($Existing.Count -gt $KeepCount) { $ToRemove = $Existing | Select-Object -Skip $KeepCount foreach ($Old in $ToRemove) { if ($PSCmdlet.ShouldProcess($Old.FullName, 'Remove old backup')) { Remove-Item -Path $Old.FullName -Force } } } } if (Test-Path $ArchivePath -PathType Leaf) { Get-Item -Path $ArchivePath } } |