dimanche, août 14, 2011

Creating and starting VirtualBox machine with PowerShell

BSD Router Project provided a VBScript for starting MS Windows based virtualbox lab. But because this vbs script works only on XP, I had to found a more powerful solution: Why not discovering PowerShell and using the VirtualBox COM API ?
I didn't found very detailed examples, then here is a PowerShell script that explains how to create, configure and start a VirtualBox Machine.
The goal is:
  1. Create a VM (OS type: FreeBSD_64)
  2. Configure it (with a serial port that redirect to a pipe)
  3. Convert a unzipped BSDRP-full-amd64-vga disk image file to a VDI file, and attach this VDI to the VM
  4. Start the VM
And here are the big steps of this script:
  1. Initialize the COM API
  2. Create the VM
  3. Configure the VM (excluding attaching medium to it)
  4. Save and register the VM
  5. Convert a RAW file to VDI (using VBoxManage.exe) and registering it
  6. Lock the VM in write mode for attaching the medium
  7. Launch the VM
Now the PowerShell code sample:


#
# VirtualBox COM API PowerShell sample script
# Example for BSD Router Project (http://bsdrp.net)

$erroractionpreference = "Stop"

#### Declaring enumeration types ######
# PowerShell can't import type library from a COM Object
# http://msdn.microsoft.com/en-us/library/hh228154.aspx
# Need to copy/write all enums type used in this script
# You can use the official API doc:
#     http://www.virtualbox.org/sdkref/index.html
# Or extracting values with oleview.exe

#StorageBus
$StorageBus_IDE = 1
$StorageBus_SATA = 2
$StorageBus_SCSI = 3
$StorageBus_Floppy = 4
$StorageBus_SAS = 5

#StorageControllerType
$StorageControllerType_LsiLogic = 1
$StorageControllerType_BusLogic = 2
$StorageControllerType_IntelAhci = 3
$StorageControllerType_PIIX3 = 4
$StorageControllerType_PIIX4 = 5
$StorageControllerType_ICH6 = 6
$StorageControllerType_I82078 = 7
$StorageControllerType_LsiLogicSas = 8

#DeviceType
$DeviceType_Null = 0
$DeviceType_Floppy = 1
$DeviceType_DVD = 2
$DeviceType_HardDisk = 3
$DeviceType_Network = 4
$DeviceType_USB = 5
$DeviceType_SharedFolder = 6

#AccessMode
$AccessMode_ReadOnly = 1
$AccessMode_ReadWrite = 2

#LockType
$LockType_Write = 2
$LockType_Shared = 1

#PortMode (serial)
$PortMode_Disconnected = 0
$PortMode_HostPipe = 1
$PortMode_HostDevice = 2
$PortMode_RawFile = 3
       
#### Scripts Variables #####

#Machine name
$MACHINE_NAME="BSDRP_template"

#OS type
$MACHINE_ARCH="FreeBSD_64"

#Raw image disk filename
$RAW_FILE="C:\BSDRP_0.35_full_amd64_vga.img"

### Here we go

write-host "First step: initialize the COM API"

# Initialize the main VirtualBox COM Object
$VIRTUALBOX = New-Object -ComObject VirtualBox.VirtualBox

write-host "Second step: Create the VM"

# Create VM
$MACHINE=$VIRTUALBOX.createMachine("",$MACHINE_NAME,$MACHINE_ARCH,"",$false)
#As the new machine will not be registered, it's in mutable (modifiable) status

Write-Host "Third step: Configuring the VM (excluding attaching medium to it)"

# Configure the VM
$MACHINE.MemorySize=128
$MACHINE.VRAMSize=6
$MACHINE.Description="BSD Router Project - Template VM"
$MACHINE.setBootOrder(1,$DeviceType_HardDisk)
$MACHINE.setBootOrder(2,$DeviceType_Null)
$MACHINE.setBootOrder(3,$DeviceType_Null)
$MACHINE.setBootOrder(4,$DeviceType_Null)

# Serial port
# Link the VM serial port to a pipe into the host
# You can connect, from the host, to the serial port of the VM
$MACHINE_SERIAL=$MACHINE.getSerialPort(0)
$MACHINE_SERIAL.path="\\.\pipe\$MACHINE_NAME"
$MACHINE_SERIAL.hostMode=$PortMode_HostPipe
$MACHINE_SERIAL.server=$true
$MACHINE_SERIAL.enabled=$true

# Adding a disk controller
$MACHINE_CTRL=$MACHINE.addStorageController("SATA Controller",$StorageBus_SATA)

write-host "Forth step: Saving and registering the VM"

# Configure the disk controller
$MACHINE_CTRL.portCount=1

# Save settings
$MACHINE.saveSettings()

# Need to register the VM (mandatory before attaching a disk to it)
# But registering the VM will change it's state to un-mutable !
$VIRTUALBOX.registerMachine($MACHINE)

write-host "Fifth step: Registering a VDI"

# Convert a raw image disk to VDI using VBoxManage.exe
$VDI_FILE=$VIRTUALBOX.SystemProperties.DefaultMachineFolder + "\$MACHINE_NAME\$MACHINE_NAME.vdi"

# Call external command VBoxManage.exe for converting the given RAW .img to VDI
# Need to add quote to the command string
$VB_MANAGE ='"' + $env:VBOX_INSTALL_PATH + "VBoxManage.exe" + '"'
$CMD="convertfromraw " + '"' + $RAW_FILE +'" "' + $VDI_FILE + '"'

$erroractionpreference = "silentlycontinue"
invoke-expression "& $VB_MANAGE $CMD"
$erroractionpreference = "Stop"
    
# Register the VDI (Mandatory before attaching it to a VM)
$MEDIUM=$VIRTUALBOX.openMedium($VDI_FILE,$DeviceType_HardDisk,$AccessMode_ReadWrite,$true)

# (optional) Compact the VDI (and create a process object for following the process)
$PROGRESS=$MEDIUM.compact()
 
# Wait for end of compacting the VDI...
$PROGRESS.waitForCompletion(-1)

Write-Host "Sixth step: Unlock the VM in write mode for attaching the medium"

# Need to unclock the VM (put it in "mutable" state) before modifying it
# (More I'm discovering the complexity of VirtualBox, more I love qemu !)
# We need to lock the MACHINE in Write mode, and use a SESSION for that

# Initialize VirtualBox Session object
$SESSION = New-Object -ComObject VirtualBox.Session

# Now lock the machine using the SESSION object
# This will create a new SESSION.machine object
$MACHINE.lockMachine($SESSION,$LockType_Write)

# Waring: MACHINE is still in un-mutable state,
# but there is a copy of MACHINE, called SESSION.MACHINE that is in mutable state.
 
# Attach the disk to the mutable state machine (SESSION.machine)
$SESSION.machine.attachDevice("SATA Controller",0,0,$DeviceType_HardDisk,$MEDIUM)
  
# Save new settings... but still on SESSION.machine
$SESSION.machine.saveSettings()
   
# Unlock the machine
$SESSION.unlockMachine()

write-host "seventh step: Launch the VM"
# Launch VM in GUI mode
$PROGRESS=$MACHINE.launchVMProcess($SESSION,"gui","")

# Wait for launching process of the VM
$PROGRESS.waitForCompletion(-1)

Write-Host "Machine started:"
Write-Host " - Graphical console: On the VirtualBox Window"
write-host " - Serial port: Configure your putty/kitty to connect to:"
write-host "     serial serial line: \\.\pipe\
$MACHINE_NAME"
write-host "     baud : 115200"
Write-Host "Press a key to continue"
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")


You can found a more complex examples (using VboxHeadless, linked clones, etc…) by looking at the BSDRP VirtualBox Lab PowerShell srcipt.

Aucun commentaire: