Exercise: The Smart Backup

Finish a backup script that copies a file only when it's needed, with parameters, a usage line, -List and a -Menu, checks for missing, folder and empty names, and a switch that says what kind of file it copied, while a Pester check runs it job by job.

Apprentice · PowerShell · Updated

Your school work deserves a backup, and the one you'll finish here is smart about it. It copies a file only when the file changed since its last copy, never lets an empty file replace a good one, turns away folders and typos with a clear message, and says what kind of file it copied. It also behaves like a real application: it takes parameters, run with nothing it explains how to use it, -List shows what's backed up, and -Menu lets someone who doesn't know the parameters choose from a menu. A Pester check runs your script for real, job by job, and tells you which jobs work.

Get the exercise code

Open this lesson's GitHub repository, github.com/ask-codey/exercise-powershell-the-smart-backup, also linked from the Exercise box beside the lesson. Click Code, then Download ZIP, and unzip it into your terminal-practice folder. Or clone it with Git.

The folder holds:

  • Backup-File.ps1: the script to finish, with nine jobs, each a comment saying what to do and exactly what to print.
  • essay.txt, notes.txt, reading-list.txt, empty-draft.txt and a photos folder: practice files to try it on.
  • README.md: the same jobs, with tips.
  • Check.Tests.ps1: the check. You don't need to change it.

What to do

Open PowerShell 7 in the exercise folder, the one with Check.Tests.ps1 in it, and open the script with code Backup-File.ps1 (Writing Scripts in VS Code). Each job is a comment, with room under it for your lines:

# 5. No such file: print "There's no file called FILE." and stop with exit 1.
  1. The parameters: -Path and -Destination (default backup), both [string], then the switches -List and -Menu (Parameters: param()).
  2. The menu: with -Menu, print three choices, ask Pick one with Read-Host, and act on the answer with a switch (Asking Questions: Read-Host, Many Choices: switch).
  3. Run with nothing: print the usage line and stop with exit code 1 (If This, Then That: if, elseif and else).
  4. -List: list what's in the backup folder, or say No backups yet.
  5. A missing file: say so, and stop with exit code 1.
  6. A folder: say so, and stop with exit code 1.
  7. An empty file: keep the last good copy, and stop with exit code 0.
  8. Copy only when needed: go on only when there's no copy yet or the file is newer than its copy; otherwise say it hasn't changed.
  9. Say what kind: a switch -Wildcard on the file's name, then copy it and print Copied FILE (KIND).

Each job's comment gives its message word for word. Save, and try your script on the practice files as you go: .\Backup-File.ps1 essay.txt twice, then .\Backup-File.ps1 -List.

Check your work

The check uses Pester, PowerShell's test tool. If you haven't installed it yet, install it once:

Install-PSResource Pester

Then, from the exercise folder:

Invoke-Pester

At first most tests fail. That's expected: each job you finish turns its tests green. A failing test says what it expected, what your script printed, and what to look at. The check runs your script in a throwaway folder of its own, with made-up files, so your practice files and your backup folder are never touched.

If PowerShell says a script can't be loaded because running scripts is disabled or the file is not digitally signed, Windows has marked the downloaded files as coming from the internet. From the exercise folder, run Get-ChildItem -Recurse | Unblock-File once, then try again (Why a Script Won't Run: The Execution Policy).

Hints

  • Work from the top. The script runs its jobs in order, and each exit stops it, so a run with nothing stops at job 3 before it tries anything else.
  • Why not Mandatory for -Path? -List and -Menu don't need a file, and a Mandatory -Path would ask for one anyway. Job 3's usage line does the explaining instead.
  • Two tests in one if. Job 3 is "no $Path and no $List": -not $Path -and -not $List. Job 8's "there's a copy, and the file isn't newer" is two tests joined with -and, and -le reads "less than or equal".
  • A folder or a file? Test-Path $Path -PathType Container is True only for a folder (Is It There? Test-Path).
  • The menu sets things up for the jobs below it. For 1, put Read-Host 'Which file' into $Path; for 2, $List = $true. Jobs 3 to 9 do the rest.
  • Keep the switch's answer: $kind = switch -Wildcard ($file.Name) { … }, and give .jpg and .png a choice each.

When you're done

Every test is green, and Pester's last line says:

Tests Passed: 18, Failed: 0, Skipped: 0, Inconclusive: 0, NotRun: 0

And by hand, in the exercise folder, the script answers like this:

PS> .\Backup-File.ps1
Usage: .\Backup-File.ps1 FILE [-Destination FOLDER], or -List or -Menu
PS> .\Backup-File.ps1 essay.txt
Copied essay.txt (a document).
PS> .\Backup-File.ps1 essay.txt
essay.txt hasn't changed since the last backup.
PS> .\Backup-File.ps1 empty-draft.txt
empty-draft.txt is empty, so the last good copy stays.
PS> .\Backup-File.ps1 photos\science-fair.jpg
Copied science-fair.jpg (a photo).

Now look back at job 8. A friend says a backup should copy every file every time, "to be safe". What would that cost on a folder of 2,000 photos, and what could job 7's empty file have done to a good copy?

Submit your exercise

The exercise is how you finish this lesson. When your work is done, put it on GitHub in a repo of your own, then submit that repo's address here.

  1. On GitHub, click +, then New repository. Name it (for example exercise-powershell-the-smart-backup), choose Public, and click Create repository. Leave out the README: your folder already has one.

  2. In a terminal in your exercise folder (PowerShell works), send your work to your new repo. If you downloaded the ZIP:

    git init -b main
    git add .
    git commit -m "My solution"
    git remote add origin https://github.com/your-name/exercise-powershell-the-smart-backup.git
    git push -u origin main
    

    If you cloned the starter instead, point your copy at your own repo, then commit and push:

    git remote set-url origin https://github.com/your-name/exercise-powershell-the-smart-backup.git
    git add .
    git commit -m "My solution"
    git push -u origin main
    
  3. Paste your repo's address, such as https://github.com/your-name/exercise-powershell-the-smart-backup, into Submit your exercise on this page. The site checks that the repo is public and holds your commits, and then the lesson is complete.

Changed something after you submitted? Push it, and submit again: your latest submission is the one that counts.

So what

Your script now takes input like a command, makes decisions like an application, and tells the person running it exactly what happened. That's the difference between a list of commands and a tool someone else can use.

Key terms

Related