# encoding: ascii
# api: powershell
# title: Import-VCBImage
# description: Script that will use the Converter to import a VCB created disk image into a datacenter
# version: 1.0
# type: function
# author: LucD
# license: CC0
# function: Invoke-Cmd
# x-poshcode-id: 1331
# x-archived: 2009-09-28T13:58:49
#
#
#
# import-VCBImage.ps1    : use the Converter to import a VCB created disk image into a datacenter
#
# Author:       LucD
#
# History:
#
#       v1.0 20/09/09   first version
#
$I2VImageDir = <directory where the VCB images are stored>
$I2VShare = <Sharename of the $I2VImageDir directory>
$tgtDatacenter = <Target-datacenter>
$I2Vuser = <account with access to the image directory and to the datacenter>
$I2Vpassword = <password of the $I2Vuser account>
$I2Vhost = <hostname where the images are stored>
$ConvProgDir = "$env:ProgramFiles (x86)\VMware\Infrastructure\Converter Enterprise" 
$ConvService = "vmware-converter" 
$I2Vprog = "converter-tool.exe" 

# Template XML file for Convertor job
$p2v = [xml]@"
<p2v version="2.2" xmlns="http://www.vmware.com/v2/sysimage/p2v" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.vmware.com/v2/sysimage/p2v p2vJob.xsd" xsi:type="P2VJob">
  <source>
    <hostedSpec networkPassword="" networkUsername="" path=""/>
  </source>
  <dest>
    <managedSpec datastore="" folder="" host="" resourcePool="" vmName="">
      <creds host="" port="0" type="sessionId" username="" password="" />
    </managedSpec>
  </dest>
  <importParams diskType="VMFS" preserveHWInfo="true" removeSystemRestore="false" targetProductVersion="PRODUCT_MANAGED">
    <nicMappings/>
    <diskLocations/>
  </importParams>
  <postProcessingParams/>
</p2v>
"@

# Function will start a DOS commmand and wait for it to finish
#
function Invoke-Cmd{
	param($cmd, $arguments)

	$global:StdOut = ""
	$global:StdErr = ""

	$pStart = new-object System.Diagnostics.ProcessStartInfo
	$pStart.Filename = $cmd
	$pStart.Arguments = $arguments
	$pStart.UseShellExecute = $false
	$pStart.ErrorDialog = $false
	$pStart.CreateNoWindow = $True
	$pStart.RedirectStandardOutput = $true
	$pStart.RedirectStandardError = $true
	$myProcess = [System.Diagnostics.Process]::Start($pStart)

	$myOutput = $myProcess.StandardOutput
	$myErrOutput = $myProcess.StandardError
	$global:StdOut = $myOutput.ReadToEnd()
	$global:StdErr = $myErrOutput.ReadToEnd()

	$myProcess.WaitForExit()

	$myProcess.ExitCode
}

# Function that builds the Converter XML file and launches the job
#
function Import-VCBImage{
	param($vmName, $portgroup) 
# Check if directory exists 
	if((Get-Item -path ($I2VImageDir + "\*") | Where-Object {$_.Name -eq $vmName} | Measure-Object).Count -ne 1){
		Write-Host "Snapshot directory not found for " $vmName 
		return 
	} 
# Determine target VmHost and target Datastore based on largest free space on datastore 
	$selectESX = "" 
	$selectDS = "" 
	$selectFree = 0 
	Get-Datacenter $tgtDatacenter | Get-VMHost | % { 
		$tmpESX = $_.Name 
		$_ | Get-Datastore | % { 
			if($_.FreeSpaceMb -gt $selectFree){ 
				$selectESX = $tmpESX 
				$selectDS = $_.Name 
				$selectFree = $_.FreeSpaceMb 
			} 
		} 
	} 
# Check if sufficient free space on ESXi server 
	if(((Get-Item -path ($I2VImageDir + "\" + $vmName + "\*") | Measure-Object -property Length -sum).Sum / 1mb) -gt $selectFree){
		Write-Host "Not enough free disk space on" $selectFree 
		return 
	} 
# Find VMX file 
	$vmxName = (Get-Item -path ($I2VImageDir + "\" + $vmName + "\*") | Where-Object {$_.Name -like "*.vmx"}).Name
# Update fields in XML tree 
	$p2v.p2v.source.hostedSpec.path = "\\" + $I2Vhost + "\" + $I2VShare + "\" + $vmName + "\" + $vmxName
	$p2v.p2v.source.hostedSpec.networkUsername = $I2Vuser
	$p2v.p2v.source.hostedSpec.networkPassword = $I2Vpassword 
	$p2v.p2v.dest.managedSpec.creds.username = $I2Vuser 
	$p2v.p2v.dest.managedSpec.creds.password = $I2Vpassword 
	$p2v.p2v.dest.managedSpec.datastore = $selectDS 
	$p2v.p2v.dest.managedSpec.host = $selectESX 
	$p2v.p2v.dest.managedSpec.folder = "" 
	$p2v.p2v.dest.managedSpec.resourcePool = "" 
	$V2VvmName = $vmName + "-" + $tgtDatacenter + "-" + (Get-Date -format yyyyMMdd-HHmmss)
	$p2v.p2v.dest.managedSpec.vmName = $V2VvmName 
	$p2v.p2v.dest.managedSpec.creds.host = $I2Vhost 
	$p2v.p2v.dest.managedSpec.creds.username = $I2Vuser 
	$p2v.p2v.dest.managedSpec.creds.password = $I2Vpassword 
# As a security measure the RDM machines are connected to the isolated network 
	$NIC = $p2v.CreateElement("nicMapping") 
	$network = $p2v.CreateAttribute("network") 
	$network.psbase.Value = $portgroup
	$dummy = $NIC.SetAttributeNode($network) 
	$p2v.p2v.importParams["nicMappings"].AppendChild($NIC) 
# Save the XML file 
	$XMLfile = $I2VImageDir + "\" + "I2V-" + $vmName + ".xml" 
	$p2v.Save($XMLfile) 
# Start Convertor service if it is not running. 
	if((Get-Service -name $ConvService).Status -eq "Stopped"){ 
		Start-Service -name $ConvService 
	} 
# Start the import 
# ! parameters are case-sensitive ! (--vchost is not accepted, must be --vcHost) ! 
	$myarg = "--vcHost " + $I2Vhost + " --jobExec " + $XMLfile + " --vcCred " + $I2Vuser + ":" + $I2Vpassword 
	$mycmd = $ConvProgDir + "\" + $I2Vprog 
	$rc = Invoke-Cmd $mycmd $myarg 

# Remove older DRM guest(s) (if present AND if V2V completed successfully) 
	if($rc -eq 0){ 
		foreach($vm in (Get-Datacenter $tgtDatacenter | Get-VM ($vmName + "-" + $tgtDatacenter + "*") | where {$_.Name -ne $V2VvmName})){ 
			$vm | Remove-VM - DeleteFromDisk:$true - Confirm:$false 
		} 
	} 
} 

# Sample call
# Import-VCBImage "PC1" "isolated"
