Jump to content

This site uses cookies. By continuing to browse the site you are agreeing to our use of cookies. Find out more here. X
X


Photo

UDF - get a list of USB-attached drives


  • Please log in to reply
9 replies to this topic

#1 blindwig

blindwig

    Universalist

  • Active Members
  • PipPipPipPipPipPip
  • 772 posts

Posted 07 June 2005 - 03:30 AM

I have a need to get a list of USB-attached drives on my system. I couldn't find any AutoIt functions to do this, and I don't know how to do any system calls or anything fancy, so I ended up writing a script to interface with DISKPART.EXE, a command-line tool for managing disks. This script obviously won't work on a system that does not have access to DISKPART.EXE
This function returns an [x][2] array, where [x][0]=drive number and [x][1]=drive size. The length of the array is in [0][0]
Notice that I return drive numbers, not letters. Letters are too ambigious - a physical drive can have multiple letters (partitions), no letter (if windows doesn't recognise the file system, or if it's letter has been removed), or a letter can represent multiple physical drives (spanned or stripped volumes).
Also note that drive numbers are 0-based.
CODE

Func DriveGetUsbList()
dim $i, $temp

;Step 1 - Get all valid drive numbers
Dim $DriveListNum[100][2], $DriveListNext=1, $DriveListText
;$DriveListNum is a table of valid drive numbers and their sizes, $DriveListNext is an index to the next free entry
;$DriveListText is a temporary variable used for parsing text in and out
$DriveListText=StringSplit(RunGetOutput(@ComSpec & " /c echo list disk | diskpart"), @CRLF)
For $i = 1 to $DriveListText[0]
if StringInStr($DriveListText[$i], "Disk ") Then
$Temp = StringMid($DriveListText[$i],8,3)
if $Temp<>"###" Then
$DriveListNum[$DriveListNext][0] = Int($Temp)
$DriveListNum[$DriveListNext][1] = StringMid($DriveListText[$i],25,7)
$DriveListNext = $DriveListNext + 1
EndIf
If $DriveListNext > Ubound($DriveListNum) Then Redim $DriveListNum[Ubound($DriveListNum)+20][2]
EndIf
Next
$DriveListNum[0][0]=$DriveListNext ;Element [0][0] contains the list size (1-based)

;Step 2 - figure out which are attached via USB
Dim $TempFile, $hndFile_Temp, $DriveUsbCur

;Step 2.1 - build a script for DiskPart
$TempFile = _TempFile()
$hndFile_Temp = FileOpen($TempFile, 2)
for $i = 1 to $DriveListNext - 1
FileWriteLine($hndFile_Temp, "Select Disk " & $DriveListNum[$i][0])
FileWriteLine($hndFile_Temp, "Detail Disk")
Next
FileClose($hndFile_Temp)

;Step 2.2 - execute the script for DiskPart
$DriveListText=StringSplit(RunGetOutput(@ComSpec & " /c echo list disk | diskpart < " & $TempFile), @CRLF)

;Step 2.3 - parse the results, build a list of USB drives
Dim $DriveListUsb[$DriveListNext-1][2]
$DriveListNext=1
For $i = 1 to $DriveListText[0]
if StringRight($DriveListText[$i], 26) = ' is now the selected disk.' Then
$DriveUsbCur = StringSection($DriveListText[$i], 2, " ")
EndIf
if $DriveListText[$i] = 'Type : USB' Then
$DriveListUsb[$DriveListNext][0] = $DriveUsbCur
$DriveListUsb[$DriveListNext][1] = TableLookUp($DriveListNum, $DriveUsbCur)
$DriveListNext = $DriveListNext + 1
EndIf
Next
$DriveListUsb[0][0]=$DriveListNext-1

;Step 3 - Return the results table
If $DriveListUsb[0][0] > 0 Then
Redim $DriveListUsb[$DriveListUsb[0][0]+1][2]
Return $DriveListUsb
Else
Return 0
EndIf

EndFunc








#2 w0uter

w0uter

    resreveR nA

  • Active Members
  • PipPipPipPipPipPip
  • 2,262 posts

