Sign in to follow this  
Followers 0

UDF - get a list of USB-attached drives

10 posts in this topic

Posted

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

Share this post


Link to post
Share on other sites



Posted

pardon me for asking. but wtf is:

RunGetOutput

Share this post


Link to post
Share on other sites

Posted

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

Share this post


Link to post
Share on other sites

Posted

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 :(

Share this post


Link to post
Share on other sites

Posted

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.

Share this post


Link to post
Share on other sites

Posted (edited)

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

Share this post


Link to post
Share on other sites

Posted

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

YES :(

Share this post


Link to post
Share on other sites

Posted

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.

Share this post


Link to post
Share on other sites

Posted (edited)

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

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0

  • Recently Browsing   0 members

    No registered users viewing this page.