5 min read

How I built NyxPE

NyxPE is my custom WinPE rescue environment, built with PhoenixPE and PEBakery. This article covers its design, toolset, offline package system, stubborn bugs, and the work behind turning a personal idea into a bootable release.

I do a lot of tech work. Reinstalls, data recovery, dead boot loaders, the usual. And for years I did all of it from other people's rescue disks, mostly Sergei Strelec's WinPE. Nothing wrong with it, honestly, it's a fantastic piece of work. But every single boot I'd be re-fixing the keyboard layout, hunting for a tool three submenus deep, staring at branding that wasn't mine. Small itch, never went away. So I finally sat down and built the thing I actually wanted, and that's NyxPE. Nyx Rescue Environment.

The base was an easy call: PhoenixPE plus PEBakery. PhoenixPE gives you a clean, scriptable WinPE project, and PEBakery is the engine that turns a pile of scripts into a bootable image. The one rule I set for myself on day one was to never touch the official PhoenixPE scripts. Everything I add lives in my own folder. That way, if I ever want to pull a newer PhoenixPE, I just drop it in and my stuff still sits on top. A little discipline now, a lot of sanity later.

Making it feel like mine

First thing was identity, because if it doesn't look like NyxPE it's just PhoenixPE with extra steps. Dark wallpaper, a moon logo, the "NYX PE" wordmark, a matching splash while it boots. OEM info so the System Properties page says NyxPE instead of the default. And the computer name, which turned out to be weirdly annoying. WinPE loves to call the machine something like PHOENIXPE-VF23 with a random suffix, and after some digging I found the culprit was PENetwork, generating the name from a profile template. So I nailed it in two places: offline in the registry hives during the build, and then again at runtime with a tiny script that fires after the network comes up, because the network stack will happily rename the box out from under you if you let it.

PENetwork itself needed to shut up. Out of the box it throws a window in your face on boot, runs a countdown, asks questions. I just want ethernet up on DHCP and the icon sitting quietly in the tray for later. So I went through the actual INI keys the bundled version uses (I refused to copy-paste settings off some 2011 forum post and hope for the best), and now it starts silent, grabs an address, and gets out of the way.

Little things after that. Firefox with exactly one bookmark, my GitHub, nothing else. Killing the Windows boot logo so you get a clean black screen instead of the spinning dots. I did that one with bootuxdisabled in the BCD, no patching of signed files, nothing sketchy with Secure Boot.

The part that ate my weekend

Then I went big. I wanted a real toolbox: backup, imaging, partitioning, file recovery, read-only forensics, malware scanners, network tools, hardware diagnostics. Dozens of programs.

The catch is the build has to stay offline. I didn't want scripts phoning home in the middle of a build. So I wrapped a little package system around it. A manifest of every app with its official source, a downloader that pulls each one straight from the vendor or the GitHub release, checks the SHA-256 and the Authenticode signature, and stages it locally. Then the PEBakery build just copies from the local stash. If a tool goes missing, the build warns and keeps going instead of blowing up.

The audit had a nice surprise: PhoenixPE already ships scripts for a ton of apps. So the smart move wasn't to reinvent those, it was to keep the good official ones and only write my own for what was missing. It also forced a decision I feel pretty strongly about. PhoenixPE bundles a whole family of credential-dumping tools, browser password grabbers, LSA secrets, all of that. I pulled every single one out of my profiles. A rescue disk is for fixing your own machines, not lifting passwords off them. The only account tool I kept is a proper local admin reset that warns you, backs up the registry hives first, and never runs silently.

Bugs. So many bugs.

This is where it got real. A few that stuck with me.

The one that made me feel dumb: my downloader kept staging exactly one app and marking every other one "no resolver defined". Turns out PowerShell variable names are case-insensitive, so $res (my per-app result) and $RES (my big lookup table) were literally the same variable. The first loop clobbered the table and the rest just found nothing. Renamed it, fixed instantly, said a few words out loud.

Then there was a helper function I named H. PowerShell has a built-in alias h for Get-History, and aliases win over functions, so every call to my H was quietly running Get-History and choking on a category name it was never meant to see. Renamed that too.

The nasty one: every app installed fine, and every single shortcut was dead. "The item has been changed or moved." Took me a while to trace. I was using DirCopy with a wildcard to drop each program into place, and it turns out DirCopy only grabs the subfolders, not the files sitting in the root. So the mappings folder made it onto the media and the actual .exe never did. Every shortcut pointed at a file that wasn't there. Swapped in FileCopy and DirCopy together and suddenly everything opened.

And the one that nearly ended me. The build would finish "successfully" and produce no ISO. The imaging tool was dying instantly. When I finally ran it by hand it told me the truth: one of the Eric Zimmerman forensic tools has map files with names over 120 characters, and oscdimg in the default ISO9660 mode caps paths around 110. GSmartControl's GTK icons blew past it too. I renamed files for a while, playing whack-a-mole, before doing the real fix, which was to switch the image to pure UDF. No path limit, and it's what every modern WinPE build uses anyway. Booted BIOS and UEFI on the first try after that.

Smaller ones too. A .NET tool with no version resource killed the whole build, because I was reading its file version for a marker file. Wrapped it so a missing version is just "n/a" instead of a hard stop.

Once it actually worked, I started caring about the feel. Command-line tools were the worst. You click one in the Start Menu and a console flashes for a tenth of a second and vanishes, because it's waiting for arguments. So now the CLI tools open a prompt already parked in their own folder, wearing the tool's own icon, ready to type. GUI apps open normally. Sysinternals gets split the same way, since half of it is windows and half is command line.

I also dropped a usage guide right on the desktop. An HTML page that lists every tool, tells you whether it's a window or a terminal thing, and gives a quick example for the command-line ones. Because future me, at 3am with a dead laptop, does not remember the exact chainsaw syntax.

All of the testing has been in VMware, watching the splash come up, the desktop load, the network grab an address, the tray behave itself. Seeing NYXPE on that wallpaper for the first time, after all the fighting, was genuinely a good moment.

It lives at nyxpe.xyz now. The ISO, the guide, a checksum, and a short honest note about licensing, because it's built on Windows PE and a mix of third-party tools, and I'd rather be upfront that this is a personal, for-study project than pretend it's something it isn't. Next I want to swap in a real graphic boot splash and start wiring up separate rescue ISOs for iVentoy, but that's a problem for another weekend.

Reply

Got a thought? Reply by email, or publish a response on your own site and it'll show up above via Webmention.

Reply by email