Skip to content

Instantly share code, notes, and snippets.

@nickrsan
Last active January 5, 2021 21:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nickrsan/b2c889e2cda888262f6218fe423180cc to your computer and use it in GitHub Desktop.
Save nickrsan/b2c889e2cda888262f6218fe423180cc to your computer and use it in GitHub Desktop.
Clone Hyper-V VM to same server
$ProductionVMName = "DAP_Production"
$StagingVMName = "DAP_Staging"
$ExportFolder = "C:/HyperVExports" # I created a folder that removed all permissions for users - could add anyone with hyper-v permissions to a group with read/write here, along with System
$ExportToFolder = "$ExportFolder/$ProductionVMName/"
$ImportToFolder = "$ExportFolder/$StagingVMName/"
# caution, deletes existing exports in the next block. The try/catch doesn't work as intended. It was supposed to abandon it if it can't find the staging VMs, but proceeds through each step. Needs some work there.
try{
Get-VM -Name $StagingVMName # (not true, but this was the design): this will throw an exception if it doesn't exist, so the following lines in this block won't run
Stop-VM -Name $StagingVMName -TurnOff # Turn of the VM forcibly - it's fine if it gets corrupted - we're about to destroy it
Get-VMHardDiskDrive -VMName $StagingVMName | Remove-VMHardDiskDrive # delete the disks - Remove-VM won't do that
Get-VM $StagingVMName | Remove-VM # now delete the VM
Remove-Item "$ExportFolder/$ProductionVMName" # remove the folder that hosted the Production VM to prevent conflicts - it's keyed by the production VM name
Remove-Item "$ExportFolder/$StagingVMName" # remove the folder that hosted the Staging VM imported to prevent conflicts - it's keyed by the production VM name
}catch{
print "No existing VM - proceeding"
}
print "exporting VM"
Export-VM -Name $ProductionVMName -Path $ExportFolder
$exported_vm_path = "$ExportToFolder/Virtual Machines/" # it'll be put into a folder in the export folder with the name of the source VM
$exported_vm = Get-ChildItem -Path $exported_vm_path -Filter *.vmcx | Select Name # find the VM config file
$exported_vm_file = $exported_vm.Name
# import the VM and set the paths to copy everything to so we don't conflict with production VM. Store the returned object so we can rename the VM
$imported_vm = Import-VM -Path "$ExportToFolder/Virtual Machines/$exported_vm_file" -Copy -GenerateNewId -VirtualMachinePath $ImportToFolder -VhdDestinationPath $ImportToFolder -SnapshotFilePath $ImportToFolder -SmartPagingFilePath $ImportToFolder
Rename-VM -VM $imported_vm -NewName $StagingVMName
Set-VMNetworkAdapter -VMName $StagingVMName -DynamicMacAddress # make sure the MAC address is dynamic so we don't interfere the production server's IP
Get-VM $StagingVMName | Remove-VMSnapshot # remove all snapshots/checkpoints of the staging VM - we don't need them
Start-VM -VMName $StagingVMName # start it, but then we'll shut it down and restart it which should cause the OS to notice a hardware/network change if it was running when snapshotted
Stop-VM -VMName $StagingVMName
Start-VM -VMName $StagingVMName
# Get the IP address of the new machine. need to wait before running this - won't work on linux guests without installing a hyper-v daemon
$ips = Get-VM -Name $StagingVMName |Select -ExpandProperty Networkadapters |Select IPAddresses
print $ips
@nickrsan
Copy link
Author

nickrsan commented Jan 5, 2021

For use as a guideline/getting started for others' needs - meant to duplicate the VM on the same host, particularly for creating a staging VM from a live production server VM. It attempts to delete any existing exports before running, so look out for that! Note that the VM must be copied twice in this configuration when it copies to the same server, so the server needs at least 2x the current VMs storage requirements in additional space it's using. Once to export it and another to import it - since it's being imported on the same server as the original, it needs a new ID, and that can only be done with a copy, not inplace.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment