Deploying a VM with PowerCLI in a Semi-Complex Environment

The following is a guest blog post by my brother Ben Liebowitz.  I guess virtualization runs in the family!  Follow him on Twitter at @ben_liebowitz.

————————————————————————

Last year, while working at a previous employer, I wanted to make it easier for less-experienced team members to deploy VMs, while making sure little to no mistakes are made.  I decided to go down the path of a PowerCLI script.

Before I get into the script that I wrote, I feel I should describe the environment.  A simple way for inexperienced co-workers to deploy VMs without them going on the wrong network/datastore, etc.

      • vCenter 4.1
      • Combination of ESX/ESXi 4.1
      • VM Platforms:
        • Development
        • Staging
        • Production
        • Workstations
      • Datastores:
        • vol_cdrives_dev
        • vol_cdrives_stg
        • vol_cdrives_prd
        • vol_transient_dev (for temp & swap files)
          (although the volume name is transient, the VMDKs don’t get removed after time)
        • vol_transient_stg (for temp & swap files)
          (although the volume name is transient, the VMDKs don’t get removed after time)
        • vol_transient_prd (for temp & swap files)
          (although the volume name is transient, the VMDKs don’t get removed after time)
        • vol_datadrives_dev
        • vol_datadrives_stg
        • vol_datadrives_prd
        • vol_workstations
      • Networks
        • DEV_STAGING
        • PROD
      • Folders
        • DEV
          • various sub-folders
        • STAGING
          • various sub-folders
        • PRODUCTION
          • various sub-folders

My templates only had a C drive, so the transient VMDK needed to be created (and data VMDK if necessary, not all VMs received data partitions).  The template VMs all lived on a templates datastore to keep space free on the production datastores.  As you can imagine, after deploying the VM from template, there were several steps that had to be done, manually.  I wanted to simplify that so other members of my team, or other teams, could deploy VMs without needing assistance from senior members of the team.

The script was written by taking examples of scripts that I found online and modifying them to fit my needs.

Here is a step by step breakdown of the script:
(you can click on each image for a larger version)

1. Run the script.
image

2.  The script connects to vCenter.
image

3.  A list of OS’s is displayed. Select a number from 1 to 11.
image

4. Once you selected a template, the choice you picked is displayed for 3 seconds.
(Along with this choice, a customization that goes with that OS is put into a variable.)
image

5.  Then you’re prompted to select a platform.
image

6.  You’re then shown what you choose, again, for 3 seconds.
(Along with this choice, a cdrives datastore, transient datastore, parent folder and network are fed into variables)
image

7.  You’re then shown a list of folders for the platform you selected in step 5.  If you just hit enter, the VM is placed at the root of the platform’s folder.
image

8.  The folder you selected (along with the platform’s folder) is displayed for 3 seconds.
image

9.  Then, you’re prompted to enter the name of the VM.
image

10.  The VM Deployment then begins.  You’ll now see a task show up in vCenter for the VM Deployment.
image

The VM is then deployed, just as it would from the VI Client.  After it’s done, the script changes the network, the folder location, and adds the transient VMDK.  Finally a message is displayed reminding them, after powering the VM on, to wait for it to restart and sysprep to run.  I always set my customizations to auto-login once, this way, I know it’s done when it’s logged in.

11. After the VM is deployed, the network portgroup is changed.
image

12. Then the folder location is changed to the choice you selected above.
image

13. And finally, the Transient VMDK is created and added.
image

The last steps were to assign an IP and change the drive letters.  C was always OS, D was always Transient, and E was always Data.  I wrote a separate script to change the CD drive letter to G, mount the new transient volume, and format/assign it’s drive letter.

When done, here’s a screenshot of the VM in vCenter.
image

 

Here is the script:
—————————————————————————–

write-host "VM Deployment Script"
write-host "Created by Ben Liebowitz"
write-host "version 1.0 - 8/27/2012 - BLiebowitz"

# Connect to vCenter
write-host "Connecting to vCenter..."
write-host "If Credentials are needed, you will be prompted."
connect-viserver -server vc.lab.local

