Automate Virtual Machine Provisioning using Netapp Powershell Toolkit, Hyper-V and SCVMM2012R2 PowerShell Cmdlets.

In this blog post i would show you a step by step process to automate the provisioning of Virtual Machines on a Hyper-V Infrastructure using Netapp Powershell Toolkit, Hyper-V and SCVMM2012R2 PowerShell Cmdlets.

 

Below Diagram shows the workflow of this entire process.

 

 

This blog post is split into 4 sections.

 

Prerequisites for this entire process requires that we create a virtual machine in Hyper-V which has windows server 2012 r2 installed.In my setup i went for the standard edition,

 

1) Create an Unattended.xml installation file - This is used to enable PS Remoting, set the execution policy to remote signed (Windows Server 2012 R2 has it set to RemoteSigned by default), run a powershell script to set Virtual Machine Configuration on the Sys-Prepped VHD and also set a few windows based parameters. Below diagram shows how your Unattended.xml file would look once you are done configuring it with the required changes using WAIK .

 

 

There's are some Excellent Blogpost's out there which illustrate a step by step process to create the unattend.xml, here are some of the blog posts which i refereed to create mine. I have attached the unattend.xml file which i created for Windows Server 2012 R2 installation along with this blogpost.

 

 

One of the issues i encountered when i tested booting the sysprepped windowsserver2012r2 vhdx file with the unattend.xml was that it was consistently stuck at the language settings page, to fix this i had to to specify language settings for the below options too, you can see this in the above figure.

 

1- Windows PE (for installing windows)

2- specialize (for system)

3- oobeSystem (for users)

 

Here are the details with screenshots on the configuration changes i made to the individual components.

 

a) Windows PE

 

Specify Language settings as en-US.

 

 

amd64_Microsoft-Windows-Setup__neutral configuration is similar to the one followed on the above blogpost by derek

 

b) Offline Servicing

 

Disable User Account Control (UAC)

 

amd64_Microsoft-Windows-LUA-Settings__neutral configuration is similar to the one followed on the above blogpost by derek

 

 

c) Generalize

 

Set SkipRearm to 1, SkipRearm setting is set to one if you plan on running the Sysprep command multiple times on a computer.

 

d) Specialize

 

Enable Local Administrator Account, Configure Internet Explorer Properties, Disable Server Manager pop up at start up, Feed in the CD Key, Enable RDP and set firewall exception

 

All configuration settings performed are illustrated in the above two blog posts.

 

e) OOBE System (  Out Of the Box Experience)

 

Enable auto logon for the local administrator and set the password, enter in the "First" log on commands which consists of executing powershell scripts to set the execution policy to remotesigned and run powershell script contained in the sysprepped vhd to enable powershell remoting, rename computer and restart. Also Hide / By-Pass the "EULA" page.

 

Below figure shows a detailed view on the first logon commands, they run hierarchicaly one after another, "Order 1" and "Order 2".

 

 

 

The Rename-Computer.ps1 is a powershell script which i placed in c:\install before i executed the sysprep of the vhdx file. It Sets First Logon parameters, next Set's Execution Policy to RemoteSigned, then run's the powershell script "Rename Computer" during first auto logon of machine which renames the host and again sets the autologon value  to "0" or false ( You would need to enter in password the next time you log in )

 

Here are the contents of the script file "Rename-Computer.ps1". It Enables PSRemoting and also restarts the computer after renaming it to the middle word from VMName which is exactly the VM Name, In My Environment i named my VM's as (d.VMWIN2K12R2-1.hng)

 

<#PowerShell Script Placed inside Rename-Computer in c:\install location in Sysprepped vhd#>

 

Enable-psremoting -Force

 

$virtualmachinename= (Get-ItemProperty 'HKLM:\software\microsoft\virtual machine\guest\parameters').virtualmachinename

 

$newvmhostname = ($virtualmachinename.Split('.')[1]).ToUpper()

 

$computer = Get-WmiObject Win32_ComputerSystem

 

$computer.Rename($newvmhostname)

 

Set-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" -name AutoAdminLogon -value 0

 

