Answered by:
Content library deployment tool vCenter

Question
-
Afternoon all
I'm building a Powershell script that will enable me to deploy VM's from my vCenter content library after filling in a brief form. This form pulls through some information from the vCenter to aid in completing it.
I've 2 current issues:
1. If a Combobox only receives only a single result to populate with, I get the below error:
exception settings "datasource": "Complex DataBinding accepts as a data source either an IList or an IListSource
2. When pulling back all the VM folder names, it doesn't list them in a nice tree view like vCenter does (for example, we have several folders identically named "compute") so in order to make these readable, I put in a command that gives the parent folder, followed by the 2nd level folder and finally the ID of that folder. Is there any way to get just the "ID" bit out of the Combobox to pass through to a variable for the rest of my script to use?
# Drawing the box Add-Type -AssemblyName System.Windows.Forms [System.Windows.Forms.Application]::EnableVisualStyles() $CDWVMDeploy = New-Object system.Windows.Forms.Form $CDWVMDeploy.ClientSize = '500,689' $CDWVMDeploy.text = "CDWVMDeploy" $CDWVMDeploy.TopMost = $false $Title = New-Object system.Windows.Forms.Label $Title.text = "CDW ServiceWorks VM Deployment Tool" $Title.AutoSize = $true $Title.width = 25 $Title.height = 10 $Title.location = New-Object System.Drawing.Point(23,25) $Title.Font = 'Microsoft Sans Serif,10,style=Bold' $Title.ForeColor = "#ff0000" $vCenterLabel = New-Object system.Windows.Forms.Label $vCenterLabel.text = "Which vCenter?" $vCenterLabel.AutoSize = $true $vCenterLabel.width = 25 $vCenterLabel.height = 10 $vCenterLabel.location = New-Object System.Drawing.Point(21,57) $vCenterLabel.Font = 'Microsoft Sans Serif,10' $vCenterChoice = New-Object system.Windows.Forms.ComboBox $vCenterChoice.DropDownStyle = [System.Windows.Forms.ComboBoxStyle]::DropDownList $vCenterChoice.width = 141 $vCenterChoice.height = 20 @('1','2') | ForEach-Object {[void] $vCenterChoice.Items.Add($_)} $vCenterChoice.location = New-Object System.Drawing.Point(19,84) $vCenterChoice.Font = 'Microsoft Sans Serif,10' $OSChoice = New-Object system.Windows.Forms.ComboBox $OSChoice.DropDownStyle = [System.Windows.Forms.ComboBoxStyle]::DropDownList $OSChoice.width = 200 $OSChoice.height = 20 @('cl_template-CentOS7','cl_template-RHL6.4','cl_template-fgvm-FGVM-5.6.4','cl_template-w2008R2-std','cl_template-w2012-std','cl_template-w2012R2-std','cl_template-w2016-std','cl_template-w2019-std') | ForEach-Object {[void] $OSChoice.Items.Add($_)} $OSChoice.location = New-Object System.Drawing.Point(19,148) $OSChoice.Font = 'Microsoft Sans Serif,10' $OSLabel = New-Object system.Windows.Forms.Label $OSLabel.text = "OS Choice?" $OSLabel.AutoSize = $true $OSLabel.width = 25 $OSLabel.height = 10 $OSLabel.location = New-Object System.Drawing.Point(21,118) $OSLabel.Font = 'Microsoft Sans Serif,10' $VMNameChoice = New-Object system.Windows.Forms.TextBox $VMNameChoice.multiline = $false $VMNameChoice.width = 244 $VMNameChoice.height = 40 $VMNameChoice.location = New-Object System.Drawing.Point(20,347) $VMNameChoice.Font = 'Microsoft Sans Serif,10' $CPUChoice = New-Object system.Windows.Forms.ComboBox $CPUChoice.DropDownStyle = [System.Windows.Forms.ComboBoxStyle]::DropDownList $CPUChoice.width = 100 $CPUChoice.height = 20 @('1','2') | ForEach-Object {[void] $CPUChoice.Items.Add($_)} $CPUChoice.location = New-Object System.Drawing.Point(19,214) $CPUChoice.Font = 'Microsoft Sans Serif,10' $CPUSocketLabel = New-Object system.Windows.Forms.Label $CPUSocketLabel.text = "vSocket" $CPUSocketLabel.AutoSize = $true $CPUSocketLabel.width = 25 $CPUSocketLabel.height = 10 $CPUSocketLabel.location = New-Object System.Drawing.Point(21,185) $CPUSocketLabel.Font = 'Microsoft Sans Serif,10' $RAMLabel = New-Object system.Windows.Forms.Label $RAMLabel.text = "RAM (GB)" $RAMLabel.AutoSize = $true $RAMLabel.width = 25 $RAMLabel.height = 10 $RAMLabel.location = New-Object System.Drawing.Point(140,185) $RAMLabel.Font = 'Microsoft Sans Serif,10' $RAMChoice = New-Object system.Windows.Forms.ComboBox $RAMChoice.width = 100 $RAMChoice.height = 20 @('2','4','6','8','10','12','16','20','24','32','48','64','128') | ForEach-Object {[void] $RAMChoice.Items.Add($_)} $RAMChoice.location = New-Object System.Drawing.Point(140,213) $RAMChoice.Font = 'Microsoft Sans Serif,10' $VMNameLabel = New-Object system.Windows.Forms.Label $VMNameLabel.text = "VM Name?" $VMNameLabel.AutoSize = $true $VMNameLabel.width = 25 $VMNameLabel.height = 10 $VMNameLabel.location = New-Object System.Drawing.Point(21,319) $VMNameLabel.Font = 'Microsoft Sans Serif,10' $DeployButton = New-Object system.Windows.Forms.Button $DeployButton.text = "DEPLOY" $DeployButton.width = 174 $DeployButton.height = 49 $DeployButton.location = New-Object System.Drawing.Point(75,617) $DeployButton.Font = 'Microsoft Sans Serif,25,style=Bold' $DeployButton.ForeColor = "#7ed321" $vCoreLabel = New-Object system.Windows.Forms.Label $vCoreLabel.text = "vCore (Socket x Core = Total vCPU)" $vCoreLabel.AutoSize = $true $vCoreLabel.width = 25 $vCoreLabel.height = 10 $vCoreLabel.location = New-Object System.Drawing.Point(21,253) $vCoreLabel.Font = 'Microsoft Sans Serif,10' $CoreBox = New-Object system.Windows.Forms.ComboBox $CoreBox.width = 100 $CoreBox.height = 20 @('1','2','3','4','6','8','10','12','16') | ForEach-Object {[void] $CoreBox.Items.Add($_)} $CoreBox.location = New-Object System.Drawing.Point(19,282) $CoreBox.Font = 'Microsoft Sans Serif,10' $ConnectButton = New-Object system.Windows.Forms.Button $ConnectButton.text = "Connect" $ConnectButton.width = 99 $ConnectButton.height = 26 $ConnectButton.location = New-Object System.Drawing.Point(185,81) $ConnectButton.Font = 'Microsoft Sans Serif,10,style=Bold' $ConnectButton.ForeColor = "#7ed321" $DatastoreChoice = New-Object system.Windows.Forms.ComboBox $DatastoreChoice.width = 244 $DatastoreChoice.height = 20 $DatastoreChoice.location = New-Object System.Drawing.Point(20,411) $DatastoreChoice.Font = 'Microsoft Sans Serif,10' $DatastoreLabel = New-Object system.Windows.Forms.Label $DatastoreLabel.text = "Datastore?" $DatastoreLabel.AutoSize = $true $DatastoreLabel.width = 25 $DatastoreLabel.height = 10 $DatastoreLabel.location = New-Object System.Drawing.Point(21,381) $DatastoreLabel.Font = 'Microsoft Sans Serif,10' $NetworkLabel = New-Object system.Windows.Forms.Label $NetworkLabel.text = "Network?" $NetworkLabel.AutoSize = $true $NetworkLabel.width = 25 $NetworkLabel.height = 10 $NetworkLabel.location = New-Object System.Drawing.Point(21,439) $NetworkLabel.Font = 'Microsoft Sans Serif,10' $NetworkChoice = New-Object system.Windows.Forms.ComboBox $NetworkChoice.width = 245 $NetworkChoice.height = 20 $NetworkChoice.location = New-Object System.Drawing.Point(19,460) $NetworkChoice.Font = 'Microsoft Sans Serif,10' $ClusterLabel = New-Object system.Windows.Forms.Label $ClusterLabel.text = "Cluster?" $ClusterLabel.AutoSize = $true $ClusterLabel.width = 25 $ClusterLabel.height = 10 $ClusterLabel.location = New-Object System.Drawing.Point(23,490) $ClusterLabel.Font = 'Microsoft Sans Serif,10' $ClusterChoice = New-Object system.Windows.Forms.ComboBox $ClusterChoice.width = 245 $ClusterChoice.height = 20 $ClusterChoice.location = New-Object System.Drawing.Point(21,511) $ClusterChoice.Font = 'Microsoft Sans Serif,10' $FolderLabel = New-Object system.Windows.Forms.Label $FolderLabel.text = "VM Folder?" $FolderLabel.AutoSize = $true $FolderLabel.width = 25 $FolderLabel.height = 10 $FolderLabel.location = New-Object System.Drawing.Point(25,548) $FolderLabel.Font = 'Microsoft Sans Serif,10' $FolderChoice = New-Object system.Windows.Forms.ComboBox $FolderChoice.width = 450 $FolderChoice.height = 20 $FolderChoice.location = New-Object System.Drawing.Point(21,575) $FolderChoice.Font = 'Microsoft Sans Serif,10' $CDWVMDeploy.controls.AddRange(@($Title,$vCenterLabel,$vCenterChoice,$OSChoice,$OSLabel,$VMNameChoice,$CPUChoice,$CPUSocketLabel,$RAMLabel,$RAMChoice,$VMNameLabel,$DeployButton,$vCoreLabel,$CoreBox,$ConnectButton,$DatastoreChoice,$DatastoreLabel,$NetworkLabel,$NetworkChoice,$ClusterLabel,$ClusterChoice,$FolderLabel,$FolderChoice)) #End GUI Region #Disable certificate checking Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false #What happens when clicking "connect" button $ConnectButton.Add_Click({ConnecttoVC}) function ConnecttoVC { #Disconnect any existing sessions disconnect-viserver -Confirm:$false #connect to vCenter connect-viserver $vCenterChoice.selecteditem #Get Folder into FolderChoice box $Folders = get-folder | where{$_.Type -eq "vm"} | select parent,name,id |Sort-Object parent $FolderChoice.DataSource = $Folders $FolderChoice.SelectedItem #Get Cluster choice $Clusters = Get-Cluster $ClusterChoice.Datasource = $Clusters $ClusterChoice.SelectedItem #Get Datastore choice $Datastores = Get-Datastore | Sort-Object $DatastoreChoice.DataSource = $Datastores $DatastoreChoice.SelectedItem #Get networks choice $Network = Get-VDPortGroup | Sort-Object $NetworkChoice.DataSource = $Network $NetworkChoice.SelectedItem } #What happens when clicking "deploy" button $DeployButton.Add_Click({DeployVM}) function DeployVM { #Need to get these variables from the combo/free text boxes from form into the below #region Starter Vars () $cluster = Get-Cluster $ClusterChoice.Text $datacenter = $cluster | Get-Datacenter $datastore = Get-Datastore $DatastoreChoice.Text $folder = Get-Folder $FolderChoice.Text $vmSubnet = Get-VDPortgroup -Name $NetworkChoice.Text $NewVM = $VMNameChoice.Text #endregion #Spin up the vm from a content library template. Get-ContentLibraryItem -Name $OSChoice.Text | New-VM -Name $NewVM -resourcePool $cluster -location $folder -datastore $datastore -DiskStorageFormat "Thin" -confirm:$false #assumes a single nic, which as a template should be your standard $NewVM | Get-NetworkAdapter | Set-NetworkAdapter -NetworkName $vmSubnet -StartConnected $true -confirm:$false #Set CPU's get-VM -name $NewVM | set-VM -NumCpu $CPUChoice.text $TotalvCPU=$CPUChoice.text*$CoreBox.text $spec=New-Object –Type VMware.Vim.VirtualMAchineConfigSpec –Property @{“NumCoresPerSocket” = $CoreBox.text} ($NewVM).ExtensionData.ReconfigVM_Task($spec) $NewVM | set-vm -numcpu $TotalvCPU -confirm:$false #Set Memory set-vm $vm -MemoryGB $RAMChoice.text -confirm:$false #Need to complete the below only if Windows OS selected (need to put an if statement in?) set-vm $vm -OSCustomizationSpec "+ServiceWorks Windows Templates" -confirm:$false Get-VM $NewVM $spec = New-Object VMware.Vim.VirtualMachineConfigSpec $spec.Firmware = [VMware.Vim.GuestOsDescriptorFirmwareType]::efi $vm.ExtensionData.ReconfigVM($spec) } [void]$CDWVMDeploy.ShowDialog()
Thanks!
Tuesday, November 26, 2019 3:47 PM
Answers
-
This would be the correct way to approach this:
$folders = get-folder -Type vm $folderChoice.Sorted = $true $folderChoice.DataSource = $folders $folderChoice.DisplayMember = 'parent' $folderChoice.SelectedItem.id # to get the object properties
\_(ツ)_/
- Marked as answer by OBerliner Friday, November 29, 2019 9:53 AM
Tuesday, November 26, 2019 4:23 PM
All replies
-
#1 Without the complete error message it is difficult to help. It appears you need to wrap the array in an array to eliminate singletons.
#2 Add object to your ComboBox and select the property of the object from the selectedItem.
\_(ツ)_/
Tuesday, November 26, 2019 3:57 PM -
Thanks for the quick response! Full error:
Exception setting "Datasource": "Complex DataBinding accepts as a data source either an IList or an IListSource."
At DeployVMGUI.ps1:221 char:1
+ $ClusterChoice.Datasource = $Clusters
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], SetValueInvocationException
+ FullyQualifiedErrorId : ExceptionWhenSetting
Sorry to be daft, but if I did the following, what would I need to put on the end of the last line to select the "ID" field?
$Folders = get-folder | where{$_.Type -eq "vm"} | select parent,name,id |Sort-Object parent $FolderChoice.DataSource = $Folders $FolderChoice.SelectedItem
Tuesday, November 26, 2019 4:07 PM -
Error message makes this easy. This forces the object(s) into an array and an arraylist (iList object)
$ClusterChoice.Datasource = [System.Collections.ArrayList]@($Clusters)
$Folders = get-folder | where{$_.Type -eq "vm"} | select parent,name,id |Sort-Object parent $FolderChoice.DataSource = $Folders $FolderChoice.DisplayMember = 'Name' $FolderChoice.SelectedItem.id # to get the object properties
\_(ツ)_/
Tuesday, November 26, 2019 4:18 PM -
This would be the correct way to approach this:
$folders = get-folder -Type vm $folderChoice.Sorted = $true $folderChoice.DataSource = $folders $folderChoice.DisplayMember = 'parent' $folderChoice.SelectedItem.id # to get the object properties
\_(ツ)_/
- Marked as answer by OBerliner Friday, November 29, 2019 9:53 AM
Tuesday, November 26, 2019 4:23 PM -
That's great, thank you so much! I'm so close to getting there now! Just one last thing, I'm trying to multiply 2 values that are returned in the form, so:
$CoreBoxValue=$CoreBox.text Write-host $CoreBoxValue $CPUChoiceValue=$CPUChoice.text Write-host $CPUChoiceValue Write-host $CoreBoxValue*$CPUChoiceValue
I'm using the write hosts to show me the value it's getting and it just keeps outputting "2*2" for example instead of the actual sum?
Should I not be using the ".text" responses?
Thanks!
Thursday, November 28, 2019 1:03 PM -
Simple math:
([int]$CoreBox.text) * ([int]$CPUChoice.text)
Things are never that complicated when you use PowerShell.
\_(ツ)_/
Thursday, November 28, 2019 6:29 PM -
Thanks JRV but it's still just outputting "2 * 4" instead of the sum :(Friday, November 29, 2019 9:09 AM
-
It works fine for me:
Write-Host (([int]$CoreBox.text) * ([int]$CPUChoice.text))
\_(ツ)_/
Friday, November 29, 2019 9:13 AM -
Ah, it was the extra set of brackets that did it :)
Thanks so much for your help on this thread for me!
Friday, November 29, 2019 9:53 AM