Is there a way to list all the available Windows' drives?

PythonWindows

Python Problem Overview


Is there a way in Python to list all the currently in-use drive letters in a Windows system?

(My Google-fu seems to have let me down on this one)

A C++ equivalent: Enumerating all available drive letters in Windows

Python Solutions


Solution 1 - Python

import win32api

drives = win32api.GetLogicalDriveStrings()
drives = drives.split('\000')[:-1]
print drives

Adapted from: http://www.faqts.com/knowledge_base/view.phtml/aid/4670

Solution 2 - Python

Without using any external libraries, if that matters to you:

import string
from ctypes import windll

def get_drives():
    drives = []
    bitmask = windll.kernel32.GetLogicalDrives()
    for letter in string.uppercase:
        if bitmask & 1:
            drives.append(letter)
        bitmask >>= 1

    return drives

if __name__ == '__main__':
    print get_drives()     # On my PC, this prints ['A', 'C', 'D', 'F', 'H']

Solution 3 - Python

Found this solution on Google, slightly modified from original. Seem pretty pythonic and does not need any "exotic" imports

import os, string
available_drives = ['%s:' % d for d in string.ascii_uppercase if os.path.exists('%s:' % d)]

Solution 4 - Python

I wrote this piece of code:

import os
drives = [ chr(x) + ":" for x in range(65,91) if os.path.exists(chr(x) + ":") ]

It's based on @Barmaley's answer, but has the advantage of not using the string module, in case you don't want to use it. It also works on my system, unlike @SingleNegationElimination's answer.

Solution 5 - Python

Those look like better answers. Here's my hackish cruft

import os, re
re.findall(r"[A-Z]+:.*$",os.popen("mountvol /").read(),re.MULTILINE)

Riffing a bit on RichieHindle's answer; it's not really better, but you can get windows to do the work of coming up with actual letters of the alphabet

>>> import ctypes
>>> buff_size = ctypes.windll.kernel32.GetLogicalDriveStringsW(0,None)
>>> buff = ctypes.create_string_buffer(buff_size*2)
>>> ctypes.windll.kernel32.GetLogicalDriveStringsW(buff_size,buff)
8
>>> filter(None, buff.raw.decode('utf-16-le').split(u'\0'))
[u'C:\\', u'D:\\']

Solution 6 - Python

The Microsoft Script Repository includes this recipe which might help. I don't have a windows machine to test it, though, so I'm not sure if you want "Name", "System Name", "Volume Name", or maybe something else.

import win32com.client 
strComputer = "." 
objWMIService = win32com.client.Dispatch("WbemScripting.SWbemLocator") 
objSWbemServices = objWMIService.ConnectServer(strComputer,"root\cimv2") 
colItems = objSWbemServices.ExecQuery("Select * from Win32_LogicalDisk") 
for objItem in colItems: 
    print "Access: ", objItem.Access 
    print "Availability: ", objItem.Availability 
    print "Block Size: ", objItem.BlockSize 
    print "Caption: ", objItem.Caption 
    print "Compressed: ", objItem.Compressed 
    print "Config Manager Error Code: ", objItem.ConfigManagerErrorCode 
    print "Config Manager User Config: ", objItem.ConfigManagerUserConfig 
    print "Creation Class Name: ", objItem.CreationClassName 
    print "Description: ", objItem.Description 
    print "Device ID: ", objItem.DeviceID 
    print "Drive Type: ", objItem.DriveType 
    print "Error Cleared: ", objItem.ErrorCleared 
    print "Error Description: ", objItem.ErrorDescription 
    print "Error Methodology: ", objItem.ErrorMethodology 
    print "File System: ", objItem.FileSystem 
    print "Free Space: ", objItem.FreeSpace 
    print "Install Date: ", objItem.InstallDate 
    print "Last Error Code: ", objItem.LastErrorCode 
    print "Maximum Component Length: ", objItem.MaximumComponentLength 
    print "Media Type: ", objItem.MediaType 
    print "Name: ", objItem.Name 
    print "Number Of Blocks: ", objItem.NumberOfBlocks 
    print "PNP Device ID: ", objItem.PNPDeviceID 
    z = objItem.PowerManagementCapabilities 
    if z is None: 
        a = 1 
    else: 
        for x in z: 
            print "Power Management Capabilities: ", x 
    print "Power Management Supported: ", objItem.PowerManagementSupported 
    print "Provider Name: ", objItem.ProviderName 
    print "Purpose: ", objItem.Purpose 
    print "Quotas Disabled: ", objItem.QuotasDisabled 
    print "Quotas Incomplete: ", objItem.QuotasIncomplete 
    print "Quotas Rebuilding: ", objItem.QuotasRebuilding 
    print "Size: ", objItem.Size 
    print "Status: ", objItem.Status 
    print "Status Info: ", objItem.StatusInfo 
    print "Supports Disk Quotas: ", objItem.SupportsDiskQuotas 
    print "Supports File-Based Compression: ", objItem.SupportsFileBasedCompression 
    print "System Creation Class Name: ", objItem.SystemCreationClassName 
    print "System Name: ", objItem.SystemName 
    print "Volume Dirty: ", objItem.VolumeDirty 
    print "Volume Name: ", objItem.VolumeName 
    print "Volume Serial Number: ", objItem.VolumeSerialNumber 

