Skip to content

Instantly share code, notes, and snippets.

@altrive
Created January 13, 2014 10:52
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save altrive/8398265 to your computer and use it in GitHub Desktop.
Save altrive/8398265 to your computer and use it in GitHub Desktop.
Sample code to handle Hyper-V VM keyboard via CIM namespace "root\virtualization\v2"

Limitation

  • Sleep delay needed between each commands.
  • Keyboard handlng don't work in Hyper-V 2012 R2 Extended Session mode.

Sample Usage

$configuration = @'
#!/bin/sh

#Initialize configurations
load /opt/vyatta/etc/config.boot.default
set system login user vyatta authentication plaintext-password vyatta
commit

#NIC Interface Settings 
set interfaces ethernet eth0 address dhcp
set interfaces ethernet eth1 address 172.16.255.254/16

#NAT Settings
#set nat source rule 10
set nat source rule 10 outbound-interface eth0
set nat source rule 10 source address 0.0.0.0/0
set nat source rule 10 translation address masquerade

#DNS Service Settings
set service dns forwarding dhcp eth0
set service dns forwarding listen-on eth1

#DHCP Service Settings
set service dhcp-server shared-network-name ETH1_POOL subnet 172.16.0.0/16 start 172.16.100.0 stop 172.16.199.255
set service dhcp-server shared-network-name ETH1_POOL subnet 172.16.0.0/16 default-router 172.16.255.254
set service dhcp-server shared-network-name ETH1_POOL subnet 172.16.0.0/16 dns-server 172.16.255.254

#set service dhcp-server shared-network-name ETH1_POOL subnet 172.16.0.0/16 static-mapping hostAD ip-address 172.16.0.1
#set service dhcp-server shared-network-name ETH1_POOL subnet 172.16.0.0/16 static-mapping hostAD mac-address 00-15-5D-00-66-0B

#NTP Settings
delete system ntp
set system ntp server ntp.jst.mfeed.ad.jp
set system time-zone Asia/Tokyo

#Network configuration tuning(IPv4 ARP table size/IPv6 NDP table size/NAT session count)
#set system ip arp table-size 8192
#set system ipv6 neighbor table-size 8192 
#set system conntrack expect-table-size 2048
#set system conntrack hash-size 16384
#set system conntrack table-size 1048576

#Commit & Save configurations
commit

#Persist setting to floppy disk
mkdir /media/floppy/config -p
save /media/floppy/config/config.boot
'@

Restart-VM Vyatta -Force
sleep 40

$console = Get-VMConsole Vyatta

#Login
$console.ExecCommand("vyatta") > $null
sleep 1
$console.ExecCommand("vyatta") > $null
sleep 1

#Execute scripts
$sr = New-Object IO.StringReader($configuration)

Write-Verbose ("Open text editor: nano" -f $line) -Verbose
$console.ExecCommand("nano") > $null
sleep 1

Write-Verbose ("Write text to editor") -Verbose
while (($line = $sr.ReadLine()) -ne $null)
{
    $console.ExecCommand($line) > $null
    sleep -Milliseconds 200
}
sleep 1

Write-Verbose ("Save text to file: {0}" -f "tmp/configure.sh") -Verbose
$console.TypeKey([Windows.Input.Key]::O, [Windows.Input.ModifierKeys]::Control) > $null
sleep -Milliseconds 500
$console.ExecCommand("/tmp/configure.sh")
sleep -Milliseconds 500
$console.TypeKey([Windows.Input.Key]::X, [Windows.Input.ModifierKeys]::Control) > $null
sleep -Milliseconds 500

Write-Verbose ("Execute script: {0}" -f "tmp/configure.sh") -Verbose

