2025, Dec 31 15:00

Ejecting USB Drives on Windows with Python diskpart: select volume by drive letter, not disk

Learn how to reliably eject USB drives on Windows from Python: use diskpart to select the volume by drive letter, not the disk. Includes code, admin tips.

Automating USB ejection on Windows from a Python script sounds straightforward: invoke diskpart, send a couple of commands, and you’re done. In practice, the device may still appear in File Explorer even though the script reports success. The root of this mismatch is subtle, but easy to fix once you target the right object.

Symptom and a minimal example

Here is a compact snippet that opens diskpart and tries to eject a removable drive by drive letter. It runs with elevated privileges without errors, yet the USB remains visible in File Explorer:

from subprocess import Popen, PIPE

proc = Popen(["diskpart"], stdin=PIPE)
proc.stdin.write(b"select disk " + unit_letter.encode() + b"\n")
proc.stdin.write(b"remove all dismount\n")
proc.stdin.write(b"exit\n")
print(f"Successfully ejected drive {done_path}.")

What’s actually going on

The commands are sent to diskpart, but they select a disk rather than a volume. The difference is critical to this operation. The approach that works is to act on a volume by its drive letter instead of addressing the underlying disk. With that adjustment, the ejection behaves as expected. Running with elevated privileges remains a requirement.

Fixing the call to target a volume

Switch the selection from disk to volume and keep sending the same command sequence. The example below invokes diskpart, feeds a small command script via stdin, and reports the outcome:

import subprocess

def unmount_media(letter_alias):
    try:
        runner = subprocess.Popen([
            "diskpart"
        ], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)

        cmd_script = f"""
        select volume {letter_alias}
        remove all dismount
        exit
        """

        out_text, err_text = runner.communicate(cmd_script)

        if runner.returncode == 0:
            print(f"Successfully ejected drive {letter_alias}.")
        else:
            print(f"Failed to eject drive {letter_alias}. Error: {err_text}")
    except Exception as exc:
        print(f"Exception occurred: {exc}")

This uses the same logic—drive-letter-driven ejection through diskpart—but explicitly selects a volume. It only works with elevated privileges.

Field notes and observations

Real-world behavior can vary across devices and states. The following experiences illustrate that context matters:

it worked when i went to disk management and reassigned it a drive letter somehow idk this isn't my specialty, but my instinct worked for once

Oh. Maybe try stopping the program, taking out the USB, then plugging it back in?

It appeared to work, but it now is not recognized by windows i can't access anything? It most likely is still running its program as far as my brain can think. any ideas lol

Why this distinction matters

Selecting the correct target in diskpart makes the difference between a script that prints success and one that actually removes the mounted volume from the system’s view. For automation that must work across multiple devices, addressing the volume by letter aligns the command with the intended object and avoids misleading results.

Takeaways

If you need to programmatically eject a USB on Windows from Python and you are sending commands to diskpart, address the device as a volume rather than a disk. Keep the process elevated, verify by drive letter, and confirm the result in File Explorer. If behavior looks inconsistent across machines, double-check the assigned drive letter and rerun the volume-based script before trying anything else.