{"id":269,"date":"2020-11-24T15:59:27","date_gmt":"2020-11-24T15:59:27","guid":{"rendered":"https:\/\/jadijkstra.nl\/?p=269"},"modified":"2021-01-04T13:56:21","modified_gmt":"2021-01-04T13:56:21","slug":"multiple-vm-deployment-with-powercli","status":"publish","type":"post","link":"https:\/\/jadijkstra.nl\/index.php\/2020\/11\/24\/multiple-vm-deployment-with-powercli\/","title":{"rendered":"Multiple VM Deployment with PowerCLI"},"content":{"rendered":"\n<p>For a customer we where checking the posibilities to deploy multiple VM&#8217;s simulatinously and in one time. Instead of deploying machine by machine<\/p>\n\n\n\n<p>We have checked vRealize Orchestration, but maybe this tool is a little too much for just deploying machines. So when looking further, there are lots of examples of deploying VM&#8217;s with PowerCLI<\/p>\n\n\n\n<p>But yet, not the way we wanted it to happen. So from all the PowerCLI scripts we have created one for our (and maybe yours) needs and I will discuss this in this post.<\/p>\n\n\n\n<p>What we want to achieve is to deploy multiple machines from 1 created Template. Unfortunately there is no option in vCenter itself. It&#8217;s also possible to deploy VM&#8217;s with vRealize Orchestrator. But for the latter, the learning curve might be high, and additional resources are needed (for the vRealize Appliance).<\/p>\n\n\n\n<p>So which options are left then? Well PowerCLI!<br>It becomes very easy to deploy multiple machines from 1 template.<br>For the customer it is not possible to just delete the current pool of machines and deploy new ones as they have 24\/7 customers. So what&#8217;s the idea next? Well, deploy the same amount of servers and do a drain on the current machines and give them access on the new &#8220;pool&#8221;<\/p>\n\n\n\n<p>So how do we setup the &#8220;pool&#8221;, they have say 18 Production Machines in use. To do the turn over to the new pool, they use even numbers for let&#8217;s say the old pool and non-even numbers for the new pool so it&#8217;s scalable from scripting perspective! Downside : you need (temporary) extra capacity for the deployment of new machines. Afterwards the old machines can be destroyed and the next month (or when needed) the whole procedure can be done again, but then from non-even to even numbering of machines<\/p>\n\n\n\n<p>So what have I done? I googled for several scripts and added my own flavor to it \ud83d\ude42<\/p>\n\n\n\n<p>To start:<br>There is 1 PowerCLI script (let&#8217;s say we call it : deployvm.ps1)<br>There is 1 Configuration File which will be used for deployment of the machine, let&#8217;s say pool.cfg, pool.cfg contains all the information regarding vCenter Connection, ESX Host, Networking, Gateway, Storage etc, here is the list of variables:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n$vcenter = $config.&quot;vcenter&quot;\n$serverRole = $config.&quot;server role&quot;\n$template = $config.&quot;template&quot;\n$templateFolder = $config.&quot;template folder&quot;\n$osCustomization = $config.&quot;oscust&quot;\n$resourcePool = $config.&quot;resourcepool&quot;\n$VMhost = $config.&quot;VMHost&quot;\n$folder = $config.&quot;folder&quot;\n$cpu = $config.&quot;cpu&quot;\n$mem = $config.&quot;mem&quot;\n$disk1 = $config.&quot;disk1&quot;\n$disk1Mode = $config.&quot;disk1 mode&quot;\n$disk1DataStore = $config.&quot;disk1 datastore&quot;\n$disk2 = $config.&quot;disk2&quot;\n$disk2Mode = $config.&quot;disk2 mode&quot;\n$disk2DataStore = $config.&quot;disk2 datastore&quot;\n$nic1 = $config.&quot;nic1&quot;\n$mask1 = $config.&quot;mask1&quot;\n$gw = $config.&quot;gw&quot;\n$dns1 = $config.&quot;dns1&quot;\n$dns2 = $config.&quot;dns2&quot;\n<\/pre><\/div>\n\n\n<p>The pool1.csv and pool2.csv contains the machines with non-even (the 1) and the even (the 2) numbers of machines, example:<\/p>\n\n\n\n<p>vmname,vmip<br>RDS_VM_001,10.0.0.167<br>RDS_VM_003,10.0.0.169<br>RDS_VM_005,10.0.0.171<br>RDS_VM_007,10.0.0.173<br>RDS_VM_009,10.0.0.175<br>RDS_VM_011,10.0.0.177<br>RDS_VM_013,10.0.0.179<br>RDS_VM_015,10.0.0.181<br>RDS_VM_017,10.0.0.183<br>RDS_VM_019,10.0.0.185<br>RDS_VM_021,10.0.0.187<br>RDS_VM_023,10.0.0.189<br>RDS_VM_025,10.0.0.191<br>RDS_VM_027,10.0.0.193<br>RDS_VM_029,10.0.0.195<br>RDS_VM_031,10.0.0.197<br>RDS_VM_033,10.0.0.199<br>RDS_VM_035,10.0.0.201<\/p>\n\n\n\n<p>If have also used non-even numbers for the ip-addresses. Feel free to use DHCP instead!<\/p>\n\n\n\n<p>The Even numbers are as expected:<\/p>\n\n\n\n<p>vmname,vmip<br>RDS_VM_002,10.0.0.168<br>RDS_VM_004,10.0.0.170<br>RDS_VM_006,10.0.0.172<br>RDS_VM_008,10.0.0.174<br>RDS_VM_010,10.0.0.176<br>RDS_VM_012,10.0.0.178<br>RDS_VM_014,10.0.0.180<br>RDS_VM_016,10.0.0.182<br>RDS_VM_018,10.0.0.184<br>RDS_VM_020,10.0.0.186<br>RDS_VM_022,10.0.0.188<br>RDS_VM_024,10.0.0.190<br>RDS_VM_026,10.0.0.192<br>RDS_VM_028,10.0.0.194<br>RDS_VM_030,10.0.0.196<br>RDS_VM_032,10.0.0.198<br>RDS_VM_034,10.0.0.200<br>RDS_VM_036,10.0.0.202<\/p>\n\n\n\n<p>So having these items in place, were going to the script.<br>To explain what I have done, when using the script, the config file (pool.cfg) must have the same name as for the input files for the vm&#8217;s i.e. pool1.csv &amp; pool2.csv. The 1 and 2 are needed to differentiate between them<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n &#91;CmdletBinding()]\nParam(\n   &#91;Parameter(Mandatory=$False,Position=1)]\n   &#91;ValidateNotNullOrEmpty()]\n   &#91;string]$csvfile\n)\n\nFunction Get-FileName($initialDirectory){\n    &#91;System.Reflection.Assembly]::LoadWithPartialName(&quot;System.windows.forms&quot;) | Out-Null\n    \n    $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog\n    $OpenFileDialog.initialDirectory = $initialDirectory\n    $OpenFileDialog.filter = &quot;CSV (*.csv)| *.csv&quot;\n    $OpenFileDialog.ShowDialog() | Out-Null\n    return $OpenFileDialog.filename\n}\n\n###############\n# Main script #\n###############\n\n#variables\n$ScriptRoot = Split-Path $MyInvocation.MyCommand.Path\n$StartTime = Get-Date -Format &quot;yyyyMMddHHmmss_&quot;\nif ($PSBoundParameters.ContainsKey('csvfile')){\n\t$vmlistfile = import-csv $csvfile\n}\nelse{\n\twhile ($csvfile -eq &quot;&quot;) {$csvfile=Get-FileName}\n\n}\n\t\n    $vmlistfile = import-csv $csvfile\n    $configfile = $csvfile.split('.')&#91;0]\n    $configfile = $configfile.Substring(0,$configfile.Length-1)\n    $configfile = $configfile + &quot;.cfg&quot;\n    $config = import-csv $configfile\n\n    $vcenter = $config.&quot;vcenter&quot;\n    $serverRole = $config.&quot;server role&quot;\n    $template = $config.&quot;template&quot;\n    $templateFolder = $config.&quot;template folder&quot;\n    $osCustomization = $config.&quot;oscust&quot;\n    $resourcePool = $config.&quot;resourcepool&quot;\n    $VMhost = $config.&quot;VMHost&quot;\n    $folder = $config.&quot;folder&quot;\n    $cpu = $config.&quot;cpu&quot;\n    $mem = $config.&quot;mem&quot;\n    $disk1 = $config.&quot;disk1&quot;\n    $disk1Mode = $config.&quot;disk1 mode&quot;\n    $disk1DataStore = $config.&quot;disk1 datastore&quot;\n    $disk2 = $config.&quot;disk2&quot;\n    $disk2Mode = $config.&quot;disk2 mode&quot;\n    $disk2DataStore = $config.&quot;disk2 datastore&quot;\n    $nic1 = $config.&quot;nic1&quot;\n    $mask1 = $config.&quot;mask1&quot;\n    $gw = $config.&quot;gw&quot;\n    $dns1 = $config.&quot;dns1&quot;\n    $dns2 = $config.&quot;dns2&quot;\n         \nConnect-VIServer $vcenter -Credential (Get-Credential $cred)\n\nforeach($vm in $vmlistfile)\n{\n   $vmname = $vm.&quot;vmname&quot;\n   $vmip = $vm.&quot;vmip&quot;\n\n#Get the Specification and set the Nic Mapping\nwrite-host $osCustomization\nwrite-host $vmip\nwrite-host $mask1\nwrite-host $gw\nwrite-host $dns1\nwrite-host $dns2\nwrite-host $vmname\n\nNew-OSCustomizationNicMapping -Spec $osCustomization -IpMode UseStaticIp \u2013Position 1 -IpAddress $vmip -SubnetMask $mask1 -DefaultGateway $gw -Dns $dns1\n\n#Create VM using Template with the adjusted Customization Specification\n\nNew-VM -Name $vmname -RunAsync -Template $template -Datastore $disk1DataStore -VMHost $VMhost -ResourcePool $resourcepool | Set-VM -OSCustomizationSpec $osCustomization -Confirm:$false\n\n#Set the Network Name\nGet-VM -Name $vmname | Get-NetworkAdapter | Set-NetworkAdapter -NetworkName $nic1 -Confirm:$false\n\n#Set the CPU and Memory\nGet-VM -Name $vmname  | Set-VM -MemoryGB $mem -NumCPU $cpu -Confirm:$false -RunAsync\n\n#Additional Disk\nGet-VM -Name $vmname | New-HardDisk -CapacityGB $disk2 -StorageFormat $disk2Mode -Confirm:$false\n\n#Remove the NicMapping\nGet-OSCustomizationSpec $osCustomization | Get-OSCustomizationNicMapping | Remove-OSCustomizationNicMapping -Confirm:$false\n\n#PowerOn VM\nStart-VM $vmname\n}\n\n#Disconnect from VC.\ndisconnect-VIServer $vcenter -Confirm:$false \n<\/pre><\/div>\n\n\n<p>Let&#8217;s start and execute the script!<br><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" loading=\"lazy\" width=\"942\" height=\"490\" src=\"https:\/\/jadijkstra.nl\/wp-content\/uploads\/2021\/01\/image-1.png\" alt=\"\" class=\"wp-image-316\" srcset=\"https:\/\/jadijkstra.nl\/wp-content\/uploads\/2021\/01\/image-1.png 942w, https:\/\/jadijkstra.nl\/wp-content\/uploads\/2021\/01\/image-1-300x156.png 300w, https:\/\/jadijkstra.nl\/wp-content\/uploads\/2021\/01\/image-1-768x399.png 768w\" sizes=\"(max-width: 942px) 100vw, 942px\" \/><\/figure>\n\n\n\n<p>When starting the script without any CSV file as parameter, a dialog box opens to open a CSV File:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" loading=\"lazy\" width=\"760\" height=\"364\" src=\"https:\/\/jadijkstra.nl\/wp-content\/uploads\/2021\/01\/image-2.png\" alt=\"\" class=\"wp-image-317\" srcset=\"https:\/\/jadijkstra.nl\/wp-content\/uploads\/2021\/01\/image-2.png 760w, https:\/\/jadijkstra.nl\/wp-content\/uploads\/2021\/01\/image-2-300x144.png 300w\" sizes=\"(max-width: 760px) 100vw, 760px\" \/><\/figure>\n\n\n\n<p>After that, you need to enter the vCenter Credentials in order to create new VM&#8217;s:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" loading=\"lazy\" width=\"650\" height=\"520\" src=\"https:\/\/jadijkstra.nl\/wp-content\/uploads\/2021\/01\/image-3.png\" alt=\"\" class=\"wp-image-318\" srcset=\"https:\/\/jadijkstra.nl\/wp-content\/uploads\/2021\/01\/image-3.png 650w, https:\/\/jadijkstra.nl\/wp-content\/uploads\/2021\/01\/image-3-300x240.png 300w\" sizes=\"(max-width: 650px) 100vw, 650px\" \/><\/figure>\n\n\n\n<p>When all goes well, the VM&#8217;s will be created:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" loading=\"lazy\" width=\"1024\" height=\"281\" src=\"https:\/\/jadijkstra.nl\/wp-content\/uploads\/2021\/01\/image-4-1024x281.png\" alt=\"\" class=\"wp-image-319\" srcset=\"https:\/\/jadijkstra.nl\/wp-content\/uploads\/2021\/01\/image-4-1024x281.png 1024w, https:\/\/jadijkstra.nl\/wp-content\/uploads\/2021\/01\/image-4-300x82.png 300w, https:\/\/jadijkstra.nl\/wp-content\/uploads\/2021\/01\/image-4-768x211.png 768w, https:\/\/jadijkstra.nl\/wp-content\/uploads\/2021\/01\/image-4-1536x422.png 1536w, https:\/\/jadijkstra.nl\/wp-content\/uploads\/2021\/01\/image-4.png 1588w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>When the deployment is finished we should have our new machines ready and running!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>For a customer we where checking the posibilities to deploy multiple VM&#8217;s simulatinously and in one time. Instead of deploying machine by machine We have checked vRealize Orchestration, but maybe this tool is a little too much for just deploying machines. So when looking further, there are lots of examples of deploying VM&#8217;s with PowerCLI [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/jadijkstra.nl\/index.php\/wp-json\/wp\/v2\/posts\/269"}],"collection":[{"href":"https:\/\/jadijkstra.nl\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jadijkstra.nl\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jadijkstra.nl\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/jadijkstra.nl\/index.php\/wp-json\/wp\/v2\/comments?post=269"}],"version-history":[{"count":6,"href":"https:\/\/jadijkstra.nl\/index.php\/wp-json\/wp\/v2\/posts\/269\/revisions"}],"predecessor-version":[{"id":320,"href":"https:\/\/jadijkstra.nl\/index.php\/wp-json\/wp\/v2\/posts\/269\/revisions\/320"}],"wp:attachment":[{"href":"https:\/\/jadijkstra.nl\/index.php\/wp-json\/wp\/v2\/media?parent=269"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jadijkstra.nl\/index.php\/wp-json\/wp\/v2\/categories?post=269"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jadijkstra.nl\/index.php\/wp-json\/wp\/v2\/tags?post=269"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}