Create-VMSingleOrBulk.ps1


<#PSScriptInfo
 
.VERSION 1.1.0
 
.GUID 1f05f4f8-ee4a-48e4-86e8-b1fcd09c213a
 
.AUTHOR Ketan Julka
 
.COMPANYNAME
 
.COPYRIGHT
 
.TAGS "VMware", "New-VM", "CreateBulkVM's", "vCenter", "PowerCLI"
 
.LICENSEURI
 
.PROJECTURI
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES VMware.PowerCLI
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
 
#>


<#
.DESCRIPTION
The script helps create single or multiple VM's in VMware vCenter. For a single VM manually populate the fields in a GUI (.NET based) and for multiple VM's the input is a csv file. Additionally, when using Template option only populate the Name and Resource Pool.
 
Click below link to download the Sample input file.
https://tinyurl.com/2ssz7yer
 
Refer the below link for details about Parameter's
 https://developer.vmware.com/docs/powercli/latest/vmware.vimautomation.core/commands/new-vm/#DefaultParameterSet
#>


Param()

#Import the required sub-module. Import-Module VMware.PowerCLI can also be used.
Import-Module VMware.VimAutomation.Core

# Used for GUI
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

# Code for Browse button for creating VM's in Bulk.
$FileBrowser = New-Object System.Windows.Forms.OpenFileDialog -Property @{ InitialDirectory = [Environment]::GetFolderPath('Desktop'); Filter = "CSV files (*.csv)|*.csv" }

# Making secure connection to the vCenter for creation of the VM's.

$VIServer = Read-Host "Enter the vCenter FQDN or IP"

try
{
    Connect-VIServer -Server $VIServer -Credential (Get-Credential administrator@o365experts.local) -ErrorAction Stop | Out-Null
}
catch
{
    Write-Host "Incorrect Host name or Credentials. Try again with correct details." -ForegroundColor Red -BackgroundColor White
    break
}

# Retrieve the list of Guest OS Details and saves it in a Variable.
try
{
[string[]]$viObjVmHostsel = Get-VMHost -ErrorAction Stop
$viObjVmHost = Get-VMHost -Name $viObjVmHostsel[0] -ErrorAction Stop
$viewObjEnvBrowser = Get-View -Id (Get-View -Id $viObjVmHost.ExtensionData.Parent).EnvironmentBrowser -ErrorAction Stop
$vmxVer = ($viewObjEnvBrowser.QueryConfigOptionDescriptor() | Where-Object {$_.DefaultConfigOption}).Key
$osDesc = $viewObjEnvBrowser.QueryConfigOption($vmxVer,$viObjVmHost.ExtensionData.MoRef).GuestOSDescriptor
}
catch
{
    Write-Host "Unable to retrieve the Guest OS details. Check if the vCenter details are correct and try again." -ForegroundColor Red -BackgroundColor White
    break
}


#GUI Code Starts

$form = New-Object System.Windows.Forms.Form
$form.Text = 'Enter VM Details. All fileds with * are mandatory.'
$form.MinimumSize = New-Object System.Drawing.Size(670,550)
$form.MaximumSize = New-Object System.Drawing.Size(670,550)
$form.StartPosition = 'CenterScreen'


$okButton = New-Object System.Windows.Forms.Button
$okButton.Location = New-Object System.Drawing.Point(40,430)
$okButton.Size = New-Object System.Drawing.Size(75,23)
$okButton.Text = 'OK'
$okButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.AcceptButton = $okButton
$form.Controls.Add($okButton)

$cancelButton = New-Object System.Windows.Forms.Button
$cancelButton.Location = New-Object System.Drawing.Point(120,430)
$cancelButton.Size = New-Object System.Drawing.Size(75,23)
$cancelButton.Text = 'Cancel'
$cancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$form.CancelButton = $cancelButton
$form.Controls.Add($cancelButton)

#browseButton

$labelbrowse = New-Object System.Windows.Forms.Label
$labelbrowse.Location = New-Object System.Drawing.Point(110,380)
$labelbrowse.Size = New-Object System.Drawing.Size(450,30)
$labelbrowse.Text = "To create VM's in bulk click Browse and select the input CSV file."
$labelbrowse.Font = 'Microsoft Sans Serif,11'
$form.Controls.Add($labelbrowse)

$browseButton = New-Object System.Windows.Forms.Button
$browseButton.Location = New-Object System.Drawing.Point(360,430)
$browseButton.Size = New-Object System.Drawing.Size(75,23)
$browseButton.Text = 'Browse'
$browseButton.Enabled = $false
$browseButton.Add_Click({$FileBrowser.ShowDialog()})
$form.Controls.Add($browseButton)