Posted 07 June 2005 - 01:31 PM

pardon me for asking. but wtf is:

RunGetOutput
My UDF's:;mem stuff_Mem;ftp stuff_FTP ( OLD );inet stuff_INetGetSource ( OLD )_INetGetImage _INetBrowse ( Collection )_EncodeUrl_NetStat_Google;random stuff_iPixelSearch_DiceRoll

#3 blindwig

blindwig

    Universalist

  • Active Members
  • PipPipPipPipPipPip
  • 772 posts

Posted 07 June 2005 - 03:51 PM

pardon me for asking. but wtf is:

RunGetOutput

<{POST_SNAPBACK}>

Oops, forgot to include that. It's another function I wrote that will run a command (intended for console-mode commands) that will return the output in a string.
Here's the code:
CODE

Func RunGetOutput($CommandLine)
Dim $Tempfile, $Return
;Find a temp file. Could use _TempFile() instead, if file.au3 is included
Do
$TempFile = @TempDir & '\' & Int(Random(65536)) & '.txt'
Until not FileExists($TempFile)
;Run the inputted command, redirect output to our tempfile
RunWait($CommandLine & " > " & $TempFile, '', @SW_HIDE)
;Read the temp file into a string, delete the temp file, return the string
$Return = FileRead($TempFile, FileGetSize($TempFile))
FileDelete($TempFile)
Return $Return
EndFunc


#4 CyberSlug

CyberSlug

    Overwhelmed with work....

  • MVPs
  • 3,587 posts

Posted 07 June 2005 - 04:22 PM

Where are StringSection and TableLookUp defined?

I did something somewhat-related a while back, but your code looks much cleaner
http://www.autoitscript.com/forum/index.ph...wtopic=8704&hl=
Use Mozilla | Take a look at My Disorganized AutoIt stuff | Very very old: AutoBuilder 11 Jan 2005 prototype I need to update my sig!

#5 blindwig

blindwig

    Universalist

  • Active Members
  • PipPipPipPipPipPip
  • 772 posts

Posted 07 June 2005 - 05:08 PM

Where are StringSection and TableLookUp defined?

<{POST_SNAPBACK}>

StringSection is like StringSplit(), except that instead of returning the entire array, it just returns the section that you want. Here's the code:
CODE

Func StringSection($Input, $Number, $Seperator="|")
;Returns a substring of $Input, between $Number and $Number+1 occurance of $Seperator
$Number=Int($Number)
If $Number>0 And $Number<=StringInCount($Input, $Seperator)+1 Then
If $Number=1 Then
$Begin=0
$End=StringInStr($Input, $Seperator, 0, 1)
Else
$Begin=StringInStr($Input, $Seperator, 0, $Number-1)
$End=StringInStr($Input, $Seperator, 0, $Number)
If @error Then $End=StringLen($Input)+1
EndIf
Return StringMid($Input, $Begin+1, $End-$Begin-1)
Else
Return ""
EndIf
EndFunc
TableLookUp looks at an array[x][2] and returns the value of [x][1] such that [x][0] matches the given key.
This is the predecessor to my table library:
http://www.autoitscript.com/forum/index.php?showtopic=12136
Here's the old code:
CODE

Func TableLookUp($Table, $Key)
;$Table is an array of [x][1]. Function finds a record such that $Key=$Table[x][0] and returns $Table[x][1]
If UBound($Table, 0)<2 Then Return ""
For $i=0 to UBound($Table, 1)-1
If $Table[$i][0]=$Key Then Return $Table[$i][1]
Next
Return ""
EndFunc
I'm glad you think my code is clean. This is probably one of the first things I wrote with AutoIt, and looking at it now I see plenty of room for improvement :(

#6 blindwig

blindwig

    Universalist

  • Active Members
  • PipPipPipPipPipPip
  • 772 posts

Posted 08 June 2005 - 06:26 PM

OK, I totally re-wrote the routine. Now it returns a table containing a list of all drives, keyed by drive number, and containing a CSV field with all the drive details. Again, this relies on shelling out to run DISKPART, so it is dependant on that.
Function _DriveGetList() takes no input, and if successful, returns a table containing the drive info, keyed by drive number
CODE