Solution 7 - Python

Here is another great solution if you want to list only drives on your disc and not mapped network drives. If you want to filter by different attributes just print drps.

import psutil
drps = psutil.disk_partitions()
drives = [dp.device for dp in drps if dp.fstype == 'NTFS']

Solution 8 - Python

On Windows you can do a os.popen

import os
print os.popen("fsutil fsinfo drives").readlines()

Solution 9 - Python

More optimal solution based on @RichieHindle

def get_drives():
    drives = []
    bitmask = windll.kernel32.GetLogicalDrives()
    letter = ord('A')
    while bitmask > 0:
        if bitmask & 1:
            drives.append(chr(letter) + ':\\')
        bitmask >>= 1
        letter += 1

    return drives

Solution 10 - Python

here's a simpler version, without installing any additional modules or any functions. Since drive letters can't go beyond A and Z, you can search if there is path available for each alphabet, like below:

>>> import os
>>> for drive_letter in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
        if os.path.exists(f'{drive_letter}:'):
            print(f'{drive_letter}:')
        else:
            pass

the one-liner:

>>> import os
>>> [f'{d}:' for d in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' if os.path.exists(f'{d}:')]
['C:', 'D:']

Solution 11 - Python

Here's my higher-performance approach (could probably be higher):

>>> from string import ascii_uppercase
>>> reverse_alphabet = ascii_uppercase[::-1]
>>> from ctypes import windll # Windows only
>>> GLD = windll.kernel32.GetLogicalDisk
>>> drives = ['%s:/'%reverse_alphabet[i] for i,v in enumerate(bin(GLD())[2:]) if v=='1']

Nobody really uses python's performative featurability...

Yes, I'm not following Windows standard path conventions ('\\')...
In all my years of using python, I've had no problems with '/' anywhere paths are used, and have made it standard in my programs.

Solution 12 - Python

This code will return of list of drivenames and letters, for example:

['Gateway(C:)', 'EOS_DIGITAL(L:)', 'Music Archive(O:)']

It only uses the standard library. It builds on a few ideas I found above. windll.kernel32.GetVolumeInformationW() returns 0 if the disk drive is empty, a CD rom without a disk for example. This code does not list these empty drives.

These 2 lines capture the letters of all of the drives:

bitmask = (bin(windll.kernel32.GetLogicalDrives())[2:])[::-1]  # strip off leading 0b and reverse
drive_letters = [ascii_uppercase[i] + ':/' for i, v in enumerate(bitmask) if v == '1']

Here is the full routine:

from ctypes import windll, create_unicode_buffer, c_wchar_p, sizeof
from string import ascii_uppercase

def get_win_drive_names():
    volumeNameBuffer = create_unicode_buffer(1024)
    fileSystemNameBuffer = create_unicode_buffer(1024)
    serial_number = None
    max_component_length = None
    file_system_flags = None
    drive_names = []
    #  Get the drive letters, then use the letters to get the drive names
    bitmask = (bin(windll.kernel32.GetLogicalDrives())[2:])[::-1]  # strip off leading 0b and reverse
    drive_letters = [ascii_uppercase[i] + ':/' for i, v in enumerate(bitmask) if v == '1']

    for d in drive_letters:
        rc = windll.kernel32.GetVolumeInformationW(c_wchar_p(d), volumeNameBuffer, sizeof(volumeNameBuffer),
                                                   serial_number, max_component_length, file_system_flags,
                                                   fileSystemNameBuffer, sizeof(fileSystemNameBuffer))
        if rc:
            drive_names.append(f'{volumeNameBuffer.value}({d[:2]})')  # disk_name(C:)
    return drive_names

Solution 13 - Python

This will help to find valid drives in windows os

import os
import string
drive = string.ascii_uppercase
valid_drives = []
for each_drive in drive:
    if os.path.exist(each_drive+":\\"):
       print(each_drive)
       valid_drives.append(each_drive+":\\")
print(valid_drives)

The output will be

C
D
E
['C:\\','D:\\','E:\\']

Solution 14 - Python

If you want only the letters for each drive, you can just:

from win32.win32api import GetLogicalDriveStrings


drives = [drive for drive in GetLogicalDriveStrings()[0]]

Solution 15 - Python

As I don't have win32api installed on my field of notebooks I used this solution using wmic:

import subprocess
import string

#define alphabet
alphabet = []
for i in string.ascii_uppercase:
    alphabet.append(i + ':')

#get letters that are mounted somewhere
mounted_letters = subprocess.Popen("wmic logicaldisk get name", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
#erase mounted letters from alphabet in nested loop
for line in mounted_letters.stdout.readlines():
    if "Name" in line:
        continue
    for letter in alphabet:
        if letter in line:
            print 'Deleting letter %s from free alphabet %s' % letter
            alphabet.pop(alphabet.index(letter))

print alphabet

alternatively you can get the difference from both list like this simpler solution (after launching wmic subprocess as mounted_letters):

#get output to list
mounted_letters_list = []
for line in mounted_letters.stdout.readlines():
    if "Name" in line:
        continue
    mounted_letters_list.append(line.strip())

rest = list(set(alphabet) - set(mounted_letters_list))
rest.sort()
print rest

both solutions are similiarly fast, yet I guess set list is better for some reason, right?

Solution 16 - Python

As part of a similar task I also needed to grab a free drive letter. I decided I wanted the highest available letter. I first wrote it out more idiomatically, then crunched it to a 1-liner to see if it still made sense. As awesome as list comprehensions are I love sets for this: unused=set(alphabet)-set(used) instead of having to do unused = [a for a in aphabet if a not in used]. Cool stuff!

def get_used_drive_letters():
    drives = win32api.GetLogicalDriveStrings()
    drives = drives.split('\000')[:-1]
    letters = [d[0] for d in drives]
    return letters

def get_unused_drive_letters():
    alphabet = map(chr, range(ord('A'), ord('Z')+1))
    used = get_used_drive_letters()
    unused = list(set(alphabet)-set(used))
    return unused

def get_highest_unused_drive_letter():
    unused = get_unused_drive_letters()
    highest = list(reversed(sorted(unused)))[0]
    return highest

The one liner:

def get_drive():
    highest = sorted(list(set(map(chr, range(ord('A'), ord('Z')+1))) -
                          set(win32api.GetLogicalDriveStrings().split(':\\\000')[:-1])))[-1]

I also chose the alphabet using map/range/ord/chr over using string since parts of string are deprecated.

Solution 17 - Python

if you don't want to worry about cross platform issues, including those across python platforms such as Pypy, and want something decently performative to be used when drives are updated during runtime:

>>> from os.path import exists
>>> from sys import platform
>>> drives = ''.join( l for l in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' if exists('%s:/'%l) ) if platform=='win32' else ''
>>> drives
'CZ'

here's my performance test of this code:

4000 iterations; threshold of min + 250ns:
__________________________________________________________________________________________________________code___|_______min______|_______max______|_______avg______|_efficiency
⡇⠀⠀⢀⠀⠀⠀⠀⠀⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⣷⣷⣶⣼⣶⣴⣴⣤⣤⣧⣤⣤⣠⣠⣤⣤⣶⣤⣤⣄⣠⣦⣤⣠⣤⣤⣤⣤⣄⣠⣤⣠⣤⣤⣠⣤⣤⣤⣤⣤⣤⣄⣤⣤⣄⣤⣄⣤⣠⣀⣀⣤⣄⣤⢀⣀⢀⣠⣠⣀⣀⣤⣀⣠
    drives = ''.join( l for l in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' if exists('%s:/'%l) ) if platform=='win32' else '' |      290.049ns |     1975.975ns |      349.911ns |  82.892%

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionElectrons_AhoyView Question on Stackoverflow
Solution 1 - PythonAyman HouriehView Answer on Stackoverflow
Solution 2 - PythonRichieHindleView Answer on Stackoverflow
Solution 3 - PythonBarmaleyView Answer on Stackoverflow
Solution 4 - PythonSebastian HietschView Answer on Stackoverflow
Solution 5 - PythonSingleNegationEliminationView Answer on Stackoverflow
Solution 6 - PythonJohn FouhyView Answer on Stackoverflow
Solution 7 - PythonPythonManView Answer on Stackoverflow
Solution 8 - Pythonuser2015144View Answer on Stackoverflow
Solution 9 - PythontiredginView Answer on Stackoverflow
Solution 10 - PythonNaveen Reddy MarthalaView Answer on Stackoverflow
Solution 11 - PythonTcllView Answer on Stackoverflow
Solution 12 - PythonEGarbusView Answer on Stackoverflow
Solution 13 - PythonJobin JamesView Answer on Stackoverflow
Solution 14 - Python1schwareView Answer on Stackoverflow
Solution 15 - PythonPulecView Answer on Stackoverflow
Solution 16 - Pythonflutefreak7View Answer on Stackoverflow
Solution 17 - PythonTcllView Answer on Stackoverflow