Skip to content

Intelligently changing the drive letter assignment for multiple CD/DVD ROM Drives

Diskpart may fail when creating more than one partition when executing the “assign letter=D” command. This is because Windows, WinPE included, by default assigns the first CD-ROM “type” drive to the first available letter after C:. So if you are partitioning a new server, or repartitioning a server that contains only 1 partition (C:), the CD-ROM drive will be assigned to D:. Therefore, if you were creating more than one partition and wanted to assign letter D: to the second partition, it would fail.

The other challenge is that sometimes you may see more than one CD-ROM “type” drive, as booting up using an ISO image is considered to be one, plus the server may actually have a physical one too, which would be assigned to letter E:.

The script below searches all logical disks, locates the CD-ROM “type” drives, and changes their drive letters starting from Z: and working backwards. This ensure that they do not interfere with any further Diskpart operations.

I have used two arrays:

  1. arrReservedDrives - used to reserve drive letters D:, E: and F:. If a CD-ROM “type” drive matches these letters, its drive letter is changed. You can certainly add letters to, or remove letters from this array.
  2. arrReservedLetters - used to reserve any other drive letters, such as network drives, etc. I have reserved I: and S: because those are network drives used by my automated build process.
You could easily extend this script to also manage the drive letters assigned to removable drives, etc.

Enjoy!!!


' This script will change the drive letter of any CD/DVD ROM drive(s) attached to a drive letter that is
' not in use starting from the Z: drive.

' Written by Jeremy@jhouseconsulting.com on 30th September 2008.

Option Explicit

Dim arrReservedDrives, strComputer, objWMIService, colDisks, objDisk, strNewDriveLetter, x

' Drive C: is always reserved. This array is setup to ensure that we reserve the first 4 drive letters for
' Fixed Disk partitions/volumes.
arrReservedDrives = Array ("D:", "E:", "F:")

  strComputer = "."
  Set objWMIService = GetObject("winmgmts:\" & strComputer & "\root\cimv2")
  Set colDisks = objWMIService.ExecQuery("Select * from Win32_LogicalDisk")
  For Each objDisk in colDisks
    Select Case objDisk.DriveType
      Case 0
'       Unknown
      Case 1
'       No Root Directory
      Case 2
'       Removable Disk
      Case 3
'       Local (Fixed) Disk
      Case 4
'       Network Drive
      Case 5
'       CD-ROM or DVD-ROM
        For x=0 to Ubound(arrReservedDrives)
          If StrComp(arrReservedDrives(x),objDisk.DeviceID) = 0 Then
            strNewDriveLetter=FindAvailableDriveLetter("Descending")
            Call ChangeDriveLetter(objDisk.DeviceID,strNewDriveLetter)
            wscript.echo "Changed the " & objDisk.Description & " from " & objDisk.DeviceID & " to " & strNewDriveLetter
          End If
        Next
      Case 6
'       RAM Disk
    End Select
  Next

Set objWMIService = Nothing
Set colDisks = Nothing

wscript.quit(0)

Sub ChangeDriveLetter(strCurrentLetter,strNewLetter)
  Dim arrDefaultString, WshShell, objFSO, strDiskPartFile, objOutFile, strCommandLine
  Const FOR_WRITING = 2
  arrDefaultString = Array ("select volume ", "remove noerr", "assign letter ", "exit")
  set WshShell = WScript.CreateObject("WScript.Shell")
  Set objFSO = CreateObject("Scripting.FileSystemObject")
  strDiskPartFile = WshShell.ExpandEnvironmentStrings("%TEMP%\Diskpart.txt")
  Set objOutFile = objfso.CreateTextFile(strDiskPartFile, True)
  objOutFile.WriteLine arrDefaultString(0) & strCurrentLetter
  objOutFile.WriteLine arrDefaultString(1)
  objOutFile.WriteLine arrDefaultString(2) & strNewLetter
  objOutFile.WriteLine arrDefaultString(3)
  objOutFile.close
  strCommandLine = "diskpart.exe /S " & chr(34) & strDiskPartFile & chr(34)
  WshShell.Run strCommandLine, 2, true
  set WshShell = Nothing
  Set objFSO = Nothing
  Set objOutFile = Nothing
End Sub

Function FindAvailableDriveLetter(strDirection)

' The purpose of this function is to take the current drive letters, plus any reservations as per arrReservedLetters,
' and return the next available drive letter from either direction as specified. This script is great for changing the
' drive letter of CD/DVD ROM drives, etc.
' Based on an article by the Scripting Guy titled "How Can I Determine the Next Available Drive Letter on a Computer?"
' found: http://www.microsoft.com/technet/scriptcenter/resources/qanda/jan05/hey0122.mspx

' Call this function by either of the two following methods.
' strNewDriveLetter=FindAvailableDriveLetter("Descending")
' strNewDriveLetter=FindAvailableDriveLetter("Ascending")

  Dim arrReservedLetters, objDictionary, strComputer, objWMIService, colDisks, objDisk
  Dim i, strDrive, intStart, intFinish, intStep

  arrReservedLetters = Array("I:", "S:")

  Set objDictionary = CreateObject("Scripting.Dictionary")

  strComputer = "."
  Set objWMIService = GetObject("winmgmts:\" & strComputer & "\root\cimv2")
  Set colDisks = objWMIService.ExecQuery("Select * from Win32_LogicalDisk")
  For Each objDisk in colDisks
    objDictionary.Add objDisk.DeviceID, objDisk.DeviceID
  Next

' If the reserved drive letter(s) are already in-use, such as network drives already mapped when this script runs, this
' process will fail with the error "This key is already associated with an element of this collection", which is error
' 457, so we need to use an "On Error Resume Next" to tell it to continue on errors.
  For i = 0 to UBound(arrReservedLetters)
    On Error Resume Next
    wscript.echo "Reserving drive letter " & arrReservedLetters(i)
    objDictionary.Add arrReservedLetters(i), arrReservedLetters(i)
    If Err.Number = 457 Then
      wscript.echo "Drive letter " & arrReservedLetters(i) & " has already been reserved because it's already in use."
    ElseIf Err.Number <> 0 Then
      wscript.echo Err.Description
    End If
    On Error Goto 0
  Next

' Note to understand this process 71 ASCII = CHAR G and 90 ASCII = CHAR Z
  Select Case lcase(strDirection)
    Case "descending"
      intStart = 90
      intFinish = 71
      intStep = -1
    Case "ascending"
      intStart = 71
      intFinish = 90
      intStep = 1
  End Select

  For i = intStart to intFinish step intStep
    strDrive = Chr(i) & ":"
    If objDictionary.Exists(strDrive) Then
    Else
'      Wscript.Echo strDrive & " is the next available drive letter."
      FindAvailableDriveLetter = strDrive
      Set objDictionary = Nothing
      Set objWMIService = Nothing
      Set colDisks = Nothing
      Exit Function
    End If
  Next

  Wscript.Echo "There are no available drive letters on this computer."
  Set objDictionary = Nothing
  Set objWMIService = Nothing
  Set colDisks = Nothing
  wscript.quit(0)

End Function

  • Technotizie
  • Google Bookmarks
  • Facebook
  • Delicious
  • LinkedIn
  • Twitter
  • Technorati Favorites
  • Digg
  • Share/Save/Bookmark

Post a Comment

Your email is never published nor shared. Required fields are marked *
*
*

Spam protection by WP Captcha-Free