Func _DriveGetList()
Dim $EOF
Dim $DriveNum, $DriveDetails, $Detail
Dim $ReadLine, $RetVal
Dim $OutputFileName, $hndFile_Output
Dim $InputFileName, $hndFile_Input
Dim $tblDriveList
Dim $i, $DriveNums

;Find names for temporary output files
Do
$OutputFileName = @TempDir & '\' & Int(Random(65536)) & '.txt'
Until not FileExists($OutputFileName)
Do
$InputFileName = @TempDir & '\' & Int(Random(65536)) & '.txt'
Until not FileExists($InputFileName)

;Write drive list to output file
$RetVal=RunWait(@COMSPEC & ' /c echo list disk | diskpart>' & $OutputFileName,'',@SW_HIDE)
If $RetVal Then Return ''

;Read output, parse to find drive list
_TableCreate($tblDriveList)
$hndFile_Output=FileOpen($OutputFileName,0)
$ReadLine = FileReadLine($hndFile_Output)
$EOF = @error
While Not $EOF
While (StringMid($ReadLine, 3, 5) <> 'Disk ' Or StringMid($ReadLine, 8, 3)='###') And Not $EOF
$ReadLine = FileReadLine($hndFile_Output)
$EOF = @error
WEnd
If Not $EOF Then
$DriveNum=StringStripWS(StringMid($ReadLine, 8, 3), 3)
$DriveDetails=StringStripWS(StringMid($ReadLine, 13, 10), 3)
$DriveDetails=$DriveDetails & ',' & StringStripWS(StringMid($ReadLine, 25, 7), 3)
$DriveDetails=$DriveDetails & ',' & StringStripWS(StringMid($ReadLine, 34, 7), 3)
$DriveDetails=$DriveDetails & ',' & StringStripWS(StringMid($ReadLine, 43, 3), 3)
$DriveDetails=$DriveDetails & ',' & StringStripWS(StringMid($ReadLine, 43, 3), 3)
_TableSetValue($tblDriveList, $DriveNum, $DriveDetails)
$ReadLine = FileReadLine($hndFile_Output)
EndIf
WEnd
FileClose($hndFile_Output)

;Build a script to get extended drive info
$DriveNums=_TableGetKeys($tblDriveList)
$hndFile_Input = FileOpen($InputFileName,2)
For $i = 1 To $DriveNums[0]
FileWriteLine($hndFile_Input, 'select disk ' & $DriveNums[$i])
FileWriteLine($hndFile_Input, 'detail disk')
Next
FileClose($hndFile_Input)

;Run script, save output
$RetVal=RunWait(@COMSPEC & ' /c echo list disk | diskpart /s ' & $InputFileName & '>' & $OutputFileName,'',@SW_HIDE)
FileDelete($InputFileName)
If $RetVal Then Return ''

;Parse output, look for extended info
$hndFile_Output=FileOpen($OutputFileName,0)
$DriveNum=-1
$ReadLine = FileReadLine($hndFile_Output)
$EOF = @error
While Not $EOF
$Detail = StringLeft($ReadLine, 9)
;look for a new drive number
If StringInStr($ReadLine, ' is now the selected disk.') Then
;if switching drives, then need to write details from the last drive to the table
If $DriveNum>=0 Then
_TableSetValue($tblDriveList, $DriveNum, $DriveDetails)
EndIf
;Get a new drive number, get details for that drive
$DriveNum = StringStripWS(StringMid($ReadLine, 6, 2), 3)
$DriveDetails = _TableGetValue($tblDriveList, $DriveNum)
;skip a line
$ReadLine = FileReadLine($hndFile_Output)
$EOF = @error
;next line should be the drive name
If Not $EOF Then
$ReadLine = FileReadLine($hndFile_Output)
$EOF = @error
$DriveDetails = $DriveDetails & ',' & $ReadLine
EndIf
EndIf
;look for details about the current drive
If _StringInSet($Detail,'Disk ID: ,Type : ,Bus : ,Target : ,LUN ID : ') Then
$DriveDetails = $DriveDetails & ',' & StringMid($ReadLine, 10)
EndIf
$ReadLine = FileReadLine($hndFile_Output)
$EOF = @error
WEnd
;Write remaining details to the table
If $DriveNum>=0 Then
_TableSetValue($tblDriveList, $DriveNum, $DriveDetails)
EndIf

