Contributor
Contributor

How to Add multiple drives to existing VMs

Jump to solution

Is there a way to add multiple disks in one shot to a VM?

I know it can be done with the new-vm cmdlet, and if I manually edit the VM I can add as many as I want.

The New-HardDisk cmdlet only allows for 1 at a time as far as I can tell.

Any suggestions?

1 Solution

Accepted Solutions
Leadership
Leadership

You are correct, the New-Harddisk cmdlet only allows the addition of 1 harddisk at the time.

If you want to add multiple harddisks you will have to use the ReconfigVM_Task method.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

View solution in original post

0 Kudos
11 Replies
Expert
Expert

do you want to add the same drive(s) to the vm(s)?

if so, you can create a script with a simple loop

$vms = get-vm

foreach ($vm in $vms) {

     New-HardDisk (insert specific command you want for disk 1) for $vm

     New-HardDisk (insert specific command you want for disk 2) for $vm

}

Obviously you need to correct syntax in the loop, but I am not sure the options you want.

0 Kudos
Leadership
Leadership

You are correct, the New-Harddisk cmdlet only allows the addition of 1 harddisk at the time.

If you want to add multiple harddisks you will have to use the ReconfigVM_Task method.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

View solution in original post

0 Kudos
Contributor
Contributor

Thanks, that seems like the correct path, though it might take a bit to wrap my head around it.

0 Kudos
Contributor
Contributor

Jpsider, this is the route I have been using but I figured there had to be a way to add more than one at a clip.

0 Kudos
Leadership
Leadership

If you need a sample script, let me know


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Contributor
Contributor

If you have a sample that would be amazing. I am just starting to work with ReconfigVM so any help would be greatly appreciated

0 Kudos
Contributor
Contributor

Are you just wanting to do a lot of disks on one vm or do you have a lot of vm's to go through and  it makes this procedure take a long time?

I'm currently working on the latter.  One to three disks to 80 vm's.  I was thinking maybe I could run the command as a job but I haven't worked through what all i need to carry to the remote job (variables, functions, pssnapins, etc.).

0 Kudos
Contributor
Contributor

It's really a mixture. I have a few hundred windows VMs that are being given replacements in a new environment. They want the same number of hard drives +20% space added to them and keep the same drive letters. This isn't really a big deal for servers that have 1-2 smaller disks, the New-HardDisk cmdlet is fine for these. But when I am trying to plow through 100+ VMs doing one drive on a VM at a time can be time consuming, especially on some that have 3-5 drives.

The ReconfigVM function allows for this but trying to find examples of syntax can be tough as I'm having a hard time finding a lot of documentation on it.

0 Kudos
Contributor
Contributor

If you have a sample that would be amazing. I am just starting to work with ReconfigVM so any help would be greatly appreciated

0 Kudos
Leadership
Leadership

This example just adds 2 harddisks (sizes 10GB and 20GB) to an existing VM.

Note that the script does not check if the controller has reached the maximum number of attached devices.

$vmName = 'MyVM'

$dsName = 'MyDS'

$hdSizeGB = 10,20

$vm = Get-VM -Name $vmName

$controller = Get-ScsiController -VM $vm

$hdUnitMax = (Get-HardDisk -VM $vm).ExtensionData.UnitNumber | Measure-Object -Maximum | select -ExpandProperty Maximum

$spec = New-Object -TypeName VMware.Vim.VirtualMachineConfigSpec

$i = 0

foreach($size in $hdSizeGB){

    $devSpec = New-Object -TypeName VMware.Vim.VirtualDeviceConfigSpec

    $hd = New-Object -TypeName VMware.Vim.VirtualDisk

    $back = New-Object -TypeName VMware.Vim.VirtualDiskFlatVer2BackingInfo

    $back.datastore = $ds.ExtensionData.MoRef

    $back.FileName = "[$($dsName)]"

    $back.diskMode = 'persistent'

    $hd.backing = $back

    $hd.CapacityInKB = $size * 1MB

    $hd.Key = -100 - $i++

    $hd.controllerKey = $controller.ExtensionData.Key

    $hd.UnitNumber = ++$hdUnitMax

    $devSpec.Operation = 'Add'

    $devSpec.FileOperation = 'Create'

    $devSpec.Device = $hd

    $spec.DeviceChange += $devSpec

}

$vm.ExtensionData.ReconfigVM($spec)


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
Contributor
Contributor

