Skip to content

arelas/Phat32

Repository files navigation

PHAT32

The FAT32 formatter that ignores the 32 GB limit.

A native Windows WPF (.NET 10) tool that formats drives as FAT32 — including drives larger than 32 GB, which Windows' built-in formatter refuses to do.

PHAT32 screenshot

License: MIT .NET Platform

Looking for instructions on how to use the app rather than build it? See USER_GUIDE.txt.

Why this exists

The 32 GB FAT32 cap in format.com / Disk Management is an artificial restriction Microsoft added — the FAT32 format itself supports volumes up to 2 TB (with 512-byte sectors). This is handy for SD cards, USB drives, or external SSDs that need to stay FAT32 for compatibility with cameras, game consoles, car stereos, smart TVs, etc. — devices that often can't read exFAT or NTFS.

This tool calculates the BPB (BIOS Parameter Block) fields, FAT size, and cluster size using the same formulas Windows itself uses internally, then writes the FAT32 structures directly to the volume, bypassing the size check.

Features

  • Lists removable and fixed drives, with size/label/filesystem shown
  • Shows only removable (USB/SD) drives by default — fixed/internal drives are hidden until you explicitly check "Show internal/fixed drives too"
  • Blocks formatting your Windows system drive
  • Advisory warnings for unusual drives (a "removable" drive reporting multiple terabytes, a very small volume, or a fixed drive once you've opted into seeing them) — these don't block you, they just make you look twice
  • Custom volume label and selectable allocation unit (cluster) size, or "Default (recommended)" to match Windows' own sizing logic
  • Confirmation checkbox + a final "this will permanently erase..." dialog before anything is written
  • Reads back the boot sector, FSInfo sector, and FAT entries after writing to confirm they actually landed correctly, rather than just assuming success
  • Optional full-format mode that scans every cluster for bad sectors and marks any found in the FAT (quick format is the default either way)
  • Remembers your last-used cluster size and "show fixed drives" choice between launches
  • Live log and progress bar while formatting
  • Dark, native UI (including a themed confirm/result dialog) that matches Windows' dark mode title bar
  • A headless CLI mode for scripting/automation — see Command-line usage
  • Native builds for both x64 and ARM64 (Windows-on-ARM) Windows devices

⚠️ Before you use it

  • This permanently erases all data on the target drive. There is no undo.
  • It requires Administrator privileges (the app prompts for UAC elevation automatically) because it locks/dismounts the volume and writes raw sectors directly to disk.
  • Quick format is the default — it lays down a clean, empty FAT32 filesystem without scanning for bad sectors. There's also a full format option (a checkbox in the GUI, --full on the CLI) that scans every cluster for bad sectors and is much slower, proportional to the drive's size.
  • This software is provided as-is (see License) with no warranty. Test on a spare/cheap drive first before trusting it with anything that matters.

Requirements

  • Windows 10 (2004+) or Windows 11 — x64 or ARM64 (Windows-on-ARM)
  • .NET 10 Desktop Runtime if running a framework-dependent build, or nothing extra if using a self-contained published build

Building

You'll need Visual Studio 2022 (Community is fine) with the ".NET desktop development" workload, or just the .NET 10 SDK for the command line.

cd Phat32
dotnet build -c Release

Or open Phat32.sln in Visual Studio and press F5. The app will prompt for UAC elevation each time it launches (required for raw disk access).

Publishing a standalone .exe

dotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true

This bundles the .NET runtime into a single portable .exe that runs on a bare Windows install with nothing pre-installed. The project is configured with IncludeNativeLibrariesForSelfExtract so WPF's native rendering libraries (e.g. PresentationNative_cor3.dll, wpfgfx_cor3.dll) get bundled into the exe and self-extracted to a temp folder at startup — without that setting, single-file WPF publishes can launch and exit instantly with no window and no visible error, since the native renderer can't be found.

For Windows-on-ARM devices, swap the RID:

dotnet publish -c Release -r win-arm64 --self-contained true -p:PublishSingleFile=true

This cross-publishes fine from an x64 machine (no ARM64 hardware needed to build it) — but that also means the ARM64 build has only ever been cross-compiled, never actually run on real ARM64 hardware. Treat it as unverified until it's been tested on an actual Windows-on-ARM device.

Or just run package.ps1 from the repo root — it does the above publish step and also bundles the resulting exe with USER_GUIDE.txt and LICENSE into a ready-to-share zip under dist/ (the same contents the GitHub Actions release workflow produces, but without needing to push a tag):

.\package.ps1                         # builds and zips BOTH win-x64 and win-arm64
.\package.ps1 -Arch x64                # just win-x64
.\package.ps1 -Arch arm64              # just win-arm64
.\package.ps1 -Version 1.2.0           # name the zip(s) explicitly
.\package.ps1 -SkipBuild               # re-zip without rebuilding

If Windows blocks the script from running (...cannot be loaded because running scripts is disabled...), either run it via powershell -ExecutionPolicy Bypass -File package.ps1, or allow local scripts for your account once with Set-ExecutionPolicy -Scope CurrentUser RemoteSigned.

If dotnet publish fails with NU1100 errors about Microsoft.NETCore.App.Runtime.win-x64 or similar, that's a NuGet restore problem (usually a corporate proxy blocking nuget.org), not a project issue — see Troubleshooting.

Code signing

The build is unsigned by default. On a machine that's never run it before, expect a SmartScreen "Windows protected your PC" prompt, and possibly a flag from behavior-based EDR/AV (the disk-locking + raw-sector-write pattern overlaps with how wiper tools behave, regardless of signing). If you're distributing this beyond your own machine, signing with a code-signing certificate or Microsoft Trusted Signing is worth doing:

signtool sign /fd SHA256 /a Phat32.exe

Troubleshooting

dotnet publish fails with NU1100 errors — NuGet can't download the runtime packs needed for a self-contained build. Check your sources:

dotnet nuget list source

Make sure nuget.org is listed and enabled; on a corporate network it may need to be added or proxied through an internal feed. As a quick workaround, drop --self-contained true -r win-x64 and just run dotnet build — the app will run fine with the .NET 10 Desktop Runtime installed instead.

Command-line usage

PHAT32 can also run headlessly for scripting, RMM deployment, or imaging workflows instead of using the GUI:

Phat32.exe --drive E --yes
Phat32.exe --drive F --yes --label BACKUP --cluster 4096
Phat32.exe --drive G --yes --allow-fixed
Phat32.exe --help
Flag Meaning
--drive <Letter> Required. Drive letter to format, e.g. E or E:
--yes Required. Confirms permanent erasure — there's no interactive prompt in CLI mode
--label <Label> Volume label, up to 11 characters
--cluster <bytes|default> Allocation unit size: 4096, 8192, 16384, 32768, 65536, or default
--allow-fixed Required to target a non-removable (fixed/internal) drive
--full Full format: scan every cluster for bad sectors instead of a quick format

Exit codes: 0 success, 1 bad arguments, 2 system drive refused, 3 fixed drive refused (use --allow-fixed), 4 drive not found, 5 format failed, 99 unexpected error.

Note: the app's manifest always requires Administrator, so even CLI invocations trigger UAC unless the calling shell is already elevated. If you run it from an already-elevated PowerShell/cmd, output prints inline in that same window. If not, Windows elevates a new process that can't share the original console, so PHAT32 opens its own console window for output instead — the exit code is still the most reliable thing to check from a calling script either way.

Signing & releases

Publishing a GitHub Release (tag + release through the GitHub UI, or gh release create) triggers .github/workflows/release.yml, which builds a self-contained single-file exe for both win-x64 and win-arm64 (as a matrix build), attempts to get each signed, and attaches two zips (Phat32-<tag>-win-x64.zip and Phat32-<tag>-win-arm64.zip, each containing the exe + USER_GUIDE.txt + LICENSE) to that release automatically.

Signing is via SignPath Foundation, which signs qualifying open-source projects for free. The publisher shown to users will be "SignPath Foundation," not an individual name — that's the tradeoff for free, properly-trusted signing instead of paying for your own certificate.

One-time setup, once your SignPath OSS application is approved:

  1. In the SignPath dashboard, create a project for this repo and a signing policy under it (e.g. release-signing). Note the project slug and signing policy slug.
  2. In this repo's Settings → Secrets and variables → Actions:
    • Add secret SIGNPATH_API_TOKEN (generate this in SignPath; the associated user needs the Submitter role on your signing policy).
    • Add variable SIGNPATH_ORGANIZATION_ID (shown in SignPath, top-right corner next to your organization name).
  3. In .github/workflows/release.yml, update the project-slug and signing-policy-slug values under the "Submit signing request to SignPath" step to match what you created in step 1.

Until SIGNPATH_API_TOKEN is set, the workflow still runs and still produces a release zip — it just ships Phat32-unsigned.exe instead of a signed Phat32.exe, with a warning in the workflow log. Nothing breaks either way; signing just turns on automatically once the secret exists.

How it works

It writes, per Microsoft's published FAT32 File System specification:

  1. Boot sector (sector 0) + backup boot sector (sector 6)
  2. FSInfo sector (sector 1)
  3. Two FAT copies, each sized via the standard FAT32 FAT-size formula
  4. An empty root directory (with a volume-label entry, if one is set)

It locks and dismounts the volume first (FSCTL_LOCK_VOLUME / FSCTL_DISMOUNT_VOLUME), writes everything with direct sector-aligned WriteFile calls, then unlocks it so Windows remounts the new filesystem.

Project layout

.github/workflows/release.yml (repo root) handles the build/sign/release pipeline described above, and package.ps1 (repo root) does the same build-and-bundle step locally without needing a tag/release. Everything else lives under the project folder:

Phat32/
  Phat32.csproj              .NET 10 WPF project, requireAdministrator manifest
  app.manifest               Forces UAC elevation prompt
  icon.ico                   App icon (exe icon + window/taskbar icon)
  App.xaml / App.xaml.cs     App entry point; branches into CLI mode or the GUI
  MainWindow.xaml / .cs      The UI: drive picker, label, cluster size, confirm/format
  Models/DriveItem.cs        UI-facing drive info
  Dialogs/
    AppDialog.xaml / .cs     Themed confirm/info/error dialog (replaces MessageBox)
  Services/
    NativeMethods.cs         P/Invoke: CreateFile, DeviceIoControl, WriteFile, console interop, etc.
    DriveEnumerator.cs       Lists candidate drives, flags the system drive
    Fat32Parameters.cs       BPB field math (cluster size table, FAT size formula)
    Fat32Formatter.cs        Builds, writes, and verifies boot sector / FSInfo / FATs / root dir
    DarkTitleBar.cs          Shared dark-title-bar helper for both windows
    AppSettingsStore.cs      Persists last-used UI choices to %AppData%
    CliRunner.cs             Headless command-line mode

Possible follow-ups

  • Add an "Eject" / safe-remove step after formatting removable media.
  • Add exFAT as an alternative for very large drives where 32 KB FAT32 clusters start to feel wasteful (exFAT has no such size cap at all).

Contributing

Issues and pull requests are welcome.

License

MIT — see LICENSE.

About

Native Windows WPF tool for formatting drives as FAT32 above Windows' built-in 32 GB limit. Includes a CLI mode for scripting.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors