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