#VM Name
$label = New-Object System.Windows.Forms.Label
$label.Location = New-Object System.Drawing.Point(10,20)
$label.Size = New-Object System.Drawing.Size(95,22)
$label.AutoSize = $false
$label.Text = 'VM Name *:'
$label.Font = 'Microsoft Sans Serif,11'
$form.Controls.Add($label)

$textBox = New-Object System.Windows.Forms.TextBox
$textBox.Location = New-Object System.Drawing.Point(150,20)
$textBox.Size = New-Object System.Drawing.Size(160,22)
$textBox.Font = 'Microsoft Sans Serif,11'
$textBox.AutoSize = $false
$form.Controls.Add($textBox)

# Resource Pool
$label1 = New-Object System.Windows.Forms.Label
$label1.Location = New-Object System.Drawing.Point(10,50)
$label1.Size = New-Object System.Drawing.Size(120,22)
$label1.AutoSize = $false
$label1.Text = 'Resource Pool *:'
$label1.Font = 'Microsoft Sans Serif,11'
$form.Controls.Add($label1)

$textBox1 = New-Object System.Windows.Forms.TextBox
$textBox1.Location = New-Object System.Drawing.Point(150,50)
$textBox1.Size = New-Object System.Drawing.Size(160,22)
$textBox1.Font = 'Microsoft Sans Serif,11'
$textBox1.AutoSize = $false
$form.Controls.Add($textBox1)


# Memory
$label2 = New-Object System.Windows.Forms.Label
$label2.Location = New-Object System.Drawing.Point(10,80)
$label2.Size = New-Object System.Drawing.Size(140,22)
$label2.AutoSize = $false
$label2.Text = 'VM Memory (GB) *:'
$label2.Font = 'Microsoft Sans Serif,11'
$form.Controls.Add($label2)

$textBox2 = New-Object System.Windows.Forms.TextBox
$textBox2.Location = New-Object System.Drawing.Point(150,80)
$textBox2.Size = New-Object System.Drawing.Size(160,22)
$textBox2.Font = 'Microsoft Sans Serif,11'
$textBox2.AutoSize = $false
$form.Controls.Add($textBox2)


# CPU Number
$label3 = New-Object System.Windows.Forms.Label
$label3.Location = New-Object System.Drawing.Point(10,110)
$label3.Size = New-Object System.Drawing.Size(140,22)
$label3.AutoSize = $false
$label3.Text = "Number of CPU's *:"
$label3.Font = 'Microsoft Sans Serif,11'
$form.Controls.Add($label3)

$textBox3 = New-Object System.Windows.Forms.TextBox
$textBox3.Location = New-Object System.Drawing.Point(150,110)
$textBox3.Size = New-Object System.Drawing.Size(160,22)
$textBox3.Font = 'Microsoft Sans Serif,11'
$textBox3.AutoSize = $false
$form.Controls.Add($textBox3)

# Number of Disk's (Size)
$label4 = New-Object System.Windows.Forms.Label
$label4.Location = New-Object System.Drawing.Point(10,140)
$label4.Size = New-Object System.Drawing.Size(125,22)
$label4.AutoSize = $false
$label4.Text = "Disks in GB *:"
$label4.Font = 'Microsoft Sans Serif,11'
$form.Controls.Add($label4)

$label4a = New-Object System.Windows.Forms.Label
$label4a.Location = New-Object System.Drawing.Point(320,135)
$label4a.Size = New-Object System.Drawing.Size(300,35)
$label4a.AutoSize = $false
$label4a.Text = "Use semicolon for multiple Disks e.g. 150;1024"
$label4a.Font = new-object System.Drawing.Font('Ariel',11,[System.Drawing.FontStyle]::Bold)
$form.Controls.Add($label4a)

$textBox4 = New-Object System.Windows.Forms.TextBox
$textBox4.Location = New-Object System.Drawing.Point(150,140)
$textBox4.Size = New-Object System.Drawing.Size(160,22)
$textBox4.Font = 'Microsoft Sans Serif,11'
$textBox4.AutoSize = $false
$form.Controls.Add($textBox4)

# DropDownBox Guest OS

$DropDownBoxlabel = New-Object System.Windows.Forms.Label
$DropDownBoxlabel.Location = New-Object System.Drawing.Point(10,180)
$DropDownBoxlabel.Size = New-Object System.Drawing.Size(115,22)
$DropDownBoxlabel.AutoSize = $false
$DropDownBoxlabel.Text = "Guest OS *:"
$DropDownBoxlabel.Font = 'Microsoft Sans Serif,11'
$form.Controls.Add($DropDownBoxlabel)

