Jump to content

Making function more reliable to acquire available drive letters.


bobomb
 Share

Go to solution Solved by Musashi,

Recommended Posts

I am using the below function in a script I posted in its entirety here earlier. 

This gets 2 available drive letters and assigns them to variables.

Func _GetDriveLetters()
$driveletter = StringSplit("C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z",",",1)
For $i = 1 to $driveletter[0] step +1
    $var = DriveStatus( $driveletter[$i] & ":" )
    If $var = "INVALID" Then
        $bootDrive=($driveletter[$i])
            For $i = 1 to $driveletter[0] step +1
                $var = DriveStatus( $driveletter[$i] & ":" )
                If $var = "INVALID" Then
                   $mainDrive=($driveletter[$i])
                EndIf
            Next
    EndIf
Next
EndFunc   ;==>_GetDriveLetters

This actually works but I believe it is luck. I merely added a second "for" command inside of the first, the first one($bootDrive) pulls from the left of the stringsplit and the second one pulls from the right side of the stringsplit. e.g. if available it will default to C and Z. 

Is there a better way to do this? I am obviously not instructing it to pull from different ends of the string it just happens to do so, is there an explanation for this? It's the only reason it is working as far as I can tell otherwise it would likely pick the same letter for both variables.

Is this something that is best left as is?

Edited by bobomb
Link to comment
Share on other sites

Try :

(from @Danny35d : how-to-list-available-drive-letters )

#include <Array.au3>
$FreeDriveList = _GetFreeDriveLetters()
_ArrayDisplay($FreeDriveList)

Func _GetFreeDriveLetters()
    Dim $aArray[1]
    For $x = 67 To 90
        If DriveStatus(Chr($x) & ':\') = 'INVALID' Then
            ReDim $aArray[UBound($aArray) + 1]
            $aArray[UBound($aArray) - 1] = Chr($x) & ':'
        EndIf
    Next
    $aArray[0] = UBound($aArray) - 1
    Return($aArray)
EndFunc

EDIT : @bobomb

For an array containing the enumerated drives see : DriveGetDrive

Edited by Musashi
enhanced

Musashi-C64.png

"In the beginning the Universe was created. This has made a lot of people very angry and been widely regarded as a bad move."

Link to comment
Share on other sites

Thank you for your speedy response! :)

While the method you posted would allow for more granular control over all available drive letters from within the created array The method I posted is already efficient at retrieving the drive letters, I think a better way to ask, is maybe...

 is there a way get the same result (2 available drive letters) with a single for command with the method I am currently using? i am following the logic and other than the double for command and the pulling from both sides of the string i am mostly worried about stepping on drive letters when getting the second one

Or would this logic be safer to not accidentally pick the same drive letter for the 2 variables?

Func _GetDriveLetters()
$driveletter = StringSplit("C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z",",",1)
For $i = 1 to $driveletter[0] step +1
    $var = DriveStatus( $driveletter[$i] & ":" )
    If $var = "INVALID" Then
        $bootDrive=($driveletter[$i])
            For $i = 1 to $driveletter[0] step +1
            ; Something like this that works lol
                If $bootDrive=($driveletter[$i]) Then
                    $i = (1 to $driveletter[0] step +1)
                EndIf
                ; end example
                $var = DriveStatus( $driveletter[$i] & ":" )
                If $var = "INVALID" Then
                   $mainDrive=($driveletter[$i])
                EndIf
            Next
    EndIf
Next
EndFunc   ;==>_GetDriveLetters

 

Edited by bobomb
Link to comment
Share on other sites

I guess I could do this and leave an empty if/then/else command while checking against the first variable to keep the loop going if they are the same, it already moves to the next delimited char (although from the other end?) when the first variable is assigned.. But this appears to check to make sure I am not picking the same letter twice in the event there is only 1 letter available.. 

Func _GetDriveLetters()
$driveletter = StringSplit("C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z",",",1)
For $i = 1 to $driveletter[0] step +1
    $var = DriveStatus( $driveletter[$i] & ":" )
    If $var = "INVALID" Then
        $bootDrive=($driveletter[$i])
            For $i = 1 to $driveletter[0] step +1
                $var = DriveStatus( $driveletter[$i] & ":" )
                If $bootDrive=($driveletter[$i]) Then
                Else
                    If $var = "INVALID" Then
                       $mainDrive=($driveletter[$i])
                    EndIf
                EndIf
            Next
    EndIf
Next
EndFunc   ;==>_GetDriveLetters

I am very unsure if I am butchering this right now.. Is this bad form/technique?

I feel like this is assigning the entire stringsplit before exiting the loop 

Edited by bobomb
Link to comment
Share on other sites

Ok this actually works perfectly getting the next 2 available drive letters without stepping on itself. Unless I'm doing something that is a nono here I guess I will settle with this.

