Page 1 of 1

is drive a usb drive?

Posted: Thu Apr 21, 2016 3:51 pm
by jassing
Is there a way to detect if a drive is physically part of the machine (sata/ide) or connected via a USB / Firewire hub? (or internal/external)

Another related -- is there a way to tell if a drive is a solid state drive (vs mechanical)?
(bonus if there's a way to reliably read the drive's actual serial # (not volume id).

I would like to avoid using wsh for speed and possible policy conflicts; but if that's the only way; I will make adjustments.

Thanks.
-josh

Re: is drive a usb drive?

Posted: Thu Apr 21, 2016 3:55 pm
by RSBasic

Re: is drive a usb drive?

Posted: Fri Apr 22, 2016 1:49 am
by jassing
RSBasic wrote:USB drive check: http://www.rsbasic.de/aktualisierung/wi ... e%20ist.pb
[/qoute]
I ran that as x86 & x64, unicode and not. Nothing was identified as a usb drive.
that's the volume id, not the drive's serial #.

Re: is drive a usb drive?

Posted: Fri Apr 22, 2016 10:59 am
by Marc56us
jassing wrote:Is there a way to detect if a drive is physically part of the machine (sata/ide) or connected via a USB / Firewire hub? (or internal/external)
GetDriveType function
Determines whether a disk drive is a removable, fixed, CD-ROM, RAM disk, or network drive.

https://msdn.microsoft.com/fr-fr/librar ... s.85).aspx

Re: is drive a usb drive?

Posted: Fri Apr 22, 2016 11:25 am
by DontTalkToMe
jassing wrote: (bonus if there's a way to reliably read the drive's actual serial # (not volume id).
MS says

https://msdn.microsoft.com/en-us/librar ... 2147217396
This function returns the volume serial number that the operating system assigns when a hard disk is formatted. To programmatically obtain the hard disk's serial number that the manufacturer assigns, use the Windows Management Instrumentation (WMI) Win32_PhysicalMedia property SerialNumber.

Re: is drive a usb drive?

Posted: Fri Apr 22, 2016 2:58 pm
by blueb
Will this help?

Code: Select all

; German forum: http://www.purebasic.fr/german/viewtopic.php?t=1895&highlight=
; Author: DataMiner (updated for PB 4.00 by Andre)
; Date: 05. February 2005
; OS: Windows
; Demo: No


Define.l Serial, type, i 
Define.s Lfwrk, FileSystem, VolName 

For i=65 To 90 
  Lfwrk=Chr(i)+":\" 
  type =GetDriveType_(Lfwrk) 
  FileSystem = Space(256) 
  VolName= Space(256) 
  GetVolumeInformation_(@Lfwrk, @VolName, 255, @Serial, 0, 0, @FileSystem, 255) 
  Select type 
    Case 0 
      Debug Lfwrk+" The drive type cannot be determined." 
    Case 2 
      Debug Lfwrk+" = DRIVE_REMOVABLE, "+VolName+", "+FileSystem+", "+  Hex(Serial) 
    Case 3 
      Debug Lfwrk+" = DRIVE_FIXED, "+VolName+", "+FileSystem+", "+  Hex(Serial) 
    Case 4 
      Debug Lfwrk+" = DRIVE_REMOTE, "+VolName+", "+FileSystem+", "+  Hex(Serial) 
    Case 5 
      Debug Lfwrk+" = DRIVE_CDROM, "+VolName+", "+FileSystem+", "+  Hex(Serial) 
    Case 6 
      Debug Lfwrk+" =  DRIVE_RAMDISK,   "+VolName+", "+FileSystem+", "+  Hex(Serial) 
  EndSelect 
Next 

Re: is drive a usb drive?

Posted: Fri Apr 22, 2016 3:13 pm
by jassing
thanks; I'll use wmi... not ideal; but it'll work. thanks.
I'll poke around that too, to see if I can find a internal/external disk identifier too.

Re: is drive a usb drive?

Posted: Fri Apr 22, 2016 7:17 pm
by Thunder93
jassing wrote:Another related -- is there a way to tell if a drive is a solid state drive (vs mechanical)?
There is, I've thrown something together and is incomplete. Unfortunately I'm heading out for a few so here it is.

Code: Select all

#StorageDeviceTrimProperty = 8

Structure DEVICE_TRIM_DESCRIPTOR Align #PB_Structure_AlignC
  Version.l
  Size.l
  TrimEnabled.b
EndStructure

#StorageDeviceSeekPenaltyProperty = 7

Structure DEVICE_SEEK_PENALTY_DESCRIPTOR Align #PB_Structure_AlignC
  Version.l
  Size.l
  IncursSeekPenalty.b
EndStructure

Structure ATA_PASS_THROUGH_EX Align #PB_Structure_AlignC
  length.w
  AtaFlags.w
  PathId.c
  TargetId.c
  Lun.c
  ReservedAsUchar.c
  DataTransferLength.l
  TimeOutValue.l
  ReservedAsUlong.l
  DataBufferOffset.i
  PreviousTaskFile.c[8]
  CurrentTaskFile.c[8]
EndStructure

Structure ATAIdentifyDeviceQuery Align #PB_Structure_AlignC
  header.ATA_PASS_THROUGH_EX
  Data.w[256]
EndStructure

Structure STORAGE_PROPERTY_QUERY Align #PB_Structure_AlignC
  PropertyId.l ;STORAGE_PROPERTY_ID
  QueryType.l  ;STORAGE_QUERY_TYPE
  AdditionalParameters.l
EndStructure

#IOCTL_STORAGE_QUERY_PROPERTY  = $2D1400
#IOCTL_ATA_PASS_THROUGH = $4D02C
#PropertyStandardQuery = 0

#ATA_FLAGS_DATA_IN  = $02


bytesReturned.l

sDrive.s = "\\.\PhysicalDrive0"

hDevice = CreateFile_(sDrive,
                      0,  ; No access To drive needed.
                      #FILE_SHARE_READ | #FILE_SHARE_WRITE, #Null,
                      #OPEN_EXISTING,  0, #Null)

If hDevice <> #INVALID_HANDLE_VALUE
  Debug sDrive
  
  ;Check TRIM -- should be Y for SSD  
  spqTrim.STORAGE_PROPERTY_QUERY
  spqTrim\PropertyId = #StorageDeviceTrimProperty
  spqTrim\QueryType = #PropertyStandardQuery
  
  bytesReturned = 0
  dtd.DEVICE_TRIM_DESCRIPTOR
  If DeviceIoControl_(hDevice, #IOCTL_STORAGE_QUERY_PROPERTY,
                      @spqTrim, SizeOf(spqTrim), @dtd, SizeOf(dtd), @bytesReturned, #Null) And bytesReturned = SizeOf(dtd)  
    
    Debug "Retrieving TRIM"
    If dtd\TrimEnabled = 1      
      Debug "  Disk is SSD"
    Else
      Debug "  Disk is non-SSD"
    EndIf
    
    
  Else
    Debug "DeviceIoControl #1 failed: Error-Code: "+GetLastError_()
  EndIf
  
  ;Check the seek-penalty value -- should be N For SSD  
  spqSeekP.STORAGE_PROPERTY_QUERY
  spqSeekP\PropertyId = #StorageDeviceSeekPenaltyProperty
  spqSeekP\QueryType = #PropertyStandardQuery
  
  bytesReturned = 0
  dspd.DEVICE_SEEK_PENALTY_DESCRIPTOR
  If DeviceIoControl_(hDevice, #IOCTL_STORAGE_QUERY_PROPERTY,
                      @spqSeekP, SizeOf(spqSeekP), @dspd, SizeOf(dspd), @bytesReturned, #Null) And bytesReturned = SizeOf(dspd)
    
    Debug "Retrieving SeekPenalty"
    If dspd\IncursSeekPenalty = 0
      Debug "  Disk is SSD"
    Else
      Debug "  Disk is non-SSD"
    EndIf
    
  Else
    Debug #CRLF$+"DeviceIoControl #2 failed: Error-Code: "+GetLastError_()
  EndIf
  
  CloseHandle_(hDevice)
EndIf


; Administrative privileges required for the below code

hDevice = CreateFile_(sDrive,
                      #GENERIC_READ | #GENERIC_WRITE, ; Administrative privileges is required
                      #FILE_SHARE_READ | #FILE_SHARE_WRITE, #Null,
                      #OPEN_EXISTING,  0, #Null)

If hDevice = -1 : Debug #CRLF$+"Requires Administrator Privileges for drive RPM reading." : End : EndIf

If hDevice <> #INVALID_HANDLE_VALUE
  ;Get drive's RPMs reading -- should be 1 for SSD
  ;CODE SOURCE: https://emoacht.wordpress.com/2012/11/06/csharp-ssd/
  
  id_query.ATAIdentifyDeviceQuery
  
  With id_query\header
    \length = SizeOf(id_query\header)   
    \AtaFlags = #ATA_FLAGS_DATA_IN
    \DataTransferLength = SizeOf(id_query\Data) * 2 ;Size of "data" in bytes    
    
    \TimeOutValue = 5 ;secs
    \DataBufferOffset = OffsetOf(ATAIdentifyDeviceQuery\Data)
    ;     \PreviousTaskFile = 0
    ;     \CurrentTaskFile  = 0
    \CurrentTaskFile[6] = $EC ; ATA IDENTIFY DEVICE    
  EndWith 
  
    
  bytesReturned = 0 : dbsize.l = SizeOf(id_query)
  If DeviceIoControl_(hDevice, #IOCTL_ATA_PASS_THROUGH,
                      @id_query, dbsize, @id_query, dbsize, @bytesReturned, #Null) ;And bytesReturned = SizeOf(id_query)
    
    
    kNominalMediaRotRateWordIndex = 217
    
    Debug "Retrieving Nominal media rotation rate"
    If id_query\Data[kNominalMediaRotRateWordIndex] = 1
      Debug "Disk is SSD"
    Else
      Debug "Disk is non-SSD"
    EndIf    
    
  Else
    Debug #CRLF$+"DeviceIoControl #3 failed: Error-Code: "+GetLastError_()
  EndIf  
  
  CloseHandle_(hDevice)
EndIf

Re: is drive a usb drive?

Posted: Fri Apr 22, 2016 8:46 pm
by jassing
Thunder93 wrote:[I've thrown something together and is incomplete. Unfortunately I'm heading out for a few so here it is.
Thanks; I'll have a look at it tonight.

Re: is drive a usb drive?

Posted: Fri Apr 22, 2016 9:29 pm
by Thunder93
I've updated it. Administrator privileges isn't requirement for the first two methods. Third method, even though incomplete, does require Admin privileges.

Re: is drive a usb drive?

Posted: Sat Apr 23, 2016 12:08 am
by Thunder93
You want drive serials not volume Ids. You want to detect type of device (like USB or Firewire), and if its Solid-State drive. WMI isn't often appealing, so without WMI usage. Requires no administrator privileges.

GetDrivesINFO.pb - Revised on 2016-04-23 | #1

Code: Select all

IncludeFile "IsSSD.pbi"

Structure STORAGE_DEVICE_DESCRIPTOR ;Align #PB_Structure_AlignC
  Version.l
  Size.l
  DeviceType.b
  DeviceTypeModifier.b
  RemovableMedia.b
  CommandQueueing.b
  VendorIdOffset.l
  ProductIdOffset.l
  ProductRevisionOffset.l
  SerialNumberOffset.l
  BusType.w
  RawPropertiesLength.l
  RawDeviceProperties.b
  Reserved.b[1024]
EndStructure

#BusTypeUnknown      = $00
#BusTypeScsi         = $01
#BusTypeAtapi        = $02
#BusTypeAta          = $03
#BusType1394         = $04
#BusTypeSsa          = $05
#BusTypeFibre        = $06
#BusTypeUsb          = $07
#BusTypeRAID         = $08
#BusTypeiSCSI        = $09
#BusTypeSas          = $0A
#BusTypeSata         = $0B
#BusTypeMaxReserved  = $7F

#IOCTL_STORAGE_QUERY_PROPERTY          = $2D1400
#IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER = $2D0C10

strDrive.s
udtQuery.STORAGE_PROPERTY_QUERY
udtOut.STORAGE_DEVICE_DESCRIPTOR

OpenConsole()
PrintN("Enumerate devices")

For Drives=1 To 26
  
  strDrive="\\.\" + Chr(64+Drives) + ":"
  
  hDrive = CreateFile_(strDrive, 0,#FILE_SHARE_READ | #FILE_SHARE_WRITE, 0, #OPEN_EXISTING, 0, 0)
  If hDrive <> #INVALID_HANDLE_VALUE
    
    PrintN("--------------------------------------------------")
    
    lngResult = DeviceIoControl_(hDrive, #IOCTL_STORAGE_QUERY_PROPERTY, udtQuery,SizeOf(udtQuery), @udtOut, SizeOf(udtOut), @dwOutBytes, 0)
    If lngResult 
      PrintN("Drive " + Chr(64+Drives) + ": is a ")
      
      Select(udtOut\Bustype) 
        Case #BusTypeUnknown
          PrintN("Bustype: Unknown bus type")
          
        Case #BusTypeScsi
          PrintN("Bustype: SCSI bus")
          
        Case #BusTypeAtapi
          PrintN("Bustype:  Atapi bus")
          
        Case #BusTypeAta
          PrintN("Bustype:  Ata Device")
          
        Case #BusType1394
          PrintN("Bustype: IEEE-1394 bus")
          
        Case #BusTypeSsa
          PrintN("Bustype: SSA bus")
          
        Case #BusTypeFibre
          PrintN("Bustype: Fibre Channel bus")
          
        Case #BusTypeUsb          
          PrintN("Bustype: USB bus")
      
        Case #BusTypeRAID
          PrintN("Bustype: RAID bus")         

        Case #BusTypeiSCSI
          PrintN("Bustype: iSCSI bus")
          
        Case #BusTypeSas
          PrintN("Bustype: Sas bus")
          
        Case #BusTypeSata
          PrintN("Bustype: SATA bus")
          
        Case #BusTypeMaxReserved
          PrintN("Bustype: iSCSI bus")
          
        Default
          PrintN("Bustype = " + Str(udtOut\BusType))
      EndSelect
      
      If IsSSD(strDrive)
        PrintN("Device is Solid-State Drive (SSD)")
      EndIf      
      
      If udtout\RemovableMedia
        PrintN("Device is Removable Media")
      EndIf
      
      If udtOut\ProductIdOffset > 0
        PrintN("ProductID = " + PeekS(@udtOut + udtOut\ProductIdOffset, -1, #PB_Ascii))
      EndIf
      
      If udtOut\ProductRevisionOffset > 0
        PrintN("ProductRevision = " + PeekS(@udtOut + udtOut\ProductRevisionOffset, -1, #PB_Ascii))
      EndIf
      
      If udtOut\VendorIdOffset  > 0
        PrintN("VendorID = " + PeekS(@udtOut + udtOut\VendorIdOffset, -1, #PB_Ascii))
      EndIf
      
      If udtOut\SerialNumberOffset  > 0       
        Serial$ = Trim(PeekS(@udtOut + udtOut\SerialNumberOffset, -1, #PB_Ascii))        
        PrintN("Serial = " + Serial$)        
      EndIf         
      
    Else
      PrintN("No Device-IO info available.. for "+Chr(64+Drives) + ":")
      
    EndIf    
    
    ClearStructure(@udtQuery, STORAGE_PROPERTY_QUERY)
    ClearStructure(@udtOut, STORAGE_DEVICE_DESCRIPTOR)
  EndIf
  CloseHandle_(hDrive)
  
  
Next Drives

wait.s=Input()
CloseConsole()
IsSSD.pbi

Code: Select all

#StorageDeviceSeekPenaltyProperty   = 7
#StorageDeviceTrimProperty          = 8

Structure DEVICE_TRIM_DESCRIPTOR Align #PB_Structure_AlignC
  Version.l
  Size.l
  TrimEnabled.b
EndStructure

Structure DEVICE_SEEK_PENALTY_DESCRIPTOR Align #PB_Structure_AlignC
  Version.l
  Size.l
  IncursSeekPenalty.b
EndStructure

Structure STORAGE_PROPERTY_QUERY Align #PB_Structure_AlignC
  PropertyId.l ;STORAGE_PROPERTY_ID
  QueryType.l  ;STORAGE_QUERY_TYPE
  AdditionalParameters.l
EndStructure

#IOCTL_STORAGE_QUERY_PROPERTY  = $2D1400
#IOCTL_ATA_PASS_THROUGH        = $4D02C
#PropertyStandardQuery         = 0

Procedure.b IsSSD(sDrive.s)  
  Protected hDevice.i, bytesReturned.l, IsSSD.b 
  
  If sDrive = "" : ProcedureReturn 0 : EndIf
  
  hDevice = CreateFile_(sDrive,
                        0,  ; No access To drive needed.
                        #FILE_SHARE_READ | #FILE_SHARE_WRITE, #Null,
                        #OPEN_EXISTING,  0, #Null)
  
  If hDevice <> #INVALID_HANDLE_VALUE
    
    ;Check TRIM -- should be Y for SSD  
    Protected spqTrim.STORAGE_PROPERTY_QUERY
    spqTrim\PropertyId = #StorageDeviceTrimProperty
    spqTrim\QueryType = #PropertyStandardQuery
    
    bytesReturned = 0
    Protected dtd.DEVICE_TRIM_DESCRIPTOR
    If DeviceIoControl_(hDevice, #IOCTL_STORAGE_QUERY_PROPERTY,
                        @spqTrim, SizeOf(spqTrim), @dtd, SizeOf(dtd), @bytesReturned, #Null) And bytesReturned = SizeOf(dtd)  
      
      If dtd\TrimEnabled = 1 : IsSSD+1 : EndIf
    EndIf
    
    ;Check the seek-penalty value -- should be N For SSD  
    Protected spqSeekP.STORAGE_PROPERTY_QUERY
    spqSeekP\PropertyId = #StorageDeviceSeekPenaltyProperty
    spqSeekP\QueryType = #PropertyStandardQuery
    
    bytesReturned = 0
    Protected dspd.DEVICE_SEEK_PENALTY_DESCRIPTOR
    If DeviceIoControl_(hDevice, #IOCTL_STORAGE_QUERY_PROPERTY,
                        @spqSeekP, SizeOf(spqSeekP), @dspd, SizeOf(dspd), @bytesReturned, #Null) And bytesReturned = SizeOf(dspd)
      
      If dspd\IncursSeekPenalty = 0 : IsSSD+2 : EndIf
    EndIf
    
    CloseHandle_(hDevice)
  EndIf
  
  ProcedureReturn IsSSD ; 0 = Non-SSD, 1 = SSD-byTRIM, 2 = SSD-bySEEKPENTALTY, 3 = SSD-byBOTH
EndProcedure


CompilerIf #PB_Compiler_IsMainFile
  Debug IsSSD("\\.\C:")
CompilerEndIf

Re: is drive a usb drive?

Posted: Sat Apr 23, 2016 1:58 am
by jassing
... AWESOME!!!!

Thank you!!! That worked perfectly!!!!

Re: is drive a usb drive?

Posted: Sat Apr 23, 2016 3:42 am
by Thunder93
You're certainly welcome. :mrgreen: