PowerShell Script to Automate Virtual Machine Provisioning using Hyper-V Version 3 Cmdlets in Windows Server 2012

PowerShell Script to Automate Virtual Machine Provisioning using Hyper-V Version 3 Cmdlets in Windows Server 2012
Hi Guys, Today i was able to fully automate the VM provisioning process Using Hyper-V Version 3 PowerShell Cmdlets Bundled with Windows Server 2012The Workflow to attain this consists of two parts

1) Creation of a sysprepped base vhd

I created a sysprepped vhd which contains of a powershell script which performs the below action

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 im Naming VM’s as (d.VMWIN2K8R2-1.hng)

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

Enable-psremoting -Force
$virtualmachinename= (Get-ItemProperty 'HKLM:softwaremicrosoftvirtual machineguestparameters').virtualmachinename

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

$computer = Get-WmiObject Win32_ComputerSystem

$computer.Rename($newvmhostname)

Set-ItemProperty "HKLM:SOFTWAREMicrosoftWindows NTCurrentVersionWinlogon" -name AutoAdminLogon -value 0

start-sleep 5
 
Restart-Computer -Force

During sysprep i used an unattend xml which i created using WSIM (Windows System Image Manager) which sets the following properties

  • Enable AutoLogon,
  • Sets the Administrator Login name and also Default password
  • Set First Logon Commands to First Set Execution Policy to RemoteSigned, then Run 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

2) Running of PowerShell Script to actually build out the VM’s

<#____________________________________________________________#>

<#
 
Author - Vinith Menon
Website - http://powershell-enthusiast.blogspot.in/
.Synopsis
Following Scripts Helps in Creation of Virtual Machines Across Specified Hyper-V Hosts, The Workflow Function Input can be given using a csv file.
The CSV File consists of all parameters Like VM Name, Computer Name, Startup Memory, Vhd Location Type etc.
 
.EXAMPLE
Import-Csv "C:2012vmsVminfo1.csv" | ForEach-Object { Install-VM -HyperVHost $_.HyperV_Host -Memory $_.Memory -VMName $_.VMname -VMPath $_.VMpath `
-VMSwitchName $_.VMSwitchName -DomainUserName "powershell-enthadministrator" -LocalUserName "$VMNameadministrator" -DomainUserPassword "Admin!2011" -LocalUserPassword "Admin!2011" -DomainName "powershell-enthusiast.com" }
 
#> 
FunctionInstall-VM
{
param
(
# Specify the Name of Hyper-V Host on which VM Needs to be Created, localhost has been specified as default.
[Parameter(Mandatory=$true)]
[String]$HyperVHost = “localhost”,
# Specifies the amount of memory, in bytes, to assign to the virtual machine. The default value is 512 MB
[Parameter(Mandatory=$true)]
[int64]$Memory = 512MB,
# Specifies the name of the new virtual machine, its read from csv file or maybe a sharepoint list using webproxy services
[Parameter(Mandatory=$true)]
[String]$VMName,

# Specifies the directory to store the files for the new virtual machine
[Parameter(Mandatory=$true)]
[String]$VMPath,
# Specifies the friendly name of the virtual switch if you want to connect the new virtual machine
[Parameter(Mandatory=$true)]
[String]$VMSwitchName,
# Domain Credential UserName required to join the VMs to a domain
[Parameter(Mandatory=$true)]
$DomainUserName,

# Domain Credential Password required to join the VMs to a domain
[Parameter(Mandatory=$true)]
$DomainUserPassword,
# Local credential password required to connect to VMs before being joined to domain
[Parameter(Mandatory=$true)]
$LocalUserName,
# Local credential username required to connect to VMs before being joined to domain
[Parameter(Mandatory=$true)]
$LocalUserPassword,
# DomainName to which the server needs to be joined
[Parameter(Mandatory=$true)]
[String]$DomainName
)
 
#Create System.Management.Automation.PsCredential object for Domain Credentials

$Domainpassword = ConvertTo-SecureString -String $DomainUserPassword -AsPlainText -force
$DomainCredential = New-Object System.Management.Automation.PsCredential($DomainUserName,$domainpassword)
 
#Create System.Management.Automation.PsCredential object for Local Credentials

$Localpassword = ConvertTo-SecureString -String $LocalUserPassword -AsPlainText -force
$LocalCredential = New-Object System.Management.Automation.PsCredential($LocalUserName,$Localpassword)

<# Create the path in which the VM needs to be stored which is like directorypathvmname,
My environment im redirecting it to c:2012VMs#>
New-Item -Path "C:2012vms" -Name $VMName -ItemType directory -Force

#Initiate RoboCopy of already sysprepped vhd disk to the Newly created Vm Location

robocopy "C:2012vmsBase VHD" "C:2012vms$VMName" VMWIN2K8R2-2.vhdx /Z /E /ETA /W:1

#Set location to the folder where VM is being created

Set-Location "C:2012vms$VMName"

 
#Rename the copied sysprepped vhd disk as per VM Name, in my environment im renaming VM as <a-z>.<vmname>.<a-z>

$vhdname = $VMName.split('.')[1]
Rename-Item VMWIN2K8R2-2.vhdx -NewName "$vhdname-OS.vhdx"

#Set path of vhd to be attached to the new virtual machine

$VHDPath = "C:2012vms$VMName$Vhdname-OS.vhdx"

#Create New Virtual machine with desired parameters

New-VM -ComputerName $HyperVHost -MemoryStartupBytes ([int64]$memory*1024*1024*1024) -Name $VMName -VHDPath $VHDPath -Path $VMPath -SwitchName $VMSwitchName -Verbose

#Set Vm properties before start

Set-VM -name $VMname -ProcessorCount 4 -DynamicMemory -AutomaticStartAction StartIfRunning -AutomaticStopAction Save -Verbose

# Start the VM

Start-VM -Name $VMName -Verbose
 

<# Here i placed a sleep of 6 minutes with write-progress to wait for the Vm to boot up first time
run the required powershell scripts and complete boot up processes when a sysprepped vhd boots up first time #>

$time = 360 # seconds, use you actual time in here
foreach($i in (1..$time)) {
$percentage = $i / $time
$remaining = New-TimeSpan -Seconds ($time - $i)

$message = "{0:p0} complete, remaining time {1}" -f $percentage, $remaining
Write-Progress -Activity $message -PercentComplete ($percentage * 100)
Start-Sleep 1

}

<# Waiting for VM to acquire an IP Address from DHCP Server#>
 
Write-Progress -Activity "Waiting for $vmname to Aquire an IPAddress"

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

while (

((Get-VMNetworkAdapter $vmname | select -ExpandProperty ipaddresses) -eq $null -or ((Get-VMNetworkAdapter $vmname | select -ExpandProperty ipaddresses) -match "169.")))

{

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

}

 
<# Once the VM gets an IP Addresse put it in a variable and write the output onto a screen #>

$VMIP=((Get-VM -Name $VMName).NetWorkAdapters.IPAddresses)[0]

Write-Output "$VMName Assigned with IP Address $VMIP" -Verbose

# Add the machine to domain and restart the virtual machine

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"

}

}
 
 
 
<#Once the VM Restarts we indeed see that the VM is domain joined #>

<#____________________________________________________________#>

# Notice that now it is joined to domain!

Get-WmiObject win32_computersystem -ComputerName <VMName> -Verbose

<#Here im calling the Install VM Function to build VM's being input from a csv file#>

Import-Csv "C:2012vmsVminfo1.csv" | ForEach-Object { Install-VM -HyperVHost $_.HyperV_Host -Memory $_.Memory -VMName $_.VMname -VMPath $_.VMpath -VMSwitchName $_.VMSwitchName -DomainUserName "powershell-enthadministrator" -LocalUserName "$VMNameadministrator" -DomainUserPassword "Admin!2011" -LocalUserPassword "Admin!2011" -DomainName "powershell-enthusiast.com" }

 

 

Here is the Content of VMInfo1.csv.

Share this post

One thought on “PowerShell Script to Automate Virtual Machine Provisioning using Hyper-V Version 3 Cmdlets in Windows Server 2012

  1. Hi Vinith,

    Here you are using one sysprepped VHD for all VMs. DOnt you think this will create mess when we will join these machines into domain?

    And normally we sysprepped each VHD first and then add into machine

    Prem Chugh

    Reply

Post Comment