I am constantly amazed at the number of new use cases that can now be enabled with some of the new and updated capabilities of our vSphere Platform. I recently discovered a new vSphere API that was introduced in vSphere 6.5 called PutUsbScanCodes() which may sound a little strange but it enables some really slick Automation capabilities. This feature allows customers to send keyboard character keystrokes directly to a VM regardless of the underlying OS. In fact, the OS does not even have to be booted up for this to work which means there is no reliance on VMware Tools as this is happening at the Virtual Hardware layer.
You might ask, why would this be interesting? Lets take a look at a scenario that I had ran into years ago when I was a customer and why this feature would have really helped. At the time, there were several Virtual Appliance solutions that I needed to deploy, although I could automate the deployment, I could not automate the initial setup process. The reason for this is that before the OS is fully booted up, it required the user to interactively provide password on boot which can only be done using the VM Console. This meant solutions like the Guest Operations API was out of the question since VMware Tools is not running during this time. I suspect many of you have probably came across a similiar situation, where you are prompted for a password or some other manual input was required and the only solution is to be in front of the VM Console. Some other interesting use cases that this feature could help with are OS installations where automated deployments may not be possible due to the type of OS, automated filesystem check (fsck) or verification where manual intervention was the only option. The possibilities for this API is truly endless and I am sure there are many many more use cases where this feature could be used.
OK, so now that are you sold on the feature, lets take a look at how it works! I have built a PowerCLI script called VMKeystrokes.ps1 which demonstrates the use of this vSphere API.
The API takes in an array of scan code events or what is referred to as USB Human Interface Device (HID) Codes which is part of the USB specification for human interactions with a computer system. There was not any details on what exactly this even looked like, so it took me awhile to figure out the input and what the API was expecting. I found this online reference here which provided a mapping of keyboard keys to their respective scan codes which I have implemented a subset of the scan codes within my script. However, upon further inspection, these scan codes could not be used as-is and required a conversion to the appropriate HID format which can be seen in my code. There also a modifier type within the API that can be associated with a given scan code. One use for this is to send an upper-case character rather than a lower case.
Lets now go through a demonstration to see how the Set-VMKeystrokes function works. In my environment, I have a PhotonOS VM running and I want to automate the login via the console which means I want to pass in the username (root), hit return, pass in the password (VMware1!) and hit return.
Here is are the two commands you would provide after retrieving the name of the VM:
Set-VMKeystrokes -VMName $VM -StringInput "root" -ReturnCarriage $true
Set-VMKeystrokes -VMName $VM -StringInput "VMware1!" -ReturnCarriage $true
If now head over to our VM and open up the VM Console, we should see that both the username and password was submitted and we have just automated the login via the console! How cool is that!?
The function also supports a -DebugOn boolean option in case you want to see or debug which characters are being sent to VM along with their respective HID Code (Hex) and their converted HID Code Value (int).
Below is an example of running the same workflow as above but debugging turned on:
Set-VMKeystrokes -VMName $VM -StringInput "root" -DebugOn $true
Set-VMKeystrokes -VMName $VM -StringInput "VMware1!" -ReturnCarriage $true -DebugOn $true
From a security standpoint, this might sound like a scary feature but users do need to have the proper privilege on a given VM to use this capability. Today, this is defined by the VirtualMachine.Interact.ConsoleInteract privilege. There is a more granular privilege for this feature called VirtualMachine.Interact.PutUsbScanCodes as the previous also controls whether you can interact within the VM Console. However, this more granular privilege currently has a bug which I have already reported where it is not doing what it states. Hopefully this should be resolve in a future update and you can truly lock down this feature if have such a requirement.
In addition, from an auditing standpoint, this API does generate the appropriate vCenter Event and this can be seen both in the UI (screenshot below) as well as API. In general, this operation is no different than someone having access to the VM Console and providing input to the VM, this is merely automating that aspect of it.
Hopefully you can see all the awesome and cool potential of this API! One other neat thing you could do is combine this API with the Screenshot feature that is also available as part of the vSphere API and using Optical Character Recognition or OCR as its known to do some interesting auto-remediation. Take for example, if a Windows VM crashes (BSOD) or Linux VM kernel panics, you could process the output and instead of just reporting on it, you could take some additional action 🙂
UPDATE (12/18/18) - For those interested, here is a govc (using vSphere SDK for Go) implementation for sending VM Keystrokes contributed by James King.
UPDATE (10/03/17) - The following snippet below demonstrates how to send CTRL+ALT+DEL combination which simply sending in the delete character (0x63) per HID Codes along with the two modifiers (CTRL and ALT) as outline in the vSphere API.
$vm = Get-View -ViewType VirtualMachine -Filter @{"Name"="DUMMY"} $hidCodesEvents = @() $tmp = New-Object VMware.Vim.UsbScanCodeSpecKeyEvent $modifer = New-Object Vmware.Vim.UsbScanCodeSpecModifierType $modifer.LeftAlt = $true $modifer.LeftControl = $true $modifer.LeftShift = $true $tmp.Modifiers = $modifer $hidCodeHexToInt = [Convert]::ToInt64('0x63',"16") $hidCodeValue = ($hidCodeHexToInt -shl 16) -bor 0007 $tmp.UsbHidCode = $hidCodeValue $hidCodesEvents+=$tmp $spec = New-Object Vmware.Vim.UsbScanCodeSpec $spec.KeyEvents = $hidCodesEvents $result = $vm.PutUsbScanCodes($spec)
Matko says
Awesome. It seems it's available since vSphere 6.0.
Lee says
Wow this introduces so many possibilities! Thanks for a great writeup.
Matko says
The method is available in vCenter Server 6.0.2 Plugin for vRO, but it's not working ("Unable to resolve WSDL method name PutUsbScanCodes"). So yeah, not available in vCenter Server 6.0. :/
William Lam says
As the vSphere API Reference (which is the bible for vSphere APIs), states this was only introduced in vSphere 6.5. Per the error, this makes sense as the underlying WSDL in 6.0 wouldn't know about this API. The vRO Plugin looks to have a bug 🙂
JB says
Thanks a lot ! This is a lifesaver to type passwords in console with non-US keyboards. 🙂
LB says
Thanks William! Very helpful! Is there a way to ready responses from console? We are automating a product installation and need to read prompts instead of synchronizing it using timeouts.
LB says
Sorry, it should say: "Is there a way to read responses from console?"
William Lam says
There is not, as mentioned in the blog post, you could use the vSphere Screenshot API & OCR to process console output
joe says
This is great stuff, thank you very much for sharing.
Do you by any chance also know if it's possible or not to utilize the mouse functions (e.g. right click, left click, move mouse) in a similar manner? e.g. do you know if the vsphere api supports that or not? if not, is there perhaps any other programmatical way to instruct the hypervisor itself to send mouse instructions to a VM, like you can via a console window in the regular [GUI] vsphere.
Arnout says
Epic!! Thanks for sharing. Amazing how little information there is on this subject.
I wrote a PowerCLI script to enter a bitlocker password, thus creating my own "network" unlock.
Ajay says
Thanks for this article, it's really great.
I'm trying to access PSC /vCenter. This function working when we are in command line page. Is there any way to send alt+f1 from this Keystroke Function to switch my slide from GUI to commandline.
Danni says
Hi there,
Maybe I'm a bit slow here but can you please provide details on how and where you run this script?
I can't understand how you connect to the VM or vSphere.
Michael F. says
Getting this error:
Exception calling "PutUsbScanCodes" with "1" argument(s): "Cannot complete the operation due to an incorrect request
to the server."
At C:\Users\user\Desktop\VMKeystrokes.ps1:160 char:5
+ $results = $vm.PutUsbScanCodes($spec)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : VimException
Danni says
I had the exact same error and it was due to the VM not being on an ESXi blade that was version 6.5. After migrating it to one, it worked.
Hutch says
Do you think it would be difficult to port this into an Ansible Module?
Khord says
What's the difference between using the bitwise OR with 0007 and just adding 7 in your script for the characters vs the enter key conversion? are they interchangeable? Line 130 vs 148
TheNewStellW says
Hey William,
I'm not sure if anyone else has done it, but I've rewritten this in JavaScript for others to use in vRealize Orchestrator: https://www.funkycloudmedina.com/2018/09/sending-vm-keystrokes-using-vrealize-orchestrator/
Preeti Nayak says
how do i use this script?Do i need to copy the VMkeystroke.ps1 script and run the command?
I tried to copy this script and run .\VMkeystroke.ps1 and then tried to run the command "Set-VMKeystrokes -VMName $VM -StringInput "root" -DebugOn $true"
Looks like the command Set-VMKetstrokes is showing as unrecognized cmdlet command..
Can you help me how to make use of this API?
I am using Vsphere Esxi6.5 version
raphael schitz (@hypervisor_fr) says
You just saved me from typing 64 chars password in VMRC William, thanks a LOT!
steve88 says
Can I run this script from any machine? I am getting error
Set-VMKeystrokes -VMName $VM -StringInput "root" -ReturnCarriage $true
Set-VMKeystrokes : The term 'Set-VMKeystrokes' is not recognized as the name of a cmdlet, function, script file, or operable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:1
+ Set-VMKeystrokes -VMName $VM -StringInput "root" -ReturnCarriage $tru ...
Ryan Mullins says
I know this is an old article, but is there a way to simulate a key hold for X seconds? Such as hold SHIFT during boot to get the isolinux boot menu.
James K says
Most say hold shift but if you do a for loop and spam the shift key, you'll likely get into the same menu .
James K says
Just an FYI: I implemented this in govc (vSphere CLI tool) to fix this issue: https://github.com/vmware/govmomi/issues/1224
AT-OHMS says
Here with Python :
https://github.com/at-ohms/VMKey
Joe says
Don't you need to pass credentials someplace and/or use Connect-VIServer $targetvcenter -Credential $creds?
I don't see where you are using credentials to pass in.
Joe says
Anyone have experience with arrow down or pressing tab keys?
Joe says
I simply defined ¢ (alt-155) as arrow down and τ (alt-231) as tab. Works great
krish says
can you elaborate more?
Joe says
Anyone know of a way to grab the screen to see what is there? Sending commands and then waiting certain amount of seconds is purely guess work.
Joe says
Sorry for being chatty. Anyone figure out how to send ctrl-alt-delete in yet?
Brent says
Here's a function to do a Control-Alt-Delete. It basically the same as William's sample code, although his has a leftShift key in it as well which doesn't work for us
Function Send-CtrlAltDel {
param(
[Parameter(Mandatory = $true)][String]$VMName
)
$vm = Get-View -ViewType VirtualMachine -Filter @{"Name" = "^$($VMName)$" }
$hidCodesEvents = @()
$tmp = New-Object VMware.Vim.UsbScanCodeSpecKeyEvent
$modifer = New-Object Vmware.Vim.UsbScanCodeSpecModifierType
$modifer.LeftAlt = $true
$modifer.LeftControl = $true
$tmp.Modifiers = $modifer
$hidCodeHexToInt = [Convert]::ToInt64('0x63',"16")
$hidCodeValue = ($hidCodeHexToInt -shl 16) -bor 0007
$tmp.UsbHidCode = $hidCodeValue
$hidCodesEvents+=$tmp
$spec = New-Object Vmware.Vim.UsbScanCodeSpec
$spec.KeyEvents = $hidCodesEvents
Write-Host "Sending Ctrl-Al-Del to $VMName ...`n"
$result = $vm.PutUsbScanCodes($spec)
}
yaniv yungerman says
is there a java API for set-vmstrokes?
hjrr says
Very interesting. I am looking for a way to automate a re-scan of the storage HBA, before auto-starting a 2nd VM. Any ideas? Can i do this inside VCenter/Esxi Host? running a cluster.
matthewit2 says
So awesome! Thank you for all that you do for the community
skarcos says
I made a silly GUI for this, built on top of https://github.com/Bigouden/VMKey
It's... https://github.com/skarcos/imbrian
Wish I could add mouse support 🙁
Deepak Jangra says
How Can I send the alt+tab to the VM? Please suggest...
William Lam says
Did you read the blog post in detail? Hint: Take a look inside of the script for required keys & updated text on 10/03 🙂
Razvan says
Trying to run this fails with the following error:
Exception calling "PutUsbScanCodes" with "1" argument(s): "Permission to perform this operation was denied."
Razvan says
Looks like it's a lack of priviledges on my user:
Privilege check failed for user some_user_name for missing permission VirtualMachine.Interact.PutUsbScanCodes. Session user performing the check:
Tobias Heyl says
Hey William & folks!
Imagine a huge vSphere environment with loads of VMs and some careless admins that left VMRC sessions open and workstations might not get locked.
It would be terrific if one used this script to send non-intrusive keystrokes like ← or → in order to (re-)activate VM Desktops and actually be able to grab the vSphere thumbnail of that VM.
That way an HTML styled output could be generated easily helping to identify VMs that currently sit in the inventory unlocked. Now where the first part is now easy to handle with the possibility to send keystrokes, how about getting a thumbnail image from each VM object?
William Lam says
See https://williamlam.com/2023/01/automating-virtual-machine-screenshots-in-vsphere.html