Not sure if this will help but this is GUI I pieced together and had in a section of a New VM from template script. My script goes through the cloning from template, creating a Customization script, setting the IP assigned for the VM, prompting for CPU, RAM, Primary drive space, and addtional drives. Here is the portion for the drive space add. There is a piece of this script for a New-popup function and I did not create this, I found it while scouring the internet one day for portions of scripts, props to the original writer.

First GUI option asks for vcenter name and VMName.

Next option prompts for the number of drives needing to be added to the VM

Finally the GUI prompts for the size of the drives being added, one prompt for each number of drives, i.e. if you say you want to add 3 drives you will be prompted for 3 drive sizes.

Drive sizes are in GB sizes.

Here is my GUI, the GUI could be removed and this could just be made into Read-host options:

Add-PSSnapin VM*

function button ($title, $vCenter, $VMName) {

###################Load Assembly for creating form & button######

[void][System.Reflection.Assembly]::LoadWithPartialName( “System.Windows.Forms”)

[void][System.Reflection.Assembly]::LoadWithPartialName( “Microsoft.VisualBasic”)

#####Define the form size & placement

$form = New-Object “System.Windows.Forms.Form”

$form.Width = 350;

$form.Height = 200;

$form.Text = $title;

$form.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen;

##############Define text label1

$textLabel1 = New-Object “System.Windows.Forms.Label”;

$textLabel1.Left = 25;

$textLabel1.Top = 15;

$textLabel1.AutoSize = $True;

$textLabel1.Text = $vCenter;

##############Define text label2

$textLabel2 = New-Object “System.Windows.Forms.Label”;

$textLabel2.Left = 25;

$textLabel2.Top = 55;

$textLabel2.AutoSize = $True;

$textLabel2.Text = $VMName;

#########END OF TEXT LABELS####################################

############Define text box1 for input

$textBox1 = New-Object “System.Windows.Forms.TextBox”;

$textBox1.Left = 150;

$textBox1.Top = 10;

$textBox1.width = 150;

############Define text box2 for input

$textBox2 = New-Object “System.Windows.Forms.TextBox”;

$textBox2.Left = 150;

$textBox2.Top = 50;

$textBox2.width = 150;

###################END OF TEXT BOX INPUT####################

#############Define default values for the input boxes

$defaultValue = “”

$textBox1.Text = $defaultValue;

$textBox2.Text = $defaultValue;

#############define OK button

$button = New-Object “System.Windows.Forms.Button”;

$button.Left = 200;

$button.Top = 100;

$button.Width = 75;

$button.Text = “Ok”;

############# This is when you have to close the form after getting values

$eventHandler = [System.EventHandler]{

$textBox1.Text;

$textBox2.Text;

$form.Close();};

$button.Add_Click($eventHandler) ;

#############Add controls to all the above objects defined

$form.Controls.Add($button);

$form.Controls.Add($textLabel1);

$form.Controls.Add($textLabel2);

$form.Controls.Add($textBox1);

$form.Controls.Add($textBox2);

$ret = $form.ShowDialog();

#################return values

return $textBox1.Text, $textBox2.Text

}

$return = button “Add Disks to VM” "Enter vCenter Name" “Enter VM Name”

$vCenter = $return[0]

$VMName = $return[1]

Function New-Popup {

### I do not claim ownership of this Function, I found it one day poking around the internet

#<

.Synopsis

Display a Popup Message

.Description

This command uses the Wscript.Shell PopUp method to display a graphical message

box. You can customize its appearance of icons and buttons. By default the user

must click a button to dismiss but you can set a timeout value in seconds to

automatically dismiss the popup.

The command will write the return value of the clicked button to the pipeline:

OK     = 1

  Cancel = 2

  Abort  = 3

  Retry  = 4

  Ignore = 5

  Yes    = 6

  No     = 7

If no button is clicked, the return value is -1.

.Example

PS: new-popup -message "The update script has completed" -title "Finished" -time 5

This will display a popup message using the default OK button and default

Information icon. The popup will automatically dismiss after 5 seconds.

.Notes

Last Updated: April 8, 2013

Version     : 1.0

.Inputs

None

.Outputs

integer

Null   = -1

OK     = 1

Cancel = 2

Abort  = 3

Retry  = 4

Ignore = 5

Yes    = 6

No     = 7

#>

Param (

[Parameter(Position=0,Mandatory=$True,HelpMessage="Enter a message for the popup")]

[ValidateNotNullorEmpty()]

[string]$Message,

[Parameter(Position=1,Mandatory=$True,HelpMessage="Enter a title for the popup")]

[ValidateNotNullorEmpty()]

[string]$Title,

[Parameter(Position=2,HelpMessage="How many seconds to display? Use 0 require a button click.")]

[ValidateScript({$_ -ge 0})]

[int]$Time=0,

[Parameter(Position=3,HelpMessage="Enter a button group")]

[ValidateNotNullorEmpty()]

[ValidateSet("OK","OKCancel","AbortRetryIgnore","YesNo","YesNoCancel","RetryCancel")]

[string]$Buttons="OK",

[Parameter(Position=4,HelpMessage="Enter an icon set")]

[ValidateNotNullorEmpty()]

[ValidateSet("Stop","Question","Exclamation","Information" )]

[string]$Icon="Information"

)

#convert buttons to their integer equivalents

Switch ($Buttons) {

    "OK"               {$ButtonValue = 0}

    "OKCancel"         {$ButtonValue = 1}

    "AbortRetryIgnore" {$ButtonValue = 2}

    "YesNo"            {$ButtonValue = 4}

    "YesNoCancel"      {$ButtonValue = 3}

    "RetryCancel"      {$ButtonValue = 5}

}

#set an integer value for Icon type

Switch ($Icon) {

    "Stop"        {$iconValue = 16}

    "Question"    {$iconValue = 32}

    "Exclamation" {$iconValue = 48}

    "Information" {$iconValue = 64}

}

#create the COM Object

Try {

    $wshell = New-Object -ComObject Wscript.Shell -ErrorAction Stop

    #Button and icon type values are added together to create an integer value

    $wshell.Popup($Message,$Time,$Title,$ButtonValue+$iconValue)

}

Catch {

    #You should never really run into an exception in normal usage

    Write-Warning "Failed to create Wscript.Shell COM object"

    Write-Warning $_.exception.message

}

} #end function

##############################################################################

### Prompting for Credentials                                    #############

$cred = Get-Credential $null

##############################################################################

### Connecting to vCenter                                        #############

Connect-VIServer -credential $cred -Server $vCenter | Out-Null

##############################################################################

### Finding Datastore VM is located on                           #############

$data = Get-VM "$VMName" | Get-Datastore

##############################################################################

### Building Prompts for Adding additional Drives to New VM      #############

$YN = New-Popup -Title "Add Additional Drives?" -Message "Do you want to add additional drives to $VMName" -Buttons YesNo -Icon Question

if($YN -eq "7"){

New-Popup -Title "No Additional Drives Added" -Message "You have chosen not to add addtional drives to the VM" -Time 5 | Out-Null

}

