2015-06-21 07:36:07 -04:00
package hyperv
import (
2018-05-05 17:54:58 -04:00
"context"
2016-07-31 11:23:40 -04:00
"errors"
2018-05-05 17:54:58 -04:00
"os/exec"
2015-10-30 04:23:30 -04:00
"strconv"
2015-06-21 07:36:07 -04:00
"strings"
2016-07-31 11:23:40 -04:00
2017-04-04 16:39:01 -04:00
"github.com/hashicorp/packer/common/powershell"
2015-06-21 07:36:07 -04:00
)
2015-06-27 17:36:39 -04:00
func GetHostAdapterIpAddressForSwitch ( switchName string ) ( string , error ) {
var script = `
param ( [ string ] $ switchName , [ int ] $ addressIndex )
2018-02-07 02:01:05 -05:00
$ HostVMAdapter = Hyper - V \ Get - VMNetworkAdapter - ManagementOS - SwitchName $ switchName
2015-06-27 17:36:39 -04:00
if ( $ HostVMAdapter ) {
$ HostNetAdapter = Get - NetAdapter | ? { $ _ . DeviceID - eq $ HostVMAdapter . DeviceId }
if ( $ HostNetAdapter ) {
$ HostNetAdapterConfiguration = @ ( get - wmiobject win32_networkadapterconfiguration - filter "IPEnabled = 'TRUE' AND InterfaceIndex=$($HostNetAdapter.ifIndex)" )
if ( $ HostNetAdapterConfiguration ) {
2015-10-25 18:28:01 -04:00
return @ ( $ HostNetAdapterConfiguration . IpAddress ) [ $ addressIndex ]
2015-06-27 17:36:39 -04:00
}
}
}
return $ false
`
var ps powershell . PowerShellCmd
cmdOut , err := ps . Output ( script , switchName , "0" )
return cmdOut , err
}
2015-06-21 07:36:07 -04:00
func GetVirtualMachineNetworkAdapterAddress ( vmName string ) ( string , error ) {
var script = `
param ( [ string ] $ vmName , [ int ] $ addressIndex )
try {
2018-02-07 02:01:05 -05:00
$ adapter = Hyper - V \ Get - VMNetworkAdapter - VMName $ vmName - ErrorAction SilentlyContinue
2018-04-30 01:03:40 -04:00
if ( $ adapter . IPAddresses ) {
$ ip = $ adapter . IPAddresses [ $ addressIndex ]
} else {
$ vm = Get - CimInstance - ClassName Msvm_ComputerSystem - Namespace root \ virtualization \ v2 - Filter "ElementName='$vmName'"
$ ip_details = ( Get - CimAssociatedInstance - InputObject $ vm - ResultClassName Msvm_KvpExchangeComponent ) . GuestIntrinsicExchangeItems | % { [ xml ] $ _ } | ? { $ _ . SelectSingleNode ( "/INSTANCE/PROPERTY[@NAME='Name']/VALUE[child::text()='NetworkAddressIPv4']" ) }
if ( $ null - eq $ ip_details ) {
return $ false
}
$ ip_addresses = $ ip_details . SelectSingleNode ( "/INSTANCE/PROPERTY[@NAME='Data']/VALUE/child::text()" ) . Value
$ ip = ( $ ip_addresses - split ";" ) [ 0 ]
2015-06-21 07:36:07 -04:00
}
} catch {
return $ false
}
$ ip
`
var ps powershell . PowerShellCmd
cmdOut , err := ps . Output ( script , vmName , "0" )
return cmdOut , err
}
2015-12-05 06:03:33 -05:00
func CreateDvdDrive ( vmName string , isoPath string , generation uint ) ( uint , uint , error ) {
2015-10-30 04:23:30 -04:00
var ps powershell . PowerShellCmd
var script string
script = `
2016-07-31 11:23:40 -04:00
param ( [ string ] $ vmName , [ string ] $ isoPath )
2018-02-07 02:01:05 -05:00
$ dvdController = Hyper - V \ Add - VMDvdDrive - VMName $ vmName - path $ isoPath - Passthru
$ dvdController | Hyper - V \ Set - VMDvdDrive - path $ null
2016-07-31 11:23:40 -04:00
$ result = "$($dvdController.ControllerNumber),$($dvdController.ControllerLocation)"
$ result
2015-10-30 04:23:30 -04:00
`
2016-07-31 11:23:40 -04:00
cmdOut , err := ps . Output ( script , vmName , isoPath )
2015-10-30 04:23:30 -04:00
if err != nil {
2016-07-31 11:23:40 -04:00
return 0 , 0 , err
2015-10-30 04:23:30 -04:00
}
2016-07-31 11:23:40 -04:00
cmdOutArray := strings . Split ( cmdOut , "," )
if len ( cmdOutArray ) != 2 {
return 0 , 0 , errors . New ( "Did not return controller number and controller location" )
}
controllerNumberTemp , err := strconv . ParseUint ( strings . TrimSpace ( cmdOutArray [ 0 ] ) , 10 , 64 )
2015-10-30 04:23:30 -04:00
if err != nil {
2016-07-31 11:23:40 -04:00
return 0 , 0 , err
2015-10-30 04:23:30 -04:00
}
2016-07-31 11:23:40 -04:00
controllerNumber := uint ( controllerNumberTemp )
2015-10-30 04:23:30 -04:00
2016-07-31 11:23:40 -04:00
controllerLocationTemp , err := strconv . ParseUint ( strings . TrimSpace ( cmdOutArray [ 1 ] ) , 10 , 64 )
if err != nil {
return controllerNumber , 0 , err
}
2015-10-30 04:23:30 -04:00
controllerLocation := uint ( controllerLocationTemp )
2016-07-31 11:23:40 -04:00
2015-10-30 04:23:30 -04:00
return controllerNumber , controllerLocation , err
}
2015-11-01 11:00:56 -05:00
func MountDvdDrive ( vmName string , path string , controllerNumber uint , controllerLocation uint ) error {
2015-10-30 04:23:30 -04:00
var script = `
param ( [ string ] $ vmName , [ string ] $ path , [ string ] $ controllerNumber , [ string ] $ controllerLocation )
2018-02-07 02:01:05 -05:00
$ vmDvdDrive = Hyper - V \ Get - VMDvdDrive - VMName $ vmName - ControllerNumber $ controllerNumber - ControllerLocation $ controllerLocation
2015-11-01 11:00:56 -05:00
if ( ! $ vmDvdDrive ) { throw ' unable to find dvd drive ' }
2018-02-07 02:01:05 -05:00
Hyper - V \ Set - VMDvdDrive - VMName $ vmName - ControllerNumber $ controllerNumber - ControllerLocation $ controllerLocation - Path $ path
2015-10-30 04:23:30 -04:00
`
var ps powershell . PowerShellCmd
err := ps . Run ( script , vmName , path , strconv . FormatInt ( int64 ( controllerNumber ) , 10 ) , strconv . FormatInt ( int64 ( controllerLocation ) , 10 ) )
return err
}
2015-11-01 11:00:56 -05:00
func UnmountDvdDrive ( vmName string , controllerNumber uint , controllerLocation uint ) error {
2015-06-21 07:36:07 -04:00
var script = `
2015-11-01 11:00:56 -05:00
param ( [ string ] $ vmName , [ int ] $ controllerNumber , [ int ] $ controllerLocation )
2018-02-07 02:01:05 -05:00
$ vmDvdDrive = Hyper - V \ Get - VMDvdDrive - VMName $ vmName - ControllerNumber $ controllerNumber - ControllerLocation $ controllerLocation
2015-11-01 11:00:56 -05:00
if ( ! $ vmDvdDrive ) { throw ' unable to find dvd drive ' }
2018-02-07 02:01:05 -05:00
Hyper - V \ Set - VMDvdDrive - VMName $ vmName - ControllerNumber $ controllerNumber - ControllerLocation $ controllerLocation - Path $ null
2015-06-21 07:36:07 -04:00
`
var ps powershell . PowerShellCmd
2015-11-01 11:00:56 -05:00
err := ps . Run ( script , vmName , strconv . FormatInt ( int64 ( controllerNumber ) , 10 ) , strconv . FormatInt ( int64 ( controllerLocation ) , 10 ) )
2015-06-21 07:36:07 -04:00
return err
}
2015-11-07 08:42:26 -05:00
func SetBootDvdDrive ( vmName string , controllerNumber uint , controllerLocation uint , generation uint ) error {
if generation < 2 {
script := `
param ( [ string ] $ vmName )
2018-02-07 02:01:05 -05:00
Hyper - V \ Set - VMBios - VMName $ vmName - StartupOrder @ ( "CD" , "IDE" , "LegacyNetworkAdapter" , "Floppy" )
2015-11-07 08:42:26 -05:00
`
var ps powershell . PowerShellCmd
err := ps . Run ( script , vmName )
return err
} else {
script := `
2015-10-30 13:19:25 -04:00
param ( [ string ] $ vmName , [ int ] $ controllerNumber , [ int ] $ controllerLocation )
2018-02-07 02:01:05 -05:00
$ vmDvdDrive = Hyper - V \ Get - VMDvdDrive - VMName $ vmName - ControllerNumber $ controllerNumber - ControllerLocation $ controllerLocation
2015-10-30 13:19:25 -04:00
if ( ! $ vmDvdDrive ) { throw ' unable to find dvd drive ' }
2018-02-07 02:01:05 -05:00
Hyper - V \ Set - VMFirmware - VMName $ vmName - FirstBootDevice $ vmDvdDrive - ErrorAction SilentlyContinue
2015-10-30 13:19:25 -04:00
`
2015-11-07 08:42:26 -05:00
var ps powershell . PowerShellCmd
err := ps . Run ( script , vmName , strconv . FormatInt ( int64 ( controllerNumber ) , 10 ) , strconv . FormatInt ( int64 ( controllerLocation ) , 10 ) )
return err
}
2015-10-30 13:19:25 -04:00
}
func DeleteDvdDrive ( vmName string , controllerNumber uint , controllerLocation uint ) error {
2015-10-30 04:23:30 -04:00
var script = `
param ( [ string ] $ vmName , [ int ] $ controllerNumber , [ int ] $ controllerLocation )
2018-02-07 02:01:05 -05:00
$ vmDvdDrive = Hyper - V \ Get - VMDvdDrive - VMName $ vmName - ControllerNumber $ controllerNumber - ControllerLocation $ controllerLocation
2015-10-30 04:23:30 -04:00
if ( ! $ vmDvdDrive ) { throw ' unable to find dvd drive ' }
2018-02-07 02:01:05 -05:00
Hyper - V \ Remove - VMDvdDrive - VMName $ vmName - ControllerNumber $ controllerNumber - ControllerLocation $ controllerLocation
2015-10-30 04:23:30 -04:00
`
var ps powershell . PowerShellCmd
2015-10-30 13:19:25 -04:00
err := ps . Run ( script , vmName , strconv . FormatInt ( int64 ( controllerNumber ) , 10 ) , strconv . FormatInt ( int64 ( controllerLocation ) , 10 ) )
2015-10-30 04:23:30 -04:00
return err
}
2015-11-30 08:34:35 -05:00
func DeleteAllDvdDrives ( vmName string ) error {
var script = `
param ( [ string ] $ vmName )
2018-02-07 02:01:05 -05:00
Hyper - V \ Get - VMDvdDrive - VMName $ vmName | Hyper - V \ Remove - VMDvdDrive
2015-11-30 08:34:35 -05:00
`
var ps powershell . PowerShellCmd
err := ps . Run ( script , vmName )
return err
}
2015-06-21 07:36:07 -04:00
func MountFloppyDrive ( vmName string , path string ) error {
var script = `
param ( [ string ] $ vmName , [ string ] $ path )
2018-02-07 02:01:05 -05:00
Hyper - V \ Set - VMFloppyDiskDrive - VMName $ vmName - Path $ path
2015-06-21 07:36:07 -04:00
`
var ps powershell . PowerShellCmd
err := ps . Run ( script , vmName , path )
return err
}
func UnmountFloppyDrive ( vmName string ) error {
var script = `
param ( [ string ] $ vmName )
2018-02-07 02:01:05 -05:00
Hyper - V \ Set - VMFloppyDiskDrive - VMName $ vmName - Path $ null
2015-06-21 07:36:07 -04:00
`
var ps powershell . PowerShellCmd
err := ps . Run ( script , vmName )
return err
}
2018-04-20 15:13:12 -04:00
func CreateVirtualMachine ( vmName string , path string , harddrivePath string , vhdRoot string , ram int64 , diskSize int64 , diskBlockSize int64 , switchName string , generation uint , diffDisks bool , fixedVHD bool ) error {
2015-06-21 07:36:07 -04:00
2015-10-30 04:23:30 -04:00
if generation == 2 {
2015-06-29 16:18:25 -04:00
var script = `
2018-02-23 14:19:26 -05:00
param ( [ string ] $ vmName , [ string ] $ path , [ string ] $ harddrivePath , [ string ] $ vhdRoot , [ long ] $ memoryStartupBytes , [ long ] $ newVHDSizeBytes , [ long ] $ vhdBlockSizeBytes , [ string ] $ switchName , [ int ] $ generation , [ string ] $ diffDisks )
2015-06-21 07:36:07 -04:00
$ vhdx = $ vmName + ' . vhdx '
2017-08-01 05:23:19 -04:00
$ vhdPath = Join - Path - Path $ vhdRoot - ChildPath $ vhdx
2017-05-21 12:29:26 -04:00
if ( $ harddrivePath ) {
2017-10-12 06:35:31 -04:00
if ( $ diffDisks - eq "true" ) {
2018-02-23 14:19:26 -05:00
New - VHD - Path $ vhdPath - ParentPath $ harddrivePath - Differencing - BlockSizeBytes $ vhdBlockSizeBytes
2017-10-12 06:35:31 -04:00
} else {
Copy - Item - Path $ harddrivePath - Destination $ vhdPath
}
2018-02-07 02:01:05 -05:00
Hyper - V \ New - VM - Name $ vmName - Path $ path - MemoryStartupBytes $ memoryStartupBytes - VHDPath $ vhdPath - SwitchName $ switchName - Generation $ generation
2017-05-21 12:29:26 -04:00
} else {
2018-02-23 14:21:22 -05:00
Hyper - V \ New - VHD - Path $ vhdPath - SizeBytes $ newVHDSizeBytes - BlockSizeBytes $ vhdBlockSizeBytes
Hyper - V \ New - VM - Name $ vmName - Path $ path - MemoryStartupBytes $ memoryStartupBytes - VHDPath $ vhdPath - SwitchName $ switchName - Generation $ generation
2017-05-21 12:29:26 -04:00
}
2015-06-21 07:36:07 -04:00
`
2015-06-29 16:18:25 -04:00
var ps powershell . PowerShellCmd
2018-02-23 14:19:26 -05:00
if err := ps . Run ( script , vmName , path , harddrivePath , vhdRoot , strconv . FormatInt ( ram , 10 ) , strconv . FormatInt ( diskSize , 10 ) , strconv . FormatInt ( diskBlockSize , 10 ) , switchName , strconv . FormatInt ( int64 ( generation ) , 10 ) , strconv . FormatBool ( diffDisks ) ) ; err != nil {
2017-10-25 01:20:46 -04:00
return err
}
2017-10-26 00:47:14 -04:00
2017-10-25 01:20:46 -04:00
return DisableAutomaticCheckpoints ( vmName )
2015-06-29 16:18:25 -04:00
} else {
var script = `
2018-04-20 15:13:12 -04:00
param ( [ string ] $ vmName , [ string ] $ path , [ string ] $ harddrivePath , [ string ] $ vhdRoot , [ long ] $ memoryStartupBytes , [ long ] $ newVHDSizeBytes , [ long ] $ vhdBlockSizeBytes , [ string ] $ switchName , [ string ] $ diffDisks , [ string ] $ fixedVHD )
if ( $ fixedVHD - eq "true" ) {
$ vhdx = $ vmName + ' . vhd '
}
else {
$ vhdx = $ vmName + ' . vhdx '
}
2017-08-01 05:23:19 -04:00
$ vhdPath = Join - Path - Path $ vhdRoot - ChildPath $ vhdx
2017-05-21 12:29:26 -04:00
if ( $ harddrivePath ) {
2017-10-12 06:35:31 -04:00
if ( $ diffDisks - eq "true" ) {
2018-02-23 14:19:26 -05:00
New - VHD - Path $ vhdPath - ParentPath $ harddrivePath - Differencing - BlockSizeBytes $ vhdBlockSizeBytes
2017-10-12 06:35:31 -04:00
}
else {
Copy - Item - Path $ harddrivePath - Destination $ vhdPath
}
2018-02-07 02:01:05 -05:00
Hyper - V \ New - VM - Name $ vmName - Path $ path - MemoryStartupBytes $ memoryStartupBytes - VHDPath $ vhdPath - SwitchName $ switchName
2017-05-21 12:29:26 -04:00
} else {
2018-04-20 15:13:12 -04:00
if ( $ fixedVHD - eq "true" ) {
Hyper - V \ New - VHD - Path $ vhdPath - Fixed - SizeBytes $ newVHDSizeBytes
}
else {
Hyper - V \ New - VHD - Path $ vhdPath - SizeBytes $ newVHDSizeBytes - BlockSizeBytes $ vhdBlockSizeBytes
}
2018-02-23 14:21:22 -05:00
Hyper - V \ New - VM - Name $ vmName - Path $ path - MemoryStartupBytes $ memoryStartupBytes - VHDPath $ vhdPath - SwitchName $ switchName
2017-05-21 12:29:26 -04:00
}
2015-06-29 16:18:25 -04:00
`
var ps powershell . PowerShellCmd
2018-04-20 15:13:12 -04:00
if err := ps . Run ( script , vmName , path , harddrivePath , vhdRoot , strconv . FormatInt ( ram , 10 ) , strconv . FormatInt ( diskSize , 10 ) , strconv . FormatInt ( diskBlockSize , 10 ) , switchName , strconv . FormatBool ( diffDisks ) , strconv . FormatBool ( fixedVHD ) ) ; err != nil {
2015-11-07 11:20:55 -05:00
return err
}
2017-10-25 01:20:46 -04:00
if err := DisableAutomaticCheckpoints ( vmName ) ; err != nil {
2017-09-21 17:51:38 -04:00
return err
}
2015-11-30 08:34:35 -05:00
return DeleteAllDvdDrives ( vmName )
2015-06-29 16:18:25 -04:00
}
2015-06-21 14:35:32 -04:00
}
2017-09-21 17:51:38 -04:00
func DisableAutomaticCheckpoints ( vmName string ) error {
var script = `
param ( [ string ] $ vmName )
2018-06-25 18:51:27 -04:00
if ( ( Get - Command Hyper - V \ Set - Vm ) . Parameters [ "AutomaticCheckpointsEnabled" ] ) {
2018-02-07 02:01:05 -05:00
Hyper - V \ Set - Vm - Name $ vmName - AutomaticCheckpointsEnabled $ false }
2017-09-21 17:51:38 -04:00
`
var ps powershell . PowerShellCmd
err := ps . Run ( script , vmName )
return err
}
2017-05-21 12:29:26 -04:00
func ExportVmxcVirtualMachine ( exportPath string , vmName string , snapshotName string , allSnapshots bool ) error {
2017-03-12 07:31:31 -04:00
var script = `
2017-05-21 12:29:26 -04:00
param ( [ string ] $ exportPath , [ string ] $ vmName , [ string ] $ snapshotName , [ string ] $ allSnapshotsString )
2017-03-12 07:31:31 -04:00
2018-06-25 18:51:27 -04:00
$ WorkingPath = Join - Path $ exportPath $ vmName
2017-03-12 07:31:31 -04:00
2017-05-21 12:29:26 -04:00
if ( Test - Path $ WorkingPath ) {
throw "Export path working directory: $WorkingPath already exists!"
}
2017-03-12 07:31:31 -04:00
2017-05-21 12:29:26 -04:00
$ allSnapshots = [ System . Boolean ] : : Parse ( $ allSnapshotsString )
2017-03-12 07:31:31 -04:00
2017-05-21 12:29:26 -04:00
if ( $ snapshotName ) {
2018-02-07 02:01:05 -05:00
$ snapshot = Hyper - V \ Get - VMSnapshot - VMName $ vmName - Name $ snapshotName
Hyper - V \ Export - VMSnapshot - VMSnapshot $ snapshot - Path $ exportPath - ErrorAction Stop
2017-03-12 07:31:31 -04:00
} else {
2017-05-21 12:29:26 -04:00
if ( ! $ allSnapshots ) {
2017-03-12 07:31:31 -04:00
# Use last snapshot if one was not specified
2018-02-07 02:01:05 -05:00
$ snapshot = Hyper - V \ Get - VMSnapshot - VMName $ vmName | Select - Last 1
2017-03-12 07:31:31 -04:00
} else {
$ snapshot = $ null
}
2018-06-25 18:51:27 -04:00
2017-03-12 07:31:31 -04:00
if ( ! $ snapshot ) {
# No snapshot clone
2018-02-07 02:01:05 -05:00
Hyper - V \ Export - VM - Name $ vmName - Path $ exportPath - ErrorAction Stop
2017-03-12 07:31:31 -04:00
} else {
# Snapshot clone
2018-02-07 02:01:05 -05:00
Hyper - V \ Export - VMSnapshot - VMSnapshot $ snapshot - Path $ exportPath - ErrorAction Stop
2017-03-12 07:31:31 -04:00
}
}
2017-05-21 12:29:26 -04:00
$ result = Get - ChildItem - Path $ WorkingPath | Move - Item - Destination $ exportPath - Force
$ result = Remove - Item - Path $ WorkingPath
`
allSnapshotsString := "False"
if allSnapshots {
allSnapshotsString = "True"
}
var ps powershell . PowerShellCmd
err := ps . Run ( script , exportPath , vmName , snapshotName , allSnapshotsString )
return err
}
func CopyVmxcVirtualMachine ( exportPath string , cloneFromVmxcPath string ) error {
var script = `
param ( [ string ] $ exportPath , [ string ] $ cloneFromVmxcPath )
if ( ! ( Test - Path $ cloneFromVmxcPath ) ) {
throw "Clone from vmxc directory: $cloneFromVmxcPath does not exist!"
}
2018-06-25 18:51:27 -04:00
2017-05-21 12:29:26 -04:00
if ( ! ( Test - Path $ exportPath ) ) {
New - Item - ItemType Directory - Force - Path $ exportPath
}
$ cloneFromVmxcPath = Join - Path $ cloneFromVmxcPath ' \ * '
Copy - Item $ cloneFromVmxcPath $ exportPath - Recurse - Force
`
var ps powershell . PowerShellCmd
err := ps . Run ( script , exportPath , cloneFromVmxcPath )
return err
}
2017-12-14 21:24:15 -05:00
func SetVmNetworkAdapterMacAddress ( vmName string , mac string ) error {
var script = `
param ( [ string ] $ vmName , [ string ] $ mac )
2018-02-07 02:01:05 -05:00
Hyper - V \ Set - VMNetworkAdapter $ vmName - staticmacaddress $ mac
2017-12-14 21:24:15 -05:00
`
var ps powershell . PowerShellCmd
err := ps . Run ( script , vmName , mac )
return err
}
2017-05-21 12:29:26 -04:00
func ImportVmxcVirtualMachine ( importPath string , vmName string , harddrivePath string , ram int64 , switchName string ) error {
var script = `
param ( [ string ] $ importPath , [ string ] $ vmName , [ string ] $ harddrivePath , [ long ] $ memoryStartupBytes , [ string ] $ switchName )
$ VirtualHarddisksPath = Join - Path - Path $ importPath - ChildPath ' Virtual Hard Disks '
if ( ! ( Test - Path $ VirtualHarddisksPath ) ) {
New - Item - ItemType Directory - Force - Path $ VirtualHarddisksPath
}
2017-03-12 07:31:31 -04:00
2017-05-21 12:29:26 -04:00
$ vhdPath = ""
if ( $ harddrivePath ) {
$ vhdx = $ vmName + ' . vhdx '
$ vhdPath = Join - Path - Path $ VirtualHarddisksPath - ChildPath $ vhdx
}
$ VirtualMachinesPath = Join - Path $ importPath ' Virtual Machines '
if ( ! ( Test - Path $ VirtualMachinesPath ) ) {
New - Item - ItemType Directory - Force - Path $ VirtualMachinesPath
}
$ VirtualMachinePath = Get - ChildItem - Path $ VirtualMachinesPath - Filter * . vmcx - Recurse - ErrorAction SilentlyContinue | select - First 1 | % { $ _ . FullName }
2017-03-12 07:31:31 -04:00
if ( ! $ VirtualMachinePath ) {
2017-05-21 12:29:26 -04:00
$ VirtualMachinePath = Get - ChildItem - Path $ VirtualMachinesPath - Filter * . xml - Recurse - ErrorAction SilentlyContinue | select - First 1 | % { $ _ . FullName }
2017-03-12 07:31:31 -04:00
}
if ( ! $ VirtualMachinePath ) {
2017-05-21 12:29:26 -04:00
$ VirtualMachinePath = Get - ChildItem - Path $ importPath - Filter * . xml - Recurse - ErrorAction SilentlyContinue | select - First 1 | % { $ _ . FullName }
2017-03-12 07:31:31 -04:00
}
2018-02-07 02:01:05 -05:00
$ compatibilityReport = Hyper - V \ Compare - VM - Path $ VirtualMachinePath - VirtualMachinePath $ importPath - SmartPagingFilePath $ importPath - SnapshotFilePath $ importPath - VhdDestinationPath $ VirtualHarddisksPath - GenerateNewId - Copy : $ false
2017-05-21 12:29:26 -04:00
if ( $ vhdPath ) {
Copy - Item - Path $ harddrivePath - Destination $ vhdPath
$ existingFirstHarddrive = $ compatibilityReport . VM . HardDrives | Select - First 1
if ( $ existingFirstHarddrive ) {
2018-02-07 02:01:05 -05:00
$ existingFirstHarddrive | Hyper - V \ Set - VMHardDiskDrive - Path $ vhdPath
2017-05-21 12:29:26 -04:00
} else {
2018-02-07 02:01:05 -05:00
Hyper - V \ Add - VMHardDiskDrive - VM $ compatibilityReport . VM - Path $ vhdPath
2018-06-25 18:51:27 -04:00
}
2017-05-21 12:29:26 -04:00
}
2018-02-07 02:01:05 -05:00
Hyper - V \ Set - VMMemory - VM $ compatibilityReport . VM - StartupBytes $ memoryStartupBytes
2017-03-12 07:31:31 -04:00
$ networkAdaptor = $ compatibilityReport . VM . NetworkAdapters | Select - First 1
2018-02-07 02:01:05 -05:00
Hyper - V \ Disconnect - VMNetworkAdapter - VMNetworkAdapter $ networkAdaptor
2018-06-25 18:51:27 -04:00
Hyper - V \ Connect - VMNetworkAdapter - VMNetworkAdapter $ networkAdaptor - SwitchName $ switchName
2018-02-07 02:01:05 -05:00
$ vm = Hyper - V \ Import - VM - CompatibilityReport $ compatibilityReport
2017-03-12 07:31:31 -04:00
if ( $ vm ) {
2018-02-07 02:01:05 -05:00
$ result = Hyper - V \ Rename - VM - VM $ vm - NewName $ VMName
2017-03-12 07:31:31 -04:00
}
2017-05-21 12:29:26 -04:00
`
2017-03-12 07:31:31 -04:00
2017-05-21 12:29:26 -04:00
var ps powershell . PowerShellCmd
err := ps . Run ( script , importPath , vmName , harddrivePath , strconv . FormatInt ( ram , 10 ) , switchName )
return err
}
func CloneVirtualMachine ( cloneFromVmxcPath string , cloneFromVmName string , cloneFromSnapshotName string , cloneAllSnapshots bool , vmName string , path string , harddrivePath string , ram int64 , switchName string ) error {
if cloneFromVmName != "" {
2017-10-25 01:20:46 -04:00
if err := ExportVmxcVirtualMachine ( path , cloneFromVmName , cloneFromSnapshotName , cloneAllSnapshots ) ; err != nil {
2017-05-21 12:29:26 -04:00
return err
}
2017-03-12 07:31:31 -04:00
}
2017-05-21 12:29:26 -04:00
if cloneFromVmxcPath != "" {
2017-10-25 01:20:46 -04:00
if err := CopyVmxcVirtualMachine ( path , cloneFromVmxcPath ) ; err != nil {
2017-05-21 12:29:26 -04:00
return err
}
}
2017-03-12 07:31:31 -04:00
2017-10-25 01:20:46 -04:00
if err := ImportVmxcVirtualMachine ( path , vmName , harddrivePath , ram , switchName ) ; err != nil {
2017-03-12 07:31:31 -04:00
return err
}
return DeleteAllDvdDrives ( vmName )
}
func GetVirtualMachineGeneration ( vmName string ) ( uint , error ) {
var script = `
param ( [ string ] $ vmName )
2018-02-07 02:01:05 -05:00
$ generation = Hyper - V \ Get - Vm - Name $ vmName | % { $ _ . Generation }
2017-03-12 07:31:31 -04:00
if ( ! $ generation ) {
$ generation = 1
}
return $ generation
`
var ps powershell . PowerShellCmd
cmdOut , err := ps . Output ( script , vmName )
if err != nil {
return 0 , err
}
generationUint32 , err := strconv . ParseUint ( strings . TrimSpace ( string ( cmdOut ) ) , 10 , 32 )
if err != nil {
return 0 , err
}
generation := uint ( generationUint32 )
return generation , err
}
2016-08-07 07:26:27 -04:00
func SetVirtualMachineCpuCount ( vmName string , cpu uint ) error {
2015-06-21 14:35:32 -04:00
var script = `
2016-08-07 07:26:27 -04:00
param ( [ string ] $ vmName , [ int ] $ cpu )
2018-02-07 02:01:05 -05:00
Hyper - V \ Set - VMProcessor - VMName $ vmName - Count $ cpu
2016-08-07 07:26:27 -04:00
`
var ps powershell . PowerShellCmd
err := ps . Run ( script , vmName , strconv . FormatInt ( int64 ( cpu ) , 10 ) )
return err
}
func SetVirtualMachineVirtualizationExtensions ( vmName string , enableVirtualizationExtensions bool ) error {
var script = `
param ( [ string ] $ vmName , [ string ] $ exposeVirtualizationExtensionsString )
$ exposeVirtualizationExtensions = [ System . Boolean ] : : Parse ( $ exposeVirtualizationExtensionsString )
2018-02-07 02:01:05 -05:00
Hyper - V \ Set - VMProcessor - VMName $ vmName - ExposeVirtualizationExtensions $ exposeVirtualizationExtensions
2015-06-21 14:35:32 -04:00
`
2016-08-06 02:59:16 -04:00
exposeVirtualizationExtensionsString := "False"
2016-08-06 02:09:33 -04:00
if enableVirtualizationExtensions {
2016-08-06 02:59:16 -04:00
exposeVirtualizationExtensionsString = "True"
2016-08-07 07:26:27 -04:00
}
var ps powershell . PowerShellCmd
err := ps . Run ( script , vmName , exposeVirtualizationExtensionsString )
return err
}
func SetVirtualMachineDynamicMemory ( vmName string , enableDynamicMemory bool ) error {
var script = `
param ( [ string ] $ vmName , [ string ] $ enableDynamicMemoryString )
$ enableDynamicMemory = [ System . Boolean ] : : Parse ( $ enableDynamicMemoryString )
2018-02-07 02:01:05 -05:00
Hyper - V \ Set - VMMemory - VMName $ vmName - DynamicMemoryEnabled $ enableDynamicMemory
2016-08-07 07:26:27 -04:00
`
enableDynamicMemoryString := "False"
if enableDynamicMemory {
enableDynamicMemoryString = "True"
}
2015-06-21 14:35:32 -04:00
var ps powershell . PowerShellCmd
2016-08-07 07:26:27 -04:00
err := ps . Run ( script , vmName , enableDynamicMemoryString )
return err
}
func SetVirtualMachineMacSpoofing ( vmName string , enableMacSpoofing bool ) error {
var script = `
param ( [ string ] $ vmName , $ enableMacSpoofing )
2018-02-07 02:01:05 -05:00
Hyper - V \ Set - VMNetworkAdapter - VMName $ vmName - MacAddressSpoofing $ enableMacSpoofing
2016-08-07 07:26:27 -04:00
`
var ps powershell . PowerShellCmd
enableMacSpoofingString := "Off"
if enableMacSpoofing {
enableMacSpoofingString = "On"
}
err := ps . Run ( script , vmName , enableMacSpoofingString )
2015-06-21 07:36:07 -04:00
return err
}
2018-05-10 13:00:35 -04:00
func SetVirtualMachineSecureBoot ( vmName string , enableSecureBoot bool , templateName string ) error {
2015-06-29 16:18:25 -04:00
var script = `
2018-06-25 09:13:43 -04:00
param ( [ string ] $ vmName , [ string ] $ enableSecureBootString , [ string ] $ templateName )
2018-06-25 18:51:27 -04:00
$ cmdlet = Get - Command Hyper - V \ Set - VMFirmware
# The SecureBootTemplate parameter is only available in later versions
if ( $ cmdlet . Parameters . SecureBootTemplate ) {
2018-06-25 09:13:43 -04:00
Hyper - V \ Set - VMFirmware - VMName $ vmName - EnableSecureBoot $ enableSecureBootString - SecureBootTemplate $ templateName
} else {
Hyper - V \ Set - VMFirmware - VMName $ vmName - EnableSecureBoot $ enableSecureBootString
}
2015-06-29 16:18:25 -04:00
`
var ps powershell . PowerShellCmd
2016-08-07 07:26:27 -04:00
enableSecureBootString := "Off"
if enableSecureBoot {
enableSecureBootString = "On"
2015-06-29 16:18:25 -04:00
}
2018-05-10 13:00:35 -04:00
if templateName == "" {
templateName = "MicrosoftWindows"
}
err := ps . Run ( script , vmName , enableSecureBootString , templateName )
2015-06-29 16:18:25 -04:00
return err
}
2015-06-21 07:36:07 -04:00
func DeleteVirtualMachine ( vmName string ) error {
var script = `
param ( [ string ] $ vmName )
2015-06-24 14:52:42 -04:00
2018-02-07 02:01:05 -05:00
$ vm = Hyper - V \ Get - VM - Name $ vmName
2015-06-24 14:52:42 -04:00
if ( ( $ vm . State - ne [ Microsoft . HyperV . PowerShell . VMState ] : : Off ) - and ( $ vm . State - ne [ Microsoft . HyperV . PowerShell . VMState ] : : OffCritical ) ) {
2018-02-07 02:01:05 -05:00
Hyper - V \ Stop - VM - VM $ vm - TurnOff - Force - Confirm : $ false
2015-06-24 14:52:42 -04:00
}
2018-02-07 02:01:05 -05:00
Hyper - V \ Remove - VM - Name $ vmName - Force - Confirm : $ false
2015-06-21 07:36:07 -04:00
`
var ps powershell . PowerShellCmd
err := ps . Run ( script , vmName )
return err
}
func ExportVirtualMachine ( vmName string , path string ) error {
var script = `
param ( [ string ] $ vmName , [ string ] $ path )
2018-02-07 02:01:05 -05:00
Hyper - V \ Export - VM - Name $ vmName - Path $ path
2015-11-30 23:44:34 -05:00
if ( Test - Path - Path ( [ IO . Path ] : : Combine ( $ path , $ vmName , ' Virtual Machines ' , ' * . VMCX ' ) ) )
{
2018-02-07 02:01:05 -05:00
$ vm = Hyper - V \ Get - VM - Name $ vmName
$ vm_adapter = Hyper - V \ Get - VMNetworkAdapter - VM $ vm | Select - First 1
2015-11-30 23:44:34 -05:00
$ config = [ xml ] @ "
< ? xml version = "1.0" ? >
< configuration >
< properties >
< subtype type = "integer" > $ ( $ vm . Generation - 1 ) < / subtype >
< name type = "string" > $ ( $ vm . Name ) < / name >
< / properties >
< settings >
< processors >
< count type = "integer" > $ ( $ vm . ProcessorCount ) < / count >
< / processors >
< memory >
< bank >
< dynamic_memory_enabled type = "bool" > $ ( $ vm . DynamicMemoryEnabled ) < / dynamic_memory_enabled >
< limit type = "integer" > $ ( $ vm . MemoryMaximum / 1 MB ) < / limit >
< reservation type = "integer" > $ ( $ vm . MemoryMinimum / 1 MB ) < / reservation >
< size type = "integer" > $ ( $ vm . MemoryStartup / 1 MB ) < / size >
< / bank >
< / memory >
< / settings >
< AltSwitchName type = "string" > $ ( $ vm_adapter . SwitchName ) < / AltSwitchName >
< boot >
< device0 type = "string" > Optical < / device0 >
< / boot >
< secure_boot_enabled type = "bool" > False < / secure_boot_enabled >
< notes type = "string" > $ ( $ vm . Notes ) < / notes >
< vm - controllers / >
< / configuration >
" @
if ( $ vm . Generation - eq 1 )
{
2018-02-07 02:01:05 -05:00
$ vm_controllers = Hyper - V \ Get - VMIdeController - VM $ vm
2015-11-30 23:44:34 -05:00
$ controller_type = $ config . SelectSingleNode ( ' / configuration / vm - controllers ' )
# IDE controllers are not stored in a special XML container
}
else
{
2018-02-07 02:01:05 -05:00
$ vm_controllers = Hyper - V \ Get - VMScsiController - VM $ vm
2015-11-30 23:44:34 -05:00
$ controller_type = $ config . CreateElement ( ' scsi ' )
$ controller_type . SetAttribute ( ' ChannelInstanceGuid ' , 'x' )
# SCSI controllers are stored in the scsi XML container
2018-02-07 02:01:05 -05:00
if ( ( Hyper - V \ Get - VMFirmware - VM $ vm ) . SecureBoot - eq [ Microsoft . HyperV . PowerShell . OnOffState ] : : On )
2015-11-30 23:44:34 -05:00
{
2018-05-10 13:00:35 -04:00
$ config . configuration . secure_boot_enabled . ' # text ' = ' True '
}
2015-11-30 23:44:34 -05:00
else
{
$ config . configuration . secure_boot_enabled . ' # text ' = ' False '
2018-05-10 13:00:35 -04:00
}
2015-11-30 23:44:34 -05:00
}
$ vm_controllers | ForEach {
$ controller = $ config . CreateElement ( ' controller ' + $ _ . ControllerNumber )
$ _ . Drives | ForEach {
$ drive = $ config . CreateElement ( ' drive ' + ( $ _ . DiskNumber + 0 ) )
$ drive_path = $ config . CreateElement ( ' pathname ' )
$ drive_path . SetAttribute ( ' type ' , ' string ' )
$ drive_path . AppendChild ( $ config . CreateTextNode ( $ _ . Path ) )
$ drive_type = $ config . CreateElement ( ' type ' )
$ drive_type . SetAttribute ( ' type ' , ' string ' )
if ( $ _ - is [ Microsoft . HyperV . PowerShell . HardDiskDrive ] )
{
$ drive_type . AppendChild ( $ config . CreateTextNode ( ' VHD ' ) )
}
elseif ( $ _ - is [ Microsoft . HyperV . PowerShell . DvdDrive ] )
{
$ drive_type . AppendChild ( $ config . CreateTextNode ( ' ISO ' ) )
}
else
{
$ drive_type . AppendChild ( $ config . CreateTextNode ( ' NONE ' ) )
}
$ drive . AppendChild ( $ drive_path )
$ drive . AppendChild ( $ drive_type )
$ controller . AppendChild ( $ drive )
}
$ controller_type . AppendChild ( $ controller )
}
if ( $ controller_type . Name - ne ' vm - controllers ' )
{
$ config . SelectSingleNode ( ' / configuration / vm - controllers ' ) . AppendChild ( $ controller_type )
}
$ config . Save ( [ IO . Path ] : : Combine ( $ path , $ vm . Name , ' Virtual Machines ' , ' box . xml ' ) )
}
2015-06-21 07:36:07 -04:00
`
var ps powershell . PowerShellCmd
err := ps . Run ( script , vmName , path )
return err
}
2018-06-16 13:02:38 -04:00
func CompactDisks ( path string ) error {
2015-06-27 17:36:39 -04:00
var script = `
2018-06-16 13:02:38 -04:00
param ( [ string ] $ srcPath )
Get - ChildItem "$srcPath" - Filter * . vhd * | % {
2015-06-27 17:36:39 -04:00
Optimize - VHD - Path $ _ . FullName - Mode Full
}
`
var ps powershell . PowerShellCmd
2018-06-16 13:02:38 -04:00
err := ps . Run ( script , path )
2015-06-27 17:36:39 -04:00
return err
}
2015-06-21 07:36:07 -04:00
func CreateVirtualSwitch ( switchName string , switchType string ) ( bool , error ) {
var script = `
param ( [ string ] $ switchName , [ string ] $ switchType )
2018-02-07 02:01:05 -05:00
$ switches = Hyper - V \ Get - VMSwitch - Name $ switchName - ErrorAction SilentlyContinue
2015-06-21 07:36:07 -04:00
if ( $ switches . Count - eq 0 ) {
2018-02-07 02:01:05 -05:00
Hyper - V \ New - VMSwitch - Name $ switchName - SwitchType $ switchType
2015-06-21 07:36:07 -04:00
return $ true
}
return $ false
`
var ps powershell . PowerShellCmd
cmdOut , err := ps . Output ( script , switchName , switchType )
var created = strings . TrimSpace ( cmdOut ) == "True"
return created , err
}
func DeleteVirtualSwitch ( switchName string ) error {
var script = `
param ( [ string ] $ switchName )
2018-02-07 02:01:05 -05:00
$ switch = Hyper - V \ Get - VMSwitch - Name $ switchName - ErrorAction SilentlyContinue
2015-06-21 07:36:07 -04:00
if ( $ switch - ne $ null ) {
2018-02-07 02:01:05 -05:00
$ switch | Hyper - V \ Remove - VMSwitch - Force - Confirm : $ false
2015-06-21 07:36:07 -04:00
}
`
var ps powershell . PowerShellCmd
err := ps . Run ( script , switchName )
return err
}
func StartVirtualMachine ( vmName string ) error {
var script = `
param ( [ string ] $ vmName )
2018-02-07 02:01:05 -05:00
$ vm = Hyper - V \ Get - VM - Name $ vmName - ErrorAction SilentlyContinue
2015-06-27 17:36:39 -04:00
if ( $ vm . State - eq [ Microsoft . HyperV . PowerShell . VMState ] : : Off ) {
2018-02-07 02:01:05 -05:00
Hyper - V \ Start - VM - Name $ vmName - Confirm : $ false
2015-06-27 17:36:39 -04:00
}
2015-06-21 07:36:07 -04:00
`
var ps powershell . PowerShellCmd
err := ps . Run ( script , vmName )
return err
}
func RestartVirtualMachine ( vmName string ) error {
var script = `
param ( [ string ] $ vmName )
2018-02-07 02:01:05 -05:00
Hyper - V \ Restart - VM $ vmName - Force - Confirm : $ false
2015-06-21 07:36:07 -04:00
`
var ps powershell . PowerShellCmd
err := ps . Run ( script , vmName )
return err
}
func StopVirtualMachine ( vmName string ) error {
var script = `
param ( [ string ] $ vmName )
2018-02-07 02:01:05 -05:00
$ vm = Hyper - V \ Get - VM - Name $ vmName
2015-06-21 07:36:07 -04:00
if ( $ vm . State - eq [ Microsoft . HyperV . PowerShell . VMState ] : : Running ) {
2018-02-07 02:01:05 -05:00
Hyper - V \ Stop - VM - VM $ vm - Force - Confirm : $ false
2015-06-21 07:36:07 -04:00
}
`
var ps powershell . PowerShellCmd
err := ps . Run ( script , vmName )
return err
}
func EnableVirtualMachineIntegrationService ( vmName string , integrationServiceName string ) error {
2016-08-02 16:41:32 -04:00
integrationServiceId := ""
switch integrationServiceName {
case "Time Synchronization" :
integrationServiceId = "2497F4DE-E9FA-4204-80E4-4B75C46419C0"
case "Heartbeat" :
integrationServiceId = "84EAAE65-2F2E-45F5-9BB5-0E857DC8EB47"
case "Key-Value Pair Exchange" :
integrationServiceId = "2A34B1C2-FD73-4043-8A5B-DD2159BC743F"
case "Shutdown" :
integrationServiceId = "9F8233AC-BE49-4C79-8EE3-E7E1985B2077"
case "VSS" :
integrationServiceId = "5CED1297-4598-4915-A5FC-AD21BB4D02A4"
case "Guest Service Interface" :
integrationServiceId = "6C09BB55-D683-4DA0-8931-C9BF705F6480"
default :
panic ( "unrecognized Integration Service Name" )
}
2015-06-21 07:36:07 -04:00
var script = `
2016-08-02 16:41:32 -04:00
param ( [ string ] $ vmName , [ string ] $ integrationServiceId )
2018-02-07 02:01:05 -05:00
Hyper - V \ Get - VMIntegrationService - VmName $ vmName | ? { $ _ . Id - match $ integrationServiceId } | Hyper - V \ Enable - VMIntegrationService
2015-06-21 07:36:07 -04:00
`
var ps powershell . PowerShellCmd
2016-08-02 16:41:32 -04:00
err := ps . Run ( script , vmName , integrationServiceId )
2015-06-21 07:36:07 -04:00
return err
}
func SetNetworkAdapterVlanId ( switchName string , vlanId string ) error {
var script = `
param ( [ string ] $ networkAdapterName , [ string ] $ vlanId )
2018-02-07 02:01:05 -05:00
Hyper - V \ Set - VMNetworkAdapterVlan - ManagementOS - VMNetworkAdapterName $ networkAdapterName - Access - VlanId $ vlanId
2015-06-21 07:36:07 -04:00
`
var ps powershell . PowerShellCmd
err := ps . Run ( script , switchName , vlanId )
return err
}
func SetVirtualMachineVlanId ( vmName string , vlanId string ) error {
var script = `
param ( [ string ] $ vmName , [ string ] $ vlanId )
2018-02-07 02:01:05 -05:00
Hyper - V \ Set - VMNetworkAdapterVlan - VMName $ vmName - Access - VlanId $ vlanId
2015-06-21 07:36:07 -04:00
`
var ps powershell . PowerShellCmd
err := ps . Run ( script , vmName , vlanId )
return err
}
func GetExternalOnlineVirtualSwitch ( ) ( string , error ) {
var script = `
$ adapters = Get - NetAdapter - Physical - ErrorAction SilentlyContinue | Where - Object { $ _ . Status - eq ' Up ' } | Sort - Object - Descending - Property Speed
2017-03-28 21:47:10 -04:00
foreach ( $ adapter in $ adapters ) {
2018-02-07 02:01:05 -05:00
$ switch = Hyper - V \ Get - VMSwitch - SwitchType External | Where - Object { $ _ . NetAdapterInterfaceDescription - eq $ adapter . InterfaceDescription }
2015-06-21 07:36:07 -04:00
if ( $ switch - ne $ null ) {
$ switch . Name
break
}
}
`
var ps powershell . PowerShellCmd
cmdOut , err := ps . Output ( script )
if err != nil {
return "" , err
}
var switchName = strings . TrimSpace ( cmdOut )
return switchName , nil
}
func CreateExternalVirtualSwitch ( vmName string , switchName string ) error {
var script = `
param ( [ string ] $ vmName , [ string ] $ switchName )
$ switch = $ null
$ names = @ ( ' ethernet ',' wi - fi ',' lan ' )
$ adapters = foreach ( $ name in $ names ) {
Get - NetAdapter - Physical - Name $ name - ErrorAction SilentlyContinue | where status - eq ' up '
}
2017-03-28 21:47:10 -04:00
foreach ( $ adapter in $ adapters ) {
2018-02-07 02:01:05 -05:00
$ switch = Hyper - V \ Get - VMSwitch - SwitchType External | where { $ _ . NetAdapterInterfaceDescription - eq $ adapter . InterfaceDescription }
2015-06-21 07:36:07 -04:00
2017-03-28 21:47:10 -04:00
if ( $ switch - eq $ null ) {
2018-02-07 02:01:05 -05:00
$ switch = Hyper - V \ New - VMSwitch - Name $ switchName - NetAdapterName $ adapter . Name - AllowManagementOS $ true - Notes ' Parent OS , VMs , WiFi '
2015-06-21 07:36:07 -04:00
}
if ( $ switch - ne $ null ) {
break
}
}
2017-03-28 21:47:10 -04:00
if ( $ switch - ne $ null ) {
2018-02-07 02:01:05 -05:00
Hyper - V \ Get - VMNetworkAdapter - VMName $ vmName | Hyper - V \ Connect - VMNetworkAdapter - VMSwitch $ switch
2017-03-28 21:47:10 -04:00
} else {
2015-06-21 07:36:07 -04:00
Write - Error ' No internet adapters found '
}
`
var ps powershell . PowerShellCmd
err := ps . Run ( script , vmName , switchName )
return err
}
func GetVirtualMachineSwitchName ( vmName string ) ( string , error ) {
var script = `
param ( [ string ] $ vmName )
2018-02-07 02:01:05 -05:00
( Hyper - V \ Get - VMNetworkAdapter - VMName $ vmName ) . SwitchName
2015-06-21 07:36:07 -04:00
`
var ps powershell . PowerShellCmd
cmdOut , err := ps . Output ( script , vmName )
if err != nil {
return "" , err
}
return strings . TrimSpace ( cmdOut ) , nil
}
func ConnectVirtualMachineNetworkAdapterToSwitch ( vmName string , switchName string ) error {
var script = `
param ( [ string ] $ vmName , [ string ] $ switchName )
2018-02-07 02:01:05 -05:00
Hyper - V \ Get - VMNetworkAdapter - VMName $ vmName | Hyper - V \ Connect - VMNetworkAdapter - SwitchName $ switchName
2015-06-21 07:36:07 -04:00
`
var ps powershell . PowerShellCmd
err := ps . Run ( script , vmName , switchName )
return err
}
2018-02-23 14:19:26 -05:00
func AddVirtualMachineHardDiskDrive ( vmName string , vhdRoot string , vhdName string , vhdSizeBytes int64 , vhdBlockSize int64 , controllerType string ) error {
2017-10-19 18:29:17 -04:00
var script = `
2018-05-17 08:50:18 -04:00
param ( [ string ] $ vmName , [ string ] $ vhdRoot , [ string ] $ vhdName , [ string ] $ vhdSizeInBytes , [ string ] $ vhdBlockSizeInByte , [ string ] $ controllerType )
2017-10-19 18:29:17 -04:00
$ vhdPath = Join - Path - Path $ vhdRoot - ChildPath $ vhdName
2018-03-25 10:30:03 -04:00
Hyper - V \ New - VHD - path $ vhdPath - SizeBytes $ vhdSizeInBytes - BlockSizeBytes $ vhdBlockSizeInByte
2018-02-07 02:01:05 -05:00
Hyper - V \ Add - VMHardDiskDrive - VMName $ vmName - path $ vhdPath - controllerType $ controllerType
2017-10-19 18:29:17 -04:00
`
var ps powershell . PowerShellCmd
2018-02-23 14:19:26 -05:00
err := ps . Run ( script , vmName , vhdRoot , vhdName , strconv . FormatInt ( vhdSizeBytes , 10 ) , strconv . FormatInt ( vhdBlockSize , 10 ) , controllerType )
2017-10-19 18:29:17 -04:00
return err
}
2015-06-21 07:36:07 -04:00
func UntagVirtualMachineNetworkAdapterVlan ( vmName string , switchName string ) error {
var script = `
param ( [ string ] $ vmName , [ string ] $ switchName )
2018-02-07 02:01:05 -05:00
Hyper - V \ Set - VMNetworkAdapterVlan - VMName $ vmName - Untagged
Hyper - V \ Set - VMNetworkAdapterVlan - ManagementOS - VMNetworkAdapterName $ switchName - Untagged
2015-06-21 07:36:07 -04:00
`
var ps powershell . PowerShellCmd
err := ps . Run ( script , vmName , switchName )
return err
}
func IsRunning ( vmName string ) ( bool , error ) {
var script = `
param ( [ string ] $ vmName )
2018-02-07 02:01:05 -05:00
$ vm = Hyper - V \ Get - VM - Name $ vmName - ErrorAction SilentlyContinue
2015-06-21 07:36:07 -04:00
$ vm . State - eq [ Microsoft . HyperV . PowerShell . VMState ] : : Running
`
var ps powershell . PowerShellCmd
cmdOut , err := ps . Output ( script , vmName )
2015-10-30 04:23:30 -04:00
if err != nil {
return false , err
}
2015-06-21 07:36:07 -04:00
var isRunning = strings . TrimSpace ( cmdOut ) == "True"
return isRunning , err
}
2015-10-30 04:23:30 -04:00
func IsOff ( vmName string ) ( bool , error ) {
var script = `
param ( [ string ] $ vmName )
2018-02-07 02:01:05 -05:00
$ vm = Hyper - V \ Get - VM - Name $ vmName - ErrorAction SilentlyContinue
2015-10-30 04:23:30 -04:00
$ vm . State - eq [ Microsoft . HyperV . PowerShell . VMState ] : : Off
`
var ps powershell . PowerShellCmd
cmdOut , err := ps . Output ( script , vmName )
if err != nil {
return false , err
}
var isRunning = strings . TrimSpace ( cmdOut ) == "True"
return isRunning , err
}
func Uptime ( vmName string ) ( uint64 , error ) {
var script = `
param ( [ string ] $ vmName )
2018-02-07 02:01:05 -05:00
$ vm = Hyper - V \ Get - VM - Name $ vmName - ErrorAction SilentlyContinue
2015-10-30 04:23:30 -04:00
$ vm . Uptime . TotalSeconds
`
var ps powershell . PowerShellCmd
cmdOut , err := ps . Output ( script , vmName )
if err != nil {
return 0 , err
}
2017-03-28 21:47:10 -04:00
uptime , err := strconv . ParseUint ( strings . TrimSpace ( cmdOut ) , 10 , 64 )
2015-10-30 04:23:30 -04:00
return uptime , err
}
2015-06-21 07:36:07 -04:00
func Mac ( vmName string ) ( string , error ) {
var script = `
2015-06-22 17:26:06 -04:00
param ( [ string ] $ vmName , [ int ] $ adapterIndex )
2015-06-21 07:36:07 -04:00
try {
2018-02-07 02:01:05 -05:00
$ adapter = Hyper - V \ Get - VMNetworkAdapter - VMName $ vmName - ErrorAction SilentlyContinue
2015-06-22 17:26:06 -04:00
$ mac = $ adapter [ $ adapterIndex ] . MacAddress
2015-06-21 07:36:07 -04:00
if ( $ mac - eq $ null ) {
2015-06-22 17:26:06 -04:00
return ""
2015-06-21 07:36:07 -04:00
}
} catch {
2015-06-22 17:26:06 -04:00
return ""
2015-06-21 07:36:07 -04:00
}
$ mac
`
var ps powershell . PowerShellCmd
cmdOut , err := ps . Output ( script , vmName , "0" )
return cmdOut , err
}
func IpAddress ( mac string ) ( string , error ) {
var script = `
param ( [ string ] $ mac , [ int ] $ addressIndex )
try {
2018-04-30 01:03:40 -04:00
$ vm = Hyper - V \ Get - VM | ? { $ _ . NetworkAdapters . MacAddress - eq $ mac }
if ( $ vm . NetworkAdapters . IpAddresses ) {
2018-06-18 00:45:33 -04:00
$ ipAddresses = $ vm . NetworkAdapters . IPAddresses
if ( $ ipAddresses - isnot [ array ] ) {
$ ipAddresses = @ ( $ ipAddresses )
}
$ ip = $ ipAddresses [ $ addressIndex ]
2018-04-30 01:03:40 -04:00
} else {
$ vm_info = Get - CimInstance - ClassName Msvm_ComputerSystem - Namespace root \ virtualization \ v2 - Filter "ElementName='$($vm.Name)'"
$ ip_details = ( Get - CimAssociatedInstance - InputObject $ vm_info - ResultClassName Msvm_KvpExchangeComponent ) . GuestIntrinsicExchangeItems | % { [ xml ] $ _ } | ? { $ _ . SelectSingleNode ( "/INSTANCE/PROPERTY[@NAME='Name']/VALUE[child::text()='NetworkAddressIPv4']" ) }
if ( $ null - eq $ ip_details ) {
return ""
}
2017-03-28 21:47:10 -04:00
2018-04-30 01:03:40 -04:00
$ ip_addresses = $ ip_details . SelectSingleNode ( "/INSTANCE/PROPERTY[@NAME='Data']/VALUE/child::text()" ) . Value
$ ip = ( $ ip_addresses - split ";" ) [ 0 ]
2015-06-21 07:36:07 -04:00
}
} catch {
2015-06-22 17:26:06 -04:00
return ""
2015-06-21 07:36:07 -04:00
}
$ ip
`
var ps powershell . PowerShellCmd
cmdOut , err := ps . Output ( script , mac , "0" )
return cmdOut , err
}
2015-06-27 17:36:39 -04:00
func TurnOff ( vmName string ) error {
2015-06-21 07:36:07 -04:00
var script = `
param ( [ string ] $ vmName )
2018-02-07 02:01:05 -05:00
$ vm = Hyper - V \ Get - VM - Name $ vmName - ErrorAction SilentlyContinue
2015-06-27 17:36:39 -04:00
if ( $ vm . State - eq [ Microsoft . HyperV . PowerShell . VMState ] : : Running ) {
2018-02-07 02:01:05 -05:00
Hyper - V \ Stop - VM - Name $ vmName - TurnOff - Force - Confirm : $ false
2015-06-21 07:36:07 -04:00
}
`
var ps powershell . PowerShellCmd
err := ps . Run ( script , vmName )
return err
}
2015-06-27 17:36:39 -04:00
func ShutDown ( vmName string ) error {
2015-06-21 07:36:07 -04:00
var script = `
param ( [ string ] $ vmName )
2018-02-07 02:01:05 -05:00
$ vm = Hyper - V \ Get - VM - Name $ vmName - ErrorAction SilentlyContinue
2015-06-21 07:36:07 -04:00
if ( $ vm . State - eq [ Microsoft . HyperV . PowerShell . VMState ] : : Running ) {
2018-02-07 02:01:05 -05:00
Hyper - V \ Stop - VM - Name $ vmName - Force - Confirm : $ false
2015-06-21 07:36:07 -04:00
}
`
var ps powershell . PowerShellCmd
err := ps . Run ( script , vmName )
return err
}
2015-06-27 17:36:39 -04:00
func TypeScanCodes ( vmName string , scanCodes string ) error {
2015-12-01 02:26:15 -05:00
if len ( scanCodes ) == 0 {
return nil
}
2015-06-21 07:36:07 -04:00
var script = `
2015-06-27 17:36:39 -04:00
param ( [ string ] $ vmName , [ string ] $ scanCodes )
# Requires - Version 3
2017-03-28 21:47:10 -04:00
2018-02-07 02:01:05 -05:00
function Hyper - V \ Get - VMConsole
2015-06-27 17:36:39 -04:00
{
[ CmdletBinding ( ) ]
param (
[ Parameter ( Mandatory ) ]
[ string ] $ VMName
)
2017-03-28 21:47:10 -04:00
2015-06-27 17:36:39 -04:00
$ ErrorActionPreference = "Stop"
2017-03-28 21:47:10 -04:00
2015-12-01 02:26:15 -05:00
$ vm = Get - CimInstance - Namespace "root\virtualization\v2" - ClassName Msvm_ComputerSystem - ErrorAction Ignore - Verbose : $ false | where ElementName - eq $ VMName | select - first 1
2015-06-27 17:36:39 -04:00
if ( $ vm - eq $ null ) {
Write - Error ( "VirtualMachine({0}) is not found!" - f $ VMName )
}
2017-03-28 21:47:10 -04:00
2015-06-27 17:36:39 -04:00
$ vmKeyboard = $ vm | Get - CimAssociatedInstance - ResultClassName "Msvm_Keyboard" - ErrorAction Ignore - Verbose : $ false
2017-03-28 21:47:10 -04:00
2015-12-05 05:31:28 -05:00
if ( $ vmKeyboard - eq $ null ) {
$ vmKeyboard = Get - CimInstance - Namespace "root\virtualization\v2" - ClassName Msvm_Keyboard - ErrorAction Ignore - Verbose : $ false | where SystemName - eq $ vm . Name | select - first 1
}
if ( $ vmKeyboard - eq $ null ) {
$ vmKeyboard = Get - CimInstance - Namespace "root\virtualization" - ClassName Msvm_Keyboard - ErrorAction Ignore - Verbose : $ false | where SystemName - eq $ vm . Name | select - first 1
}
2017-03-28 21:47:10 -04:00
2015-06-27 17:36:39 -04:00
if ( $ vmKeyboard - eq $ null ) {
Write - Error ( "VirtualMachine({0}) keyboard class is not found!" - f $ VMName )
}
2017-03-28 21:47:10 -04:00
2015-06-27 17:36:39 -04:00
# TODO : It may be better using New - Module - AsCustomObject to return console object ?
2017-03-28 21:47:10 -04:00
2015-06-27 17:36:39 -04:00
# Console object to return
$ console = [ pscustomobject ] @ {
Msvm_ComputerSystem = $ vm
Msvm_Keyboard = $ vmKeyboard
}
2017-03-28 21:47:10 -04:00
2015-06-27 17:36:39 -04:00
# Need to import assembly to use System . Windows . Input . Key
Add - Type - AssemblyName WindowsBase
2017-03-28 21:47:10 -04:00
2015-06-27 17:36:39 -04:00
# region Add Console Members
$ console | Add - Member - MemberType ScriptMethod - Name TypeText - Value {
[ OutputType ( [ bool ] ) ]
param (
[ ValidateNotNullOrEmpty ( ) ]
[ Parameter ( Mandatory ) ]
[ string ] $ AsciiText
)
$ result = $ this . Msvm_Keyboard | Invoke - CimMethod - MethodName "TypeText" - Arguments @ { asciiText = $ AsciiText }
return ( 0 - eq $ result . ReturnValue )
}
2017-03-28 21:47:10 -04:00
2015-06-27 17:36:39 -04:00
# Define method : TypeCtrlAltDel
$ console | Add - Member - MemberType ScriptMethod - Name TypeCtrlAltDel - Value {
$ result = $ this . Msvm_Keyboard | Invoke - CimMethod - MethodName "TypeCtrlAltDel"
return ( 0 - eq $ result . ReturnValue )
}
2017-03-28 21:47:10 -04:00
2015-06-27 17:36:39 -04:00
# Define method : TypeKey
$ console | Add - Member - MemberType ScriptMethod - Name TypeKey - Value {
[ OutputType ( [ bool ] ) ]
param (
[ Parameter ( Mandatory ) ]
[ Windows . Input . Key ] $ Key ,
[ Windows . Input . ModifierKeys ] $ ModifierKey = [ Windows . Input . ModifierKeys ] : : None
)
2017-03-28 21:47:10 -04:00
2015-06-27 17:36:39 -04:00
$ keyCode = [ Windows . Input . KeyInterop ] : : VirtualKeyFromKey ( $ Key )
2017-03-28 21:47:10 -04:00
2015-06-27 17:36:39 -04:00
switch ( $ ModifierKey )
{
( [ Windows . Input . ModifierKeys ] : : Control ) { $ modifierKeyCode = [ Windows . Input . KeyInterop ] : : VirtualKeyFromKey ( [ Windows . Input . Key ] : : LeftCtrl ) }
( [ Windows . Input . ModifierKeys ] : : Alt ) { $ modifierKeyCode = [ Windows . Input . KeyInterop ] : : VirtualKeyFromKey ( [ Windows . Input . Key ] : : LeftAlt ) }
( [ Windows . Input . ModifierKeys ] : : Shift ) { $ modifierKeyCode = [ Windows . Input . KeyInterop ] : : VirtualKeyFromKey ( [ Windows . Input . Key ] : : LeftShift ) }
( [ Windows . Input . ModifierKeys ] : : Windows ) { $ modifierKeyCode = [ Windows . Input . KeyInterop ] : : VirtualKeyFromKey ( [ Windows . Input . Key ] : : LWin ) }
}
2017-03-28 21:47:10 -04:00
2015-06-27 17:36:39 -04:00
if ( $ ModifierKey - eq [ Windows . Input . ModifierKeys ] : : None )
{
$ result = $ this . Msvm_Keyboard | Invoke - CimMethod - MethodName "TypeKey" - Arguments @ { keyCode = $ keyCode }
}
else
{
$ this . Msvm_Keyboard | Invoke - CimMethod - MethodName "PressKey" - Arguments @ { keyCode = $ modifierKeyCode }
$ result = $ this . Msvm_Keyboard | Invoke - CimMethod - MethodName "TypeKey" - Arguments @ { keyCode = $ keyCode }
$ this . Msvm_Keyboard | Invoke - CimMethod - MethodName "ReleaseKey" - Arguments @ { keyCode = $ modifierKeyCode }
}
$ result = return ( 0 - eq $ result . ReturnValue )
}
2017-03-28 21:47:10 -04:00
2015-06-27 17:36:39 -04:00
# Define method : Scancodes
$ console | Add - Member - MemberType ScriptMethod - Name TypeScancodes - Value {
[ OutputType ( [ bool ] ) ]
param (
[ Parameter ( Mandatory ) ]
[ byte [ ] ] $ ScanCodes
)
$ result = $ this . Msvm_Keyboard | Invoke - CimMethod - MethodName "TypeScancodes" - Arguments @ { ScanCodes = $ ScanCodes }
return ( 0 - eq $ result . ReturnValue )
}
2017-03-28 21:47:10 -04:00
2015-06-27 17:36:39 -04:00
# Define method : ExecCommand
$ console | Add - Member - MemberType ScriptMethod - Name ExecCommand - Value {
param (
[ Parameter ( Mandatory ) ]
[ string ] $ Command
)
if ( [ String ] : : IsNullOrEmpty ( $ Command ) ) {
return
}
2017-03-28 21:47:10 -04:00
2015-06-27 17:36:39 -04:00
$ console . TypeText ( $ Command ) > $ null
$ console . TypeKey ( [ Windows . Input . Key ] : : Enter ) > $ null
# sleep - Milliseconds 100
}
2017-03-28 21:47:10 -04:00
2015-06-27 17:36:39 -04:00
# Define method : Dispose
$ console | Add - Member - MemberType ScriptMethod - Name Dispose - Value {
$ this . Msvm_ComputerSystem . Dispose ( )
$ this . Msvm_Keyboard . Dispose ( )
}
2017-03-28 21:47:10 -04:00
2015-06-27 17:36:39 -04:00
# endregion
2017-03-28 21:47:10 -04:00
2015-06-27 17:36:39 -04:00
return $ console
}
2017-03-28 21:47:10 -04:00
2018-02-07 02:01:05 -05:00
$ vmConsole = Hyper - V \ Get - VMConsole - VMName $ vmName
2015-06-27 17:36:39 -04:00
$ scanCodesToSend = ' '
$ scanCodes . Split ( ' ' ) | % {
$ scanCode = $ _
2017-03-28 21:47:10 -04:00
2015-06-27 17:36:39 -04:00
if ( $ scanCode . StartsWith ( ' wait ' ) ) {
$ timeToWait = $ scanCode . Substring ( 4 )
if ( ! $ timeToWait ) {
2015-11-04 16:45:37 -05:00
$ timeToWait = "1"
2015-06-27 17:36:39 -04:00
}
2017-03-28 21:47:10 -04:00
2015-06-27 17:36:39 -04:00
if ( $ scanCodesToSend ) {
$ scanCodesToSendByteArray = [ byte [ ] ] @ ( $ scanCodesToSend . Split ( ' ' ) | % { "0x$_" } )
2017-03-28 21:47:10 -04:00
2015-06-27 17:36:39 -04:00
$ scanCodesToSendByteArray | % {
$ vmConsole . TypeScancodes ( $ _ )
}
}
2017-03-28 21:47:10 -04:00
2015-11-07 18:33:47 -05:00
write - host "Special code <wait> found, will sleep $timeToWait second(s) at this point."
Start - Sleep - s $ timeToWait
2017-03-28 21:47:10 -04:00
2015-06-27 17:36:39 -04:00
$ scanCodesToSend = ' '
} else {
if ( $ scanCodesToSend ) {
2015-11-07 12:07:40 -05:00
write - host "Sending special code '$scanCodesToSend' '$scanCode'"
2015-06-27 17:36:39 -04:00
$ scanCodesToSend = "$scanCodesToSend $scanCode"
} else {
2015-11-07 12:07:40 -05:00
write - host "Sending char '$scanCode'"
2015-06-27 17:36:39 -04:00
$ scanCodesToSend = "$scanCode"
}
}
}
if ( $ scanCodesToSend ) {
$ scanCodesToSendByteArray = [ byte [ ] ] @ ( $ scanCodesToSend . Split ( ' ' ) | % { "0x$_" } )
2017-03-28 21:47:10 -04:00
2015-06-27 17:36:39 -04:00
$ scanCodesToSendByteArray | % {
$ vmConsole . TypeScancodes ( $ _ )
}
}
2015-06-21 07:36:07 -04:00
`
var ps powershell . PowerShellCmd
2015-06-27 17:36:39 -04:00
err := ps . Run ( script , vmName , scanCodes )
2015-06-21 07:36:07 -04:00
return err
}
2018-05-05 17:54:58 -04:00
2018-05-10 07:50:56 -04:00
func ConnectVirtualMachine ( vmName string ) ( context . CancelFunc , error ) {
2018-05-05 17:54:58 -04:00
ctx , cancel := context . WithCancel ( context . Background ( ) )
cmd := exec . CommandContext ( ctx , "vmconnect.exe" , "localhost" , vmName )
2018-05-10 07:50:56 -04:00
err := cmd . Start ( )
if err != nil {
// Failed to start so cancel function not required
cancel = nil
}
return cancel , err
2018-05-05 17:54:58 -04:00
}
func DisconnectVirtualMachine ( cancel context . CancelFunc ) {
cancel ( )
}