Skip to main content
Thoughts from David Cornelius

User ProfilesIf you support Remote Desktop Services (RDS) environments, you've probably dealt with User Profile Disks at some point, either configuring where they live or removing a corrupted one for a user who can no longer log in. Browsing and managing these can be cumbersome as the file names are cryptic and must be mounted, then unmounted before the user logs in. I asked AI if a tool could be built to identify, mount, explore, and dismount these disks all in one interface. Of course, AI is always optimistic but it actually did produce a nifty tool in Delphi that does exactly what I needed; plus, I learned about a Windows API in the process!

Here's the rundown.

Why User Profile Disks Matter

A User Profile Disk (UPD) is what RDS uses to store a user's profile data. This includes their personal downloads, desktop icons, documents, settings, and other application data that would normally be under C:\Users\<username> on a local Windows machine. Instead of profiles living on whatever server a user happens to land on, this profile data sits in a virtual disk file, VHD, mounted on demand when the user signs in. This is especially important for systems with load-balancing, where the user may be assigned to one server on one day but a different one on a different day, depending on current load; they need to retain the same "user" files regardless of which machine happens to contain their session.

For the most part, these UPDs need very little attention, they all just work silently behind the scenes, mounting on the proper server when the user logs in and unmounting when the user has signed out. However, there are times when a system administrator needs to manage them:

  • Evaluating usage — disk size is typically capped to prevent a user from hogging all the space on a server; if not, it's necessary to keep an eye on how big the UPDs get.
  • Transferring files — sometimes you need to pull a document out of (or push one into) a UPD without making the user log in to do it.
  • Cleaning up storage — stale disks for disabled accounts just sit there consuming disk space until someone deletes them.

Unfriendly Names

The file names of the UPDs are generated from a user's SID the first time that user logs in. SIDs (Security IDentifiers) are long sequences of characters (mostly numbers) with no obvious mapping to user names. A directory of these looks like this:

Directory listing of UPD files with cryptic SID-based names

So, the first step in managing these is to identify which one you need. Years ago, I found an open source utility, Sidder, that maps these SIDs to their corresponding user names. Armed with this information, I would pull up Windows Explorer, find that file, and mount it as a local drive. Once I was done, I would go to "My PC" in Windows Explorer, right-click on the mounted drive, and select "Eject" to free it up for the user on their next login.

Just Ask AI!

For rare use, this process was workable and I was too lazy (and cheap) to look for something better. But with AI and an increased need to manage these more diligently, I pulled up Claude Code to see if I could get a customized tool for my needs. (Of course, I could have looked at the source for Sidder and updated my old copy of Visual Studio but if Claude can build me a Delphi version, why not?)

In very little time, Claude had a nice VCL application built and after a little tweaking and applying a style and custom icon, I had a new tool that made managing these UPDs much easier.

The result is on Github.

What the Tool Does

The program is a standard Windows desktop app built with the VCL framework. At a high level, it:

  • Lists UPDs in the selected folder: including associated user name, size, and last-modified date.
  • Mounts the selected disk upon double-click and displays the contents in a familiar tree view.
  • Explores files just like the standard Windows Explorer, including launching files in the Windows-associated application for that extension (.txt files in Notepad, .jpg files in Paint, etc.).
  • While in explorer view, provides two buttons:
    • Unmount the disk and return to the UPD list.
    • Delete the disk after a prompt and proper dismount if you deem the UPD is no longer needed.

Nothing exotic really; the interesting bits are how it manages these UPDs.

File Exploration UI: VirtualTreeView

For browsing the contents of a mounted UPD, I used VirtualTreeView, the open-source tree component a lot of Delphi developers already know from other contexts.

It's a good fit here for a few reasons:

  • Virtual by design — it only asks for data on the nodes actually visible, so a UPD with tens of thousands of files in deep folder structures doesn't choke the UI on load.
  • Responsiveness — expanding a folder with a huge number of children doesn't freeze the app while it builds out the whole subtree.
  • Familiarity — if you've used it for anything else (file managers, log viewers, settings trees), the mental model transfers directly; you're not learning a new component paradigm just because the data source changed.

If you've only used VirtualTreeView for small in-memory hierarchies before, this is a good excuse to actually exercise its lazy-population callbacks; the difference becomes obvious if you're staring at a profile disk with 30,000 cached files in it.

Tree Building: Shell APIs and Node Creation

VirtualTreeView gives you the UI scaffold, but it doesn't know anything about file systems — you have to feed it data. For that, the tool uses Windows shell APIs to enumerate the contents of the mounted disk and translate that into tree nodes.

Basically, it works like this:

  • The mounted UPD's root gets resolved into a shell item.
  • Shell enumeration interfaces walk child items (folders and files) under that root.
  • Each enumerated item gets mapped into a lightweight node record (name, type, size, a reference back to the shell item) that VirtualTreeView can render.

One design decision mattered a lot here: lazy loading. Rather than walking the entire disk up front and building a full in-memory tree, child nodes are only enumerated when a parent is expanded. This keeps initial load fast and avoids a wall of expensive shell calls for folders the user never opens. A small amount of caching on already-expanded folders avoids re-enumerating if the user collapses and re-expands the same node.

The New-to-Me Highlight: Virtual Disk API

Here's the part that was genuinely new territory for me: getting a VHDX file to act like a normal mounted drive in the first place. That's handled through the Virtual Disk API Windows exposes for working with virtual disk files programmatically in virtdisk.dll.

At a conceptual level, this API lets you:

  • Open and attach a VHD/VHDX file so its contents become accessible, similar to plugging in a physical drive — without needing Disk Management or PowerShell open.
  • Inspect the disk structure, partition layout, whether it's already attached elsewhere, basic metadata, all before you commit to mounting it.
  • Detach cleanly afterward, so you're not leaving orphaned mounts behind on a server that might have dozens of these operations happening in a day.

Why this matters for UPD management specifically: a profile disk is useless to you as a file-tree until it's mounted. All browsing and file management depends on getting a clean, no-side-effects mount/unmount cycle. Mount it wrong (or fail to detach it), and you risk leaving a lock on a disk a user needs at next login.

Delphi Takeaways

A few things worth keeping in mind if you ever do something similar from Delphi:

  • Remote resources need extra error handling — a mount that works fine locally can fail silently against a flaky network share or a server under load. Don't assume the happy path.
  • Always pair mount with a guaranteed detach — wrap it in try/finally (or equivalent), because an unmounted disk left attached is a support headache for someone else later.
  • Shell enumeration costs add up — lazy-load anything tree-shaped, especially over a network path. What's instant on a local SSD is not instant over RDS storage.

Closing Thoughts

What started as "I wonder if I can make identifying and managing UPDs easier" turned into a genuinely useful little tool and a learning opportunity for the usefulness of the VirtualTreeView and Virtual Disk API. I would not likely have taken the time to write this as I already had a process that worked, albeit inefficiently.

This is one example of how AI is enhancing my life, not only by speeding up coding but also bringing fleeting ideas to life! If you're a Delphi developer who's been putting off learning a new Windows API because the ramp-up time looks painful, this is a decent argument for treating AI tools as a way to compress that ramp-up, not as a replacement for understanding what's happening, but as a much faster way to get to that understanding.

To download this tool or just view the source, check it out on Github.

Here's a screenshot of it in use:
User Profile Manager on Windows Server

Add new comment

The content of this field is kept private and will not be shown publicly.