At some point in the near future, I have to create several hundred new VM’s. These VM’s will be using the same Customization Specification, but some will need to have Static IP addresses, and others will need to have DHCP addresses that are reserved based on Mac Address.
The Task
Alright, how am I going to create 400-500 VM’s with specific names and specific IP’s (with some being DHCP)? I know there are some tools like the RCU from NetApp that will rapidly provision VM’s, but I’m not looking for 100% clones, as not all of these are going to be used for the same purpose (not using VDI here).
Customization Specifications typically can only be used once per VM when attempting to use a Static IP address. Using DHCP, a Customization Specification can be easily reused, as it doesn’t change. The problem is, what if I want to give each VM a Static IP. That requirement makes it a little more difficult.
The Tool: PowerCLI
There are a couple new cmdlets in the 4.0 Update 1 release of the PowerCLI that will help accomplish this task.
- Get-OSCustomizationNicMapping
- Set-OSCustomizationNicMapping
Using these together in a PowerCLI script, settings like IP address (if static), DHCP, gateway, DNS & WINS settings, and Mac Address can easily be set.
The syntax for these are as follows:
Get-OSCustomizationNicMapping
SYNTAX
Get-OSCustomizationNicMapping [-Spec] <OSCustomizationSpec[]> [-Server <VIServer[]>] [<CommonParameters>]Set-OSCustomizationNicMapping
SYNTAX
Set-OSCustomizationNicMapping -OSCustomizationNicMapping <OSCustomizationNicMapping[]> [-Position <Int32>] [-Server <VIServer[]>] [-IpMode <OSCustomizationIPMode>] [-VCApplicationArgument <String>] [[-IpAddress] <String>] [[-SubnetMask] <String>] [[-DefaultGateway] <String>] [-AlternateGateway <String>] [[-Dns] <String[]>] [-Wins <String[]>] [-WhatIf] [-Confirm] [<CommonParameters>]Set-OSCustomizationNicMapping -OSCustomizationNicMapping <OSCustomizationNicMapping[]> [-NetworkAdapterMac <String>] [-Server <VIServer[]>] [-IpMode <OSCustomizationIPMode>] [-VCApplicationArgument <String>] [[-IpAddress] <String>] [[-SubnetMask] <String>] [[-DefaultGateway] <String>] [-AlternateGateway <String>] [[-Dns] <String[]>] [-Wins <String[]>] [-WhatIf] [-Confirm] [<CommonParameters>]
Get-Help Get/Set-OSCustomizationNicMapping -full can give you more information on each of these cmdlets.
My Script
So I put together a little script to read content from a file, set a nic mapping for the selected Customization Specification, clone the VM, and set the appropriate VLAN for the VM.
The text file proceeds with the assumption that the DNS and WINS servers are the same. The pdnswins and sdnswins variables are used twice each, one for the primary DNS/WINS and once for the secondary DNS/WINS. Here are the contents of my text file that contains my VM names and other settings.
basevm,datastore,vmhost,custspec,vmname,ipaddress,subnet,gateway,pdnswins,sdnswins,vlan
BASEVM,DS1,ESXi1,W2K3,VM01,192.168.0.80,255.255.255.0,192.168.0.1,192.168.0.199,192.168.0.198,Primary
BASEVM,DS1,ESXi1,W2K3,VM02,192.168.0.81,255.255.255.0,192.168.0.1,192.168.0.199,192.168.0.198,Primary
BASEVM,DS1,ESXi1,W2K3,VM03,192.168.0.82,255.255.255.0,192.168.0.1,192.168.0.199,192.168.0.198,Primary
BASEVM,DS1,ESXi1,W2K3,VM04,192.168.255.83,255.255.255.0,192.168.0.1,192.168.0.199,192.168.0.198,Secondary
BASEVM,DS1,ESXi1,W2K3,VM05,192.168.255.84,255.255.255.0,192.168.0.1,192.168.0.199,192.168.0.198,Secondary
I saved the file as C:vms.csv. Even though I named the file with a .csv extenstion, I decided to use colons rather than commas. I did this because I wanted to send multiple DNS/WINS entries to my script, but I’ll get into that a little later. I have updated the script to use the standard comma delimiter.
The script to clone the VM’s and set their appropriate values
########################################################## # cloneandsetip.ps1 # Jase McCarty 6/5/2010 # Posh Script to clone VM's and set appropriate # IP addresses in Windows Virtual Machines ########################################################## Connect-VIServer vcenter.jasemccarty.com $vmlist = Import-CSV C:vms.csv foreach ($item in $vmlist) { # I like to map out my variables $basevm = $item.basevm $datastore = $item.datastore $vmhost = $item.vmhost $custspec = $item.custspec $vmname = $item.vmname $ipaddr = $item.ipaddress $subnet = $item.subnet $gateway = $item.gateway $pdns = $item.pdnswins $pwins = $item.pdnswins $sdns = $item.sdnswins $swins = $item.sdnswins $vlan = $item.vlan #Get the Specification and set the Nic Mapping (Apply 2 DNS/WINS if 2 are present) If ($Varable) { Get-OSCustomizationSpec $custspec | Get-OSCustomizationNicMapping | Set-OSCustomizationNicMapping -IpMode UseStaticIp -IpAddress $ipaddr -SubnetMask $subnet -DefaultGateway $gateway -Dns $pdns,$sdns -Wins $pwins,$swins } else { Get-OSCustomizationSpec $custspec | Get-OSCustomizationNicMapping | Set-OSCustomizationNicMapping -IpMode UseStaticIp -IpAddress $ipaddr -SubnetMask $subnet -DefaultGateway $gateway -Dns $pdns -Wins $pwins } #Clone the BaseVM with the adjusted Customization Specification New-VM -Name $vmname -VM $basevm -Datastore $datastore -VMHost $vmhost | Set-VM -OSCustomizationSpec $custspec -Confirm:$false #Set the Network Name (I often match PortGroup names with the VLAN name) Get-VM -Name $vmname | Get-NetworkAdapter | Set-NetworkAdapter -NetworkName $vlan -Confirm:$false #Remove the NicMapping (Don't like to leave things unkept) Get-OSCustomizationSpec $custspec | Get-OSCustomizationNicMapping | Remove-OSCustomizationNicMapping -Confirm:$false }
Set-OSCustomizationNicMapping is very powerful. Further examination of the documentation will show that things like setting the Mac Address and Alternate Gateway are also possible.
The Gotchas
There are a couple gotchas that I found, and you might want to be aware of.
- The setting -PrimaryWins in the documentation does not work, use -Wins. Documentation and error messages will continue to state -PrimaryWins, but that attribute doesn’t work.
- Multiple settings for DNS/WINS must read something like this 192.168.0.199,192.168.0.198.I had some difficulty passing 2 DNS/WINS entries into a single variable, so I am basically performing a check to see if a second entry is present.
In Closing
Thanks VMware for the very useful cmdlets to help make our jobs easier.
For more info on each of these commands, look here for the VMware documentation:
Great stuff Jase, thanks for posting
Quick question, where do you specify which vm template to use when deploying these? Is that ‘basevm?’
Thanks
Doh! Just re-read it and saw where you specified the custom spec. However what did you specify when making your customization specifications file? Specifically under Network? Typical? and just allowed the script to set the IP addresses? Or Custom setting?
Also you are deploying these from a template? Just cloning another VM? Is that correct?
Just a template. And the CustomizationSpec is setup for DHCP.
Cheers,
Jase
Thanks Jase
However, I run into 2 problems when I attempt to use a template:
“New-VM : 3/9/2011 2:23:10 PM New-VM Could not find VirtualMachine with name ‘Template_w2k3r2e64’.” When in fact there is a template with that name.
“New-VM : 3/9/2011 2:23:10 PM New-VM Value cannot be found for the mandatory parameter VM”
Any ideas?
Ok, I got it working(sort of)with some changes to your script. Now its failing when it attempts to run Remove-OSCustomizationNicMapping after it creates the first VM. It fails in the same spot no matter how many I try to deploy at once.
cmdlet Remove-OSCustomizationNicMapping at command pipeline position 3
Supply values for the following parameters:
OSCustomizationNicMapping[0]:
Can you contact me offline to discuss? Would be more than happy to share my results once this is working as it should.
Thanks Jase!
I got around that error with this.
Get-OSCustomizationSpec $custspec | Get-OSCustomizationNicMapping | Set-OSCustomizationNicMapping -IPMode UseDHCP
To just set it back to dchp.
My issue is Im not getting the IP’s to apply at all. Ive tried lots of variations to the syntax and nothing works. I can open the custspec and see the IP’s getting added in there but they dont apply to the VM created from my template.
Did you change and of the New-VM stuff?
I haven’t made any changes to the script.
I’ll have to run through this in my new lab and see if there are any updates for vSphere 4.1.
Thanks,
Jase
The IP’s are working now as you wrote it. I blew away the template and made a new one.
Thanks Jase
I have a very similiar script that will do the same, the only thing I am unsure of, is how do you set the Network Label (PortGroup) for the network adapter you are creating the NicMapping for? There does not seem to be a switch for attaching network label.
We have many PortGroups in the cluster and I need to assign the correct network label to the NetworkAdapter so that the cusomisation wizard can complete and connect to the domain.
thanks
Paul
Please ignore that last post, I had not read all of the script and can see you set it with:
Get-VM -Name $vmname | Get-NetworkAdapter | Set-NetworkAdapter -NetworkName $vlan -Confirm:$false
I had thought maybe we could have done it through the Set-OSCustomizationNicMapping
cmdlt.
Cheers
Paul
I tried using the script on Linux templates?
Its not setting the default gateway on boot?
Is there something I am missing? Do I need to modify script for linux VMs?
I’m not certain it will work on Linux.
I’ll have to try it out.
I am going to be testing this out, but I was wondering what the if ($Varable) section is doing. Where was Varable set?
@Mark
Also seeing these errors, not sure what to do?
New-VM : 2/17/2012 12:29:04 PM New-VM An item with the same key has a
lready been added.
At U:\powercli\deployvm.ps1:36 char:11
+ New-VM <<<< -Name $vmname -template $basevm -Datastore $datastore -VMHos
t $vmhost | Set-VM -OSCustomizationSpec $custspec -Confirm:$false
+ CategoryInfo : NotSpecified: (:) [New-VM], VimException
+ FullyQualifiedErrorId : Core_BaseCmdlet_UnknownError,VMware.VimAutomatio
n.ViCore.Cmdlets.Commands.NewVM
cmdlet Remove-OSCustomizationNicMapping at command pipeline position 3
Supply values for the following parameters:
OSCustomizationNicMapping[0]: 0
OSCustomizationNicMapping[1]: false
OSCustomizationNicMapping[2]: false
OSCustomizationNicMapping[3]: false
OSCustomizationNicMapping[4]: true
OSCustomizationNicMapping[5]:
Remove-OSCustomizationNicMapping : Cannot bind parameter 'OSCustomizationNicMap
ping'. Cannot convert the "0" value of type "System.String" to type "VMware.Vim
Automation.ViCore.Types.V1.OSCustomization.OSCustomizationNicMapping".
At U:\powercli\deployvm.ps1:42 char:105
+ Get-OSCustomizationSpec $custspec | Get-OSCustomizationNicMapping | Remov
e-OSCustomizationNicMapping <<<< -Confirm:$false
+ CategoryInfo : InvalidArgument: (:) [Remove-OSCustomizationNicM
apping], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,VMware.VimAutomat
ion.ViCore.Cmdlets.Commands.RemoveOSCustomizationNicMapping
@Mark
Note that you can no longer pipe to Remove-OSCustomizationNicMapping which is why your problem is occuring and now the command may look something more like this,
Remove-OSCustomizationNicMapping -OSCustomizationNicMapping (Get-OSCustomizationSpec $custspec | Get-OSCustomizationNicMapping) -Confirm:$false
This will stop you getting that error
but beware as I believe this will remove the NIC1 altogether meaning you would have to create a new one on the next run of the script.
If anyone knows the new commands that would be great.
@Jase, I am currently developing this for multiple NICs, think I am going to add the adapters every time rather than just modify the existing ones. Unless you already had something that did multiple NICs? If not don’t worry I’ll try and create new ones, thanks for this post really gave me a great starting point.
@drew
drew, how did you modify the script to pickup the template name and the new vmname?
Hi, I am trying to use this script to deploy about 45 servers. All with static IP’s.
I find that I have to run it in the 32 bit version of PowerCLI.
My problem is that the Set-OSCustomizationNicMapping does not work. It does not modify the Custom Spec at all. I am working on vSphere 5.5 and PowerCLI 5.5 Release 1. Is this a problem?
here is the code:
$custspec = “PowerCLI”
$ipaddr = “10.0.0.2”
$subnet = “255.255.255.0”
$gateway = “10.0.0.1”
$pdns = “10.0.0.20”
Get-OSCustomizationSpec $custspec |
Get-OSCustomizationNicMapping |
Set-OSCustomizationNicMapping -IpMode UseStaticIp -IpAddress $ipaddr -SubnetMask $subnet -DefaultGateway $gateway -Dns $pdns
@OldDog
I copied a working OSCustomizationSpec and used that. It worked, at least on one machine. So I am thinking there was something wrong with my original, I will try with the rest of my servers in the morning.
#Remove the NicMapping (Don’t like to leave things unkept) Get-OSCustomizationSpec ++
This was causing the script to fail. apparently in 5.5 the Set-OSCustomizationNicMapping expects there to be something in the Nic fields, even if its just DHCP. When I commented this piece out, the script ran as expected. It just overwrites whatever might be in there. It might pay to set everything back to DHCP after the script has run in order to get ready for the next batch.
Any body tried this script with even MAC address assignment to VM to be cloned along with static IP?
Not certain.
Hi,
I have a code for NIC customization:
My Query : I have 2 NIC cards, first IP requires a gateway and second IP should have no gateway. I get error for below code that when i use ‘UseStaticIP’ IPmode it requires gateway for second IP too. Can you please suggest how to handle in customization code ? I have used same cmds using if else based on number of NICs.
CODE:
$nicMapping = Get-OSCustomizationNicMapping -OSCustomizationSpec $specClone
$specClone | New-OSCustomizationNicMapping -Position $l -IpMode UseStaticIP -IpAddress $ipTemp -SubnetMask $subnetMaskTemp -Dns $dnsServers[$k].split(‘,’)