⚡ PowerShell 5.1+

Backup Documents to Zip

Compresses a source folder into a timestamped zip archive and prunes old backups beyond a configurable retention count.

By WindowsScripting.com · 2 KB
Backup-Documents.ps1
<#
.SYNOPSIS
    Backs up a source folder to a timestamped zip archive.

.DESCRIPTION
    Compresses the contents of -SourcePath into a zip file named
    "<foldername>_yyyyMMdd-HHmmss.zip" inside -DestinationPath, then
    optionally prunes older backups beyond -KeepCount.

.PARAMETER SourcePath
    Folder to back up.

.PARAMETER DestinationPath
    Folder where the zip archive will be created. Created if missing.

.PARAMETER KeepCount
    Number of most recent backups to keep. Older ones are deleted. 0 = keep all.

.EXAMPLE
    .\Backup-Documents.ps1 -SourcePath "C:\Users\me\Documents" -DestinationPath "D:\Backups" -KeepCount 5
#>

[CmdletBinding()]
param(
    [Parameter(Mandatory)]
    [ValidateScript({ Test-Path $_ -PathType Container })]
    [string]$SourcePath,

    [Parameter(Mandatory)]
    [string]$DestinationPath,

    [int]$KeepCount = 0
)

if (-not (Test-Path $DestinationPath)) {
    New-Item -ItemType Directory -Path $DestinationPath -Force | Out-Null
}

$folderName = Split-Path -Leaf ($SourcePath.TrimEnd('\'))
$timestamp  = Get-Date -Format "yyyyMMdd-HHmmss"
$zipName    = "{0}_{1}.zip" -f $folderName, $timestamp
$zipPath    = Join-Path $DestinationPath $zipName

Write-Host "Compressing '$SourcePath' -> '$zipPath' ..." -ForegroundColor Cyan
Compress-Archive -Path (Join-Path $SourcePath '*') -DestinationPath $zipPath -CompressionLevel Optimal

if (Test-Path $zipPath) {
    $sizeMB = [math]::Round((Get-Item $zipPath).Length / 1MB, 2)
    Write-Host "Backup created: $zipPath ($sizeMB MB)" -ForegroundColor Green
} else {
    Write-Error "Backup failed: archive was not created."
    exit 1
}

if ($KeepCount -gt 0) {
    $existing = Get-ChildItem -Path $DestinationPath -Filter "$folderName`_*.zip" |
                Sort-Object LastWriteTime -Descending

    $toRemove = $existing | Select-Object -Skip $KeepCount
    foreach ($old in $toRemove) {
        Write-Host "Removing old backup: $($old.Name)" -ForegroundColor DarkYellow
        Remove-Item $old.FullName -Force
    }
}