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:
- 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.
- 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. ' It will also change the letter of any Removable Disks. This is to manage the Virtual Floppy device ' presented from the Dell Remote Access Controller (DRAC), which by default is connected starting from ' the letter C, and will break the Disk partitioning process. ' Release 1.3 Modified by Jeremy@jhouseconsulting.com on 14th June 2010 ' Written by Jeremy@jhouseconsulting.com on 30th September 2008. Option Explicit Dim blnDebug, arrReservedDrives, strComputer, objWMIService, colDisks, objDisk, strNewDriveLetter, x blnDebug = False ' Drive C: is always reserved. This array is setup to ensure that we reserve the first 6 drive letters for ' Fixed Disk partitions/volumes and H is typically used as a network home drive. arrReservedDrives = Array ("C:","D:","E:","F:","G:","H:") 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 If blnDebug Then wscript.echo objDisk.DeviceID & " is an Unknown device." Case 1 If blnDebug Then wscript.echo objDisk.DeviceID & " has No Root Directory." Case 2 If blnDebug Then wscript.echo objDisk.DeviceID & " is a Removable Disk." If instr(1,objDisk.Description,"Removable Disk",1) > 0 Then For x=0 to Ubound(arrReservedDrives) If StrComp(arrReservedDrives(x),objDisk.DeviceID) = 0 Then wscript.echo "There is a " & objDisk.Description & " connected as drive " & objDisk.DeviceID strNewDriveLetter=FindAvailableDriveLetter("Descending") Call ChangeDriveLetter(objDisk.DeviceID,strNewDriveLetter) wscript.echo "Changed the " & objDisk.Description & " from " & objDisk.DeviceID & " to " & strNewDriveLetter End If Next End If Case 3 If blnDebug Then wscript.echo objDisk.DeviceID & " is a Local (Fixed) Disk." Case 4 If blnDebug Then wscript.echo objDisk.DeviceID & " is a Network Drive." Case 5 If blnDebug Then wscript.echo objDisk.DeviceID & " is a CD-ROM or DVD-ROM Drive." For x=0 to Ubound(arrReservedDrives) If StrComp(arrReservedDrives(x),objDisk.DeviceID) = 0 Then wscript.echo "There is a " & objDisk.Description & " connected as drive " & objDisk.DeviceID strNewDriveLetter=FindAvailableDriveLetter("Descending") Call ChangeDriveLetter(objDisk.DeviceID,strNewDriveLetter) wscript.echo "Changed the " & objDisk.Description & " from " & objDisk.DeviceID & " to " & strNewDriveLetter End If Next Case 6 If blnDebug Then wscript.echo objDisk.DeviceID & " is a RAM Disk." Case Else If blnDebug Then wscript.echo objDisk.DeviceID & " is an undocumented device type." 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("X:","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