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 objectpropertyCollector
on vCenter Servervcenter
failed.
VMware published a KB about that on 2 august 2011 : KB1025367
Here is the workaround :
- Power off the virtual machine.
- Note the ESX/ESXi host on which the virtual machine resides.
- Right-click the virtual machine and click Remove from Inventory.
- Browse the datastore and locate the virtual machine.
- Right-click the
<vm name>.vmx
file and click Add to Inventory.- If you are unable to add the virtual machine, close the vSphere Client from vCenter Server.
- 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.
- Browse the datastore and locate the virtual machine.
- Right-click the
<vm name>.vmx
file and click Add to Inventory.- 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 http://www.lucd.info/2009/12/02/raiders-of-the-lost-vmx/ and @hypervisor_fr http://www.hypervisor.fr/?p=2927, 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,
[Parameter(ValueFromPipeline=$true)]
[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))) {
Get-Usage
Break
}
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 | ?{$_.id -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 ($VMField.name -match "^Annotation$") {
Set-VM -VM $VM -Description $tab_VM.Annotation -Confirm:$false | Out-Null
} elseif ($VMField.name -notmatch "^VMName$") {
Set-Annotation -Entity $VM -CustomAttribute $VMField.name -Value $tab_VM."$($VMField.name)" -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.