After looking at For...To...Step...Next in help section I saw the steps being used are being counted and I was using the same variable for both loops..

Func _GetDriveLetters()
$driveletter = StringSplit("Z,Y,X,W,V,U,T,S,R,Q,P,O,N,M,L,K,J,I,H,G,F,E,D,C",",",1)
For $i = 1 to $driveletter[0] step +1
    $var = DriveStatus($driveletter[$i] & ":")
    If $var = "INVALID" Then
        $bootDrive=($driveletter[$i])
            For $x = 1 to $driveletter[0] step +1
                $var = DriveStatus($driveletter[$x] & ":")
                If $bootDrive=($driveletter[$x]) Then
                Else
                    If $var = "INVALID" Then
                       $mainDrive=($driveletter[$x])
                    EndIf
                EndIf
            Next
    EndIf
Next
EndFunc   ;==>_GetDriveLetters

;).. I know when I learn more I will cringe at these questions I've asked..

Edited by bobomb
Link to comment
Share on other sites

  • Solution
1 hour ago, bobomb said:

and leave an empty if/then/else command

Why :

[...]
                If $bootDrive=($driveletter[$x]) Then
                Else
                    If $var = "INVALID" Then
                       $mainDrive=($driveletter[$x])
                    EndIf
                EndIf
[...]

instead of :

[...]
                If Not ($bootDrive=($driveletter[$x])) Then
                    If $var = "INVALID" Then
                       $mainDrive=($driveletter[$x])
                    EndIf
                EndIf
[...]

BTW : A small but runnable reproducer script would be helpful to see, e.g. which variables are declared Global ;).

Edited by Musashi
typo

Musashi-C64.png

"In the beginning the Universe was created. This has made a lot of people very angry and been widely regarded as a bad move."

Link to comment
Share on other sites

7 minutes ago, bobomb said:

... source is listed in another post

Ah, Ok, I hadn't looked into that thread.

Musashi-C64.png

"In the beginning the Universe was created. This has made a lot of people very angry and been widely regarded as a bad move."

Link to comment
Share on other sites

I am not sure what you are exactly trying to find out for the different drives

are you saying: If I have drives a,b,c,d then i want to have [e-z] returned as beeing free drive letters to use? and as such e and z you want to have returned

 

I probably would start with 

https://www.autoitscript.com/autoit3/docs/functions/DriveGetDrive.htm
 

#include <AutoItConstants.au3>
#include <MsgBoxConstants.au3>

local $allDriveLetters="CDEFGHIJKLMNOPQRSTUVWXXYZ"

Local $aArray = DriveGetDrive($DT_ALL)
If @error Then
    ; An error occurred when retrieving the drives.
    MsgBox($MB_SYSTEMMODAL, "", "It appears an error occurred.")
Else
    For $i = 1 To $aArray[0]
         ; Show all the drives found and convert the drive letter to uppercase.
         ;MsgBox($MB_SYSTEMMODAL, "", "Drive " & $i & "/" & $aArray[0] & ":" & @CRLF & StringUpper($aArray[$i]))
         $driveLetter=stringleft(StringUpper($aArray[$i]),1)
         $allDriveLetters=stringreplace($allDriveLetters,$driveLetter,"")
    Next
 EndIf

consolewrite("Drive letters available :" & @CRLF & $allDriveLetters & @CRLF)
consolewrite("First: " & stringleft($allDriveLetters,1) & @CRLF)
consolewrite("Last:  " & stringright($allDriveLetters,1) & @CRLF)

 

and with wmi you can query info

$oWMISvc = ObjGet("winmgmts:\\" & @ComputerName & "\root\cimv2")
$colDiskDrives = $oWMISvc.ExecQuery("SELECT * FROM Win32_DiskDrive")
For $oDiskDrive In $colDiskDrives
    ConsoleWrite("DiskDrive = " & $oDiskDrive.DeviceId & "  Caption = " & $oDiskDrive.Caption & @LF)

    $sQuery = "ASSOCIATORS OF {Win32_DiskDrive.DeviceID='" & $oDiskDrive.DeviceId & "'} WHERE AssocClass = Win32_DiskDriveToDiskPartition"
    $colPartitions = $oWMISvc.ExecQuery($sQuery)

    For $oPartition In $colPartitions
        ConsoleWrite(@TAB & "Partition = " & $oPartition.DeviceId & @LF)

        $sQuery = "ASSOCIATORS OF {Win32_DiskPartition.DeviceID='" & $oPartition.DeviceId & "'} WHERE AssocClass = Win32_LogicalDiskToPartition"
        $colLogicalDisks = $oWMISvc.ExecQuery($sQuery)

        For $oLogicalDisk In $colLogicalDisks
            ConsoleWrite(@TAB & @TAB & "LogicalDisk = " & $oLogicalDisk.DeviceId & @LF)
        Next
    Next
Next

 

Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...