2015-06-21 07:36:07 -04:00
package hyperv
import (
2016-07-31 11:23:40 -04:00
"errors"
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 )
$ HostVMAdapter = Get - VMNetworkAdapter - ManagementOS - SwitchName $ switchName
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 {
$ adapter = Get - VMNetworkAdapter - VMName $ vmName - ErrorAction SilentlyContinue
$ ip = $ adapter . IPAddresses [ $ addressIndex ]
if ( $ ip - eq $ null ) {
return $ false
}
} 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 )
$ dvdController = Add - VMDvdDrive - VMName $ vmName - path $ isoPath - Passthru
2015-12-05 06:13:38 -05:00
$ dvdController | 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 )
2015-11-01 11:00:56 -05:00
$ vmDvdDrive = Get - VMDvdDrive - VMName $ vmName - ControllerNumber $ controllerNumber - ControllerLocation $ controllerLocation
if ( ! $ vmDvdDrive ) { throw ' unable to find dvd drive ' }
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 )
$ vmDvdDrive = Get - VMDvdDrive - VMName $ vmName - ControllerNumber $ controllerNumber - ControllerLocation $ controllerLocation
if ( ! $ vmDvdDrive ) { throw ' unable to find dvd drive ' }
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 )
Set - VMBios - VMName $ vmName - StartupOrder @ ( "CD" , "IDE" , "LegacyNetworkAdapter" , "Floppy" )
`
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 )
$ vmDvdDrive = Get - VMDvdDrive - VMName $ vmName - ControllerNumber $ controllerNumber - ControllerLocation $ controllerLocation
if ( ! $ vmDvdDrive ) { throw ' unable to find dvd drive ' }
2015-12-05 06:41:30 -05:00
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 )
$ vmDvdDrive = Get - VMDvdDrive - VMName $ vmName - ControllerNumber $ controllerNumber - ControllerLocation $ controllerLocation
if ( ! $ vmDvdDrive ) { throw ' unable to find dvd drive ' }
Remove - VMDvdDrive - VMName $ vmName - ControllerNumber $ controllerNumber - ControllerLocation $ controllerLocation
`
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 )
Get - VMDvdDrive - VMName $ vmName | Remove - VMDvdDrive
`
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 )
Set - VMFloppyDiskDrive - VMName $ vmName - Path $ path
`
var ps powershell . PowerShellCmd
err := ps . Run ( script , vmName , path )
return err
}
func UnmountFloppyDrive ( vmName string ) error {
var script = `
param ( [ string ] $ vmName )
Set - VMFloppyDiskDrive - VMName $ vmName - Path $ null
`
var ps powershell . PowerShellCmd
err := ps . Run ( script , vmName )
return err
}
2015-10-30 04:23:30 -04:00
func CreateVirtualMachine ( vmName string , path string , ram int64 , diskSize int64 , switchName string , generation uint ) 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 = `
2015-06-22 17:26:06 -04:00
param ( [ string ] $ vmName , [ string ] $ path , [ long ] $ memoryStartupBytes , [ long ] $ newVHDSizeBytes , [ string ] $ switchName , [ int ] $ generation )
2015-06-21 07:36:07 -04:00
$ vhdx = $ vmName + ' . vhdx '
$ vhdPath = Join - Path - Path $ path - ChildPath $ vhdx
2015-06-21 14:35:32 -04:00
New - VM - Name $ vmName - Path $ path - MemoryStartupBytes $ memoryStartupBytes - NewVHDPath $ vhdPath - NewVHDSizeBytes $ newVHDSizeBytes - SwitchName $ switchName - Generation $ generation
2015-06-21 07:36:07 -04:00
`
2015-06-29 16:18:25 -04:00
var ps powershell . PowerShellCmd
2015-10-30 04:23:30 -04:00
err := ps . Run ( script , vmName , path , strconv . FormatInt ( ram , 10 ) , strconv . FormatInt ( diskSize , 10 ) , switchName , strconv . FormatInt ( int64 ( generation ) , 10 ) )
2015-06-29 16:18:25 -04:00
return err
} else {
var script = `
param ( [ string ] $ vmName , [ string ] $ path , [ long ] $ memoryStartupBytes , [ long ] $ newVHDSizeBytes , [ string ] $ switchName )
$ vhdx = $ vmName + ' . vhdx '
$ vhdPath = Join - Path - Path $ path - ChildPath $ vhdx
New - VM - Name $ vmName - Path $ path - MemoryStartupBytes $ memoryStartupBytes - NewVHDPath $ vhdPath - NewVHDSizeBytes $ newVHDSizeBytes - SwitchName $ switchName
`
var ps powershell . PowerShellCmd
2015-10-30 04:23:30 -04:00
err := ps . Run ( script , vmName , path , strconv . FormatInt ( ram , 10 ) , strconv . FormatInt ( diskSize , 10 ) , switchName )
2015-11-07 11:20:55 -05:00
if err != nil {
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
}
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 )
Set - VMProcessor - VMName $ vmName - Count $ cpu
`
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 )
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 )
Set - VMMemory - VMName $ vmName - DynamicMemoryEnabled $ enableDynamicMemory
`
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 )
Set - VMNetworkAdapter - VMName $ vmName - MacAddressSpoofing $ enableMacSpoofing
`
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
}
2016-08-07 07:26:27 -04:00
func SetVirtualMachineSecureBoot ( vmName string , enableSecureBoot bool ) error {
2015-06-29 16:18:25 -04:00
var script = `
param ( [ string ] $ vmName , $ enableSecureBoot )
Set - VMFirmware - VMName $ vmName - EnableSecureBoot $ enableSecureBoot
`
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
}
2016-08-07 07:26:27 -04:00
err := ps . Run ( script , vmName , enableSecureBootString )
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
$ vm = Get - VM - Name $ vmName
if ( ( $ vm . State - ne [ Microsoft . HyperV . PowerShell . VMState ] : : Off ) - and ( $ vm . State - ne [ Microsoft . HyperV . PowerShell . VMState ] : : OffCritical ) ) {
2015-06-27 17:36:39 -04:00
Stop - VM - VM $ vm - TurnOff - Force - Confirm : $ false
2015-06-24 14:52:42 -04:00
}
2015-07-14 02:51:03 -04:00
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 )
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 ' ) ) )
{
$ vm = Get - VM - Name $ vmName
$ vm_adapter = Get - VMNetworkAdapter - VM $ vm | Select - First 1
$ 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 )
{
$ vm_controllers = Get - VMIdeController - VM $ vm
$ controller_type = $ config . SelectSingleNode ( ' / configuration / vm - controllers ' )
# IDE controllers are not stored in a special XML container
}
else
{
$ vm_controllers = Get - VMScsiController - VM $ vm
$ controller_type = $ config . CreateElement ( ' scsi ' )
$ controller_type . SetAttribute ( ' ChannelInstanceGuid ' , 'x' )
# SCSI controllers are stored in the scsi XML container
if ( ( Get - VMFirmware - VM $ vm ) . SecureBoot - eq [ Microsoft . HyperV . PowerShell . OnOffState ] : : On )
{
$ config . configuration . secure_boot_enabled . ' # text ' = ' True '
}
else
{
$ config . configuration . secure_boot_enabled . ' # text ' = ' False '
}
}
$ 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
}
2015-06-27 17:36:39 -04:00
func CompactDisks ( expPath string , vhdDir string ) error {
var script = `
param ( [ string ] $ srcPath , [ string ] $ vhdDirName )
Get - ChildItem "$srcPath/$vhdDirName" - Filter * . vhd * | % {
Optimize - VHD - Path $ _ . FullName - Mode Full
}
`
var ps powershell . PowerShellCmd
err := ps . Run ( script , expPath , vhdDir )
return err
}
2015-06-21 07:36:07 -04:00
func CopyExportedVirtualMachine ( expPath string , outputPath string , vhdDir string , vmDir string ) error {
var script = `
param ( [ string ] $ srcPath , [ string ] $ dstPath , [ string ] $ vhdDirName , [ string ] $ vmDir )
2015-07-16 15:48:08 -04:00
Move - Item - Path $ srcPath / * . * - Destination $ dstPath
Move - Item - Path $ srcPath / $ vhdDirName - Destination $ dstPath
Move - Item - Path $ srcPath / $ vmDir - Destination $ dstPath
2015-06-21 07:36:07 -04:00
`
var ps powershell . PowerShellCmd
err := ps . Run ( script , expPath , outputPath , vhdDir , vmDir )
return err
}
func CreateVirtualSwitch ( switchName string , switchType string ) ( bool , error ) {
var script = `
param ( [ string ] $ switchName , [ string ] $ switchType )
$ switches = Get - VMSwitch - Name $ switchName - ErrorAction SilentlyContinue
if ( $ switches . Count - eq 0 ) {
New - VMSwitch - Name $ switchName - SwitchType $ switchType
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 )
$ switch = Get - VMSwitch - Name $ switchName - ErrorAction SilentlyContinue
if ( $ switch - ne $ null ) {
2015-07-14 02:51:03 -04:00
$ switch | 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 )
2015-06-27 17:36:39 -04:00
$ vm = Get - VM - Name $ vmName - ErrorAction SilentlyContinue
if ( $ vm . State - eq [ Microsoft . HyperV . PowerShell . VMState ] : : Off ) {
2015-07-14 02:51:03 -04:00
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 )
2015-07-14 02:51:03 -04:00
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 )
$ vm = Get - VM - Name $ vmName
if ( $ vm . State - eq [ Microsoft . HyperV . PowerShell . VMState ] : : Running ) {
2015-10-26 20:12:41 -04:00
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 )
Get - VMIntegrationService - VmName $ vmName | ? { $ _ . Id - match $ integrationServiceId } | 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 )
Set - VMNetworkAdapterVlan - ManagementOS - VMNetworkAdapterName $ networkAdapterName - Access - VlanId $ vlanId
`
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 )
Set - VMNetworkAdapterVlan - VMName $ vmName - Access - VlanId $ vlanId
`
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 ) {
2015-06-21 07:36:07 -04:00
$ switch = Get - VMSwitch - SwitchType External | Where - Object { $ _ . NetAdapterInterfaceDescription - eq $ adapter . InterfaceDescription }
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 ) {
2015-06-21 07:36:07 -04:00
$ switch = Get - VMSwitch - SwitchType External | where { $ _ . NetAdapterInterfaceDescription - eq $ adapter . InterfaceDescription }
2017-03-28 21:47:10 -04:00
if ( $ switch - eq $ null ) {
2015-06-21 07:36:07 -04:00
$ switch = New - VMSwitch - Name $ switchName - NetAdapterName $ adapter . Name - AllowManagementOS $ true - Notes ' Parent OS , VMs , WiFi '
}
if ( $ switch - ne $ null ) {
break
}
}
2017-03-28 21:47:10 -04:00
if ( $ switch - ne $ null ) {
Get - VMNetworkAdapter - VMName $ vmName | Connect - VMNetworkAdapter - VMSwitch $ switch
} 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 )
( Get - VMNetworkAdapter - VMName $ vmName ) . SwitchName
`
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 )
2015-06-27 17:36:39 -04:00
Get - VMNetworkAdapter - VMName $ vmName | Connect - VMNetworkAdapter - SwitchName $ switchName
2015-06-21 07:36:07 -04:00
`
var ps powershell . PowerShellCmd
err := ps . Run ( script , vmName , switchName )
return err
}
func UntagVirtualMachineNetworkAdapterVlan ( vmName string , switchName string ) error {
var script = `
param ( [ string ] $ vmName , [ string ] $ switchName )
Set - VMNetworkAdapterVlan - VMName $ vmName - Untagged
Set - VMNetworkAdapterVlan - ManagementOS - VMNetworkAdapterName $ switchName - Untagged
`
var ps powershell . PowerShellCmd
err := ps . Run ( script , vmName , switchName )
return err
}
func IsRunning ( vmName string ) ( bool , error ) {
var script = `
param ( [ string ] $ vmName )
$ vm = Get - VM - Name $ vmName - ErrorAction SilentlyContinue
$ 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 )
$ vm = Get - VM - Name $ vmName - ErrorAction SilentlyContinue
$ 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 )
$ vm = Get - VM - Name $ vmName - ErrorAction SilentlyContinue
$ 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 {
$ adapter = 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 {
$ ip = Get - Vm | % { $ _ . NetworkAdapters } | ? { $ _ . MacAddress - eq $ mac } | % { $ _ . IpAddresses [ $ addressIndex ] }
2017-03-28 21:47:10 -04:00
2015-06-21 07:36:07 -04:00
if ( $ ip - 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
}
$ 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 )
$ vm = Get - VM - Name $ vmName - ErrorAction SilentlyContinue
2015-06-27 17:36:39 -04:00
if ( $ vm . State - eq [ Microsoft . HyperV . PowerShell . VMState ] : : Running ) {
2015-10-26 20:12:41 -04:00
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 )
$ vm = Get - VM - Name $ vmName - ErrorAction SilentlyContinue
if ( $ vm . State - eq [ Microsoft . HyperV . PowerShell . VMState ] : : Running ) {
2015-10-26 20:12:41 -04:00
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
# Requires - RunAsAdministrator
2017-03-28 21:47:10 -04:00
2015-06-27 17:36:39 -04:00
function Get - VMConsole
{
[ 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
2015-06-27 17:36:39 -04:00
$ vmConsole = Get - VMConsole - VMName $ vmName
$ 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
}