Bulletproof Windows User Backups with PowerShell and Robocopy

Migrating a Windows user profile sounds simple until you're actually doing it. Files spread across standard folders, OneDrive sync folders, hidden AppData paths, and whatever the user decided to dump on the Desktop. A manual copy misses things. xcopy doesn't handle conflicts well. And doing it interactively for every machine you touch doesn't scale.

Windows Tools is two PowerShell scripts that make this reliable, resumable, and hands-off once you've answered a couple of prompts.

The backup script — UserBackup.ps1

Robocopy is the real workhorse here. It handles retries, multi-threading, and — critically — resume. If a backup gets interrupted mid-way through a large Documents folder, you can restart it and it picks up exactly where it left off without re-copying files already transferred.

robocopy $Source $Dest /E /COPYALL /R:3 /W:5 /MT:8 /LOG+:$LogFile /XF "*.pst"

Key flags worth noting:

OneDrive detection

This was the awkward edge case. When OneDrive sync is enabled, folders like Documents and Desktop may physically live under C:\Users\Name\OneDrive\Documents rather than C:\Users\Name\Documents. A naive path assumption will silently back up the wrong (often empty) directory.

The script reads the registry to find the actual OneDrive root path, then checks whether each standard folder has been redirected into the OneDrive tree. If it has, the script follows the redirect. If not, it uses the standard path.

The restore script — UserRestore.ps1

Restoring is more complex than backing up because you're often merging data from multiple sources — a backup from the old machine plus a partial backup from an even older one. The restore script handles this by letting you select multiple source directories and process them in order.

Conflict resolution uses a simple but effective rule: newer file wins. Robocopy's /XO flag (exclude older) handles this natively. The log output shows every skipped file so you can verify the decisions it made.

Both scripts can be run remotely via Invoke-Command on PowerShell remoting-enabled machines, which makes them practical for handling multiple PCs without physically sitting at each one.

What gets backed up


← Back to all posts  ·  View on GitHub ↗