Force a VM to boot from several devices

One thing vCO users and administrators always ask for is changing the boot order for virtual machines. The bad news is: It is part of the BIOS of the virtual machine (.nvram). But based on this community discussion and the solutions in PowerShell, I decided to test it with the vCenter Orchestrator and I was surprised how easy it is!

1
2
3
4
5
6
7
var changedValue = new Array();
changedValue[0] = new VcOptionValue(); 
changedValue[0].key = "bios.bootDeviceClasses"; 
changedValue[0].value = "allow:"+device; 
var ConfigSpec = new VcVirtualMachineConfigSpec(); 
ConfigSpec.extraConfig = changedValue; 
task = vm.reconfigVM_Task(ConfigSpec);

With this little code you are able to set the VcOptionValue for the virtual machine. I used 2 input parameters: the vm(VC:VirtualMachine) and device(string) for defining which device should be used (cd, net, hd). Based on the selected device the VM is reconfigured and starts only from this device. Please keep in mind to change it back!

To review the settings I use a second simple workflow:

1
2
3
4
5
System.log(vm.config.extraConfig.length); 
for(i in vm.config.extraConfig){
 System.log("Key: " + vm.config.extraConfig[i].key);
 System.log("Value: " + vm.config.extraConfig[i].value); 
}

which shows all keys and values of the virtual machine .extraConfig definition. So, as you can see, really simple thing


Example for vCenter 5.5+: (slightly different than the above) - updating Feb 12, 2015

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
var ethValue = new VcVirtualMachineBootOptionsBootableEthernetDevice();
ethValue.DeviceKey = "4000";
var hddValue = new VcVirtualMachineBootOptionsBootableDiskDevice();
hddValue.DeviceKey = "2000";
var changedValue = new VcVirtualMachineBootOptions();

changedValue.BootOrder = new Array(ethValue, hddValue);
var ConfigSpec = new VcVirtualMachineConfigSpec();
ConfigSpec.BootOptions = changedValue;
task = vm.reconfigVM_Task(ConfigSpec);


The example code above assumes the device keys of 4000 and 2000 for the Nic and HD respectively. You should change these as needed for your environment, or better - update the code to dynamically grab the appropriate DeviceKey property based on your boot order selection. The script above takes an input named "vm" of type "VC:VirtualMachine".

UPDATE - Sep, 2017: from the comments below, adding code snippet fromThe Butsch - thanks for sharing!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
var devices = virtualMachine.config.hardware.device;

for ( i in devices )  {
  if (devices[i] instanceof VcVirtualCdrom)  
	{
	    var cdKey = devices[i].key;
		System.log("cdkey "+cdKey);		
	}
  if (devices[i] instanceof VcVirtualDisk)  
	{
	  var hddKey = devices[i].key;
	  var label = devices[i].deviceInfo.label;
      //looking for Festplatte 1 or Hard Disk 1, hopefully there is no 10th disk
	  if(label.indexOf("1") != -1)
		{
		System.log("hddkey "+hddKey);		
		}
    }
   if (devices[i] instanceof VcVirtualVmxnet    
	   || devices[i] instanceof VcVirtualVmxnet2    
	   || devices[i] instanceof VcVirtualVmxnet3  
	   || devices[i] instanceof VcVirtualE1000    
	   || devices[i] instanceof VcVirtualPCNet32    
	   || devices[i] instanceof VcVirtualEthernetCard)   
	 {
	   var ethKey = devices[i].key;
		System.log("ethkey "+ethKey);		
	 }
} //end for

var eth = new VcVirtualMachineBootOptionsBootableEthernetDevice();
eth.DeviceKey = ethKey;
var hdd = new VcVirtualMachineBootOptionsBootableDiskDevice();
hdd.DeviceKey = hddKey;
var cd = new VcVirtualMachineBootOptionsBootableCdromDevice();
//VcVirtualMachineBootOptionsBootableCdromDevice doesn't have the DeviceKey property
//cd.DeviceKey = cdKey; 

var changedValue = new VcVirtualMachineBootOptions();
 
changedValue.BootOrder = new Array(cd, hdd, eth);
//changedValue.BootOrder = new Array(hdd, cd, eth);
//changedValue.BootOrder = new Array(eth, cd, hdd);
var ConfigSpec = new VcVirtualMachineConfigSpec();
ConfigSpec.BootOptions = changedValue;
task = virtualMachine.reconfigVM_Task(ConfigSpec);