blindwig Posted June 7, 2005 Share Posted June 7, 2005 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 My UDF Threads:Pseudo-Hash: Binary Trees, Flat TablesFiles: Filter by Attribute, Tree List, Recursive Find, Recursive Folders Size, exported to XMLArrays: Nested, Pull Common Elements, Display 2dSystem: Expand Environment Strings, List Drives, List USB DrivesMisc: Multi-Layer Progress Bars, Binary FlagsStrings: Find Char(s) in String, Find String in SetOther UDF Threads I Participated:Base64 Conversions Link to comment Share on other sites More sharing options...
w0uter Posted June 7, 2005 Share Posted June 7, 2005 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 Link to comment Share on other sites More sharing options...
blindwig Posted June 7, 2005 Author Share Posted June 7, 2005 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:CODEFunc 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 $ReturnEndFunc My UDF Threads:Pseudo-Hash: Binary Trees, Flat TablesFiles: Filter by Attribute, Tree List, Recursive Find, Recursive Folders Size, exported to XMLArrays: Nested, Pull Common Elements, Display 2dSystem: Expand Environment Strings, List Drives, List USB DrivesMisc: Multi-Layer Progress Bars, Binary FlagsStrings: Find Char(s) in String, Find String in SetOther UDF Threads I Participated:Base64 Conversions Link to comment Share on other sites More sharing options...
CyberSlug Posted June 7, 2005 Share Posted June 7, 2005 Where are StringSection and TableLookUp defined?I did something somewhat-related a while back, but your code looks much cleanerhttp://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! Link to comment Share on other sites More sharing options...
blindwig Posted June 7, 2005 Author Share Posted June 7, 2005 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:CODEFunc 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 "" EndIfEndFuncTableLookUp 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=12136Here's the old code:CODEFunc 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 ""EndFuncI'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 My UDF Threads:Pseudo-Hash: Binary Trees, Flat TablesFiles: Filter by Attribute, Tree List, Recursive Find, Recursive Folders Size, exported to XMLArrays: Nested, Pull Common Elements, Display 2dSystem: Expand Environment Strings, List Drives, List USB DrivesMisc: Multi-Layer Progress Bars, Binary FlagsStrings: Find Char(s) in String, Find String in SetOther UDF Threads I Participated:Base64 Conversions Link to comment Share on other sites More sharing options...
blindwig Posted June 8, 2005 Author Share Posted June 8, 2005 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 numberCODEFunc _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 $tblDriveListEndFuncFunc _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 $UsbListEndFuncFunction _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.CODEFunc _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 $UsbListEndFuncBoth of these functions require my tables UDF and my _StringInSet() function. My UDF Threads:Pseudo-Hash: Binary Trees, Flat TablesFiles: Filter by Attribute, Tree List, Recursive Find, Recursive Folders Size, exported to XMLArrays: Nested, Pull Common Elements, Display 2dSystem: Expand Environment Strings, List Drives, List USB DrivesMisc: Multi-Layer Progress Bars, Binary FlagsStrings: Find Char(s) in String, Find String in SetOther UDF Threads I Participated:Base64 Conversions Link to comment Share on other sites More sharing options...
Wus Posted June 9, 2005 Share Posted June 9, 2005 (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 June 9, 2005 by Wus Link to comment Share on other sites More sharing options...
Westi Posted June 11, 2005 Share Posted June 11, 2005 i dont suppose youd be willing top make a zip of all of your udf's and pst em? some look very useful...YES Link to comment Share on other sites More sharing options...
blindwig Posted June 13, 2005 Author Share Posted June 13, 2005 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. My UDF Threads:Pseudo-Hash: Binary Trees, Flat TablesFiles: Filter by Attribute, Tree List, Recursive Find, Recursive Folders Size, exported to XMLArrays: Nested, Pull Common Elements, Display 2dSystem: Expand Environment Strings, List Drives, List USB DrivesMisc: Multi-Layer Progress Bars, Binary FlagsStrings: Find Char(s) in String, Find String in SetOther UDF Threads I Participated:Base64 Conversions Link to comment Share on other sites More sharing options...
jzn2 Posted September 24, 2006 Share Posted September 24, 2006 (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 September 25, 2006 by jzn2 Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now