FileClose($hndFile_Output)
FileDelete($OutputFileName)

Return $tblDriveList
EndFunc

Func _DriveGetListUSB($tblDrives)
Dim $tblDrives, $DriveNums, $DriveDetails, $i
If Not _TableIsValid($tblDrives) Then $tblDrives = _DriveGetList()
$DriveNums = _TableGetKeys($tblDrives)
Dim $UsbList[$DriveNums[0]+1]
$UsbList[0]=1
For $i = 1 to $DriveNums[0]
$DriveDetails = StringSplit(_TableGetValue($tblDrives,$DriveNums[$i]), ',')
If UBound($DriveDetails)>=7 Then
If $DriveDetails[8]='USB' Then
$UsbList[$UsbList[0]]=$DriveNums[$i]
$UsbList[0] = $UsbList[0] + 1
EndIf
EndIf
Next
Redim $UsbList[$UsbList[0]]
$UsbList[0] = $UsbList[0] - 1
Return $UsbList
EndFunc
Function _DriveGetListUSB will return an array containing the numbers of USB drives. It will take a table returned by _DriveGetList(), or will generate a fresh one.
CODE

Func _DriveGetListUSB($tblDrives = -1)
Dim $tblDrives, $DriveNums, $DriveDetails, $i
If Not _TableIsValid($tblDrives) Then $tblDrives = _DriveGetList()
$DriveNums = _TableGetKeys($tblDrives)
Dim $UsbList[$DriveNums[0]+1]
$UsbList[0]=1
For $i = 1 to $DriveNums[0]
$DriveDetails = StringSplit(_TableGetValue($tblDrives,$DriveNums[$i]), ',')
If UBound($DriveDetails)>=7 Then
If $DriveDetails[8]='USB' Then
$UsbList[$UsbList[0]]=$DriveNums[$i]
$UsbList[0] = $UsbList[0] + 1
EndIf
EndIf
Next
Redim $UsbList[$UsbList[0]]
$UsbList[0] = $UsbList[0] - 1
Return $UsbList
EndFunc
Both of these functions require my tables UDF and my _StringInSet() function.

#7 Wus

Wus

    Indentured Servant

  • Active Members
  • PipPipPipPipPipPip
  • 513 posts

Posted 09 June 2005 - 08:43 PM

i dont suppose youd be willing top make a zip of all of your udf's and pst em? some look very useful...

perty plz :(

Edited by Wus, 09 June 2005 - 08:44 PM.

Posted Image

#8 Westi

Westi

    Adventurer

  • Active Members
  • PipPip
  • 108 posts

Posted 11 June 2005 - 09:37 PM

i dont suppose youd be willing top make a zip of all of your udf's and pst em? some look very useful...

YES :(

#9 blindwig

blindwig

    Universalist

  • Active Members
  • PipPipPipPipPipPip
  • 772 posts

Posted 13 June 2005 - 05:49 AM

i dont suppose youd be willing top make a zip of all of your udf's and pst em? some look very useful...

perty plz :(

<{POST_SNAPBACK}>

Right now they're mostly works in progress. As I complete a function I post it here for some peer review. Maybe once I have a good collection of functions that form a logical module I'll post it up here. But if you like my work, just do a search for my name and UDF in the title.

#10 jzn2

jzn2

    Seeker

  • Active Members
  • 35 posts

Posted 24 September 2006 - 09:39 PM

could you also retrieve a drive letter or perhaps a list of drive letters?or can an optical drive be called by the drive number? as i do here:

CDTray("F:", "close")

Edit: Also, I am asuming that Func _DriveGetList() is not dependent upon Func _DriveGetListUSB and visa versa is that correct?

Edited by jzn2, 25 September 2006 - 05:55 AM.





0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users