# Template & Customization Selection
write-host "Select which template to deploy from:"
write-host ""
write-host "1. Windows 2008 R2 Standard Edition x64"
write-host "2. Windows 2008 R2 Enterprise Edition x64"
write-host "3. Windows 2008 R1 Standard Edition x86"
write-host "4. Windows 2008 R1 Enterprise Edition x86"
write-host "5. Windows 2008 R1 Enterprise Edition x64"
write-host "6. Windows 2003 R2 Standard Edition x86"
write-host "7. Windows 2003 R2 Standard Edition x64"
write-host "8. Windows 2003 R2 Enterprise Edition x86"
write-host "9. Windows 2003 R2 Enterprise Edition x64"
write-host "10. Windows 2000"
write-host "11. Windows XP"

$SIndex = read-host "Select a Template. Enter a number ( 1 - 11 )"

if ($SIndex -eq 1) {
$OS = "Windows 2008 R2 Standard Edition x64"
$TEMP = get-template -name "win2008r2std"
$CUSTOM = get-oscustomizationspec -Name "Windows Server 2008 (R2)"
} elseif ($SIndex -eq 2) {
$OS = "Windows 2008 R2 Enterprise Edition x64"
$TEMP = get-template -name "w2k8r2ent64"
$CUSTOM = get-oscustomizationspec -Name "Windows Server 2008 (R2)"
} elseif ($SIndex -eq 3) {
$OS = "Windows 2008 R1 Standard Edition x86"
$TEMP = get-template -name "w2k8r1std32sp1"
$CUSTOM = get-oscustomizationspec -Name "Windows Server 2008 (R1)"
} elseif ($SIndex -eq 4) {
$OS = "Windows 2008 R1 Enterprise Edition x86"
$TEMP = get-template -name "w2k8r1ent32sp1"
$CUSTOM = get-oscustomizationspec -Name "Windows Server 2008 (R1)"
} elseif ($SIndex -eq 5) {
$OS = "Windows 2008 R1 Enterprise Edition x64"
$TEMP = get-template -name "w2k8r1ent64sp1"
$CUSTOM = get-oscustomizationspec -Name "Windows Server 2008 (R1)"
} elseif ($SIndex -eq 6) {
$OS = "Windows 2003 R2 Standard Edition x86"
$TEMP = get-template -name "w2k3r2std32sp2"
$CUSTOM = get-oscustomizationspec -Name "Windows Server 2003 R2 x86 Standard Edition"
} elseif ($SIndex -eq 7) {
$OS = "Windows 2003 R2 Standard Edition x64"
$TEMP = get-template -name "w2k3r2std64sp2"
$CUSTOM = get-oscustomizationspec -Name "Windows Server 2003 R2 x64 Standard Edition"
} elseif ($SIndex -eq 8) {
$OS = "Windows 2003 R2 Enterprise Edition x86"
$TEMP = get-template -name "w2k3r2ent32sp2"
$CUSTOM = get-oscustomizationspec -Name "Windows Server 2003 R2 x86 Enterprise Edition"
} elseif ($SIndex -eq 9) {
$OS = "Windows 2003 R2 Enterprise Edition x64"
$TEMP = get-template -name "w2k3r2ent64sp2"
$CUSTOM = get-oscustomizationspec -Name "Windows Server 2003 R2 x64 Enterprise Edition"
} elseif ($SIndex -eq 10) {
$OS = "Windows 2000"
$TEMP = get-template -name "WIN2000"
$CUSTOM = ""
} else {
$OS = "Windows XP"
$TEMP = get-template -name "WINXP"
$CUSTOM = Get-oscustomizationspec -Name "Windows XP Professional"
}
write-host ""
write-host "You Picked: "$OS
write-host ""
start-sleep -s 3

# DEV/STG/PROD
write-host "Select Dev, Staging, Production or Workstation."
write-host ""
write-host "1. DEV"
write-host "2. STAGING"
write-host "3. PRODUCTION"
write-host "4. WORKSTATION"
$cdrive = read-host "Enter a number ( 1 - 4 )"
if ($cdrive -eq 1) {
$DATASTORE = "vol_vm_cdrives_dev"
$TRANSIENT = "vol_vm_transient_dev"
$TFOLDER = "Development"
$NETWORK = "Dev_Staging"
} elseif ($cdrive -eq 2) {
$DATASTORE = "vol_vm_cdrives_stg"
$TRANSIENT = "vol_vm_transient_stg"
$TFOLDER = "Staging"
$NETWORK = "Dev_Staging"
} elseif ($cdrive -eq 3) {
$DATASTORE = "vol_cdrives_prd"
$TRANSIENT = "vol_transient_prd"
$TFOLDER = "Production"
$NETWORK = "PROD"
} else {
$DATASTORE = "vol_vm_workstations"
$TFOLDER = "Workstations"
$NETWORK = "Prod_view"
}
write-host ""
write-host "You Picked: "$TFOLDER
write-host ""
start-sleep -s 3

