github.com/atorr/packer@v1.2.2/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 = Hyper-V\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 = Hyper-V\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 = Hyper-V\Add-VMDvdDrive -VMName $vmName -path $isoPath -Passthru 63 $dvdController | Hyper-V\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 = Hyper-V\Get-VMDvdDrive -VMName $vmName -ControllerNumber $controllerNumber -ControllerLocation $controllerLocation 98 if (!$vmDvdDrive) {throw 'unable to find dvd drive'} 99 Hyper-V\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 = Hyper-V\Get-VMDvdDrive -VMName $vmName -ControllerNumber $controllerNumber -ControllerLocation $controllerLocation 111 if (!$vmDvdDrive) {throw 'unable to find dvd drive'} 112 Hyper-V\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 Hyper-V\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 = Hyper-V\Get-VMDvdDrive -VMName $vmName -ControllerNumber $controllerNumber -ControllerLocation $controllerLocation 134 if (!$vmDvdDrive) {throw 'unable to find dvd drive'} 135 Hyper-V\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 = Hyper-V\Get-VMDvdDrive -VMName $vmName -ControllerNumber $controllerNumber -ControllerLocation $controllerLocation 147 if (!$vmDvdDrive) {throw 'unable to find dvd drive'} 148 Hyper-V\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 Hyper-V\Get-VMDvdDrive -VMName $vmName | Hyper-V\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 Hyper-V\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 Hyper-V\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, harddrivePath string, vhdRoot string, ram int64, diskSize int64, switchName string, generation uint, diffDisks bool) error { 191 192 if generation == 2 { 193 var script = ` 194 param([string]$vmName, [string]$path, [string]$harddrivePath, [string]$vhdRoot, [long]$memoryStartupBytes, [long]$newVHDSizeBytes, [string]$switchName, [int]$generation, [string]$diffDisks) 195 $vhdx = $vmName + '.vhdx' 196 $vhdPath = Join-Path -Path $vhdRoot -ChildPath $vhdx 197 if ($harddrivePath){ 198 if($diffDisks -eq "true"){ 199 New-VHD -Path $vhdPath -ParentPath $harddrivePath -Differencing 200 } else { 201 Copy-Item -Path $harddrivePath -Destination $vhdPath 202 } 203 Hyper-V\New-VM -Name $vmName -Path $path -MemoryStartupBytes $memoryStartupBytes -VHDPath $vhdPath -SwitchName $switchName -Generation $generation 204 } else { 205 Hyper-V\New-VM -Name $vmName -Path $path -MemoryStartupBytes $memoryStartupBytes -NewVHDPath $vhdPath -NewVHDSizeBytes $newVHDSizeBytes -SwitchName $switchName -Generation $generation 206 } 207 ` 208 var ps powershell.PowerShellCmd 209 if err := ps.Run(script, vmName, path, harddrivePath, vhdRoot, strconv.FormatInt(ram, 10), strconv.FormatInt(diskSize, 10), switchName, strconv.FormatInt(int64(generation), 10), strconv.FormatBool(diffDisks)); err != nil { 210 return err 211 } 212 213 return DisableAutomaticCheckpoints(vmName) 214 } else { 215 var script = ` 216 param([string]$vmName, [string]$path, [string]$harddrivePath, [string]$vhdRoot, [long]$memoryStartupBytes, [long]$newVHDSizeBytes, [string]$switchName, [string]$diffDisks) 217 $vhdx = $vmName + '.vhdx' 218 $vhdPath = Join-Path -Path $vhdRoot -ChildPath $vhdx 219 if ($harddrivePath){ 220 if($diffDisks -eq "true"){ 221 New-VHD -Path $vhdPath -ParentPath $harddrivePath -Differencing 222 } 223 else{ 224 Copy-Item -Path $harddrivePath -Destination $vhdPath 225 } 226 Hyper-V\New-VM -Name $vmName -Path $path -MemoryStartupBytes $memoryStartupBytes -VHDPath $vhdPath -SwitchName $switchName 227 } else { 228 Hyper-V\New-VM -Name $vmName -Path $path -MemoryStartupBytes $memoryStartupBytes -NewVHDPath $vhdPath -NewVHDSizeBytes $newVHDSizeBytes -SwitchName $switchName 229 } 230 ` 231 var ps powershell.PowerShellCmd 232 if err := ps.Run(script, vmName, path, harddrivePath, vhdRoot, strconv.FormatInt(ram, 10), strconv.FormatInt(diskSize, 10), switchName, strconv.FormatBool(diffDisks)); err != nil { 233 return err 234 } 235 236 if err := DisableAutomaticCheckpoints(vmName); err != nil { 237 return err 238 } 239 240 return DeleteAllDvdDrives(vmName) 241 } 242 } 243 244 func DisableAutomaticCheckpoints(vmName string) error { 245 var script = ` 246 param([string]$vmName) 247 if ((Get-Command Hyper-V\Set-Vm).Parameters["AutomaticCheckpointsEnabled"]) { 248 Hyper-V\Set-Vm -Name $vmName -AutomaticCheckpointsEnabled $false } 249 ` 250 var ps powershell.PowerShellCmd 251 err := ps.Run(script, vmName) 252 return err 253 } 254 255 func ExportVmxcVirtualMachine(exportPath string, vmName string, snapshotName string, allSnapshots bool) error { 256 var script = ` 257 param([string]$exportPath, [string]$vmName, [string]$snapshotName, [string]$allSnapshotsString) 258 259 $WorkingPath = Join-Path $exportPath $vmName 260 261 if (Test-Path $WorkingPath) { 262 throw "Export path working directory: $WorkingPath already exists!" 263 } 264 265 $allSnapshots = [System.Boolean]::Parse($allSnapshotsString) 266 267 if ($snapshotName) { 268 $snapshot = Hyper-V\Get-VMSnapshot -VMName $vmName -Name $snapshotName 269 Hyper-V\Export-VMSnapshot -VMSnapshot $snapshot -Path $exportPath -ErrorAction Stop 270 } else { 271 if (!$allSnapshots) { 272 #Use last snapshot if one was not specified 273 $snapshot = Hyper-V\Get-VMSnapshot -VMName $vmName | Select -Last 1 274 } else { 275 $snapshot = $null 276 } 277 278 if (!$snapshot) { 279 #No snapshot clone 280 Hyper-V\Export-VM -Name $vmName -Path $exportPath -ErrorAction Stop 281 } else { 282 #Snapshot clone 283 Hyper-V\Export-VMSnapshot -VMSnapshot $snapshot -Path $exportPath -ErrorAction Stop 284 } 285 } 286 287 $result = Get-ChildItem -Path $WorkingPath | Move-Item -Destination $exportPath -Force 288 $result = Remove-Item -Path $WorkingPath 289 ` 290 291 allSnapshotsString := "False" 292 if allSnapshots { 293 allSnapshotsString = "True" 294 } 295 296 var ps powershell.PowerShellCmd 297 err := ps.Run(script, exportPath, vmName, snapshotName, allSnapshotsString) 298 299 return err 300 } 301 302 func CopyVmxcVirtualMachine(exportPath string, cloneFromVmxcPath string) error { 303 var script = ` 304 param([string]$exportPath, [string]$cloneFromVmxcPath) 305 if (!(Test-Path $cloneFromVmxcPath)){ 306 throw "Clone from vmxc directory: $cloneFromVmxcPath does not exist!" 307 } 308 309 if (!(Test-Path $exportPath)){ 310 New-Item -ItemType Directory -Force -Path $exportPath 311 } 312 $cloneFromVmxcPath = Join-Path $cloneFromVmxcPath '\*' 313 Copy-Item $cloneFromVmxcPath $exportPath -Recurse -Force 314 ` 315 316 var ps powershell.PowerShellCmd 317 err := ps.Run(script, exportPath, cloneFromVmxcPath) 318 319 return err 320 } 321 322 func SetVmNetworkAdapterMacAddress(vmName string, mac string) error { 323 var script = ` 324 param([string]$vmName, [string]$mac) 325 Hyper-V\Set-VMNetworkAdapter $vmName -staticmacaddress $mac 326 ` 327 328 var ps powershell.PowerShellCmd 329 err := ps.Run(script, vmName, mac) 330 331 return err 332 } 333 334 func ImportVmxcVirtualMachine(importPath string, vmName string, harddrivePath string, ram int64, switchName string) error { 335 var script = ` 336 param([string]$importPath, [string]$vmName, [string]$harddrivePath, [long]$memoryStartupBytes, [string]$switchName) 337 338 $VirtualHarddisksPath = Join-Path -Path $importPath -ChildPath 'Virtual Hard Disks' 339 if (!(Test-Path $VirtualHarddisksPath)) { 340 New-Item -ItemType Directory -Force -Path $VirtualHarddisksPath 341 } 342 343 $vhdPath = "" 344 if ($harddrivePath){ 345 $vhdx = $vmName + '.vhdx' 346 $vhdPath = Join-Path -Path $VirtualHarddisksPath -ChildPath $vhdx 347 } 348 349 $VirtualMachinesPath = Join-Path $importPath 'Virtual Machines' 350 if (!(Test-Path $VirtualMachinesPath)) { 351 New-Item -ItemType Directory -Force -Path $VirtualMachinesPath 352 } 353 354 $VirtualMachinePath = Get-ChildItem -Path $VirtualMachinesPath -Filter *.vmcx -Recurse -ErrorAction SilentlyContinue | select -First 1 | %{$_.FullName} 355 if (!$VirtualMachinePath){ 356 $VirtualMachinePath = Get-ChildItem -Path $VirtualMachinesPath -Filter *.xml -Recurse -ErrorAction SilentlyContinue | select -First 1 | %{$_.FullName} 357 } 358 if (!$VirtualMachinePath){ 359 $VirtualMachinePath = Get-ChildItem -Path $importPath -Filter *.xml -Recurse -ErrorAction SilentlyContinue | select -First 1 | %{$_.FullName} 360 } 361 362 $compatibilityReport = Hyper-V\Compare-VM -Path $VirtualMachinePath -VirtualMachinePath $importPath -SmartPagingFilePath $importPath -SnapshotFilePath $importPath -VhdDestinationPath $VirtualHarddisksPath -GenerateNewId -Copy:$false 363 if ($vhdPath){ 364 Copy-Item -Path $harddrivePath -Destination $vhdPath 365 $existingFirstHarddrive = $compatibilityReport.VM.HardDrives | Select -First 1 366 if ($existingFirstHarddrive) { 367 $existingFirstHarddrive | Hyper-V\Set-VMHardDiskDrive -Path $vhdPath 368 } else { 369 Hyper-V\Add-VMHardDiskDrive -VM $compatibilityReport.VM -Path $vhdPath 370 } 371 } 372 Hyper-V\Set-VMMemory -VM $compatibilityReport.VM -StartupBytes $memoryStartupBytes 373 $networkAdaptor = $compatibilityReport.VM.NetworkAdapters | Select -First 1 374 Hyper-V\Disconnect-VMNetworkAdapter -VMNetworkAdapter $networkAdaptor 375 Hyper-V\Connect-VMNetworkAdapter -VMNetworkAdapter $networkAdaptor -SwitchName $switchName 376 $vm = Hyper-V\Import-VM -CompatibilityReport $compatibilityReport 377 378 if ($vm) { 379 $result = Hyper-V\Rename-VM -VM $vm -NewName $VMName 380 } 381 ` 382 383 var ps powershell.PowerShellCmd 384 err := ps.Run(script, importPath, vmName, harddrivePath, strconv.FormatInt(ram, 10), switchName) 385 386 return err 387 } 388 389 func CloneVirtualMachine(cloneFromVmxcPath string, cloneFromVmName string, cloneFromSnapshotName string, cloneAllSnapshots bool, vmName string, path string, harddrivePath string, ram int64, switchName string) error { 390 if cloneFromVmName != "" { 391 if err := ExportVmxcVirtualMachine(path, cloneFromVmName, cloneFromSnapshotName, cloneAllSnapshots); err != nil { 392 return err 393 } 394 } 395 396 if cloneFromVmxcPath != "" { 397 if err := CopyVmxcVirtualMachine(path, cloneFromVmxcPath); err != nil { 398 return err 399 } 400 } 401 402 if err := ImportVmxcVirtualMachine(path, vmName, harddrivePath, ram, switchName); err != nil { 403 return err 404 } 405 406 return DeleteAllDvdDrives(vmName) 407 } 408 409 func GetVirtualMachineGeneration(vmName string) (uint, error) { 410 var script = ` 411 param([string]$vmName) 412 $generation = Hyper-V\Get-Vm -Name $vmName | %{$_.Generation} 413 if (!$generation){ 414 $generation = 1 415 } 416 return $generation 417 ` 418 var ps powershell.PowerShellCmd 419 cmdOut, err := ps.Output(script, vmName) 420 421 if err != nil { 422 return 0, err 423 } 424 425 generationUint32, err := strconv.ParseUint(strings.TrimSpace(string(cmdOut)), 10, 32) 426 427 if err != nil { 428 return 0, err 429 } 430 431 generation := uint(generationUint32) 432 433 return generation, err 434 } 435 436 func SetVirtualMachineCpuCount(vmName string, cpu uint) error { 437 438 var script = ` 439 param([string]$vmName, [int]$cpu) 440 Hyper-V\Set-VMProcessor -VMName $vmName -Count $cpu 441 ` 442 var ps powershell.PowerShellCmd 443 err := ps.Run(script, vmName, strconv.FormatInt(int64(cpu), 10)) 444 return err 445 } 446 447 func SetVirtualMachineVirtualizationExtensions(vmName string, enableVirtualizationExtensions bool) error { 448 449 var script = ` 450 param([string]$vmName, [string]$exposeVirtualizationExtensionsString) 451 $exposeVirtualizationExtensions = [System.Boolean]::Parse($exposeVirtualizationExtensionsString) 452 Hyper-V\Set-VMProcessor -VMName $vmName -ExposeVirtualizationExtensions $exposeVirtualizationExtensions 453 ` 454 exposeVirtualizationExtensionsString := "False" 455 if enableVirtualizationExtensions { 456 exposeVirtualizationExtensionsString = "True" 457 } 458 var ps powershell.PowerShellCmd 459 err := ps.Run(script, vmName, exposeVirtualizationExtensionsString) 460 return err 461 } 462 463 func SetVirtualMachineDynamicMemory(vmName string, enableDynamicMemory bool) error { 464 465 var script = ` 466 param([string]$vmName, [string]$enableDynamicMemoryString) 467 $enableDynamicMemory = [System.Boolean]::Parse($enableDynamicMemoryString) 468 Hyper-V\Set-VMMemory -VMName $vmName -DynamicMemoryEnabled $enableDynamicMemory 469 ` 470 enableDynamicMemoryString := "False" 471 if enableDynamicMemory { 472 enableDynamicMemoryString = "True" 473 } 474 var ps powershell.PowerShellCmd 475 err := ps.Run(script, vmName, enableDynamicMemoryString) 476 return err 477 } 478 479 func SetVirtualMachineMacSpoofing(vmName string, enableMacSpoofing bool) error { 480 var script = ` 481 param([string]$vmName, $enableMacSpoofing) 482 Hyper-V\Set-VMNetworkAdapter -VMName $vmName -MacAddressSpoofing $enableMacSpoofing 483 ` 484 485 var ps powershell.PowerShellCmd 486 487 enableMacSpoofingString := "Off" 488 if enableMacSpoofing { 489 enableMacSpoofingString = "On" 490 } 491 492 err := ps.Run(script, vmName, enableMacSpoofingString) 493 return err 494 } 495 496 func SetVirtualMachineSecureBoot(vmName string, enableSecureBoot bool) error { 497 var script = ` 498 param([string]$vmName, $enableSecureBoot) 499 Hyper-V\Set-VMFirmware -VMName $vmName -EnableSecureBoot $enableSecureBoot 500 ` 501 502 var ps powershell.PowerShellCmd 503 504 enableSecureBootString := "Off" 505 if enableSecureBoot { 506 enableSecureBootString = "On" 507 } 508 509 err := ps.Run(script, vmName, enableSecureBootString) 510 return err 511 } 512 513 func DeleteVirtualMachine(vmName string) error { 514 515 var script = ` 516 param([string]$vmName) 517 518 $vm = Hyper-V\Get-VM -Name $vmName 519 if (($vm.State -ne [Microsoft.HyperV.PowerShell.VMState]::Off) -and ($vm.State -ne [Microsoft.HyperV.PowerShell.VMState]::OffCritical)) { 520 Hyper-V\Stop-VM -VM $vm -TurnOff -Force -Confirm:$false 521 } 522 523 Hyper-V\Remove-VM -Name $vmName -Force -Confirm:$false 524 ` 525 526 var ps powershell.PowerShellCmd 527 err := ps.Run(script, vmName) 528 return err 529 } 530 531 func ExportVirtualMachine(vmName string, path string) error { 532 533 var script = ` 534 param([string]$vmName, [string]$path) 535 Hyper-V\Export-VM -Name $vmName -Path $path 536 537 if (Test-Path -Path ([IO.Path]::Combine($path, $vmName, 'Virtual Machines', '*.VMCX'))) 538 { 539 $vm = Hyper-V\Get-VM -Name $vmName 540 $vm_adapter = Hyper-V\Get-VMNetworkAdapter -VM $vm | Select -First 1 541 542 $config = [xml]@" 543 <?xml version="1.0" ?> 544 <configuration> 545 <properties> 546 <subtype type="integer">$($vm.Generation - 1)</subtype> 547 <name type="string">$($vm.Name)</name> 548 </properties> 549 <settings> 550 <processors> 551 <count type="integer">$($vm.ProcessorCount)</count> 552 </processors> 553 <memory> 554 <bank> 555 <dynamic_memory_enabled type="bool">$($vm.DynamicMemoryEnabled)</dynamic_memory_enabled> 556 <limit type="integer">$($vm.MemoryMaximum / 1MB)</limit> 557 <reservation type="integer">$($vm.MemoryMinimum / 1MB)</reservation> 558 <size type="integer">$($vm.MemoryStartup / 1MB)</size> 559 </bank> 560 </memory> 561 </settings> 562 <AltSwitchName type="string">$($vm_adapter.SwitchName)</AltSwitchName> 563 <boot> 564 <device0 type="string">Optical</device0> 565 </boot> 566 <secure_boot_enabled type="bool">False</secure_boot_enabled> 567 <notes type="string">$($vm.Notes)</notes> 568 <vm-controllers/> 569 </configuration> 570 "@ 571 572 if ($vm.Generation -eq 1) 573 { 574 $vm_controllers = Hyper-V\Get-VMIdeController -VM $vm 575 $controller_type = $config.SelectSingleNode('/configuration/vm-controllers') 576 # IDE controllers are not stored in a special XML container 577 } 578 else 579 { 580 $vm_controllers = Hyper-V\Get-VMScsiController -VM $vm 581 $controller_type = $config.CreateElement('scsi') 582 $controller_type.SetAttribute('ChannelInstanceGuid', 'x') 583 # SCSI controllers are stored in the scsi XML container 584 if ((Hyper-V\Get-VMFirmware -VM $vm).SecureBoot -eq [Microsoft.HyperV.PowerShell.OnOffState]::On) 585 { 586 $config.configuration.secure_boot_enabled.'#text' = 'True' 587 } 588 else 589 { 590 $config.configuration.secure_boot_enabled.'#text' = 'False' 591 } 592 } 593 594 $vm_controllers | ForEach { 595 $controller = $config.CreateElement('controller' + $_.ControllerNumber) 596 $_.Drives | ForEach { 597 $drive = $config.CreateElement('drive' + ($_.DiskNumber + 0)) 598 $drive_path = $config.CreateElement('pathname') 599 $drive_path.SetAttribute('type', 'string') 600 $drive_path.AppendChild($config.CreateTextNode($_.Path)) 601 $drive_type = $config.CreateElement('type') 602 $drive_type.SetAttribute('type', 'string') 603 if ($_ -is [Microsoft.HyperV.PowerShell.HardDiskDrive]) 604 { 605 $drive_type.AppendChild($config.CreateTextNode('VHD')) 606 } 607 elseif ($_ -is [Microsoft.HyperV.PowerShell.DvdDrive]) 608 { 609 $drive_type.AppendChild($config.CreateTextNode('ISO')) 610 } 611 else 612 { 613 $drive_type.AppendChild($config.CreateTextNode('NONE')) 614 } 615 $drive.AppendChild($drive_path) 616 $drive.AppendChild($drive_type) 617 $controller.AppendChild($drive) 618 } 619 $controller_type.AppendChild($controller) 620 } 621 if ($controller_type.Name -ne 'vm-controllers') 622 { 623 $config.SelectSingleNode('/configuration/vm-controllers').AppendChild($controller_type) 624 } 625 626 $config.Save([IO.Path]::Combine($path, $vm.Name, 'Virtual Machines', 'box.xml')) 627 } 628 ` 629 630 var ps powershell.PowerShellCmd 631 err := ps.Run(script, vmName, path) 632 return err 633 } 634 635 func CompactDisks(expPath string, vhdDir string) error { 636 var script = ` 637 param([string]$srcPath, [string]$vhdDirName) 638 Get-ChildItem "$srcPath/$vhdDirName" -Filter *.vhd* | %{ 639 Optimize-VHD -Path $_.FullName -Mode Full 640 } 641 ` 642 643 var ps powershell.PowerShellCmd 644 err := ps.Run(script, expPath, vhdDir) 645 return err 646 } 647 648 func CopyExportedVirtualMachine(expPath string, outputPath string, vhdDir string, vmDir string) error { 649 650 var script = ` 651 param([string]$srcPath, [string]$dstPath, [string]$vhdDirName, [string]$vmDir) 652 Move-Item -Path $srcPath/*.* -Destination $dstPath 653 Move-Item -Path $srcPath/$vhdDirName -Destination $dstPath 654 Move-Item -Path $srcPath/$vmDir -Destination $dstPath 655 ` 656 657 var ps powershell.PowerShellCmd 658 err := ps.Run(script, expPath, outputPath, vhdDir, vmDir) 659 return err 660 } 661 662 func CreateVirtualSwitch(switchName string, switchType string) (bool, error) { 663 664 var script = ` 665 param([string]$switchName,[string]$switchType) 666 $switches = Hyper-V\Get-VMSwitch -Name $switchName -ErrorAction SilentlyContinue 667 if ($switches.Count -eq 0) { 668 Hyper-V\New-VMSwitch -Name $switchName -SwitchType $switchType 669 return $true 670 } 671 return $false 672 ` 673 674 var ps powershell.PowerShellCmd 675 cmdOut, err := ps.Output(script, switchName, switchType) 676 var created = strings.TrimSpace(cmdOut) == "True" 677 return created, err 678 } 679 680 func DeleteVirtualSwitch(switchName string) error { 681 682 var script = ` 683 param([string]$switchName) 684 $switch = Hyper-V\Get-VMSwitch -Name $switchName -ErrorAction SilentlyContinue 685 if ($switch -ne $null) { 686 $switch | Hyper-V\Remove-VMSwitch -Force -Confirm:$false 687 } 688 ` 689 690 var ps powershell.PowerShellCmd 691 err := ps.Run(script, switchName) 692 return err 693 } 694 695 func StartVirtualMachine(vmName string) error { 696 697 var script = ` 698 param([string]$vmName) 699 $vm = Hyper-V\Get-VM -Name $vmName -ErrorAction SilentlyContinue 700 if ($vm.State -eq [Microsoft.HyperV.PowerShell.VMState]::Off) { 701 Hyper-V\Start-VM -Name $vmName -Confirm:$false 702 } 703 ` 704 705 var ps powershell.PowerShellCmd 706 err := ps.Run(script, vmName) 707 return err 708 } 709 710 func RestartVirtualMachine(vmName string) error { 711 712 var script = ` 713 param([string]$vmName) 714 Hyper-V\Restart-VM $vmName -Force -Confirm:$false 715 ` 716 717 var ps powershell.PowerShellCmd 718 err := ps.Run(script, vmName) 719 return err 720 } 721 722 func StopVirtualMachine(vmName string) error { 723 724 var script = ` 725 param([string]$vmName) 726 $vm = Hyper-V\Get-VM -Name $vmName 727 if ($vm.State -eq [Microsoft.HyperV.PowerShell.VMState]::Running) { 728 Hyper-V\Stop-VM -VM $vm -Force -Confirm:$false 729 } 730 ` 731 732 var ps powershell.PowerShellCmd 733 err := ps.Run(script, vmName) 734 return err 735 } 736 737 func EnableVirtualMachineIntegrationService(vmName string, integrationServiceName string) error { 738 739 integrationServiceId := "" 740 switch integrationServiceName { 741 case "Time Synchronization": 742 integrationServiceId = "2497F4DE-E9FA-4204-80E4-4B75C46419C0" 743 case "Heartbeat": 744 integrationServiceId = "84EAAE65-2F2E-45F5-9BB5-0E857DC8EB47" 745 case "Key-Value Pair Exchange": 746 integrationServiceId = "2A34B1C2-FD73-4043-8A5B-DD2159BC743F" 747 case "Shutdown": 748 integrationServiceId = "9F8233AC-BE49-4C79-8EE3-E7E1985B2077" 749 case "VSS": 750 integrationServiceId = "5CED1297-4598-4915-A5FC-AD21BB4D02A4" 751 case "Guest Service Interface": 752 integrationServiceId = "6C09BB55-D683-4DA0-8931-C9BF705F6480" 753 default: 754 panic("unrecognized Integration Service Name") 755 } 756 757 var script = ` 758 param([string]$vmName,[string]$integrationServiceId) 759 Hyper-V\Get-VMIntegrationService -VmName $vmName | ?{$_.Id -match $integrationServiceId} | Hyper-V\Enable-VMIntegrationService 760 ` 761 762 var ps powershell.PowerShellCmd 763 err := ps.Run(script, vmName, integrationServiceId) 764 return err 765 } 766 767 func SetNetworkAdapterVlanId(switchName string, vlanId string) error { 768 769 var script = ` 770 param([string]$networkAdapterName,[string]$vlanId) 771 Hyper-V\Set-VMNetworkAdapterVlan -ManagementOS -VMNetworkAdapterName $networkAdapterName -Access -VlanId $vlanId 772 ` 773 774 var ps powershell.PowerShellCmd 775 err := ps.Run(script, switchName, vlanId) 776 return err 777 } 778 779 func SetVirtualMachineVlanId(vmName string, vlanId string) error { 780 781 var script = ` 782 param([string]$vmName,[string]$vlanId) 783 Hyper-V\Set-VMNetworkAdapterVlan -VMName $vmName -Access -VlanId $vlanId 784 ` 785 var ps powershell.PowerShellCmd 786 err := ps.Run(script, vmName, vlanId) 787 return err 788 } 789 790 func GetExternalOnlineVirtualSwitch() (string, error) { 791 792 var script = ` 793 $adapters = Get-NetAdapter -Physical -ErrorAction SilentlyContinue | Where-Object { $_.Status -eq 'Up' } | Sort-Object -Descending -Property Speed 794 foreach ($adapter in $adapters) { 795 $switch = Hyper-V\Get-VMSwitch -SwitchType External | Where-Object { $_.NetAdapterInterfaceDescription -eq $adapter.InterfaceDescription } 796 797 if ($switch -ne $null) { 798 $switch.Name 799 break 800 } 801 } 802 ` 803 804 var ps powershell.PowerShellCmd 805 cmdOut, err := ps.Output(script) 806 if err != nil { 807 return "", err 808 } 809 810 var switchName = strings.TrimSpace(cmdOut) 811 return switchName, nil 812 } 813 814 func CreateExternalVirtualSwitch(vmName string, switchName string) error { 815 816 var script = ` 817 param([string]$vmName,[string]$switchName) 818 $switch = $null 819 $names = @('ethernet','wi-fi','lan') 820 $adapters = foreach ($name in $names) { 821 Get-NetAdapter -Physical -Name $name -ErrorAction SilentlyContinue | where status -eq 'up' 822 } 823 824 foreach ($adapter in $adapters) { 825 $switch = Hyper-V\Get-VMSwitch -SwitchType External | where { $_.NetAdapterInterfaceDescription -eq $adapter.InterfaceDescription } 826 827 if ($switch -eq $null) { 828 $switch = Hyper-V\New-VMSwitch -Name $switchName -NetAdapterName $adapter.Name -AllowManagementOS $true -Notes 'Parent OS, VMs, WiFi' 829 } 830 831 if ($switch -ne $null) { 832 break 833 } 834 } 835 836 if($switch -ne $null) { 837 Hyper-V\Get-VMNetworkAdapter -VMName $vmName | Hyper-V\Connect-VMNetworkAdapter -VMSwitch $switch 838 } else { 839 Write-Error 'No internet adapters found' 840 } 841 ` 842 var ps powershell.PowerShellCmd 843 err := ps.Run(script, vmName, switchName) 844 return err 845 } 846 847 func GetVirtualMachineSwitchName(vmName string) (string, error) { 848 849 var script = ` 850 param([string]$vmName) 851 (Hyper-V\Get-VMNetworkAdapter -VMName $vmName).SwitchName 852 ` 853 854 var ps powershell.PowerShellCmd 855 cmdOut, err := ps.Output(script, vmName) 856 if err != nil { 857 return "", err 858 } 859 860 return strings.TrimSpace(cmdOut), nil 861 } 862 863 func ConnectVirtualMachineNetworkAdapterToSwitch(vmName string, switchName string) error { 864 865 var script = ` 866 param([string]$vmName,[string]$switchName) 867 Hyper-V\Get-VMNetworkAdapter -VMName $vmName | Hyper-V\Connect-VMNetworkAdapter -SwitchName $switchName 868 ` 869 870 var ps powershell.PowerShellCmd 871 err := ps.Run(script, vmName, switchName) 872 return err 873 } 874 875 func AddVirtualMachineHardDiskDrive(vmName string, vhdRoot string, vhdName string, vhdSizeBytes int64, controllerType string) error { 876 877 var script = ` 878 param([string]$vmName,[string]$vhdRoot, [string]$vhdName, [string]$vhdSizeInBytes, [string]$controllerType) 879 $vhdPath = Join-Path -Path $vhdRoot -ChildPath $vhdName 880 New-VHD $vhdPath -SizeBytes $vhdSizeInBytes 881 Hyper-V\Add-VMHardDiskDrive -VMName $vmName -path $vhdPath -controllerType $controllerType 882 ` 883 var ps powershell.PowerShellCmd 884 err := ps.Run(script, vmName, vhdRoot, vhdName, strconv.FormatInt(vhdSizeBytes, 10), controllerType) 885 return err 886 } 887 888 func UntagVirtualMachineNetworkAdapterVlan(vmName string, switchName string) error { 889 890 var script = ` 891 param([string]$vmName,[string]$switchName) 892 Hyper-V\Set-VMNetworkAdapterVlan -VMName $vmName -Untagged 893 Hyper-V\Set-VMNetworkAdapterVlan -ManagementOS -VMNetworkAdapterName $switchName -Untagged 894 ` 895 896 var ps powershell.PowerShellCmd 897 err := ps.Run(script, vmName, switchName) 898 return err 899 } 900 901 func IsRunning(vmName string) (bool, error) { 902 903 var script = ` 904 param([string]$vmName) 905 $vm = Hyper-V\Get-VM -Name $vmName -ErrorAction SilentlyContinue 906 $vm.State -eq [Microsoft.HyperV.PowerShell.VMState]::Running 907 ` 908 909 var ps powershell.PowerShellCmd 910 cmdOut, err := ps.Output(script, vmName) 911 912 if err != nil { 913 return false, err 914 } 915 916 var isRunning = strings.TrimSpace(cmdOut) == "True" 917 return isRunning, err 918 } 919 920 func IsOff(vmName string) (bool, error) { 921 922 var script = ` 923 param([string]$vmName) 924 $vm = Hyper-V\Get-VM -Name $vmName -ErrorAction SilentlyContinue 925 $vm.State -eq [Microsoft.HyperV.PowerShell.VMState]::Off 926 ` 927 928 var ps powershell.PowerShellCmd 929 cmdOut, err := ps.Output(script, vmName) 930 931 if err != nil { 932 return false, err 933 } 934 935 var isRunning = strings.TrimSpace(cmdOut) == "True" 936 return isRunning, err 937 } 938 939 func Uptime(vmName string) (uint64, error) { 940 941 var script = ` 942 param([string]$vmName) 943 $vm = Hyper-V\Get-VM -Name $vmName -ErrorAction SilentlyContinue 944 $vm.Uptime.TotalSeconds 945 ` 946 var ps powershell.PowerShellCmd 947 cmdOut, err := ps.Output(script, vmName) 948 949 if err != nil { 950 return 0, err 951 } 952 953 uptime, err := strconv.ParseUint(strings.TrimSpace(cmdOut), 10, 64) 954 955 return uptime, err 956 } 957 958 func Mac(vmName string) (string, error) { 959 var script = ` 960 param([string]$vmName, [int]$adapterIndex) 961 try { 962 $adapter = Hyper-V\Get-VMNetworkAdapter -VMName $vmName -ErrorAction SilentlyContinue 963 $mac = $adapter[$adapterIndex].MacAddress 964 if($mac -eq $null) { 965 return "" 966 } 967 } catch { 968 return "" 969 } 970 $mac 971 ` 972 973 var ps powershell.PowerShellCmd 974 cmdOut, err := ps.Output(script, vmName, "0") 975 976 return cmdOut, err 977 } 978 979 func IpAddress(mac string) (string, error) { 980 var script = ` 981 param([string]$mac, [int]$addressIndex) 982 try { 983 $ip = Hyper-V\Get-Vm | %{$_.NetworkAdapters} | ?{$_.MacAddress -eq $mac} | %{$_.IpAddresses[$addressIndex]} 984 985 if($ip -eq $null) { 986 return "" 987 } 988 } catch { 989 return "" 990 } 991 $ip 992 ` 993 994 var ps powershell.PowerShellCmd 995 cmdOut, err := ps.Output(script, mac, "0") 996 997 return cmdOut, err 998 } 999 1000 func TurnOff(vmName string) error { 1001 1002 var script = ` 1003 param([string]$vmName) 1004 $vm = Hyper-V\Get-VM -Name $vmName -ErrorAction SilentlyContinue 1005 if ($vm.State -eq [Microsoft.HyperV.PowerShell.VMState]::Running) { 1006 Hyper-V\Stop-VM -Name $vmName -TurnOff -Force -Confirm:$false 1007 } 1008 ` 1009 1010 var ps powershell.PowerShellCmd 1011 err := ps.Run(script, vmName) 1012 return err 1013 } 1014 1015 func ShutDown(vmName string) error { 1016 1017 var script = ` 1018 param([string]$vmName) 1019 $vm = Hyper-V\Get-VM -Name $vmName -ErrorAction SilentlyContinue 1020 if ($vm.State -eq [Microsoft.HyperV.PowerShell.VMState]::Running) { 1021 Hyper-V\Stop-VM -Name $vmName -Force -Confirm:$false 1022 } 1023 ` 1024 1025 var ps powershell.PowerShellCmd 1026 err := ps.Run(script, vmName) 1027 return err 1028 } 1029 1030 func TypeScanCodes(vmName string, scanCodes string) error { 1031 if len(scanCodes) == 0 { 1032 return nil 1033 } 1034 1035 var script = ` 1036 param([string]$vmName, [string]$scanCodes) 1037 #Requires -Version 3 1038 1039 function Hyper-V\Get-VMConsole 1040 { 1041 [CmdletBinding()] 1042 param ( 1043 [Parameter(Mandatory)] 1044 [string] $VMName 1045 ) 1046 1047 $ErrorActionPreference = "Stop" 1048 1049 $vm = Get-CimInstance -Namespace "root\virtualization\v2" -ClassName Msvm_ComputerSystem -ErrorAction Ignore -Verbose:$false | where ElementName -eq $VMName | select -first 1 1050 if ($vm -eq $null){ 1051 Write-Error ("VirtualMachine({0}) is not found!" -f $VMName) 1052 } 1053 1054 $vmKeyboard = $vm | Get-CimAssociatedInstance -ResultClassName "Msvm_Keyboard" -ErrorAction Ignore -Verbose:$false 1055 1056 if ($vmKeyboard -eq $null) { 1057 $vmKeyboard = Get-CimInstance -Namespace "root\virtualization\v2" -ClassName Msvm_Keyboard -ErrorAction Ignore -Verbose:$false | where SystemName -eq $vm.Name | select -first 1 1058 } 1059 1060 if ($vmKeyboard -eq $null) { 1061 $vmKeyboard = Get-CimInstance -Namespace "root\virtualization" -ClassName Msvm_Keyboard -ErrorAction Ignore -Verbose:$false | where SystemName -eq $vm.Name | select -first 1 1062 } 1063 1064 if ($vmKeyboard -eq $null){ 1065 Write-Error ("VirtualMachine({0}) keyboard class is not found!" -f $VMName) 1066 } 1067 1068 #TODO: It may be better using New-Module -AsCustomObject to return console object? 1069 1070 #Console object to return 1071 $console = [pscustomobject] @{ 1072 Msvm_ComputerSystem = $vm 1073 Msvm_Keyboard = $vmKeyboard 1074 } 1075 1076 #Need to import assembly to use System.Windows.Input.Key 1077 Add-Type -AssemblyName WindowsBase 1078 1079 #region Add Console Members 1080 $console | Add-Member -MemberType ScriptMethod -Name TypeText -Value { 1081 [OutputType([bool])] 1082 param ( 1083 [ValidateNotNullOrEmpty()] 1084 [Parameter(Mandatory)] 1085 [string] $AsciiText 1086 ) 1087 $result = $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "TypeText" -Arguments @{ asciiText = $AsciiText } 1088 return (0 -eq $result.ReturnValue) 1089 } 1090 1091 #Define method:TypeCtrlAltDel 1092 $console | Add-Member -MemberType ScriptMethod -Name TypeCtrlAltDel -Value { 1093 $result = $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "TypeCtrlAltDel" 1094 return (0 -eq $result.ReturnValue) 1095 } 1096 1097 #Define method:TypeKey 1098 $console | Add-Member -MemberType ScriptMethod -Name TypeKey -Value { 1099 [OutputType([bool])] 1100 param ( 1101 [Parameter(Mandatory)] 1102 [Windows.Input.Key] $Key, 1103 [Windows.Input.ModifierKeys] $ModifierKey = [Windows.Input.ModifierKeys]::None 1104 ) 1105 1106 $keyCode = [Windows.Input.KeyInterop]::VirtualKeyFromKey($Key) 1107 1108 switch ($ModifierKey) 1109 { 1110 ([Windows.Input.ModifierKeys]::Control){ $modifierKeyCode = [Windows.Input.KeyInterop]::VirtualKeyFromKey([Windows.Input.Key]::LeftCtrl)} 1111 ([Windows.Input.ModifierKeys]::Alt){ $modifierKeyCode = [Windows.Input.KeyInterop]::VirtualKeyFromKey([Windows.Input.Key]::LeftAlt)} 1112 ([Windows.Input.ModifierKeys]::Shift){ $modifierKeyCode = [Windows.Input.KeyInterop]::VirtualKeyFromKey([Windows.Input.Key]::LeftShift)} 1113 ([Windows.Input.ModifierKeys]::Windows){ $modifierKeyCode = [Windows.Input.KeyInterop]::VirtualKeyFromKey([Windows.Input.Key]::LWin)} 1114 } 1115 1116 if ($ModifierKey -eq [Windows.Input.ModifierKeys]::None) 1117 { 1118 $result = $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "TypeKey" -Arguments @{ keyCode = $keyCode } 1119 } 1120 else 1121 { 1122 $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "PressKey" -Arguments @{ keyCode = $modifierKeyCode } 1123 $result = $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "TypeKey" -Arguments @{ keyCode = $keyCode } 1124 $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "ReleaseKey" -Arguments @{ keyCode = $modifierKeyCode } 1125 } 1126 $result = return (0 -eq $result.ReturnValue) 1127 } 1128 1129 #Define method:Scancodes 1130 $console | Add-Member -MemberType ScriptMethod -Name TypeScancodes -Value { 1131 [OutputType([bool])] 1132 param ( 1133 [Parameter(Mandatory)] 1134 [byte[]] $ScanCodes 1135 ) 1136 $result = $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "TypeScancodes" -Arguments @{ ScanCodes = $ScanCodes } 1137 return (0 -eq $result.ReturnValue) 1138 } 1139 1140 #Define method:ExecCommand 1141 $console | Add-Member -MemberType ScriptMethod -Name ExecCommand -Value { 1142 param ( 1143 [Parameter(Mandatory)] 1144 [string] $Command 1145 ) 1146 if ([String]::IsNullOrEmpty($Command)){ 1147 return 1148 } 1149 1150 $console.TypeText($Command) > $null 1151 $console.TypeKey([Windows.Input.Key]::Enter) > $null 1152 #sleep -Milliseconds 100 1153 } 1154 1155 #Define method:Dispose 1156 $console | Add-Member -MemberType ScriptMethod -Name Dispose -Value { 1157 $this.Msvm_ComputerSystem.Dispose() 1158 $this.Msvm_Keyboard.Dispose() 1159 } 1160 1161 1162 #endregion 1163 1164 return $console 1165 } 1166 1167 $vmConsole = Hyper-V\Get-VMConsole -VMName $vmName 1168 $scanCodesToSend = '' 1169 $scanCodes.Split(' ') | %{ 1170 $scanCode = $_ 1171 1172 if ($scanCode.StartsWith('wait')){ 1173 $timeToWait = $scanCode.Substring(4) 1174 if (!$timeToWait){ 1175 $timeToWait = "1" 1176 } 1177 1178 if ($scanCodesToSend){ 1179 $scanCodesToSendByteArray = [byte[]]@($scanCodesToSend.Split(' ') | %{"0x$_"}) 1180 1181 $scanCodesToSendByteArray | %{ 1182 $vmConsole.TypeScancodes($_) 1183 } 1184 } 1185 1186 write-host "Special code <wait> found, will sleep $timeToWait second(s) at this point." 1187 Start-Sleep -s $timeToWait 1188 1189 $scanCodesToSend = '' 1190 } else { 1191 if ($scanCodesToSend){ 1192 write-host "Sending special code '$scanCodesToSend' '$scanCode'" 1193 $scanCodesToSend = "$scanCodesToSend $scanCode" 1194 } else { 1195 write-host "Sending char '$scanCode'" 1196 $scanCodesToSend = "$scanCode" 1197 } 1198 } 1199 } 1200 if ($scanCodesToSend){ 1201 $scanCodesToSendByteArray = [byte[]]@($scanCodesToSend.Split(' ') | %{"0x$_"}) 1202 1203 $scanCodesToSendByteArray | %{ 1204 $vmConsole.TypeScancodes($_) 1205 } 1206 } 1207 ` 1208 1209 var ps powershell.PowerShellCmd 1210 err := ps.Run(script, vmName, scanCodes) 1211 return err 1212 }