The Walk of Shame In The Land of No Data Recovery

I've been gone for a bit. The reason is a truly embarrassing one, that would make you Picard facepalm in quiet rage.
Buckle up Dorothy! We're going on a tour of self-inflicted disasters, after which I will introduce you to a small PowerShell script that I should've written approximately two-to-five years ago. 🫠
RIP
The storage controller on my motherboard died. A first-gen B450 board with a 5950X slapped on top of it (undervolted ofc - I'm not a complete savage). I think the VRM/power delivery slowly got cooked over the years. The CPU was technically supported, but "technically supported" and "actually fine for years of daily use" turn out to be different things.
And I don't know why I was surprised by this but the mobo took victims into hell with it - the NVME SSD storage controller. I tested the drive in different machines, slots, while singing to it... no dice. Dead.
About 80 to 100 hours of work, gone. 💀
The SSD and the Temple of Lost Data
Where was the lost work?
On my desktop. 🌞
The ONE, SINGLE place I don't back up.
This is where you, dear reader, are allowed to laugh out loud, because here's the inventory of backup-capable infrastructure I personally own and operate:
- A rather large home NAS
- A production hosting server
- A remote-location, non-redundant backup server
- A personal cloud VPS
- Multiple VPS hosting servers
Any one of these could've been backing up my desktop daily. Multiple times daily. Hourly, even.
But nooo. "Eeeh, it'll be fine, I'll get to it eventually." The same logic that brought down the Titanic and OceanGate. Too soon?
I Kinda Knew it Would Happen
The worst part is that I knew it would happen and I allowed it.
The storage controller had been throwing tantrums for a while. Random restarts where the system would suddenly lose visibility of all drives - every blue moon at first, then more frequently.
I thought: "nope, aint nobody got time for that, imma run it till it's dead."
It died. With my work on it. Both tangible and emotional damage. Shame. Just deep shame.
It took me about two weeks to get back up and running normally. A couple of those days I didn't sleep, because I was restoring whatever I could while also juggling actual obligations and important events that don't care that your PC just had a stroke. Fun times. 🙃
Shoutout to My Mentor
This whole episode reminded me of a "mentor" I had at a previous job. The dude just literally played League of Legends in the office all of the time. Sometimes, maybe reply to an email.
Eventually he got promoted into a new position (somehow) and was asked to hand off his work to me so I could pick up where he left off. I had been asking him to put his stuff in version control for a while, which ofc he didn't. And wouldn't you know it - his SSD conveniently died the week before the handover.
You would at least figure that he would be a pretty good Lux mid. Nope. INTING feeder all the way.
So I'd sincerely like to thank that clown 🤡 for allowing me to develop the skills to always deliver. I made up for his work then and I did it this time, again.
But seriously, fuck that guy.
And Then, As A Cherry On Top...
While all of this was unfolding, I paid off my car 🎉. Then I found out that to get the title transferred to me there's a municipal tax of 800+ EUR. That's to move a piece of paper from one column to another in a database that already exists.
Out of curiosity, I looked up the equivalent in Germany and I'm not 100% sure about this still but apparently it's a flat 35 EUR, one time. So either Germans are running an underfunded DMV, or I live somewhere where the system has identified that any time you do something correctly and on time, it should immediately punish you for it.
The system always finds a way to scam you. Unless, of course, you find a way to scam it - legally, of course. 😇
So I Finally Created The Damn Backup Script
After ugly-laughing at my own situation for a while and rebuilding everything from scratch, I sat down and did the thing I should've done years ago: a real, reliable, scheduled backup of my desktop.
I built it with llamaman running Qwen 3.6 27B as the local model, paired with hermes-webui as the frontend.
The result is robocp-ps-backup - a small Windows backup tool built on top of robocopy /MIR, with the bits added that robocopy itself doesn't do.
What It Actually Does
First of all, you can find the project here: nullata/SideQuests/blob/main/robocp-ps-backup
For each configured source, it mirrors to one or more target directories with robocopy /MIR. Around that, it layers:
- Deletion tracking - if a file disappears from the source, it doesn't immediately get nuked from the target. It gets parked in
<DeletedDir>\<yyyy-MM-dd>\for a few days. So when (not if) yourmthe wrong thing at 1 AM, you have a window to grab it back. - Per-pair excludes - skip noisy stuff like
.git,node_modules,.venv,*.log. Both robocopy and the deletion-tracking scan respect them. - Per-run timestamped logs - every run gets its own
backup-<dd-MM-yyyy--HH-mm>.log. Auto-pruned. - A markdown run ledger (
runs.md) - one row per real run with status (✅ / ⚠️ / ❌), timestamp, robocopy exit code, and a summary. Browseable in any editor. - Windows toast notifications - on start, success, warning, and failure. Each toast has a clickable button that opens the relevant log or the ledger. (No more wondering whether the backup actually ran last night.)
- Three-tier outcome - robocopy
rc 0–7is OK,8–15is WARN (locked files - common, not a real failure),16+is FAIL. - Optional targets - mark an external USB drive as
Optional = $trueand the run won't fail just because the drive isn't plugged in. It'll just note the skip in the ledger and move on.
It's designed to be the thing that runs three times a day, doesn't ask questions, and survives me ignoring it for months at a time and you don't even have to upgrade powershell for it.
Configuration
All user-facing config lives in a single backup.config.psd1 file next to the script. Here's the shape of it:
@{
BackupPairs = @(
@{
Source = 'D:\Repos'
Targets = @(
@{ Path = 'E:\Backup\Repos'; DeletedDir = 'E:\Backup\Repos_deleted' }
@{ Path = '\\nas\backup\Repos'; DeletedDir = '\\nas\backup\Repos_deleted' }
@{ Path = 'F:\Backup\Repos'; DeletedDir = 'F:\Backup\Repos_deleted'; Optional = $true }
)
ExcludeDirs = @('.git', 'node_modules', '.venv', 'logs')
ExcludeFiles = @('*.log', '*.tmp')
}
@{
Source = 'C:\Users\null\Desktop'
Targets = @(
@{ Path = 'E:\Backup\Desktop'; DeletedDir = 'E:\Backup\Desktop_deleted' }
@{ Path = '\\nas\backup\Desktop'; DeletedDir = '\\nas\backup\Desktop_deleted' }
)
ExcludeDirs = @('node_modules', '.venv')
ExcludeFiles = @()
}
)
UseDailyFlag = $false # $true = only first successful run per day mirrors
RetentionDays = 3 # dated DeletedDir folders to keep
LogDir = 'D:\Repos\sidequests\robocp-ps-backup\logs'
LogRetentionDays = 14
LogOpener = 'code' # what opens the log/ledger from toast buttons
}
Set UseDailyFlag = $false if you want it to fire multiple times a day. Set RetentionDays to how long you want the deletion parking lot to remember things. Mark dodgy USB drives as Optional = $true and forget about them.
Once configured, run it once manually to verify:
.\backup.ps1
Then install the scheduled task:
.\install-task.ps1
Default schedule is 02:00, 14:00, and 21:00 every day. The task runs through a tiny .vbs wrapper so there's no console flash on trigger - it fires silently, runs hidden, and surfaces only via toast notifications when something happens.
The complete documentation - all the gotchas, the exit code tiers, the encoding rules (because PowerShell 5.1 is a delight 🙃), the Optional-target semantics, the toast plumbing, the recovery - it's all in the README.
I encourage you to check it out. If you find a bug or want a feature, open an issue.
If your motherboard is currently misbehaving but you're "running it till it's dead" - Stop it. Get some help. Set up backups.
Live long and prosper. 🖖👽
Join the conversation
Like & Comment on