if ($YN -eq "6"){

### Building Yes No Prompt                                       #############

[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")

[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")

### Setting Window Title                                         #############

$objForm = New-Object System.Windows.Forms.Form

$objForm.Text = "Number of Drives"

$objForm.Size = New-Object System.Drawing.Size(300,200)

$objForm.StartPosition = "CenterScreen"

$objForm.KeyPreview = $True

$objForm.Add_KeyDown({if ($_.KeyCode -eq "Enter")

    {$x=$objTextBox.Text;$objForm.Close()}})

$objForm.Add_KeyDown({if ($_.KeyCode -eq "Escape")

    {$objForm.Close()}})

### Setting Ok Button                                            #############

$OKButton = New-Object System.Windows.Forms.Button

$OKButton.Location = New-Object System.Drawing.Size(75,120)

$OKButton.Size = New-Object System.Drawing.Size(75,23)

$OKButton.Text = "OK"

$OKButton.Add_Click({$x=$objTextBox.Text;$objForm.Close()})

$objForm.Controls.Add($OKButton)

### Setting Cancel Button                                        #############

$CancelButton = New-Object System.Windows.Forms.Button

$CancelButton.Location = New-Object System.Drawing.Size(150,120)

$CancelButton.Size = New-Object System.Drawing.Size(75,23)

$CancelButton.Text = "Cancel"

$CancelButton.Add_Click({$objForm.Close()})

$objForm.Controls.Add($CancelButton)

### Setting Window Text Label                                    #############

$objLabel = New-Object System.Windows.Forms.Label

$objLabel.Location = New-Object System.Drawing.Size(10,20)

$objLabel.Size = New-Object System.Drawing.Size(280,20)

$objLabel.Text = "Enter Number if Drives Needed:"

$objForm.Controls.Add($objLabel)

### Setting the TextBox for Input                                #############

$objTextBox = New-Object System.Windows.Forms.TextBox

$objTextBox.Location = New-Object System.Drawing.Size(10,40)

$objTextBox.Size = New-Object System.Drawing.Size(260,20)

$objForm.Controls.Add($objTextBox)

$objForm.Topmost = $True

$objForm.Add_Shown({$objForm.Activate()})

[void] $objForm.ShowDialog()

### Assigning Text Box input to variable $Num

$Num = $ObjTextBox.Text

### Logic Check to see if Drives Needed is 0 or blank

if ($Num -eq "0" -or [string]::IsNullOrEmpty($Num)){

New-Popup -Title "No Drives" -Message "You have selected either Blank or Zero drives to added. Moving on in script" -Time 3 | Out-Null

}

### End of Yes No Prompt                                         #############

##############################################################################

##############################################################################

### Generating a Pop-Up to request number of drives and total GB #############

### for each. This is a loop that cycles through the total       #############

### count for the variable $Num                                  #############

### Beginning of Loop

for($item=1;$item -le $num;$item++){

New-Popup -Title "Adding Requested Extra Drives..." -Message "In order to add additional drives a prompt will appear requesting the drive(s) sizes." -Time 5 -Icon Information | Out-Null

[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")

[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")

$objForm = New-Object System.Windows.Forms.Form

$objForm.Text = "Additional Drive Entry"

$objForm.Size = New-Object System.Drawing.Size(300,200)

$objForm.StartPosition = "CenterScreen"

$objForm.KeyPreview = $True

$objForm.Add_KeyDown({if ($_.KeyCode -eq "Enter")

    {$x=$objTextBox.Text;$objForm.Close()}})

$objForm.Add_KeyDown({if ($_.KeyCode -eq "Escape")

    {$objForm.Close()}})

$OKButton = New-Object System.Windows.Forms.Button

$OKButton.Location = New-Object System.Drawing.Size(75,120)

$OKButton.Size = New-Object System.Drawing.Size(75,23)

$OKButton.Text = "OK"

$OKButton.Add_Click({$x=$objTextBox.Text;$objForm.Close()})

$objForm.Controls.Add($OKButton)

$CancelButton = New-Object System.Windows.Forms.Button

$CancelButton.Location = New-Object System.Drawing.Size(150,120)

$CancelButton.Size = New-Object System.Drawing.Size(75,23)

$CancelButton.Text = "Cancel"

$CancelButton.Add_Click({$objForm.Close()})

$objForm.Controls.Add($CancelButton)

$objLabel = New-Object System.Windows.Forms.Label

$objLabel.Location = New-Object System.Drawing.Size(10,20)

$objLabel.Size = New-Object System.Drawing.Size(280,20)

$objLabel.Text = "Enter Size of the Drive(s) in GB in the space below:"

$objForm.Controls.Add($objLabel)

$objTextBox = New-Object System.Windows.Forms.TextBox

$objTextBox.Location = New-Object System.Drawing.Size(10,40)

$objTextBox.Size = New-Object System.Drawing.Size(260,20)

$objForm.Controls.Add($objTextBox)

$objForm.Topmost = $True

$objForm.Add_Shown({$objForm.Activate()})

[void] $objForm.ShowDialog()

$size = $ObjTextBox.Text

### End of Size of Drive Prompt                                  #############

##############################################################################

### Executing the Add new disk portion                                     ###

##############################################################################

New-Popup -Title "Adding Drive $item" -Message "Adding new $size GB to $VMName" -Time 3 | Out-Null

### Change Storage Format to change the type Thin, Thick, EagerZeroedThick

### or you could add a textbox in the GUI for selecting this option

New-HardDisk -vm "$vmname" -CapacityGB $size -Datastore $data -StorageFormat Thin | Out-Null # for Log edit out all prior text including pound AKA Comment | Select Name , CapacityGB , StorageFormat , Parent | FT -AutoSize |  Out-file c:\Temp\drives.txt -Append -Force

}

}

}

### End of Loop

Disconnect-VIServer -Server * -Confirm:$false