# Folder Selection
write-host "Select which folder to store the VM..."
$FOLDER = get-folder -location $TFOLDER | Select Name | Sort-Object Name
$i = 1
$FOLDER | %{write-host $i":" $_.Name; $i++}
$SIndex = read-host "Select a Folder. Enter a number ( 1 -" $FOLDER.Count ")"
$SFOLDER = $FOLDER[$SIndex - 1].Name
write-host ""
write-host "You Picked folder: "$TFOLDER" "$SFOLDER
write-host ""
start-sleep -s 3

# VM Name Selection
$NAME = read-host "Please Enter the VM's Name: "

write-host ""
write-host "You Entered: "$NAME
write-host ""
start-sleep -s 3

# DEPLOYMENT VM
# *** You must use an ESX/ESXi host with the new-vm command, not your vCenter server.
new-vM -VMHost host1.lab.local -Name $NAME -Template $TEMP -Datastore $DATASTORE -OSCustomizationSpec $CUSTOM

# Change Network
# *** the Virtual Switch name may need to be changed to reflect the vswitch in your Environment
write-host "Changing the Network Portgroup..."
write-host ""
$VirtualPortGroup = get-vmhost host1.lab.local | get-virtualswitch -Name vSwitch0 | get-virtualportgroup -name $NETWORK

Get-VM -Name $NAME | get-networkadapter | set-networkadapter -NetworkName $VirtualportGroup -Confirm:$False

# Change Location
write-host "Moving the VM to the folder you selected above."
write-host ""
Move-VM -VM $NAME -Destination (Get-Folder -Name $SFOLDER -Location $TFOLDER) -confirm:$false

# Add Transient Hard Disk
write-host "Adding Transient Hard Disk."
write-host ""
new-harddisk -VM $NAME -CapacityKB 8388608 -StorageFormat Thin -datastore $TRANSIENT

write-host "After powering the VM on, wait for it to restart and sysprep to run."
write-host "After rebooting, the VM will auto-login once."
write-host "Then mount/format the D (Transient) drive, assign IP and join domain"

—————————————————————————–

As I mentioned, here is the script I wrote to change the CD drive letter and mount the D drive.  (the FORMAT command in DISKPART doesn’t work with some versions of Windows, so YMMV.)

—————————————————————————–

# Powershell script to change CD Drive Letter from D to G
# Created by BLiebowitz on 28-AUG-2012

(gwmi Win32_cdromdrive).drive | %{$a = mountvol $_ /l;mountvol $_ /d;$a = $a.Trim();mountvol G: $a}

# Get-WmiObject -Class Win32_LogicalDisk -ComputerName $NAME -Filter "DriveType=5" |foreach-Object {$_.DeviceID}

{
$DiskNum = 1
$DiskLBL = "Local Disk"

$command = $Null
$command = @"
SELECT DISK $DiskNum
ATTRIBUTES DISK CLEAR READONLY
ONLINE DISK
CONVERT MBR
CREATE PARTITION PRIMARY ALIGN=64
ASSIGN LETTER=D
FORMAT FS=NTFS UNIT=64k LABEL=$DiskLBL QUICK
"@
$command | diskpart
}

—————————————————————————–

Enjoy!

Share This:

3 thoughts on “Deploying a VM with PowerCLI in a Semi-Complex Environment

  1. Can this script support deployment of multiple VMs? (I want to automate the manual task of deploying many vms per day.)

    1. Not out of the box, but you can probably add a loop like from this post:

      Note: I’ve never tested this, so YMMV…

      Taken from: http://www.thinkvirt.com/?q=node/133

      Add a loop counter like the one below, and add the loop to the VMname variable like below.

      for($i = 1; $i -le 10; $i++)
      {
      $tempvm = “vServer-“+$i
      $array += $tempvm
      }
      foreach ($vm in $array)
      {
      $vm=new-vm -VMHost host1.lab.local -Name {$NAME + $i} -Template $TEMP -Datastore $DATASTORE -OSCustomizationSpec $CUSTOM -Confirm:$false
      }

Leave a Reply to sahilexe Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.