Search code examples
powershellsdkvmwarevsphere

VMware vSphere cross vCenter VM template clone via SDK


Creating a VM template clone cross vCenter via SDK - not PowerCLI cmdlet! - is done by the method CloneVM_Task of a VM template object.

This task is done like this:

$vc_source = '____DNSNAME1____'
$vc_dest = '____DNSNAME2____'
$cred = Get-Credential -Title 'credential for destination vCenter'
Connect-VIServer -Server $vc_source
$vc = Connect-VIServer -Server $vc_dest

### get VM template...
$tmpl = Get-View -ViewType VirtualMachine -Filter @{ Name = '____VM_TEMPLATE_NAME____'; 'Config.Template' = 'TRUE' } -Server $vc_source
# get VM template ESXi host name:
(Get-View -Id $tmpl.Runtime.Host -Property Name -Server $vc_source).Name
# get all VM template disks:
$aHD_tmpl = $tmpl.Config.Hardware.Device | ?{ $_ -is [VMware.Vim.VirtualDisk] }
# get all VM template network interface cards:
$aNIC_tmpl = $tmpl.Config.Hardware.Device | ?{ $_ -is [VMware.Vim.VirtualVmxnet] }

### create VM template clone specification...
$spec = [VMware.Vim.VirtualMachineCloneSpec]::new()
...
$spec.Location = [VMware.Vim.VirtualMachineRelocateSpec]::new()
...
$spec.Location.Service = [VMware.Vim.ServiceLocator]::new()
...

To place the new VM template clone in the destination vCenter, it is required to specify $spec.Location.Service.Credential with following property Token (using Code Capture):

### failed to use "[VMware.Vim.ServiceLocatorSAMLCredential]"...
$spec.Location.Service.Credential = [VMware.Vim.ServiceLocatorSAMLCredential]::new()
$spec.Location.Service.Credential.Token = 'Sensitive data is not recorded'

$spec.Location.Service.SslThumbprint = ...
$spec.Location.Service.InstanceUuid = ...
$spec.Location.Service.Url = 'https://____FQDN_VC____:443/sdk'

To start the VM template cloning task:

...
$folder = [VMware.Vim.ManagedObjectReference]::new()
$folder.Type = 'Folder'
$folder.Value = ...

$name = '____VMNAME____'

$vmClone_task = $tmpl.CloneVM_Task($folder, $name, $spec)

I failed to set $spec.Location.Service.Credential = [VMware.Vim.ServiceLocatorSAMLCredential]::new()

Using the other way:

$spec.Location.Service.Credential = [VMware.Vim.ServiceLocatorNamePassword]::new()
$spec.Location.Service.Credential.Username = $cred.UserName
$spec.Location.Service.Credential.Password = $cred.GetNetworkCredential().Password

is obviously a very bad solution (with regard to safety).

How to create the value of property $spec.Location.Service.Credential.Token?


Solution

  • $vc_dest = '____DNSNAME2____'
    $vc = Connect-VIServer -Server $vc_dest
    ...
    $vcClient = $vc.GetClient()
    $token = $vcClient.ConnectivityService.GetSamlBearerToken()
    $spec.Location.Service.Credential.Token = $token.OuterXML
    ...
    

    This solution is damned annoying simple.