Pues eso… yo pensaba que todas las unidades (de tipo pendrive) USB devolverían un valor del tipo DriveType.Removable, pero resulta que no. Al igual que ocurre con los discos duros conectados por USB, los pendrives también pueden ser de tipo fijo (DriveType.Fixed).
Y lo que te voy a mostrar es el código para C# y Visual Basic (usando .NET 5.0 con Visual Studio 2019) para saber todas las unidades conectadas por USB (sean fijas o extraíbles), además de una función para saber si el path indicado está o no en una unidad extraíble.
También incluyo un ejemplo de cómo saber las unidades (y el tipo de unidad que es) usando el «clásico» método para saber las unidades instaladas con DriveInfo.GetDrives().
En la siguiente captura puedes ver el programa funcionando en mi equipo.

En mi equipo tengo conectado 2 discos duros por usb (letras S y T), un pendrive de tipo fijo (letra F) y uno de tipo extraíble (letra G).
En la primera lista (usando el método GetDrives de la clase DriveInfo) el único que se muestra como «extraíble» es el disco G, el resto se muestran como fijos (fixed).
En la segunda lista se muestran las unidades extraíbles, sean o no fijas.
Ya sin más rollos te muestro el código tanto para C# como para Visual Basic.
El código lo puedes descargar de GitHub (UnidadesExternas), pero si quieres crearlo por tu cuenta, decirte que he tenido que añadir una referencia al paquete de Nuget System.Management versión 5.0 ya que estos proyectos los he creado con Visual Studio 2019 y esa versión de Visual Studio no utiliza versiones posteriores a .NET 5.0.
El tipo de proyecto es Consola de Windows, aunque he tenido que cambiar el tipo del proyecto, ya que al elegir que sea para .NET 5.0 ha intentado usarlo para cualquier plataforma.
En el fichero del proyecto (de C# o de VB) busca <TargetFramework> y cambia net5.0 por net5.0-windows, ya que System.Management solo se puede usar en el sistema operativo Windows.
Nota:
Comentarte que el código (de C#) está basado en dos ejemplos encontrados en la red y de esos dos códigos de ejemplo he sacado el código del método GetUsbDriveLetters.
Estos son los enlaces que he usado:
El primero es prácticamente el usado en ese código, pero añadiendo la comprobación de que MediaType también pueda ser External, que saqué del segundo.
https://stackoverflow.com/a/31560283/14338047
https://stackoverflow.com/a/10018438/14338047
Código de C# de la utilidad para saber las unidades externas
public class USBUtil { /// <summary> /// Comprueba si es una unidad externa. /// </summary> /// <param name="elPath">Path completo del que se extraerá la letra de unidad.</param> /// <returns></returns> public static bool EsUnidadExterna(string elPath) { var disco = Path.GetPathRoot(Path.GetFullPath(elPath)); var usbD = GetUsbDriveLetters(); return usbD.Contains(disco); } // Código basado en dos ejemplos de "la red". // https://stackoverflow.com/a/31560283/14338047 // https://stackoverflow.com/a/10018438/14338047 /// <summary> /// Las letras de las unidades externas conectadas por USB. /// </summary> /// <returns></returns> public static List<string> GetUsbDriveLetters() { // Hay que usar External para que también tenga en cuenta los USB de tipo fijo. var usbDrivesLetters = from drive in new ManagementObjectSearcher("select * from Win32_DiskDrive WHERE MediaType like '%External%' OR InterfaceType='USB'").Get().Cast<ManagementObject>() from o in drive.GetRelated("Win32_DiskPartition").Cast<ManagementObject>() from i in o.GetRelated("Win32_LogicalDisk").Cast<ManagementObject>() select string.Format("{0}\\", i["Name"]); return usbDrivesLetters.ToList(); } }
Código de Visual Basic de la utilidad para saber las unidades externas
Public Class USBUtil ''' <summary> ''' Comprueba si es una unidad externa. ''' </summary> ''' <param name="elPath">Path completo del que se extraerá la letra de unidad.</param> ''' <returns></returns> Public Shared Function EsUnidadExterna(elPath As String) As Boolean Dim disco = Path.GetPathRoot(Path.GetFullPath(elPath)) Dim usbD = GetUsbDriveLetters() Return usbD.Contains(disco) End Function ''' <summary> ''' Las letras de las unidades externas conectadas por USB. ''' </summary> ''' <returns></returns> Public Shared Function GetUsbDriveLetters() As List(Of String) ' Hay que usar External para que también tenga en cuenta los USB de tipo fijo. Dim usbDrivesLetters = From drive In New ManagementObjectSearcher("select * from Win32_DiskDrive WHERE MediaType like '%External%' OR InterfaceType='USB'").[Get]().Cast(Of ManagementObject)() From o In drive.GetRelated("Win32_DiskPartition").Cast(Of ManagementObject)() From i In o.GetRelated("Win32_LogicalDisk").Cast(Of ManagementObject)() Select String.Format("{0}\", i("Name")) Return usbDrivesLetters.ToList() End Function
Nota:
Debes añadir importación de los espacios de nombres:
System
System.Collections.Generic
System.IO
System.Linq
System.Management (de NuGet)
Código de ejemplo usar estas los métodos de USBUtil.
class Program { static void Main(string[] args) { Console.Title = "Ejemplo de Visual C# usando .NET 5.0 (net5.0-windows) y System.Management Version=5.0.0"; Console.WriteLine("Mostrar las unidades usando DriveInfo.GetDrives()."); foreach (var dr in DriveInfo.GetDrives()) Console.WriteLine("Unidad: {0}, tipo: {1}", dr.Name, dr.DriveType); Console.WriteLine(); Console.WriteLine("Mostrar las unidades extraíbles."); var usb = USBUtil.GetUsbDriveLetters(); foreach (var s in usb) Console.WriteLine("{0}", s); Console.WriteLine(); Console.ReadKey(); }
Module Program Sub Main(args As String()) Console.Title = "Ejemplo de Visual Basic usando .NET 5.0 (net5.0-windows) y System.Management Version=5.0.0" Console.WriteLine("Mostrar las unidades usando DriveInfo.GetDrives().") For Each dr In DriveInfo.GetDrives() Console.WriteLine("Unidad: {0}, tipo: {1}", dr.Name, dr.DriveType) Next Console.WriteLine() Console.WriteLine("Mostrar las unidades extraíbles.") Dim usb = USBUtil.GetUsbDriveLetters() For Each s In usb Console.WriteLine("{0}", s) Next Console.WriteLine() Console.ReadLine() End Sub End Module
Y esto es todo, espero te resulte de utilidad 😉
Nos vemos.
Guillermo
Buen día, tarde o noche,
No se que sea por aquel lado del charco (yo de México) y vaya, a demás de siempre interesantes y muy útiles las publicaciones que hace, solo paso a agradecer la enseñanza que por decadas a dejado en varios de nosotros.
Hacia muchos años no me paseaba por «El Guille Info» y hoy, no se por que, me dio por entrar a ver que había de nuevo.
Hace muchos años, por aquel lejano 2001, empecé con la aventura de aprender las artes oscuras (por aquello de los skins 😀 ) del la programación, y en su sitio siempre encontré respuestas y ayudas a mi aprendizaje; y aun que ahora crecí y busque cortar el cordón y dar pasos yo solito para ser como los grandes (así como el Guille Som), siempre agradezco esa labor de compartir tanta información.
Gracias estimado Guille, por ser una de mis inspiraciones en la programación.
Buenas «noches» aquí son las 21:39 (9 p.m. y 39 minutos).
Gracias a ti y espero que tu aventura «descordonado» te vaya bien y seas más grande que el «tal Guillermo Som» ese 😉
Saludos desde el sur de España… en los montes que vivo ahora y veremos si esta noche no me lleva el viento 😀