This is special because VMM does not support this natively. So you have to contact the target HyperV host (via WMI) to create the Diff disk. In addition to need to make sure that the HyperV host has the parent VHD already in place.
The Powershell cmdlet below does the following
- Looks up the specified Hardware profile
- Looks up the specified template (this is used to get the parent VHD location/name)
- Looks up info on the specified target HyperV host (so we can find the placement drive)
- Checks to see if the ParentVHD already exists on the HyperV hosts Placement Drive
- If the VHD does not exist it copies it to the HyperV host
- Creates Diff Disk via WMI on hyperV host pointing to parent VHD
- Creates the VM via the New-SCVirtualMachine cmdlet using the UseLocalVirtualHardDisk command. (this tells VMM to allow Diff disks).
param($VMName,$TemplateName = "Windows Server 2008 R2 SP1 Enterprise", $HardwareProfileName = "ServerHardware", $VMMHost = "SCVMM",$targethostname = $null) $Err = 0 If ($VMName -eq $null) { Write-Host "`nERROR: Incorrect arguments" -foregroundcolor red -backgroundcolor black Write-Host "`nREQUIRED ARGUMENTS:" -foregroundcolor cyan Write-Host "`n -VMName `"Name of the VM to create`"" -foregroundcolor cyan Write-Host "`n -TemplateName `"Name of the VMM Template`"" -foregroundcolor cyan Write-Host "`n -HardwareProfileName `"Name of the VMM Hardware Profile to use with the template`"" -foregroundcolor cyan Write-Host "`n -VMMHost `"VMM Computername`"" -foregroundcolor cyan Write-Host "`n -targetHostname `"Computername of HyperV host to target`"" -foregroundcolor cyan Exit $Err } function CreateDiffDiskOnHost { param([string]$hostComputerName, [string]$childPath, [string]$parentPath) #get the image mgmt service instance for the host computer $VHDService = get-wmiobject -class "Msvm_ImageManagementService" -namespace "root\virtualization" -computername $hostComputerName #create a differencing disk from the base disk $Result = $VHDService.CreateDifferencingVirtualHardDisk($childPath, $parentPath) } function TestFileLock { ## Attempts to open a file and trap the resulting error if the file is already open/locked param ([string]$filePath ) $filelocked = $false $fileInfo = New-Object System.IO.FileInfo $filePath trap { Set-Variable -name locked -value $true -scope 1 continue } $fileStream = $fileInfo.Open( [System.IO.FileMode]::OpenOrCreate, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None ) if ($fileStream) { $fileStream.Close() } $obj = New-Object Object $obj | Add-Member Noteproperty FilePath -value $filePath $obj | Add-Member Noteproperty IsLocked -value $filelocked $obj } write-host "VMName is $VMName" write-host "Template is $TemplateName" write-host "Hardware Profile is $HardwareProfileName" write-host "VMMHost is $VMMHost" write-host "Target Host is $targethostname" $guid = [guid]::NewGuid() write-host "Lookup the base hardware Profile $HardwareProfileName" $HardwareProfile = Get-SCHardwareProfile -VMMServer $VMMHost | where {$_.Name -eq $HardwareProfileName} if ($HardwareProfile -eq $null) { write-host "Failed to lookup HardwareProfile $HardwareProfileName" -foregroundcolor red -backgroundcolor black EXIT 1 } write-host "Getting information for template $TemplateName" $Template = Get-SCVMTemplate -VMMServer $VMMHost -All | where {$_.Name -eq $TemplateName} if ($Template -eq $null) { write-host "Failed to lookup Template $TemplateName" -foregroundcolor red -backgroundcolor black EXIT 1 } #Get the VHD info for the template $VHD = Get-SCVirtualharddisk | where {$_.Name -eq $template.VirtualDiskDrives[0].VirtualHardDisk} write-host "Template VHD Path " $VHD.SharePath if ($targethostname -eq $null) { write-host "Invalid targethostname" -foregroundcolor red -backgroundcolor black exit 1 } $vmhost = Get-SCVMHost $targethostname $vmHostPath = [string]$vmhost.vmpaths write-host "Target VMHost: " $vmhost.name write-host "Target Drive: " $vmhost.VMPaths $remotePath = "\\" + $vmhost.name + "\" + $vmHostPath.substring(0,1) + "$\" + [system.io.path]::GetFileName($VHD.SharePath) "Checking to see if Parent VHD exists on HV Host Drive" "RemotePath: $remotePath" if (Test-Path $remotePath) { "Parent VHD already exists on HV Host" } else { "$RemotePath does not exist, going to Copy" [System.IO.File]::Copy($VHD.SharePath,$remotePath); } "Creating Diff Disk" $targetVHDPath = $vmHostPath + $VMName + ".vhd" $ParentVHDPath = $vmHostPath + [system.io.path]::GetFileName($VHD.SharePath) CreateDiffDiskOnHost "$vmhost" "$targetVHDPath" "$ParentVHDPath" Start-Sleep -s 20 $targetVHDRemotePath = "\\" + $vmhost.name + "\" + $vmHostPath.substring(0,1) + "$\" + $VMName + ".vhd" if (Test-Path $targetVHDRemotePath) { "Diff Disk Created at:$targetVHDRemotePath" } else { "$targetVHDRemotePath does not exist yet. Sleeping for a few" Start-Sleep -s 30 if (Test-Path $targetVHDRemotePath) { "Disk was created." } else { write-host "Failed to find VHD $targetVHDRemotePath after sleep, exiting" -foregroundcolor red -backgroundcolor black exit 1 } } #Set a random startup delay to reduce VM startup IOPs overload $startDelay = Get-Random -minimum 1 -maximum 30 $lockstate = TestFileLock "$targetVHDRemotePath" if ($lockstate.IsLocked) { "File locked, sleeping" Start-Sleep -s 30 } $mv = move-SCvirtualharddisk -Bus 0 -Lun 0 -IDE -path $targetVHDPath -jobgroup $guid $description = $template.tag New-SCVirtualMachine -Name $vmName -VMHost $vmHost -VMTemplate $template -UseLocalVirtualHardDisk -HardwareProfile $HardwareProfile -ComputerName $vmName -path $vmHostPath -delaystartseconds $startDelay -Description "$description" -mergeanswerfile $true -BlockDynamicOptimization $false -StartVM -JobGroup "$guid" -RunAsynchronously -StartAction "AlwaysAutoTurnOnVM" -StopAction "SaveVM"
Hi Mike,
ReplyDeletecould you please guide the way to import data from a .csv file in to your script for the first line:
param($VMName,$TemplateName = "Windows Server 2008 R2 SP1 Enterprise", $HardwareProfileName = "ServerHardware", $VMMHost = "SCVMM",$targethostname = $null)
How to import those information like VMName, Template... from csv file?
Davtup,
ReplyDeleteIf your CSV has fields like
VMName, Template etc and has associated value, do following
$csvlist = import-csv ""
foreach($entry in $csvlist)
{
$entry.VMName
$entry.Template
}
Try this,
-Rahul Tarambale