locked
Content library deployment tool vCenter RRS feed

  • 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