10 October 2011 / #Powercli #Vsphere

PropertyCollector.RetrieveContents Failed


If you’re used to work with vSphere template, and if like us are still in vSphere 4.1 (still not upgraded in vSphere 5 = added in todolist :p), you may have encounter the following issue after trying to edit settings of a template (after VM > Template convertion) :


We got an ugly-mean-not-happy-error :

Call PropertyCollector.RetrieveContents for object propertyCollector on vCenter Server vcenter failed.

VMware published a KB about that on 2 august 2011 : KB1025367

Here is the workaround :

  1. Power off the virtual machine.
  2. Note the ESX/ESXi host on which the virtual machine resides.
  3. Right-click the virtual machine and click Remove from Inventory.
  4. Browse the datastore and locate the virtual machine.
  5. Right-click the <vm name>.vmx file and click Add to Inventory.
  6. If you are unable to add the virtual machine, close the vSphere Client from vCenter Server.
  7. Log in directly to the ESX/ESXi host on which the virtual machine resides using the vSphere Client. To do this, you must know the root password.
  8. Browse the datastore and locate the virtual machine.
  9. Right-click the <vm name>.vmx file and click Add to Inventory.
  10. Log in to vCenter Server using the vSphere Client.

You can do it manually once, but it’ll soon be boring if you have to do it a lot, and the important thing to know is the unregister/register VM task will erase all Custom Field (normal behavior) ^^ So we made a small PowerCLI script (of course) in order to do the job for us ! Basing on the amazing scripts from @LucD22 and @hypervisor_fr, our script will backup all informations which could be lost during the Unregister (Custom Field, VM Folder, etc!), and then will perform an Unregister/Register task, and finally restore the previously backuped informations.

Function Fix-VMPropCol {
    PARAM (
        [switch]$IsVM = $false,
        [switch]$IsTemplate = $false,
        [string]$VM = $null

    Function Get-Usage {
        Write-Host "Incorrect Parameters" -ForegroundColor red
        Write-Host "Fix-VMPropCol [-IsVM / -IsTemplate]"
        Write-Host "IsVM        : input object is virtual machine"
        Write-Host "IsTemplate    : input object is template"

    Function Log-Console([string]$log) {
        [string]$logText = (Get-Date -Format "yyyy.MM.dd HH:mm:ss") + " - " + $log
        Write-Host -ForegroundColor green $logText

    # Hiding Write-Progress bar of Set-VM cmdlet
    $ProgressPreference = "SilentlyContinue"

    if (($IsVM -and $IsTemplate) -or ((-not $IsVM) -and (-not $IsTemplate))) {

    Log-Console("Gathering informations")
    $VM_View = Get-View -ViewType VirtualMachine -Filter @{"Name"="^$VM$"}
    $exp_VMName = $VM_View.Name
    $exp_VMHost = Get-View $VM_View.Runtime.Host
    $exp_VMXPath = $VM_View.Config.Files.vmPathName
    $exp_Folder = Get-View $VM_View.parent
    $tab_VM = "" | Select VMName
    $tab_VM.VMName = $exp_VMName

    # Backup informations
    # Backup custom fields
    Log-Console("Gathering Custom Fields")
    if ($VM_View.Summary.CustomValue) {
        foreach ($vmField in $VM_View.Summary.CustomValue) {
            $tab_VM | Add-Member -MemberType NoteProperty -Name ($VM_View.AvailableField | ?{$vmField.Key -eq $_.Key}).name -Value $vmField.value

    # Backup Notes
    Log-Console("Gathering Notes")
    if ($VM_View.Config.Annotation.length -gt 0) {
        $tab_VM | Add-Member -MemberType NoteProperty -Name "Annotation" -Value $VM_View.Config.Annotation

    # Unregister VirtualMachine
    Log-Console("Unregister VirtualMachine")
    if (($tab_VM | Get-Member -MemberType NoteProperty | Measure-Object).count -gt "1") {
        if ($IsTemplate) {
            Get-Template -Name $VM | Remove-Template -DeletePermanently:$false -Confirm:$false
        } elseif ($IsVM) {
            Get-VM -Name $VM | Remove-VM -DeletePermanently:$false -Confirm:$false

    # Register VirtualMachine
    Log-Console("Register VirtualMachine")
    #$params = @($exp_VMXPath,$null,$true,$null,$exp_VMHost.MoRef)
    $params = @($exp_VMXPath,$null,(!$IsTemplate -eq $null),(get-view $exp_VMHost.Parent).ResourcePool,$exp_VMHost.MoRef)
    $taskMoRef = $exp_Folder.GetType().GetMethod("RegisterVM_Task").Invoke($exp_Folder, $params)

    # Waiting just a little bit to be sure object is here ...
    Log-Console("Waiting for task to finalize")
    While ( (Get-Task | ?{$ -match $taskMoRef.value}).state -match "Running") { Sleep 4 }

    # Convert into VirtualMachine
    if ($IsTemplate) {
        Log-Console("Convert Template to Virtual Machine in order to set up back Custom Fields and Notes")
        Set-Template -Template $VM -ToVM | Out-Null

    # Reconfigure Custom fields
    Log-Console("Set up back Custom Fields and Notes")
    Foreach ($VMField in ($tab_VM | Get-Member -MemberType NoteProperty)) {
        if ($ -match "^Annotation$") {
            Set-VM -VM $VM -Description $tab_VM.Annotation -Confirm:$false | Out-Null
        } elseif ($ -notmatch "^VMName$") {
            Set-Annotation -Entity $VM -CustomAttribute $ -Value $tab_VM."$($" -Confirm:$false | Out-Null

    # Convert back into template
    if ($IsTemplate) {
        Log-Console("Convert back to Template")
        Set-VM -VM $VM -ToTemplate -Confirm:$false | Out-Null

This function have to be used straight after a Get-VM or a Get-Template pipe and take as only one argument a switch in order to match the input object type (-IsVM for a machine virtuelle and -IsTemplate for a template) :

Get-VM -Name VM | Fix-VMPropCol -IsVM
Get-Template -Name TEMPLATE | Fix-VMPropCol -IsTemplate


In the future update, we plan to add the automatic detection of the InputObject in order to avoid the need of the -IsVM or -IsTemplate switch and also allowing the launch of the cmdlet alone without piping.

> Frederic MARTIN