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