I'm new to PowerCLI and can't seem to find any 'newer' information on this process.
I'm attempting to automate the adding of a cloned hard drive (VMDK) from VM(1) to another existing VM(2). I figured out how to "Copy-HardDisk" of VM1 to the datastore of VM2, but can't seem the formula to attach it to VM2.
To copy the disk, I'm using the following command:
$vm1 = "vm1 name"
$vm2 = "vm2 name"
$ds = "datastore"
Get-HardDisk -VM $vm1 | Where {$_.CapacityGB -lt 10} | Copy-HardDisk -DestinationPath "[$ds] $vm2/$vm2-2.vmdk" -Force
Here is actually what it looks like:
Get-HardDisk -VM System1 | Where {$_.CapacityGB -lt 10} | Copy-HardDisk -DestinationPath "[NFS2] System2/System2-2.vmdk" -Force
The GUI way we do this today via vCenter is - Edit Setting s > Hardware tab > Add > Hard Disk > Use an existing virtual disk > Browse > Verify the Virtual Device Node (SCSI (0:x) - and it works. I can boot VM2 and the Windows OS works fine and everyone is happy.
To attach the hard disk via PowerCLI, I'm using the following command:
New-HardDisk -VM $vm2 -DiskPath "[$ds] $vm2/$vm2-2.vmdk"
Here is actually what it looks like:
New-HardDisk -VM System2 -DiskPath "[NFS2] System2/System2-2.vmdk"
When I run the command, I see vCenter 'working' and then errors out with Incompatible device backing specified for device '0'. I've ready many forums stating the error when doing a RDM or attempting to add a secondary SCSI controller which I don't want to do.
A few things to note:
Needs to be on the default SCSI controller 0 (Virtual LSI Logic SAS)
Virtual device node needs to be SCSI 0:2 (this would be a third drive on the system)
The datastore is a different datastore than the other disks attached to VM2 (disks 1 and 2 are on NFS1, new disk would be on NFS2).
When I first copy the disk, it states the Persistence as Unknown, not sure if this is a factor. Any help would be appreciated.
ESXi, 5.0 Update 1 (5.0.0,821926)
PowerCLI 5.5 Release 2
Thanks,
SC
Lol, I'll type slowly :smileylaugh:
No, I'm afraid we can't change the API, nor the coding behind the cmdlet.
But we can call the API directly from within PowerCLI, something like this for example
function add-HD {
param($VMname, $Filename, $Controller)
$dsName = $Filename.Split(']')[0].TrimStart('[')
$vm = (Get-VM $VMname).ExtensionData
$ds = (Get-Datastore -Name $dsName).ExtensionData
foreach($dev in $vm.config.hardware.device){
if ($dev.deviceInfo.label -eq $Controller){
$CntrlKey = $dev.key
}
}
$Unitnumber = 0
$DevKey = 0
foreach($dev in $vm.config.hardware.device){
if ($dev.controllerKey -eq $CntrlKey){
if ($dev.Unitnumber -gt $Unitnumber){$Unitnumber = $dev.Unitnumber}
if ($dev.key -gt $DevKey) {$DevKey = $dev.key}
}
}
$spec = New-Object VMware.Vim.VirtualMachineConfigSpec
$spec.deviceChange = @()
$spec.deviceChange += New-Object VMware.Vim.VirtualDeviceConfigSpec
$spec.deviceChange[0].device = New-Object VMware.Vim.VirtualDisk
$spec.deviceChange[0].device.backing = New-Object VMware.Vim.VirtualDiskFlatVer2BackingInfo
$spec.deviceChange[0].device.backing.datastore = $ds.MoRef
$spec.deviceChange[0].device.backing.fileName = $Filename
$spec.deviceChange[0].device.backing.diskMode = "independent_persistent"
$spec.deviceChange[0].device.key = $DevKey + 1
## The UnitNUmber SCSIID 7 is reserved for the Controller - so ignore it and skip to 8.
if ($Unitnumber -eq 6) {$Unitnumber = $Unitnumber + 1}
$spec.deviceChange[0].device.unitnumber = $Unitnumber + 1
$spec.deviceChange[0].device.controllerKey = $CntrlKey
$spec.deviceChange[0].operation = "add"
$vm.ReconfigVM_Task($spec)
}
Add-HD -VMname "System2" -FileName "[NFS2] System2/System2-2.vmdk" -Controller "SCSI Controller 0"
I created a function, called Add-HD, that will do more or less the same thing as the New-Harddisk cmdlet does when used with the Filename parameter, but instead of calling the cmdlet, the function calls the API method ReconfigVM_Task directly.
The disadvantage of this is, that we will have to compile the parameter that is passed to this method.
In fact, most of the PowerCLI cmdlets are doing exactly the same thing, they are calling the API methods.
You can see these calls when you trace a cmdlet with the Onyx tool.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Did you already try adding "-Persistence Persistent" to the New-Harddisk cmdlet ?
I suspect the New-HardDisk cmdlet might be using an incorrect default in the underlying API it calls.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Attempted adding '-Persistence Persistent" as well as '-Controller "name"' with no luck. Still getting Incompatible device backing specified for device '0'.
Tried the following with no luck:
New-HardDisk -VM System2 -Persistence Persistent -DiskPath "[NFS2] System2/System2-2.vmdk"
New-HardDisk -VM System2 -Persistence Persistent -Controller "SCSI controller 0" -DiskPath "[NFS2] System2/System2-2.vmdk"
Is there a way to correct the API's? (speak... slowly... please...)
Thanks for the quick responce LucD22.
Lol, I'll type slowly :smileylaugh:
No, I'm afraid we can't change the API, nor the coding behind the cmdlet.
But we can call the API directly from within PowerCLI, something like this for example
function add-HD {
param($VMname, $Filename, $Controller)
$dsName = $Filename.Split(']')[0].TrimStart('[')
$vm = (Get-VM $VMname).ExtensionData
$ds = (Get-Datastore -Name $dsName).ExtensionData
foreach($dev in $vm.config.hardware.device){
if ($dev.deviceInfo.label -eq $Controller){
$CntrlKey = $dev.key
}
}
$Unitnumber = 0
$DevKey = 0
foreach($dev in $vm.config.hardware.device){
if ($dev.controllerKey -eq $CntrlKey){
if ($dev.Unitnumber -gt $Unitnumber){$Unitnumber = $dev.Unitnumber}
if ($dev.key -gt $DevKey) {$DevKey = $dev.key}
}
}
$spec = New-Object VMware.Vim.VirtualMachineConfigSpec
$spec.deviceChange = @()
$spec.deviceChange += New-Object VMware.Vim.VirtualDeviceConfigSpec
$spec.deviceChange[0].device = New-Object VMware.Vim.VirtualDisk
$spec.deviceChange[0].device.backing = New-Object VMware.Vim.VirtualDiskFlatVer2BackingInfo
$spec.deviceChange[0].device.backing.datastore = $ds.MoRef
$spec.deviceChange[0].device.backing.fileName = $Filename
$spec.deviceChange[0].device.backing.diskMode = "independent_persistent"
$spec.deviceChange[0].device.key = $DevKey + 1
## The UnitNUmber SCSIID 7 is reserved for the Controller - so ignore it and skip to 8.
if ($Unitnumber -eq 6) {$Unitnumber = $Unitnumber + 1}
$spec.deviceChange[0].device.unitnumber = $Unitnumber + 1
$spec.deviceChange[0].device.controllerKey = $CntrlKey
$spec.deviceChange[0].operation = "add"
$vm.ReconfigVM_Task($spec)
}
Add-HD -VMname "System2" -FileName "[NFS2] System2/System2-2.vmdk" -Controller "SCSI Controller 0"
I created a function, called Add-HD, that will do more or less the same thing as the New-Harddisk cmdlet does when used with the Filename parameter, but instead of calling the cmdlet, the function calls the API method ReconfigVM_Task directly.
The disadvantage of this is, that we will have to compile the parameter that is passed to this method.
In fact, most of the PowerCLI cmdlets are doing exactly the same thing, they are calling the API methods.
You can see these calls when you trace a cmdlet with the Onyx tool.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
You are invaluable LucD!!
The Add-HD function call works great. I also took a look at Onyx, what a great tool!!
Thanks for your assistance and introducing me to a great troubleshooting tool.
All the best,
SC
This works flawlessly.
Thank you!