Set custom property’s on VM creation

It seems like you cant set custom property’s on VM creation, you will encounter these problems if you use a powershell function to deploy a VM like below and you want to set a custom property in the same function.

Function CreateVM {
#Create unique Guid as JobGroupID
$JobGroupID = [Guid]::NewGuid().ToString()
$VMTemplate = Get-SCVMTemplate | where {$_.Name -eq "VMTemplate01"}
$VMHost = Get-SCVMHost -ComputerName ""
Move-SCVirtualHardDisk -IDE -BUS 0 -LUN 0 -Path "L:\OS.VHD" -JobGroup $JobGroupID
New-SCVirtualMachine -Name "VM06" -Path "L:" -VMTemplate $VMTemplate -VMHost $VMHost -JobGroup $JobGroupID -UseLocalVirtualHardDisk

Normally you can set custom property’s with the following cmdlet’s:


Set-SCVirtualMachine -Custom1 "Example1" -Custom8 "Example8"


$VM = Get-SCVirtualMachine -Name "VM01"
$CustomProp = Get-SCCustomProperty -Name "Custom1"
Set-SCCustomPropertyValue -InputObject $VM -CustomProperty $CustomProp -Value "Example1"

In order to get the Set-SCVirtualMachine cmdlet to work, you will need the VM.
You can get the VM obvious with Get-SCVirtualMachine, but you cant execute the Set-SCVirtualMachine cmdlet on the VM because the creation job is still running.
You will get the following error:

Set-SCVirtualMachine : Unable to perform the job because one or more of the selected objects are locked by another job. (Error ID: 2606)

The Set-SCCustomPropertyValue cmdlet has the “-jobgroup” parameter but when you include it in the same jobgroup as the new-scvirtualmachine you will get the following error:

One or more of the cmdlets is not valid for inclusion in that JobGroup. (Error ID: 1703)

So to workarround these limits we will have to wait till the creation job is done before setting the Custom property with Set-SCVirtualMachine, but you dont want build in a “Sleep” otherwise your CreateVm function will take very long.

You can use the “Start-job” cmdlet to fire away jobs but you could also execute a external powershell script by “dot sourceing” it.
The solution is to “dot source” a powershell script in your CreateVM function in combination with the “Start-job” cmdlet that will take care of the custom attributes as soon as the creation script is done.

Start-Job {. c:\scripts\SetCustomProperty.ps1;SetCustomProperty $args[0] $args[1] }  -ArgumentList @($VMID,$Custom1)

And the SetCustomProperty.ps1 powershell script will look like below
See comments in script.

Import-Module -Name virtualmachinemanager -ErrorAction SilentlyContinue
Function SetCustomProperty{

# Wait for VM to other state then "Creating..", then change custom properties
$VM = Get-SCVirtualMachine | where {$_.Description -eq $VMID}
do {
$VM = Get-SCVirtualMachine | where {$_.Description -eq $VMID}
sleep 1
while ($VM.StatusString -match "Creating")

#Create JobGuid and set custom property's
$JobGroupID = [Guid]::NewGuid().ToString()
Set-scvirtualmachine -VM $VM -Description "" -custom1 $custom 1 -JobGroup $JobGroupID}

Make sure that when your creationjob does not get the status “Completed”, you kill the job after some time. (in case of error)
You could do a do,while countdown.
I almost forgot, I created a new variable called $VMID which I populate the “Description” property with.
With this unique ID I can do a “Get-scvirtualmachine” and always get the right VM in the SetCustomProperty script, This property gets deleted again when the custom property’s are set.

So, at the end, your VM creation powershell function will look like:

Function CreateVM {
#Create unique Guid as JobGroupID
$JobGroupID = [Guid]::NewGuid().ToString()
#Create unique Guid as VMID
$VMID = [Guid]::NewGuid().ToString()
$VMTemplate = Get-SCVMTemplate | where {$_.Name -eq "VMTemplate01"}
$VMHost = Get-SCVMHost -ComputerName ""
Move-SCVirtualHardDisk -IDE -BUS 0 -LUN 0 -Path "L:\OS.VHD" -JobGroup $JobGroupID
New-SCVirtualMachine -Name "VM06" -Path "L:" -VMTemplate $VMTemplate -VMHost $VMHost -JobGroup $JobGroupID -UseLocalVirtualHardDisk -Description $VMID
$Custom1 = "Example1"
Start-Job {. c:\scripts\SetCustomProperty.ps1;SetCustomProperty $args[0] $args[1] $args[2]}  -ArgumentList @($JobGroupID,$VMID,$Custom1)

Have Fun!
Any idea how to do this better? Let me know!

Leave a Reply

Your email address will not be published. Required fields are marked *