start-sleep 5

 

Restart-Computer -Force

 

Once you complete creating the unattend.xml file, place it the sysprep directory.

 

Also below figure shows the location of the powershell script (Rename-Computer.ps1) placed in c:\install.

 

 

Once you are done with all the above prerequisites, execute the sysprep command giving reference to the unattend.xml,

 

 

During the sysprep process you would see that the VM shuts down, so effectively what happens is that next time you create a virtual machine using this sysprepped vhd, all the configurations specified on the unattend.xml file get applied to the VM.

 

2) SCORCH - SCSM Workflow to Create VM's on Hyper-V Host  -

 

 

Next we would use a SCORCH / SCSM Workflow to Create VM's on the Hyper-V Host Cluster, Get-Unused IP address, Create a List Item ( Update a Share Point list with The Virtual Machine Details) and Finally Assign IP Address to the Virtual Machine

 

SCSM allows you to create SCORCH-SCSM connectors which allow you to import the run books created in SCORCH and pass values to the SCORCH run books from SCSM templates, on more details on how to configure this setup have a look at my other blog post "NetApp Storage Provisioning Using System Center Service Manager (SCSM) and Orchestrator (SCORCH) and DataOntap PowerShell Toolkit"

 

SCORCH workflows use the "Initialize Data" OIP to get the custom values passed  from SCSM.

 

So now lets look at the actual SCORCH work flow which kicks of the VM Creation Factory .

 

As you can see in the figure below, Initialize data gets the input from SCSM, these values are passed on to the Create-VM "Run.Net Script" OIP to create the VM with intelligent VM placement, next we get the list of unused IP addresses, create a share point list item update with VM details and finally assign this IP address to the VM.

 

 

Next lets look at the individual OIP's

 

Initialize Data &colon;-

 

 

The Initialize Data OIP consists of defined parameters which takes its input from SCSM generated Incidents, It get the Operating system Type, TME Name ( The requester of VM  in our case ), VLAN ( Virtual Network Name for the Virtual Machine ), VmName ( Virtual Machine Name), Ip Address and the Memory (RAM) details.

 

Next lets take a look at the "Create-VM" OIP

 

Create-VM : -

 

The Create VM OIP consists of the actual PowerShel Code which does all the magic of creating VM's.

 

 

Below is the Actual Code, i have updated comments where ever required. Ignore the GUIDS which show up below, as i copy pasted this script out from SCORCH OIP to PowerShell ISE it retained its GUID  characteristics.

 

######################################################## 

#Create Credential Objects to Connect to the Hyper-V Host 

######################################################## 

$password =  ConvertTo-SecureString  -String "P@^&^!*@*!*((*!*(^&" -AsPlainText -force 

$credential = New-Object System.Management.Automation.PsCredential("VMHOST\admin",$password) 

 

 

######################################################## 

#Create PowerShell Remote sessions to the Hyper-V Host 

######################################################## 

$session = New-PSSession -ComputerName VMHOSTHOST1103.VMHOST.com -credential $credential -Authentication Credssp 