$DropDownBox = New-Object System.Windows.Forms.ComboBox
$DropDownBox.Location = New-Object System.Drawing.Point(150,180)
$DropDownBox.Size = New-Object System.Drawing.Size(350,22)
$DropDownBox.Font = 'Microsoft Sans Serif,11'
$DropDownBox.AutoSize = $false
$DropDownBox.AutoCompleteMode = 'Suggest'
$DropDownBox.AutoCompleteSource = 'ListItems'
$DropDownBox.Sorted = $true
$DropDownBox.DropDownHeight = ($osDesc).count
$form.Controls.Add($DropDownBox)

$osver = @{}
foreach ($osd in $osDesc)
{
    $osver.Add($osd.FullName,$osd.Id)
}
$osver.Keys | ForEach-Object {$DropDownBox.Items.Add($_)} | Out-Null


# Datastore

$DataStore_list = Get-Datastore

$label5 = New-Object System.Windows.Forms.Label
$label5.Location = New-Object System.Drawing.Point(10,210)
$label5.Size = New-Object System.Drawing.Size(115,22)
$label5.AutoSize = $false
$label5.Text = "Datastore *:"
$label5.Font = 'Microsoft Sans Serif,11'
$form.Controls.Add($label5)

$textBox5 = New-Object System.Windows.Forms.ComboBox
$textBox5.Location = New-Object System.Drawing.Point(150,210)
$textBox5.Size = New-Object System.Drawing.Size(320,22)
$textBox5.Font = 'Microsoft Sans Serif,11'
$textBox5.AutoCompleteMode = 'Suggest'
$textBox5.AutoCompleteSource = 'ListItems'
$textBox5.AutoSize = $false
$textBox5.Sorted = $true
$form.Controls.Add($textBox5)

$DataStore_list | ForEach-Object {$textBox5.Items.Add($_)} | Out-Null


# Network Name
$label6 = New-Object System.Windows.Forms.Label
$label6.Location = New-Object System.Drawing.Point(10,240)
$label6.Size = New-Object System.Drawing.Size(125,22)
$label6.AutoSize = $false
$label6.Text = "Network Name *:"
$label6.Font = 'Microsoft Sans Serif,11'
$form.Controls.Add($label6)

$label6a = New-Object System.Windows.Forms.Label
$label6a.Location = New-Object System.Drawing.Point(320,235)
$label6a.Size = New-Object System.Drawing.Size(310,35)
$label6a.AutoSize = $false
$label6a.Text = "Use semicolon for adding multiple Networks e.g. Prod-Net;DEV-Net"
$label6a.Font = new-object System.Drawing.Font('Ariel',11,[System.Drawing.FontStyle]::Bold)
$form.Controls.Add($label6a)

$textBox6 = New-Object System.Windows.Forms.TextBox
$textBox6.Location = New-Object System.Drawing.Point(150,240)
$textBox6.Size = New-Object System.Drawing.Size(160,22)
$textBox6.Font = 'Microsoft Sans Serif,11'
$textBox6.AutoSize = $false
$form.Controls.Add($textBox6)


# Template Name
$label7 = New-Object System.Windows.Forms.Label
$label7.Location = New-Object System.Drawing.Point(10,290)
$label7.Size = New-Object System.Drawing.Size(125,40)
$label7.AutoSize = $false
$label7.Text = "Template Name: (Optional)"
$label7.Font = 'Microsoft Sans Serif,11'
$form.Controls.Add($label7)

$label7a = New-Object System.Windows.Forms.Label
$label7a.Location = New-Object System.Drawing.Point(320,290)
$label7a.Size = New-Object System.Drawing.Size(310,35)
$label7a.AutoSize = $false
$label7a.Text = "Only add VM Name and Resource Pool when using Templates."
$label7a.Font = new-object System.Drawing.Font('Ariel',11,[System.Drawing.FontStyle]::Bold)
$form.Controls.Add($label7a)

$textBox7 = New-Object System.Windows.Forms.TextBox
$textBox7.Location = New-Object System.Drawing.Point(150,290)
$textBox7.Size = New-Object System.Drawing.Size(160,22)
$textBox7.Font = 'Microsoft Sans Serif,11'
$textBox7.AutoSize = $false
$textBox7.Add_Click({

    $textBox2.Enabled = $false
    $textBox3.Enabled = $false
    $textBox4.Enabled = $false
    $textBox5.Enabled = $false
    $textBox6.Enabled = $false
    $DropDownBox.Enabled = $false
})
$form.Controls.Add($textBox7)

#Radio Buttons