#Enter configure mode
$console.ExecCommand("configure") > $null
sleep -Milliseconds 500
$console.ExecCommand(". /tmp/configure.sh") > $null
sleep 15
$console.ExecCommand("exit") > $null
sleep -Milliseconds 500
$console.ExecCommand("reboot now") > $null
#Requires -Version 3
#Requires -RunAsAdministrator
function Get-VMConsole
{
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[string] $VMName
)
$ErrorActionPreference = "Stop"
$vm = Get-CimInstance -ComputerName localhost -Namespace "root\virtualization\v2" -ClassName Msvm_ComputerSystem -ErrorAction Ignore -Verbose:$false | where ElementName -eq $VMName | select -first 1
if ($vm -eq $null){
Write-Error ("VirtualMachine({0}) is not found!" -f $VMName)
}
$vmKeyboard = $vm | Get-CimAssociatedInstance -ResultClassName "Msvm_Keyboard" -ErrorAction Ignore -Verbose:$false
if ($vmKeyboard -eq $null){
Write-Error ("VirtualMachine({0}) keyboard class is not found!" -f $VMName)
}
#TODO: It may be better using New-Module -AsCustomObject to return console object?
#Console object to return
$console = [pscustomobject] @{
Msvm_ComputerSystem = $vm
Msvm_Keyboard = $vmKeyboard
}
#Need to import assembly to use System.Windows.Input.Key
Add-Type -AssemblyName WindowsBase
#region Add Console Members
$console | Add-Member -MemberType ScriptMethod -Name TypeText -Value {
[OutputType([bool])]
param (
[ValidateNotNullOrEmpty()]
[Parameter(Mandatory)]
[string] $AsciiText
)
$result = $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "TypeText" -Arguments @{ asciiText = $AsciiText }
return (0 -eq $result.ReturnValue)
}
#Define method:TypeCtrlAltDel
$console | Add-Member -MemberType ScriptMethod -Name TypeCtrlAltDel -Value {
$result = $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "TypeCtrlAltDel"
return (0 -eq $result.ReturnValue)
}
#Define method:TypeKey
$console | Add-Member -MemberType ScriptMethod -Name TypeKey -Value {
[OutputType([bool])]
param (
[Parameter(Mandatory)]
[Windows.Input.Key] $Key,
[Windows.Input.ModifierKeys] $ModifierKey = [Windows.Input.ModifierKeys]::None
)
$keyCode = [Windows.Input.KeyInterop]::VirtualKeyFromKey($Key)
switch ($ModifierKey)
{
([Windows.Input.ModifierKeys]::Control){ $modifierKeyCode = [Windows.Input.KeyInterop]::VirtualKeyFromKey([Windows.Input.Key]::LeftCtrl)}
([Windows.Input.ModifierKeys]::Alt){ $modifierKeyCode = [Windows.Input.KeyInterop]::VirtualKeyFromKey([Windows.Input.Key]::LeftAlt)}
([Windows.Input.ModifierKeys]::Shift){ $modifierKeyCode = [Windows.Input.KeyInterop]::VirtualKeyFromKey([Windows.Input.Key]::LeftShift)}
([Windows.Input.ModifierKeys]::Windows){ $modifierKeyCode = [Windows.Input.KeyInterop]::VirtualKeyFromKey([Windows.Input.Key]::LWin)}
}
if ($ModifierKey -eq [Windows.Input.ModifierKeys]::None)
{
$result = $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "TypeKey" -Arguments @{ keyCode = $keyCode }
}
else
{
$this.Msvm_Keyboard | Invoke-CimMethod -MethodName "PressKey" -Arguments @{ keyCode = $modifierKeyCode }
$result = $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "TypeKey" -Arguments @{ keyCode = $keyCode }
$this.Msvm_Keyboard | Invoke-CimMethod -MethodName "ReleaseKey" -Arguments @{ keyCode = $modifierKeyCode }
}
$result = return (0 -eq $result.ReturnValue)
}
#Define method:Scancodes
$console | Add-Member -MemberType ScriptMethod -Name Scancodes -Value {
[OutputType([bool])]
param (
[Parameter(Mandatory)]
[byte[]] $ScanCodes
)
$result = $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "Scancodes" -Arguments @{ ScanCodes = $ScanCodes }
return (0 -eq $result.ReturnValue)
}
#Define method:ExecCommand
$console | Add-Member -MemberType ScriptMethod -Name ExecCommand -Value {
param (
[Parameter(Mandatory)]
[string] $Command
)
if ([String]::IsNullOrEmpty($Command)){
return
}
$console.TypeText($Command) > $null
$console.TypeKey([Windows.Input.Key]::Enter) > $null
#sleep -Milliseconds 100
}
#Define method:Dispose
$console | Add-Member -MemberType ScriptMethod -Name Dispose -Value {
$this.Msvm_ComputerSystem.Dispose()
$this.Msvm_Keyboard.Dispose()
}
#endregion
return $console
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment