PowerShell: Create Hyper-V Guest VM From Virtual Disk (VHDX)

Part 1: Creating Hyper-V Guest VM From a Virtual Disk

# createHyperVGuestVmFromDisk.ps1
# Version 0.02
# The intent of this script is to create a Hyper-V Guest VM basing on existing backup VHDX file(s)


$secureBoot=$true # Windows: True, Linux: False
$extraDisks=@($null) # $extraDisks=@('test')

function createHyperVGuestVmFromDisk{
  $ErrorActionPreference = 'stop'
  function confirmation($content,$testValue="I confirm",$maxAttempts=3){
    write-host $($content|out-string).trim()
    write-host "`r`nPlease review this content for accuracy.`r`n"
    while ($attempts -le $maxAttempts){
        if($attempts++ -ge $maxAttempts){
            write-host "A maximum number of attempts have reached. No confirmations received!`r`n"
        $userInput = Read-Host -Prompt "Please type in this value => $testValue <= to confirm. Input CANCEL to skip this item";
        if ($userInput.ToLower() -eq $testValue.ToLower()){
            write-host "Confirmed!`r`n";
        }elseif($userInput.tolower() -in $cancelCondition){
            write-host 'Cancel command received.'
            write-host "Attempt number $attempts of $maxAttempts`: $userInput does not match $testValue. Try again or Input CANCEL to skip this item`r`n"
    return $confirmed

      if(!(test-path $newFolder)){new-item -ItemType Directory -Path $newFolder -force}              
      if(!(test-path $newVhdx)){
          New-Item -ItemType File -Path $newVhdx -Force # touch before copying contents
          Copy-Item -Path $sourceVhdx -Destination $newVhdx
          write-warning "Volume $newVhdx already exists. Thus, that VMDK will be used instead of a clone."
      New-VM -Name $newVmName `
              -MemoryStartupBytes $($memory/1) `
              -BootDevice VHD `
              -VHDPath $newVhdx `
              -Path $newFolder `
              -Generation $generation `
              -Switch $network         
      if($vlan){Set-VMNetworkAdapterVlan -VMName $newVmName -Access -VlanId $vlan}
              if($cpus -gt 1){Set-VMProcessor $newVmName -Count $cpus}
      Set-VMProcessor $newVmName -CompatibilityForMigrationEnabled $true
      if(!$secureBoot){Set-VMFirmware -VMName $newVmName -DisableSecureBoot}
      # Adding disks (optional)
          for($i=0;$i -lt $extraDisks.count;$i++){
            $isvalidDisk=if(test-path $extraDisk){$extraDisk}else{$null}
              $newDiskPath=(join-path $destinationFolder $vmName) + "\$vmName`_disk$($i+1).vmdk"
              if(!(test-path $newDiskPath)){
                New-Item -ItemType File -Path $newDiskPath -Force # touch before copying contents
                Copy-Item -Path $extraDisk -Destination $newDiskPath
                  write-warning "Volume $newDiskPath already exists. Thus, that VMDK will be used instead of a copy."
              Add-VMHardDiskDrive -VMName $newVmName -Path $newDiskPath 
              write-warning "Disk path '$extraDisk' in invalid."
        write-host "$newVmName has no extra disks to attach."
      $disksToRemove=[array]$extraDisks+$sourceVhdx|?{$_} # join string to array and remove empty entries
      foreach($diskToRemove in $disksToRemove){
        $confirmed=confirmation "Remove source disk $diskToRemove"
          remove-item $diskToRemove -force
          write-host "$diskToRemove NOT removed."
          start-vm $newVmName
      return $true
      write-warning "$($error[0])"
      return $false

createHyperVGuestVmFromDisk $sourceVhdx `
  $newVmName `
  $destinationFolder `
  $memory `
  $cpus `
  $network `
  $vlan `
  $extraDisks `
  $generation `
  $secureBoot `
  $onlineVm `

Part 2: Adding New VM to Cluster

function addVmToCluster{
    foreach ($vmName in $vmNames){
            #Start-VM -Name $vmName -EA Stop
            if(!$targetCluster){$targetCluster=(get-cluster -ea SilentlyContinue).Name}
                $null=Add-ClusterVirtualMachineRole -Cluster $targetCluster -VirtualMachine $vmName -EA Stop
                write-host "No clusters defined."
            $moved=if(get-cluster -ea SilentlyContinue){Move-ClusterVirtualMachineRole $newVmName}else{$false}
            if($moved){write-host "'$newVmname' has been moved to $($moved.OwnerNode)"}
            write-warning "$($error[0])"
    return $results

addVmToCluster $newVmName

Possible Error Message:

Microsoft Hyper-V UEFI

Virtual Machine Boot Summary

1.SCSI Disk (0,0) the boot loader did not load an operating system
2. Network adapter (00155D406142) a boot image was not found

No operating system was loaded. Your virtual machine may be configured incorrectly. Exit and rec-configure your VM or click restart to retry the current boot sequence again.


The case where this error has been thrown has been associated with an incorrect virtual machine generation type. Hence, the resolution has been:

A. Convert Generation 2 machine type back to Generation 1 as the original source disk VM must match its re-creation.
B. The misconfigured VM must be ‘deleted’ and re-created as a Generation 1 VM.

# Converting Generation 2 virtual disk to Gen 1
Convert-VHD -Path $diskFile -DestinationPath $fixedFile -VHDType Dynamic

Leave a Reply

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