$radiobutton1 = New-Object System.Windows.Forms.RadioButton
$radiobutton1.Location = New-Object System.Drawing.Point(40,330)
$radiobutton1.Size = New-Object System.Drawing.Size(150,40)
$radiobutton1.Font = 'Microsoft Sans Serif,11'
$radiobutton1.Text = "Create single VM"
$radiobutton1.Checked = $true
$radiobutton1.Add_Click({
    $textBox.Enabled = $true
    $textBox1.Enabled = $true
    $textBox2.Enabled = $true
    $textBox3.Enabled = $true
    $textBox4.Enabled = $true
    $textBox5.Enabled = $true
    $textBox6.Enabled = $true
    $textBox7.Enabled = $true
    $DropDownBox.Enabled = $true
    $browseButton.Enabled = $false
})
$form.Controls.Add($radiobutton1)

$radiobutton2 = New-Object System.Windows.Forms.RadioButton
$radiobutton2.Location = New-Object System.Drawing.Point(200,330)
$radiobutton2.Size = New-Object System.Drawing.Size(150,40)
$radiobutton2.Font = 'Microsoft Sans Serif,11'
$radiobutton2.Text = "Create bulk VM's"
$radiobutton2.Add_Click({
    $textBox.Enabled = $false
    $textBox1.Enabled = $false
    $textBox2.Enabled = $false
    $textBox3.Enabled = $false
    $textBox4.Enabled = $false
    $textBox5.Enabled = $false
    $textBox6.Enabled = $false
    $textBox7.Enabled = $false
    $DropDownBox.Enabled = $false
    $browseButton.Enabled = $true
})
$form.Controls.Add($radiobutton2)

$form.Topmost = $true

$form.Add_Shown({$textBox.Select()})
$form.ShowDialog()

#GUI Code Ends

# If the condition matches the Loop is used for creating VM's from a Input csv file. Error handling is also built in to the code.
try
{
    if (![string]::IsNullOrEmpty($FileBrowser.FileName))
    {
        Write-Host "You have selected the input file: "$FileBrowser.FileName"" -BackgroundColor Green -ForegroundColor Black -ErrorAction Stop

        $VM_CSV = Import-Csv -Path $FileBrowser.FileName -Encoding UTF8

        foreach($vm in $VM_CSV)
        {
            $VM_Name = $vm.Name
            $Resource_Pool = $vm.ResourcePool
            $Memory_GB = $vm.MemoryGB
            $Num_Cpu = $vm.CpuNumber
            $Disk_GB = $vm.DiskGB.Split(';')
            $GuestOS = $osver[$vm.GuestOS]
            $Datastore = $vm.Datastore
            $Network_Name = $vm.Network_Name.Split(';')
            $VMTemplate = $vm.VMTemplate

            if ($VMTemplate)
            {
                New-VM -Name $VM_Name -ResourcePool $Resource_Pool -Template (Get-Template $VMTemplate) -ErrorAction Stop
            }
            else
            {
                New-VM -Name $VM_Name -ResourcePool $Resource_Pool -MemoryGB $Memory_GB -NumCpu $Num_Cpu -DiskGB $Disk_GB -GuestId $GuestOS -Datastore $Datastore -Portgroup (Get-VDPortgroup -Name $Network_Name) -CD -ErrorAction Stop
            }
        }
   }
   else
   {
        $VM_Name = ($textBox).Text
        $Resource_Pool = ($textBox1).Text
        $Memory_GB = ($textBox2).Text
        $Num_Cpu = ($textBox3).Text
        $Disk_GB = ($textBox4).Text.Split(';')
        $GuestOS = $osver[($DropDownBox).Text]
        $Datastore = ($textBox5).Text
        $Network_Name = ($textBox6).Text.Split(';')
        $VMTemplate = ($textBox7).Text

        if ($VMTemplate)
        {
            New-VM -Name $VM_Name -ResourcePool $Resource_Pool -Template (Get-Template $VMTemplate) -ErrorAction Stop
        }
        else
        {
            New-VM -Name $VM_Name -ResourcePool $Resource_Pool -MemoryGB $Memory_GB -NumCpu $Num_Cpu -DiskGB $Disk_GB -GuestId $GuestOS -Datastore $Datastore -Portgroup (Get-VDPortgroup -Name $Network_Name) -CD -ErrorAction Stop
        }
    }
}
catch
{
    Write-Host "VM details not entered properly or a proper input file is not selected. Please try again." -ForegroundColor White -BackgroundColor Red
}

#Disconnect the open session to the ESXi or vCenter.
Disconnect-VIServer * -Confirm:$false -Force