github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/common/powershell/hyperv/hyperv.go (about) 1 package hyperv 2 3 import ( 4 "errors" 5 "strconv" 6 "strings" 7 8 "github.com/hashicorp/packer/common/powershell" 9 ) 10 11 func GetHostAdapterIpAddressForSwitch(switchName string) (string, error) { 12 var script = ` 13 param([string]$switchName, [int]$addressIndex) 14 15 $HostVMAdapter = Get-VMNetworkAdapter -ManagementOS -SwitchName $switchName 16 if ($HostVMAdapter){ 17 $HostNetAdapter = Get-NetAdapter | ?{ $_.DeviceID -eq $HostVMAdapter.DeviceId } 18 if ($HostNetAdapter){ 19 $HostNetAdapterConfiguration = @(get-wmiobject win32_networkadapterconfiguration -filter "IPEnabled = 'TRUE' AND InterfaceIndex=$($HostNetAdapter.ifIndex)") 20 if ($HostNetAdapterConfiguration){ 21 return @($HostNetAdapterConfiguration.IpAddress)[$addressIndex] 22 } 23 } 24 } 25 return $false 26 ` 27 28 var ps powershell.PowerShellCmd 29 cmdOut, err := ps.Output(script, switchName, "0") 30 31 return cmdOut, err 32 } 33 34 func GetVirtualMachineNetworkAdapterAddress(vmName string) (string, error) { 35 36 var script = ` 37 param([string]$vmName, [int]$addressIndex) 38 try { 39 $adapter = Get-VMNetworkAdapter -VMName $vmName -ErrorAction SilentlyContinue 40 $ip = $adapter.IPAddresses[$addressIndex] 41 if($ip -eq $null) { 42 return $false 43 } 44 } catch { 45 return $false 46 } 47 $ip 48 ` 49 50 var ps powershell.PowerShellCmd 51 cmdOut, err := ps.Output(script, vmName, "0") 52 53 return cmdOut, err 54 } 55 56 func CreateDvdDrive(vmName string, isoPath string, generation uint) (uint, uint, error) { 57 var ps powershell.PowerShellCmd 58 var script string 59 60 script = ` 61 param([string]$vmName, [string]$isoPath) 62 $dvdController = Add-VMDvdDrive -VMName $vmName -path $isoPath -Passthru 63 $dvdController | Set-VMDvdDrive -path $null 64 $result = "$($dvdController.ControllerNumber),$($dvdController.ControllerLocation)" 65 $result 66 ` 67 68 cmdOut, err := ps.Output(script, vmName, isoPath) 69 if err != nil { 70 return 0, 0, err 71 } 72 73 cmdOutArray := strings.Split(cmdOut, ",") 74 if len(cmdOutArray) != 2 { 75 return 0, 0, errors.New("Did not return controller number and controller location") 76 } 77 78 controllerNumberTemp, err := strconv.ParseUint(strings.TrimSpace(cmdOutArray[0]), 10, 64) 79 if err != nil { 80 return 0, 0, err 81 } 82 controllerNumber := uint(controllerNumberTemp) 83 84 controllerLocationTemp, err := strconv.ParseUint(strings.TrimSpace(cmdOutArray[1]), 10, 64) 85 if err != nil { 86 return controllerNumber, 0, err 87 } 88 controllerLocation := uint(controllerLocationTemp) 89 90 return controllerNumber, controllerLocation, err 91 } 92 93 func MountDvdDrive(vmName string, path string, controllerNumber uint, controllerLocation uint) error { 94 95 var script = ` 96 param([string]$vmName,[string]$path,[string]$controllerNumber,[string]$controllerLocation) 97 $vmDvdDrive = Get-VMDvdDrive -VMName $vmName -ControllerNumber $controllerNumber -ControllerLocation $controllerLocation 98 if (!$vmDvdDrive) {throw 'unable to find dvd drive'} 99 Set-VMDvdDrive -VMName $vmName -ControllerNumber $controllerNumber -ControllerLocation $controllerLocation -Path $path 100 ` 101 102 var ps powershell.PowerShellCmd 103 err := ps.Run(script, vmName, path, strconv.FormatInt(int64(controllerNumber), 10), strconv.FormatInt(int64(controllerLocation), 10)) 104 return err 105 } 106 107 func UnmountDvdDrive(vmName string, controllerNumber uint, controllerLocation uint) error { 108 var script = ` 109 param([string]$vmName,[int]$controllerNumber,[int]$controllerLocation) 110 $vmDvdDrive = Get-VMDvdDrive -VMName $vmName -ControllerNumber $controllerNumber -ControllerLocation $controllerLocation 111 if (!$vmDvdDrive) {throw 'unable to find dvd drive'} 112 Set-VMDvdDrive -VMName $vmName -ControllerNumber $controllerNumber -ControllerLocation $controllerLocation -Path $null 113 ` 114 115 var ps powershell.PowerShellCmd 116 err := ps.Run(script, vmName, strconv.FormatInt(int64(controllerNumber), 10), strconv.FormatInt(int64(controllerLocation), 10)) 117 return err 118 } 119 120 func SetBootDvdDrive(vmName string, controllerNumber uint, controllerLocation uint, generation uint) error { 121 122 if generation < 2 { 123 script := ` 124 param([string]$vmName) 125 Set-VMBios -VMName $vmName -StartupOrder @("CD", "IDE","LegacyNetworkAdapter","Floppy") 126 ` 127 var ps powershell.PowerShellCmd 128 err := ps.Run(script, vmName) 129 return err 130 } else { 131 script := ` 132 param([string]$vmName,[int]$controllerNumber,[int]$controllerLocation) 133 $vmDvdDrive = Get-VMDvdDrive -VMName $vmName -ControllerNumber $controllerNumber -ControllerLocation $controllerLocation 134 if (!$vmDvdDrive) {throw 'unable to find dvd drive'} 135 Set-VMFirmware -VMName $vmName -FirstBootDevice $vmDvdDrive -ErrorAction SilentlyContinue 136 ` 137 var ps powershell.PowerShellCmd 138 err := ps.Run(script, vmName, strconv.FormatInt(int64(controllerNumber), 10), strconv.FormatInt(int64(controllerLocation), 10)) 139 return err 140 } 141 } 142 143 func DeleteDvdDrive(vmName string, controllerNumber uint, controllerLocation uint) error { 144 var script = ` 145 param([string]$vmName,[int]$controllerNumber,[int]$controllerLocation) 146 $vmDvdDrive = Get-VMDvdDrive -VMName $vmName -ControllerNumber $controllerNumber -ControllerLocation $controllerLocation 147 if (!$vmDvdDrive) {throw 'unable to find dvd drive'} 148 Remove-VMDvdDrive -VMName $vmName -ControllerNumber $controllerNumber -ControllerLocation $controllerLocation 149 ` 150 151 var ps powershell.PowerShellCmd 152 err := ps.Run(script, vmName, strconv.FormatInt(int64(controllerNumber), 10), strconv.FormatInt(int64(controllerLocation), 10)) 153 return err 154 } 155 156 func DeleteAllDvdDrives(vmName string) error { 157 var script = ` 158 param([string]$vmName) 159 Get-VMDvdDrive -VMName $vmName | Remove-VMDvdDrive 160 ` 161 162 var ps powershell.PowerShellCmd 163 err := ps.Run(script, vmName) 164 return err 165 } 166 167 func MountFloppyDrive(vmName string, path string) error { 168 var script = ` 169 param([string]$vmName, [string]$path) 170 Set-VMFloppyDiskDrive -VMName $vmName -Path $path 171 ` 172 173 var ps powershell.PowerShellCmd 174 err := ps.Run(script, vmName, path) 175 return err 176 } 177 178 func UnmountFloppyDrive(vmName string) error { 179 180 var script = ` 181 param([string]$vmName) 182 Set-VMFloppyDiskDrive -VMName $vmName -Path $null 183 ` 184 185 var ps powershell.PowerShellCmd 186 err := ps.Run(script, vmName) 187 return err 188 } 189 190 func CreateVirtualMachine(vmName string, path string, vhdRoot string, ram int64, diskSize int64, switchName string, generation uint) error { 191 192 if generation == 2 { 193 var script = ` 194 param([string]$vmName, [string]$path, [string]$vhdRoot, [long]$memoryStartupBytes, [long]$newVHDSizeBytes, [string]$switchName, [int]$generation) 195 $vhdx = $vmName + '.vhdx' 196 $vhdPath = Join-Path -Path $vhdRoot -ChildPath $vhdx 197 New-VM -Name $vmName -Path $path -MemoryStartupBytes $memoryStartupBytes -NewVHDPath $vhdPath -NewVHDSizeBytes $newVHDSizeBytes -SwitchName $switchName -Generation $generation 198 ` 199 var ps powershell.PowerShellCmd 200 err := ps.Run(script, vmName, path, vhdRoot, strconv.FormatInt(ram, 10), strconv.FormatInt(diskSize, 10), switchName, strconv.FormatInt(int64(generation), 10)) 201 return err 202 } else { 203 var script = ` 204 param([string]$vmName, [string]$path, [string]$vhdRoot, [long]$memoryStartupBytes, [long]$newVHDSizeBytes, [string]$switchName) 205 $vhdx = $vmName + '.vhdx' 206 $vhdPath = Join-Path -Path $vhdRoot -ChildPath $vhdx 207 New-VM -Name $vmName -Path $path -MemoryStartupBytes $memoryStartupBytes -NewVHDPath $vhdPath -NewVHDSizeBytes $newVHDSizeBytes -SwitchName $switchName 208 ` 209 var ps powershell.PowerShellCmd 210 err := ps.Run(script, vmName, path, vhdRoot, strconv.FormatInt(ram, 10), strconv.FormatInt(diskSize, 10), switchName) 211 212 if err != nil { 213 return err 214 } 215 216 err = DisableAutomaticCheckpoints(vmName) 217 218 if err != nil { 219 return err 220 } 221 222 return DeleteAllDvdDrives(vmName) 223 } 224 } 225 226 func DisableAutomaticCheckpoints(vmName string) error { 227 var script = ` 228 param([string]$vmName) 229 if ((Get-Command Set-Vm).Parameters["AutomaticCheckpointsEnabled"]) { 230 Set-Vm -Name $vmName -AutomaticCheckpointsEnabled $false } 231 ` 232 var ps powershell.PowerShellCmd 233 err := ps.Run(script, vmName) 234 return err 235 } 236 237 func SetVirtualMachineCpuCount(vmName string, cpu uint) error { 238 239 var script = ` 240 param([string]$vmName, [int]$cpu) 241 Set-VMProcessor -VMName $vmName -Count $cpu 242 ` 243 var ps powershell.PowerShellCmd 244 err := ps.Run(script, vmName, strconv.FormatInt(int64(cpu), 10)) 245 return err 246 } 247 248 func SetVirtualMachineVirtualizationExtensions(vmName string, enableVirtualizationExtensions bool) error { 249 250 var script = ` 251 param([string]$vmName, [string]$exposeVirtualizationExtensionsString) 252 $exposeVirtualizationExtensions = [System.Boolean]::Parse($exposeVirtualizationExtensionsString) 253 Set-VMProcessor -VMName $vmName -ExposeVirtualizationExtensions $exposeVirtualizationExtensions 254 ` 255 exposeVirtualizationExtensionsString := "False" 256 if enableVirtualizationExtensions { 257 exposeVirtualizationExtensionsString = "True" 258 } 259 var ps powershell.PowerShellCmd 260 err := ps.Run(script, vmName, exposeVirtualizationExtensionsString) 261 return err 262 } 263 264 func SetVirtualMachineDynamicMemory(vmName string, enableDynamicMemory bool) error { 265 266 var script = ` 267 param([string]$vmName, [string]$enableDynamicMemoryString) 268 $enableDynamicMemory = [System.Boolean]::Parse($enableDynamicMemoryString) 269 Set-VMMemory -VMName $vmName -DynamicMemoryEnabled $enableDynamicMemory 270 ` 271 enableDynamicMemoryString := "False" 272 if enableDynamicMemory { 273 enableDynamicMemoryString = "True" 274 } 275 var ps powershell.PowerShellCmd 276 err := ps.Run(script, vmName, enableDynamicMemoryString) 277 return err 278 } 279 280 func SetVirtualMachineMacSpoofing(vmName string, enableMacSpoofing bool) error { 281 var script = ` 282 param([string]$vmName, $enableMacSpoofing) 283 Set-VMNetworkAdapter -VMName $vmName -MacAddressSpoofing $enableMacSpoofing 284 ` 285 286 var ps powershell.PowerShellCmd 287 288 enableMacSpoofingString := "Off" 289 if enableMacSpoofing { 290 enableMacSpoofingString = "On" 291 } 292 293 err := ps.Run(script, vmName, enableMacSpoofingString) 294 return err 295 } 296 297 func SetVirtualMachineSecureBoot(vmName string, enableSecureBoot bool) error { 298 var script = ` 299 param([string]$vmName, $enableSecureBoot) 300 Set-VMFirmware -VMName $vmName -EnableSecureBoot $enableSecureBoot 301 ` 302 303 var ps powershell.PowerShellCmd 304 305 enableSecureBootString := "Off" 306 if enableSecureBoot { 307 enableSecureBootString = "On" 308 } 309 310 err := ps.Run(script, vmName, enableSecureBootString) 311 return err 312 } 313 314 func DeleteVirtualMachine(vmName string) error { 315 316 var script = ` 317 param([string]$vmName) 318 319 $vm = Get-VM -Name $vmName 320 if (($vm.State -ne [Microsoft.HyperV.PowerShell.VMState]::Off) -and ($vm.State -ne [Microsoft.HyperV.PowerShell.VMState]::OffCritical)) { 321 Stop-VM -VM $vm -TurnOff -Force -Confirm:$false 322 } 323 324 Remove-VM -Name $vmName -Force -Confirm:$false 325 ` 326 327 var ps powershell.PowerShellCmd 328 err := ps.Run(script, vmName) 329 return err 330 } 331 332 func ExportVirtualMachine(vmName string, path string) error { 333 334 var script = ` 335 param([string]$vmName, [string]$path) 336 Export-VM -Name $vmName -Path $path 337 338 if (Test-Path -Path ([IO.Path]::Combine($path, $vmName, 'Virtual Machines', '*.VMCX'))) 339 { 340 $vm = Get-VM -Name $vmName 341 $vm_adapter = Get-VMNetworkAdapter -VM $vm | Select -First 1 342 343 $config = [xml]@" 344 <?xml version="1.0" ?> 345 <configuration> 346 <properties> 347 <subtype type="integer">$($vm.Generation - 1)</subtype> 348 <name type="string">$($vm.Name)</name> 349 </properties> 350 <settings> 351 <processors> 352 <count type="integer">$($vm.ProcessorCount)</count> 353 </processors> 354 <memory> 355 <bank> 356 <dynamic_memory_enabled type="bool">$($vm.DynamicMemoryEnabled)</dynamic_memory_enabled> 357 <limit type="integer">$($vm.MemoryMaximum / 1MB)</limit> 358 <reservation type="integer">$($vm.MemoryMinimum / 1MB)</reservation> 359 <size type="integer">$($vm.MemoryStartup / 1MB)</size> 360 </bank> 361 </memory> 362 </settings> 363 <AltSwitchName type="string">$($vm_adapter.SwitchName)</AltSwitchName> 364 <boot> 365 <device0 type="string">Optical</device0> 366 </boot> 367 <secure_boot_enabled type="bool">False</secure_boot_enabled> 368 <notes type="string">$($vm.Notes)</notes> 369 <vm-controllers/> 370 </configuration> 371 "@ 372 373 if ($vm.Generation -eq 1) 374 { 375 $vm_controllers = Get-VMIdeController -VM $vm 376 $controller_type = $config.SelectSingleNode('/configuration/vm-controllers') 377 # IDE controllers are not stored in a special XML container 378 } 379 else 380 { 381 $vm_controllers = Get-VMScsiController -VM $vm 382 $controller_type = $config.CreateElement('scsi') 383 $controller_type.SetAttribute('ChannelInstanceGuid', 'x') 384 # SCSI controllers are stored in the scsi XML container 385 if ((Get-VMFirmware -VM $vm).SecureBoot -eq [Microsoft.HyperV.PowerShell.OnOffState]::On) 386 { 387 $config.configuration.secure_boot_enabled.'#text' = 'True' 388 } 389 else 390 { 391 $config.configuration.secure_boot_enabled.'#text' = 'False' 392 } 393 } 394 395 $vm_controllers | ForEach { 396 $controller = $config.CreateElement('controller' + $_.ControllerNumber) 397 $_.Drives | ForEach { 398 $drive = $config.CreateElement('drive' + ($_.DiskNumber + 0)) 399 $drive_path = $config.CreateElement('pathname') 400 $drive_path.SetAttribute('type', 'string') 401 $drive_path.AppendChild($config.CreateTextNode($_.Path)) 402 $drive_type = $config.CreateElement('type') 403 $drive_type.SetAttribute('type', 'string') 404 if ($_ -is [Microsoft.HyperV.PowerShell.HardDiskDrive]) 405 { 406 $drive_type.AppendChild($config.CreateTextNode('VHD')) 407 } 408 elseif ($_ -is [Microsoft.HyperV.PowerShell.DvdDrive]) 409 { 410 $drive_type.AppendChild($config.CreateTextNode('ISO')) 411 } 412 else 413 { 414 $drive_type.AppendChild($config.CreateTextNode('NONE')) 415 } 416 $drive.AppendChild($drive_path) 417 $drive.AppendChild($drive_type) 418 $controller.AppendChild($drive) 419 } 420 $controller_type.AppendChild($controller) 421 } 422 if ($controller_type.Name -ne 'vm-controllers') 423 { 424 $config.SelectSingleNode('/configuration/vm-controllers').AppendChild($controller_type) 425 } 426 427 $config.Save([IO.Path]::Combine($path, $vm.Name, 'Virtual Machines', 'box.xml')) 428 } 429 ` 430 431 var ps powershell.PowerShellCmd 432 err := ps.Run(script, vmName, path) 433 return err 434 } 435 436 func CompactDisks(expPath string, vhdDir string) error { 437 var script = ` 438 param([string]$srcPath, [string]$vhdDirName) 439 Get-ChildItem "$srcPath/$vhdDirName" -Filter *.vhd* | %{ 440 Optimize-VHD -Path $_.FullName -Mode Full 441 } 442 ` 443 444 var ps powershell.PowerShellCmd 445 err := ps.Run(script, expPath, vhdDir) 446 return err 447 } 448 449 func CopyExportedVirtualMachine(expPath string, outputPath string, vhdDir string, vmDir string) error { 450 451 var script = ` 452 param([string]$srcPath, [string]$dstPath, [string]$vhdDirName, [string]$vmDir) 453 Move-Item -Path $srcPath/*.* -Destination $dstPath 454 Move-Item -Path $srcPath/$vhdDirName -Destination $dstPath 455 Move-Item -Path $srcPath/$vmDir -Destination $dstPath 456 ` 457 458 var ps powershell.PowerShellCmd 459 err := ps.Run(script, expPath, outputPath, vhdDir, vmDir) 460 return err 461 } 462 463 func CreateVirtualSwitch(switchName string, switchType string) (bool, error) { 464 465 var script = ` 466 param([string]$switchName,[string]$switchType) 467 $switches = Get-VMSwitch -Name $switchName -ErrorAction SilentlyContinue 468 if ($switches.Count -eq 0) { 469 New-VMSwitch -Name $switchName -SwitchType $switchType 470 return $true 471 } 472 return $false 473 ` 474 475 var ps powershell.PowerShellCmd 476 cmdOut, err := ps.Output(script, switchName, switchType) 477 var created = strings.TrimSpace(cmdOut) == "True" 478 return created, err 479 } 480 481 func DeleteVirtualSwitch(switchName string) error { 482 483 var script = ` 484 param([string]$switchName) 485 $switch = Get-VMSwitch -Name $switchName -ErrorAction SilentlyContinue 486 if ($switch -ne $null) { 487 $switch | Remove-VMSwitch -Force -Confirm:$false 488 } 489 ` 490 491 var ps powershell.PowerShellCmd 492 err := ps.Run(script, switchName) 493 return err 494 } 495 496 func StartVirtualMachine(vmName string) error { 497 498 var script = ` 499 param([string]$vmName) 500 $vm = Get-VM -Name $vmName -ErrorAction SilentlyContinue 501 if ($vm.State -eq [Microsoft.HyperV.PowerShell.VMState]::Off) { 502 Start-VM -Name $vmName -Confirm:$false 503 } 504 ` 505 506 var ps powershell.PowerShellCmd 507 err := ps.Run(script, vmName) 508 return err 509 } 510 511 func RestartVirtualMachine(vmName string) error { 512 513 var script = ` 514 param([string]$vmName) 515 Restart-VM $vmName -Force -Confirm:$false 516 ` 517 518 var ps powershell.PowerShellCmd 519 err := ps.Run(script, vmName) 520 return err 521 } 522 523 func StopVirtualMachine(vmName string) error { 524 525 var script = ` 526 param([string]$vmName) 527 $vm = Get-VM -Name $vmName 528 if ($vm.State -eq [Microsoft.HyperV.PowerShell.VMState]::Running) { 529 Stop-VM -VM $vm -Force -Confirm:$false 530 } 531 ` 532 533 var ps powershell.PowerShellCmd 534 err := ps.Run(script, vmName) 535 return err 536 } 537 538 func EnableVirtualMachineIntegrationService(vmName string, integrationServiceName string) error { 539 540 integrationServiceId := "" 541 switch integrationServiceName { 542 case "Time Synchronization": 543 integrationServiceId = "2497F4DE-E9FA-4204-80E4-4B75C46419C0" 544 case "Heartbeat": 545 integrationServiceId = "84EAAE65-2F2E-45F5-9BB5-0E857DC8EB47" 546 case "Key-Value Pair Exchange": 547 integrationServiceId = "2A34B1C2-FD73-4043-8A5B-DD2159BC743F" 548 case "Shutdown": 549 integrationServiceId = "9F8233AC-BE49-4C79-8EE3-E7E1985B2077" 550 case "VSS": 551 integrationServiceId = "5CED1297-4598-4915-A5FC-AD21BB4D02A4" 552 case "Guest Service Interface": 553 integrationServiceId = "6C09BB55-D683-4DA0-8931-C9BF705F6480" 554 default: 555 panic("unrecognized Integration Service Name") 556 } 557 558 var script = ` 559 param([string]$vmName,[string]$integrationServiceId) 560 Get-VMIntegrationService -VmName $vmName | ?{$_.Id -match $integrationServiceId} | Enable-VMIntegrationService 561 ` 562 563 var ps powershell.PowerShellCmd 564 err := ps.Run(script, vmName, integrationServiceId) 565 return err 566 } 567 568 func SetNetworkAdapterVlanId(switchName string, vlanId string) error { 569 570 var script = ` 571 param([string]$networkAdapterName,[string]$vlanId) 572 Set-VMNetworkAdapterVlan -ManagementOS -VMNetworkAdapterName $networkAdapterName -Access -VlanId $vlanId 573 ` 574 575 var ps powershell.PowerShellCmd 576 err := ps.Run(script, switchName, vlanId) 577 return err 578 } 579 580 func SetVirtualMachineVlanId(vmName string, vlanId string) error { 581 582 var script = ` 583 param([string]$vmName,[string]$vlanId) 584 Set-VMNetworkAdapterVlan -VMName $vmName -Access -VlanId $vlanId 585 ` 586 var ps powershell.PowerShellCmd 587 err := ps.Run(script, vmName, vlanId) 588 return err 589 } 590 591 func GetExternalOnlineVirtualSwitch() (string, error) { 592 593 var script = ` 594 $adapters = Get-NetAdapter -Physical -ErrorAction SilentlyContinue | Where-Object { $_.Status -eq 'Up' } | Sort-Object -Descending -Property Speed 595 foreach ($adapter in $adapters) { 596 $switch = Get-VMSwitch -SwitchType External | Where-Object { $_.NetAdapterInterfaceDescription -eq $adapter.InterfaceDescription } 597 598 if ($switch -ne $null) { 599 $switch.Name 600 break 601 } 602 } 603 ` 604 605 var ps powershell.PowerShellCmd 606 cmdOut, err := ps.Output(script) 607 if err != nil { 608 return "", err 609 } 610 611 var switchName = strings.TrimSpace(cmdOut) 612 return switchName, nil 613 } 614 615 func CreateExternalVirtualSwitch(vmName string, switchName string) error { 616 617 var script = ` 618 param([string]$vmName,[string]$switchName) 619 $switch = $null 620 $names = @('ethernet','wi-fi','lan') 621 $adapters = foreach ($name in $names) { 622 Get-NetAdapter -Physical -Name $name -ErrorAction SilentlyContinue | where status -eq 'up' 623 } 624 625 foreach ($adapter in $adapters) { 626 $switch = Get-VMSwitch -SwitchType External | where { $_.NetAdapterInterfaceDescription -eq $adapter.InterfaceDescription } 627 628 if ($switch -eq $null) { 629 $switch = New-VMSwitch -Name $switchName -NetAdapterName $adapter.Name -AllowManagementOS $true -Notes 'Parent OS, VMs, WiFi' 630 } 631 632 if ($switch -ne $null) { 633 break 634 } 635 } 636 637 if($switch -ne $null) { 638 Get-VMNetworkAdapter -VMName $vmName | Connect-VMNetworkAdapter -VMSwitch $switch 639 } else { 640 Write-Error 'No internet adapters found' 641 } 642 ` 643 var ps powershell.PowerShellCmd 644 err := ps.Run(script, vmName, switchName) 645 return err 646 } 647 648 func GetVirtualMachineSwitchName(vmName string) (string, error) { 649 650 var script = ` 651 param([string]$vmName) 652 (Get-VMNetworkAdapter -VMName $vmName).SwitchName 653 ` 654 655 var ps powershell.PowerShellCmd 656 cmdOut, err := ps.Output(script, vmName) 657 if err != nil { 658 return "", err 659 } 660 661 return strings.TrimSpace(cmdOut), nil 662 } 663 664 func ConnectVirtualMachineNetworkAdapterToSwitch(vmName string, switchName string) error { 665 666 var script = ` 667 param([string]$vmName,[string]$switchName) 668 Get-VMNetworkAdapter -VMName $vmName | Connect-VMNetworkAdapter -SwitchName $switchName 669 ` 670 671 var ps powershell.PowerShellCmd 672 err := ps.Run(script, vmName, switchName) 673 return err 674 } 675 676 func UntagVirtualMachineNetworkAdapterVlan(vmName string, switchName string) error { 677 678 var script = ` 679 param([string]$vmName,[string]$switchName) 680 Set-VMNetworkAdapterVlan -VMName $vmName -Untagged 681 Set-VMNetworkAdapterVlan -ManagementOS -VMNetworkAdapterName $switchName -Untagged 682 ` 683 684 var ps powershell.PowerShellCmd 685 err := ps.Run(script, vmName, switchName) 686 return err 687 } 688 689 func IsRunning(vmName string) (bool, error) { 690 691 var script = ` 692 param([string]$vmName) 693 $vm = Get-VM -Name $vmName -ErrorAction SilentlyContinue 694 $vm.State -eq [Microsoft.HyperV.PowerShell.VMState]::Running 695 ` 696 697 var ps powershell.PowerShellCmd 698 cmdOut, err := ps.Output(script, vmName) 699 700 if err != nil { 701 return false, err 702 } 703 704 var isRunning = strings.TrimSpace(cmdOut) == "True" 705 return isRunning, err 706 } 707 708 func IsOff(vmName string) (bool, error) { 709 710 var script = ` 711 param([string]$vmName) 712 $vm = Get-VM -Name $vmName -ErrorAction SilentlyContinue 713 $vm.State -eq [Microsoft.HyperV.PowerShell.VMState]::Off 714 ` 715 716 var ps powershell.PowerShellCmd 717 cmdOut, err := ps.Output(script, vmName) 718 719 if err != nil { 720 return false, err 721 } 722 723 var isRunning = strings.TrimSpace(cmdOut) == "True" 724 return isRunning, err 725 } 726 727 func Uptime(vmName string) (uint64, error) { 728 729 var script = ` 730 param([string]$vmName) 731 $vm = Get-VM -Name $vmName -ErrorAction SilentlyContinue 732 $vm.Uptime.TotalSeconds 733 ` 734 var ps powershell.PowerShellCmd 735 cmdOut, err := ps.Output(script, vmName) 736 737 if err != nil { 738 return 0, err 739 } 740 741 uptime, err := strconv.ParseUint(strings.TrimSpace(cmdOut), 10, 64) 742 743 return uptime, err 744 } 745 746 func Mac(vmName string) (string, error) { 747 var script = ` 748 param([string]$vmName, [int]$adapterIndex) 749 try { 750 $adapter = Get-VMNetworkAdapter -VMName $vmName -ErrorAction SilentlyContinue 751 $mac = $adapter[$adapterIndex].MacAddress 752 if($mac -eq $null) { 753 return "" 754 } 755 } catch { 756 return "" 757 } 758 $mac 759 ` 760 761 var ps powershell.PowerShellCmd 762 cmdOut, err := ps.Output(script, vmName, "0") 763 764 return cmdOut, err 765 } 766 767 func IpAddress(mac string) (string, error) { 768 var script = ` 769 param([string]$mac, [int]$addressIndex) 770 try { 771 $ip = Get-Vm | %{$_.NetworkAdapters} | ?{$_.MacAddress -eq $mac} | %{$_.IpAddresses[$addressIndex]} 772 773 if($ip -eq $null) { 774 return "" 775 } 776 } catch { 777 return "" 778 } 779 $ip 780 ` 781 782 var ps powershell.PowerShellCmd 783 cmdOut, err := ps.Output(script, mac, "0") 784 785 return cmdOut, err 786 } 787 788 func TurnOff(vmName string) error { 789 790 var script = ` 791 param([string]$vmName) 792 $vm = Get-VM -Name $vmName -ErrorAction SilentlyContinue 793 if ($vm.State -eq [Microsoft.HyperV.PowerShell.VMState]::Running) { 794 Stop-VM -Name $vmName -TurnOff -Force -Confirm:$false 795 } 796 ` 797 798 var ps powershell.PowerShellCmd 799 err := ps.Run(script, vmName) 800 return err 801 } 802 803 func ShutDown(vmName string) error { 804 805 var script = ` 806 param([string]$vmName) 807 $vm = Get-VM -Name $vmName -ErrorAction SilentlyContinue 808 if ($vm.State -eq [Microsoft.HyperV.PowerShell.VMState]::Running) { 809 Stop-VM -Name $vmName -Force -Confirm:$false 810 } 811 ` 812 813 var ps powershell.PowerShellCmd 814 err := ps.Run(script, vmName) 815 return err 816 } 817 818 func TypeScanCodes(vmName string, scanCodes string) error { 819 if len(scanCodes) == 0 { 820 return nil 821 } 822 823 var script = ` 824 param([string]$vmName, [string]$scanCodes) 825 #Requires -Version 3 826 827 function Get-VMConsole 828 { 829 [CmdletBinding()] 830 param ( 831 [Parameter(Mandatory)] 832 [string] $VMName 833 ) 834 835 $ErrorActionPreference = "Stop" 836 837 $vm = Get-CimInstance -Namespace "root\virtualization\v2" -ClassName Msvm_ComputerSystem -ErrorAction Ignore -Verbose:$false | where ElementName -eq $VMName | select -first 1 838 if ($vm -eq $null){ 839 Write-Error ("VirtualMachine({0}) is not found!" -f $VMName) 840 } 841 842 $vmKeyboard = $vm | Get-CimAssociatedInstance -ResultClassName "Msvm_Keyboard" -ErrorAction Ignore -Verbose:$false 843 844 if ($vmKeyboard -eq $null) { 845 $vmKeyboard = Get-CimInstance -Namespace "root\virtualization\v2" -ClassName Msvm_Keyboard -ErrorAction Ignore -Verbose:$false | where SystemName -eq $vm.Name | select -first 1 846 } 847 848 if ($vmKeyboard -eq $null) { 849 $vmKeyboard = Get-CimInstance -Namespace "root\virtualization" -ClassName Msvm_Keyboard -ErrorAction Ignore -Verbose:$false | where SystemName -eq $vm.Name | select -first 1 850 } 851 852 if ($vmKeyboard -eq $null){ 853 Write-Error ("VirtualMachine({0}) keyboard class is not found!" -f $VMName) 854 } 855 856 #TODO: It may be better using New-Module -AsCustomObject to return console object? 857 858 #Console object to return 859 $console = [pscustomobject] @{ 860 Msvm_ComputerSystem = $vm 861 Msvm_Keyboard = $vmKeyboard 862 } 863 864 #Need to import assembly to use System.Windows.Input.Key 865 Add-Type -AssemblyName WindowsBase 866 867 #region Add Console Members 868 $console | Add-Member -MemberType ScriptMethod -Name TypeText -Value { 869 [OutputType([bool])] 870 param ( 871 [ValidateNotNullOrEmpty()] 872 [Parameter(Mandatory)] 873 [string] $AsciiText 874 ) 875 $result = $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "TypeText" -Arguments @{ asciiText = $AsciiText } 876 return (0 -eq $result.ReturnValue) 877 } 878 879 #Define method:TypeCtrlAltDel 880 $console | Add-Member -MemberType ScriptMethod -Name TypeCtrlAltDel -Value { 881 $result = $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "TypeCtrlAltDel" 882 return (0 -eq $result.ReturnValue) 883 } 884 885 #Define method:TypeKey 886 $console | Add-Member -MemberType ScriptMethod -Name TypeKey -Value { 887 [OutputType([bool])] 888 param ( 889 [Parameter(Mandatory)] 890 [Windows.Input.Key] $Key, 891 [Windows.Input.ModifierKeys] $ModifierKey = [Windows.Input.ModifierKeys]::None 892 ) 893 894 $keyCode = [Windows.Input.KeyInterop]::VirtualKeyFromKey($Key) 895 896 switch ($ModifierKey) 897 { 898 ([Windows.Input.ModifierKeys]::Control){ $modifierKeyCode = [Windows.Input.KeyInterop]::VirtualKeyFromKey([Windows.Input.Key]::LeftCtrl)} 899 ([Windows.Input.ModifierKeys]::Alt){ $modifierKeyCode = [Windows.Input.KeyInterop]::VirtualKeyFromKey([Windows.Input.Key]::LeftAlt)} 900 ([Windows.Input.ModifierKeys]::Shift){ $modifierKeyCode = [Windows.Input.KeyInterop]::VirtualKeyFromKey([Windows.Input.Key]::LeftShift)} 901 ([Windows.Input.ModifierKeys]::Windows){ $modifierKeyCode = [Windows.Input.KeyInterop]::VirtualKeyFromKey([Windows.Input.Key]::LWin)} 902 } 903 904 if ($ModifierKey -eq [Windows.Input.ModifierKeys]::None) 905 { 906 $result = $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "TypeKey" -Arguments @{ keyCode = $keyCode } 907 } 908 else 909 { 910 $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "PressKey" -Arguments @{ keyCode = $modifierKeyCode } 911 $result = $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "TypeKey" -Arguments @{ keyCode = $keyCode } 912 $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "ReleaseKey" -Arguments @{ keyCode = $modifierKeyCode } 913 } 914 $result = return (0 -eq $result.ReturnValue) 915 } 916 917 #Define method:Scancodes 918 $console | Add-Member -MemberType ScriptMethod -Name TypeScancodes -Value { 919 [OutputType([bool])] 920 param ( 921 [Parameter(Mandatory)] 922 [byte[]] $ScanCodes 923 ) 924 $result = $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "TypeScancodes" -Arguments @{ ScanCodes = $ScanCodes } 925 return (0 -eq $result.ReturnValue) 926 } 927 928 #Define method:ExecCommand 929 $console | Add-Member -MemberType ScriptMethod -Name ExecCommand -Value { 930 param ( 931 [Parameter(Mandatory)] 932 [string] $Command 933 ) 934 if ([String]::IsNullOrEmpty($Command)){ 935 return 936 } 937 938 $console.TypeText($Command) > $null 939 $console.TypeKey([Windows.Input.Key]::Enter) > $null 940 #sleep -Milliseconds 100 941 } 942 943 #Define method:Dispose 944 $console | Add-Member -MemberType ScriptMethod -Name Dispose -Value { 945 $this.Msvm_ComputerSystem.Dispose() 946 $this.Msvm_Keyboard.Dispose() 947 } 948 949 950 #endregion 951 952 return $console 953 } 954 955 $vmConsole = Get-VMConsole -VMName $vmName 956 $scanCodesToSend = '' 957 $scanCodes.Split(' ') | %{ 958 $scanCode = $_ 959 960 if ($scanCode.StartsWith('wait')){ 961 $timeToWait = $scanCode.Substring(4) 962 if (!$timeToWait){ 963 $timeToWait = "1" 964 } 965 966 if ($scanCodesToSend){ 967 $scanCodesToSendByteArray = [byte[]]@($scanCodesToSend.Split(' ') | %{"0x$_"}) 968 969 $scanCodesToSendByteArray | %{ 970 $vmConsole.TypeScancodes($_) 971 } 972 } 973 974 write-host "Special code <wait> found, will sleep $timeToWait second(s) at this point." 975 Start-Sleep -s $timeToWait 976 977 $scanCodesToSend = '' 978 } else { 979 if ($scanCodesToSend){ 980 write-host "Sending special code '$scanCodesToSend' '$scanCode'" 981 $scanCodesToSend = "$scanCodesToSend $scanCode" 982 } else { 983 write-host "Sending char '$scanCode'" 984 $scanCodesToSend = "$scanCode" 985 } 986 } 987 } 988 if ($scanCodesToSend){ 989 $scanCodesToSendByteArray = [byte[]]@($scanCodesToSend.Split(' ') | %{"0x$_"}) 990 991 $scanCodesToSendByteArray | %{ 992 $vmConsole.TypeScancodes($_) 993 } 994 } 995 ` 996 997 var ps powershell.PowerShellCmd 998 err := ps.Run(script, vmName, scanCodes) 999 return err 1000 }