Programmatically Discovering and Adding VMware Templates with PowerCLI

I received an email asking how to perform a batch import of orphaned VMware Template files into a vSphere environment. You may recall that template files have an extension of VMTX and offer some minor benefits for administrators looking to solidify a golden master virtual machine. I’m not a fan of the format and avoid using them; they are treated like a second class citizen from most API and automation perspectives. In my customization specification provisioning post, I prove that regular virtual machines can do everything a template is able to do without the headache of invalid backing errors related to vCenter restarts.

But let’s assume you want to use templates – perhaps with the content library feature. The script below is a derivative of Luc Dekens’ VMX Raiders Revisited code and am contributing the content back into the wild. I’ve added some functionality and refactored the layout:

  • The focus is on VMTX (template) instead of VMX (virtual machine) files.
  • Added logic to determine your version of PowerCLI.
  • Leveraging the New-Template cmdlet.
  • I’m not aware of an inventory name property associated with the template file. The template is imported using its file name (something.vmtx).

You can use the code snipet below or snag a copy from my scripts repository on GitHub.

  1. Edit the values of the #Variables section.
  2. Fire up the script with an account that has administrative authority to vCenter.
  3. Templates that are not already part of your vSphere inventory will be added to the folder specified in the #Variables section.

The script takes several minutes to comb through an average sized datastore, as noted by Luc in his effort to keep the script more purely PowerShell. My assumption is that this is a one-off activity, but if you need more speed, try using the HostDatastoreBrowser.

kerbal-powershell

#requires -Version 2

# Variables
$vcenter = 'vc1.glacier.local'
$Cluster = 'Lab'
$Datastores = 'NAS2-Lab'
$VMFolder = 'Staging'

# Import modules or snapins
$powercli = Get-PSSnapin -Name VMware.VimAutomation.Core -Registered

try
{
switch ($powercli.Version.Major) {
{
$_ -ge 6
}
{
Import-Module -Name VMware.VimAutomation.Core -ErrorAction Stop
Write-Host -Object 'PowerCLI 6+ module imported'
}
5
{
Add-PSSnapin -Name VMware.VimAutomation.Core -ErrorAction Stop
Write-Warning -Message 'PowerCLI 5 snapin added; recommend upgrading your PowerCLI version'
}
default
{
throw 'This script requires PowerCLI version 5 or later'
}
}
}
catch
{
throw 'Could not load the required VMware.VimAutomation.Vds cmdlets'
}

# Ignore self-signed SSL certificates for vCenter Server (optional)
Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -DisplayDeprecationWarnings:$false -Scope User -Confirm:$false

# Connect to vCenter
try
{
$null = Connect-VIServer $vcenter -ErrorAction Stop
}
catch
{
throw 'Could not connect to vCenter'
}

# Select an ESXi host to own the templates for the import process
$ESXHost = Get-Cluster $Cluster | Get-VMHost | Select-Object -First 1

foreach($Datastore in Get-Datastore $Datastores)
{
# Collect .vmtx paths of registered VMs on the datastore
$registered = @{}
Get-Template -Datastore $Datastore | ForEach-Object -Process {
$registered.Add($_.Name+'.vmtx',$true)
}

# Set up Search for .VMTX Files in Datastore
$null = New-PSDrive -Name TgtDS -Location $Datastore -PSProvider VimDatastore -Root '\'
$unregistered = @(Get-ChildItem -Path TgtDS: -Recurse | `
Where-Object -FilterScript {
$_.FolderPath -notmatch '.snapshot' -and $_.Name -like '*.vmtx' -and !$registered.ContainsKey($_.Name)
}
)
Remove-PSDrive -Name TgtDS

#Register all .vmtx Files as VMs on the datastore
foreach($vmtxFile in $unregistered)
{
New-Template -Name $vmtxFile.Name -TemplateFilePath $vmtxFile.DatastoreFullPath -VMHost $ESXHost -Location $VMFolder -RunAsync
}
}