Invoke-Command -Session $session -ScriptBlock {  

 

 

######################################################## 

#Create Credential Objects to Connect to the NetApp Controller 

######################################################## 

import-module dataontap 

$password =  ConvertTo-SecureString  -String "N%^@pp121" -AsPlainText -force 

$credential = New-Object System.Management.Automation.PsCredential("root",$password) 

 

 

New-Item -Path "C:\ClusterStorage\Volume1\MSBU_TME_VMS" -Name \`d.T.~Ed/{3CE71B12-AA22-441B-9AE3-0090AC97F606}.{4692D316-0DC2-4702-93A6-9236B524F229}\`d.T.~Ed/ -ItemType directory -Force 

 

 

Connect-NaController 192.188.188.14 -credential $credential 

 

 

#################################################################################### 

#Use SIS Clone / ODX based copy process to copy across the VHD in seconds 

#################################################################################### 

Copy-NaHostFile "C:\ClusterStorage\Volume1\winserver2012standard unattend vhd\standard2012.vhdx" "C:\ClusterStorage\Volume1\MSBU_TME_VMS\\`d.T.~Ed/{3CE71B12-AA22-441B-9AE3-0090AC97F606}.{4692D316-0DC2-4702-93A6-9236B524F229}\`d.T.~Ed/\standard2012.vhdx_1.vhdx" 

 

 

Set-Location "C:\ClusterStorage\Volume1\MSBU_TME_VMS\\`d.T.~Ed/{3CE71B12-AA22-441B-9AE3-0090AC97F606}.{4692D316-0DC2-4702-93A6-9236B524F229}\`d.T.~Ed/" 

 

 

$VMPath = "C:\ClusterStorage\Volume1\MSBU_TME_VMS\\`d.T.~Ed/{3CE71B12-AA22-441B-9AE3-0090AC97F606}.{4692D316-0DC2-4702-93A6-9236B524F229}\`d.T.~Ed/" 

 

 

 

 

Rename-Item standard2012.vhdx_1.vhdx -NewName "\`d.T.~Ed/{3CE71B12-AA22-441B-9AE3-0090AC97F606}.{4692D316-0DC2-4702-93A6-9236B524F229}\`d.T.~Ed/-WINSERVER2012-FIXED-OS.vhdx" 

 

 

#################################################################################### 

#Intelligent VM Provisioning by finding the optimal host to place the VM's 

#################################################################################### 

 

 

$password =  ConvertTo-SecureString  -String "P@^&^!*@*!*((*!*(^&" -AsPlainText -force 

$credential = New-Object System.Management.Automation.PsCredential("VMHOST\admin",$password) 

 

 

$session1 = New-PSSession -ComputerName scvmm2012sp1 -credential $credential 

 

 

Invoke-Command -Session $session1 -ScriptBlock { 

 

 

ipmo virtualmachinemanager 

 

 

$password =  ConvertTo-SecureString  -String "P@^&^!*@*!*((*!*(^&" -AsPlainText -force 

$credential = New-Object System.Management.Automation.PsCredential("VMHOST\admin",$password) 

 

 

$VMM = Get-VMMServer scvmm2012sp1 -Credential $credential 

 

 

$VMHostGroup = Get-SCVMHostGroup -Name "All Hosts" 

$HWProfile = Get-SCHardwareProfile | where {$_.Name -eq "MSBU"} 

$HostRatings = Get-SCVMHostRating -VMHostGroup $VMHostGroup -HardwareProfile $HWProfile -DiskSpaceGB 20 -VMName "VMNAMEorchestrator" -CPUPriority 8 -MemoryPriority 5 -DiskPriority 3 -NetworkPriority 1 

 

 

$PlacementHost=($HostRatings | select vmhost,rating | sort -Descending rating | select -First 1 | select -ExpandProperty VMhost).name 

 

 

$PH = (Invoke-Command -Session $session1  -ScriptBlock { $PlacementHost }) 

 

 

 

 

#Get-Module | ?{$_.name -match "virtual"} | Remove-Module 

 

 

$VMPath = "C:\ClusterStorage\Volume1\MSBU_TME_VMS\\`d.T.~Ed/{3CE71B12-AA22-441B-9AE3-0090AC97F606}.{4692D316-0DC2-4702-93A6-9236B524F229}\`d.T.~Ed/" 

 

 

$password =  ConvertTo-SecureString  -String "P@^&^!*@*!*((*!*(^&" -AsPlainText -force 

$credential = New-Object System.Management.Automation.PsCredential("VMHOST\admin",$password) 

 

 

 

 

#################################################################################### 

#Create Virtual Machine on the Hyper-V host and Configure its properties 

#################################################################################### 

Import-Module hyper-v 

 

 

$VHDPath = "C:\ClusterStorage\Volume1\MSBU_TME_VMS\\`d.T.~Ed/{3CE71B12-AA22-441B-9AE3-0090AC97F606}.{4692D316-0DC2-4702-93A6-9236B524F229}\`d.T.~Ed/\\`d.T.~Ed/{3CE71B12-AA22-441B-9AE3-0090AC97F606}.{4692D316-0DC2-4702-93A6-9236B524F229}\`d.T.~Ed/-WINSERVER2012-FIXED-OS.vhdx" 

 

 

 

 

New-VM -ComputerName $PH -MemoryStartupBytes ([int64]"\`d.T.~Ed/{3CE71B12-AA22-441B-9AE3-0090AC97F606}.{0C042B7E-AC8C-4525-AB9F-F52C1DD8F400}\`d.T.~Ed/"*1024*1024*1024) -Name \`d.T.~Ed/{3CE71B12-AA22-441B-9AE3-0090AC97F606}.{4692D316-0DC2-4702-93A6-9236B524F229}\`d.T.~Ed/ -VHDPath $VHDPath -Path $VMPath -SwitchName "Virtual Uplink"  

 

 

 

 

#Set Vm properties before start, enable dynamic memory for memory optimization 

Set-VM -name \`d.T.~Ed/{3CE71B12-AA22-441B-9AE3-0090AC97F606}.{4692D316-0DC2-4702-93A6-9236B524F229}\`d.T.~Ed/ -ComputerName $PH -ProcessorCount 4 -DynamicMemory -AutomaticStartAction StartIfRunning -AutomaticStopAction Save  

 

 

# Disable Time Sync on a VM so that it sync's time from a domain controller 

Disable-VMIntegrationService -VMName \`d.T.~Ed/{3CE71B12-AA22-441B-9AE3-0090AC97F606}.{4692D316-0DC2-4702-93A6-9236B524F229}\`d.T.~Ed/ -Name "Time Synchronization" 

 

 

 

 

Start-VM -Name \`d.T.~Ed/{3CE71B12-AA22-441B-9AE3-0090AC97F606}.{4692D316-0DC2-4702-93A6-9236B524F229}\`d.T.~Ed/ -Verbose 

 

 

Start-Sleep 15 

 

 

Set-VM -name \`d.T.~Ed/{3CE71B12-AA22-441B-9AE3-0090AC97F606}.{4692D316-0DC2-4702-93A6-9236B524F229}\`d.T.~Ed/ -ComputerName $PH -AutomaticStartAction StartIfRunning 

 

 

 

 

 

 

#################################################################################### 

#Make the Virtual Machines Highly Available and add them to the clustered instance 

#################################################################################### 

Import-Module failoverclusters 

 

 

Add-ClusterVirtualMachineRole -VirtualMachine \`d.T.~Ed/{3CE71B12-AA22-441B-9AE3-0090AC97F606}.{4692D316-0DC2-4702-93A6-9236B524F229}\`d.T.~Ed/ 

 

 

 

 

 

 

#Get-Module | ?{$_.name -match "hyper-v"} | Remove-Module 

 

 

# Set VM OwnerShip Details 

 

 

$password =  ConvertTo-SecureString  -String "P@^&^!*@*!*((*!*(^&" -AsPlainText -force 

$credential = New-Object System.Management.Automation.PsCredential("VMHOST\admin",$password) 

 

 

$session2 = New-PSSession -ComputerName scvmm2012sp1 -credential $credential 

 

 

Invoke-Command -Session $session2 -ScriptBlock { 

 

 

import-module  virtualmachinemanager 

 

 

$password =  ConvertTo-SecureString  -String "P@^&^!*@*!*((*!*(^&" -AsPlainText -force 

$credential = New-Object System.Management.Automation.PsCredential("VMHOST\admin",$password) 

 

 

$VMM = Get-VMMServer scvmm2012sp1 -Credential $credential 

 

 

Set-SCVirtualMachine -VM \`d.T.~Ed/{3CE71B12-AA22-441B-9AE3-0090AC97F606}.{4692D316-0DC2-4702-93A6-9236B524F229}\`d.T.~Ed/ -Owner \`d.T.~Ed/{3CE71B12-AA22-441B-9AE3-0090AC97F606}.{2E01791B-E389-46C4-9717-62199E050313}\`d.T.~Ed/ 

 

 

 

 

 

 

################################################################################################################################ 

<# Here we put a while loop to repeatedly keep on checking till VM gets assigned an IPAddress From DHCP Server #> 

################################################################################################################################ 

while ( 

 

 

((Get-VMNetworkAdapter \`d.T.~Ed/{3CE71B12-AA22-441B-9AE3-0090AC97F606}.{4692D316-0DC2-4702-93A6-9236B524F229}\`d.T.~Ed/ | select -ExpandProperty ipaddresses) -eq $null -or ((Get-VMNetworkAdapter \`d.T.~Ed/{3CE71B12-AA22-441B-9AE3-0090AC97F606}.{4692D316-0DC2-4702-93A6-9236B524F229}\`d.T.~Ed/ | select -ExpandProperty ipaddresses) -match "169."))) 

 

 

 

 

 

 

Write-Progress -Activity "Waiting for VM to Aquire an IPAddress" 

 

 

 

 

Start-Sleep 10 

 

 

$VMIP=(Get-VM -Name \`d.T.~Ed/{3CE71B12-AA22-441B-9AE3-0090AC97F606}.{4692D316-0DC2-4702-93A6-9236B524F229}\`d.T.~Ed/).networkadapters.ipaddresses 

 

 

Write-Output "\`d.T.~Ed/{3CE71B12-AA22-441B-9AE3-0090AC97F606}.{4692D316-0DC2-4702-93A6-9236B524F229}\`d.T.~Ed/ Assigned with IP Address $VMIP" -Verbose 

 

 

 

 

 

 

################################################################################################################################ 

<# Add Virtual Machine to Domain #> 

################################################################################################################################ 

$DomainUserPassword = "P@^&^!*@*!*((*!*(^&" 

$DomainUserName = "VMHOST\admin" 

$Domainpassword = ConvertTo-SecureString -String $DomainUserPassword -AsPlainText -force 

$DomainCredential = New-Object System.Management.Automation.PsCredential($DomainUserName,$domainpassword) 

 

 

$LocalUserPassword = "N%^@pp121" 

$LocalUserName = "standard2012\administrator" 

$Localpassword = ConvertTo-SecureString -String $LocalUserPassword -AsPlainText -force 

$LocalCredential = New-Object System.Management.Automation.PsCredential($LocalUserName,$Localpassword) 

 

 

 

 

if ($DomainName -ne $null) 

 

 

 

 

Add-Computer -ComputerName $VMIP -DomainName $domainName -LocalCredential $LocalCredential -Credential $DomainCredential -Verbose -Restart 

 

 

 

 

 

else { 

 

 

Write-Output "VM Does Not need To be Joined to Domain" 

 

 

 

 

Next lets look at the OIP " Get-Unused IP" which creates the newip, gateway and the ipstatus variables and passes them as published data variables.

 

Get-Unused IP Address  OIP :-

 

Here's the actual script content in Get-Unused IP address.

 

 

Next Create List Item Creates a list Item on the SharePoint site with the appropriate details on the VM, More details are illustrated in the video below

 

Next lets look at the next OIP which is "Assign IP Address to VM", this OIP effectively assigns the IP address specified by the requester of the SCSM ticket to the Virtual Machine.

 

 

So effectively all these OIP's interconnect with each other and create the required Virtual Machine.

 

Here's a Video below which shows this VM Creation Factory in Action.

 

Video Link : 3802

 

 

 

I hope that you have enjoyed this blog entry and have found this information helpful. More Stuff in Progress. Till then Chao!

 

Good Luck!

 

Thanks,

Vinith

Comments

HI Vinith,

Can we automate this flow in Netapp, or we have to run all these steps manually everytime, we are creating VM machine using Netapp?

Rahul Sehgal

vinith Former NetApp Employee

Hello Rahul,

These scripts are the integral pieces of the workflow created using SCORCH and SCSM, you can sutomate the vm creation using a powershell script which i wrote some time back, check it out- http://gallery.technet.microsoft.com/Automate-Virtual-Machine-6c17929c

Thanks,

Vinith