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?
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
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.
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
Thanks, that seems like the correct path, though it might take a bit to wrap my head around it.
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.
If you need a sample script, let me know
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
If you have a sample that would be amazing. I am just starting to work with ReconfigVM so any help would be greatly appreciated
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.).
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.
If you have a sample that would be amazing. I am just starting to work with ReconfigVM so any help would be greatly appreciated
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
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