Skip to content

Instantly share code, notes, and snippets.

Last active Oct 30, 2016
What would you like to do?
Create encrypted and compressed backups only when warranted
Backs up and encrypts a directory or file
Backs up files or directories by adding it them a tar file and then
encrypting it with a public key. Becuase public key encryption is used
there are no passwords stored anywhere.
gpg must be installed and the public key you want to use must be imported.
Encrypted items will keep their orignal name but have the following
added to the start YYYYMMDD_XXXXXXXX_ and .tar.gpg added to the end.
YYYYMMDD represents the date and XXXXXXXX represents the fingerprint
(last 8 hex characters) of a hash created with DirHash.
i.e. test.txt may become
The encryption process also compresses the data first. It is set to zlib
level 9. This is maximum compression. You may want to change it
If an encrypted backup with the same original name and fingerprint exists,
the file will not be updated. If an encrypted backup with the same name
and a different fingerprint exists, it will be deleted and a new backup
created. This is because if the fingerprints are different the files have
changed and the backup needs to be updated.
If an origal file is deleted, the encrypted backup will not be delted.
Items backed up will be written the console
Version: 1.0
Author: Grant Trebbin
Creation Date: 29/10/2016
Purpose/Change: Initial Script
# Fill these variables with the required parameters
$pathToBackup = ""
$outputLocation = ""
$public_key_fingerprint = ""
function New-TemporaryDirectory{
# Create a new temporary directory in the system
# temporary location and return its full path
$parent = [System.IO.Path]::GetTempPath()
# Create a directory name and make sure it doesn't exist
[string] $name = [System.Guid]::NewGuid()
} while ((Test-Path (Join-Path $parent $name)))
# Create a directory and return its name
$newPath = Join-Path $parent $name
New-Item -ItemType Directory -Path $newPath > $null
return $newPath
$date = Get-Date
$dateString = $date.ToString("yyyyMMdd")
$temporaryLocation = New-TemporaryDirectory
$items = Get-ChildItem -Path $pathToBackup -Filter "" -Force| Select FullName
ForEach($item in $items){
# Get the name of each item
$itemName = (Get-Item -Force $item.FullName)
$leafItemName = Split-Path -Path $item.FullName -Leaf
# Get the hash of the item
$itemHash = D:\Grant\Projects\Scripts\DirHash.ps1 -Path $itemName.FullName
# Get the fingerprint of the hash (last 8 characters)
$itemFingerPrint = $itemHash.substring($itemHash.length -8, 8)
# Generate FileNames
# Filename will take the form
# YYYYMMDD_<8 character hex fingerprint>_<original item name>.tar.gpg
$tarName = $leafItemName + '.tar'
$fingerPrintFileName = "_" + $itemFingerPrint + "_"+ $tarName + '.gpg'
$encryptedFileName = $dateString + $fingerPrintFileName
# See if a matching backup already exists
$backupNameWildcard =
Join-Path $outputLocation ("********" + $fingerPrintFileName)
$doesBackupExist = (Test-Path($backupNameWildcard))
if ($doesBackupExist -eq $false){
# Find OldBackup if one already exists
# Only check if original file names match
$oldBackupWildcard =
Join-Path $outputLocation ("******_********_" + $tarName + ".gpg")
$oldBackups = Get-ChildItem -Path $oldBackupWildcard -Force
# Tar the file or directory to archive and add the .tar extension
$tarFile = Join-Path $temporaryLocation $tarName
cmd /c 7z.exe a -ttar $tarFile $itemName.FullName > $null 2>&1
# Encrypt the file
# The file is redirected in and out of the gpg command because it
# doesn't seem to handle unicode filenames. The filenames in the
# command need to be surrounded by quotes in case the filename
# contains a space.
$encryptedFilePath = Join-Path $temporaryLocation $encryptedFileName
$encryptionCommand = "gpg -o- --batch -r " + $public_key_fingerprint +
" -z 9 --encrypt" + " < `"" + $tarFile + "`"" + " > `"" +
$encryptedFilePath + "`""
cmd /c $encryptionCommand
# The redirection causes a problem though. If the encryption process
# fails for any reason it still writes the output file, it's just
# empty. That's why the encrypted file is written to the temporary
# directory. The new encrypted backup is moved into the ouptut
# directory and the old backups are deleted only if $LASTEXITCODE
# equals zero indicating that the gpg command has succeeded
if ($LASTEXITCODE -eq 0){
Move-Item $encryptedFilePath (
Join-Path $outputLocation $encryptedFileName)
foreach($test in $oldBackups){
Remove-Item ($test)
# Write status message
Write-Host ("Backing up " + $leafItemName +
" to " + $encryptedFileName)
# Remove the temporary tar file
Remove-Item $tarFile
Remove-Item $temporaryLocation -Recurse
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment