Sending Text To BMC (iDRAC, XClarity, iLO, Etc) Remote Consoles
Posted on May 29, 2022
- and tagged as
- javascript,
- powershell
I wasn’t planning on writing a post on this but after spending far too long looking for a simple solution I figured it was worth sharing. Plus I haven’t blogged in a while so this is what you get 😀.
The problem
You’re connected to the remote console using Dell iDRAC, Lenovo XClarity, HP iLO, or whatever flavour of BMC you happen to use. A login prompt is on the screen that doesn’t allow text to be pasted and the BMC doesn’t have a Paste as keystrokes function.
The password you need to enter is 30+ random characters. This is fine if you only need to do it once but often there are multiple servers or multiple reboots and logins required.
Let’s get the TL;DR out of the way as there’s a bit more to unpack towards the end.
Sending keys into iDRAC, XClarity, or iLO with PowerShell
PowerShell combined with WScript can target a specific window and send key presses into that Window. Cool. Here’s the code.
function Send-KeysToBMC {
[CmdletBinding()]
Param (
[Parameter(Mandatory=$false)]
[SecureString]$Text,
[Parameter(Mandatory)]
[ValidateSet("iDRAC","XClarity","IMM","iLO")]
[string]$BMCType
)
$WindowTitle = switch ($BMCType) {
"iDRAC" {"FPS"; break}
"XClarity" {"XClarity"; break}
"IMM" {"HTML5"; break}
"iLO" {"iLO"; break}
}
$Window = Get-Process | Select -ExpandProperty MainWindowTitle | ? {$_ -match $WindowTitle}
if ($null -eq $WindowTitle) {Write-Error "Unable to locate window"}
if ($null -eq $Text) {$Text = Read-Host -AsSecureString -Prompt "Enter Text"}
$WShell = New-Object -ComObject wscript.shell
$Result = $WShell.AppActivate($Window)
if ($Result -eq $True) {
Sleep 1
$WShell.SendKeys((New-Object PSCredential "user",$Text).GetNetworkCredential().Password)
} else {
Write-Host "Unable to find target window - keys not sent"
}
}
Let’s skim over what this does. The user provides the BMCType
during invocation and we use that to assign a string to the $WindowTitle
variable. Our code needs to know the title of the window that contains the remote console. Some are obvious, others like IMM title the remote console window “HTML5 Viewer”.
These could change with different versions so you may need to update the code to suit your needs. Just look at the window title and pick an appropriate string for matching.
We then create the WSHell
object, change the focus to the remote console window, and finally use the SendKeys
method to send the keystrokes.
The MainWindowTitle
property can be a little iffy with Chrome (the only browser I tested with). For consistent results it helps to make sure that the remote console is the last window you had selected prior to switching to the PowerShell prompt.
Here’s an example how the code works with Dell iDRAC and a baremetal Windows server.
A note on security
The function offers a parameter for the user to supply the text as a SecureString
or via Read-Host
where again the input is treated as a SecureString
. The default PSReadLine module saves text typed into the terminal in the ConsoleHost_history.txt file so we want to avoid pasting in anything sensitive as it could end up being stored in plaintext in the history file.
Lenovo XClarity bug
Lenovo XClarity has a bug that causes the Shift key to get stuck down when Shift and Caps Lock are pressed together. Now I don’t know how exactly the SendKeys
method works under the hood, but whatever it does it seems to trigger the bug consistently.
Here is the Lenovo KB: Shift and CapsLock keys not functioning as expected when using XCC remote console on ThinkSystems - Lenovo ThinkAgile and Lenovo ThinkSystem
It was meant to be fixed in Q3 2020 but it looks like it never got done or wasn’t implemented well.
This is what it looks like when we try to inject text into the XClarity console. We’re going to be using the string abc123Xabc123
. Notice what happens after the X
.
The issue persists if manually typing into the console after the injection. You need to either refresh the page or use the fix in the Lenovo support article.
Sadly I began this whole exercise testing with XClarity and didn’t find out about the bug until well after most of my hair had been ripped out.
Can we use JavaScript instead?
JavaScript gives us one advantage in that we don’t need to leave the browser to run PowerShell. Our code could be created as an extension and would make the workflow that much smoother.
The best option I found for using Javascript is to dispatch a KeyboardEvent.
We can send a single key with the following code:
window.dispatchEvent(new KeyboardEvent('keydown', {keyCode: 65}));
Let’s see it in action.
What is the keyCode
? It’s the JavaScript representation of the character we want to send, but it’s deprecated and not particularly recommended for our use case as it doesn’t work well for characters requiring Shift
(uppercase, symbols, etc).
There’s also a keypress
event, but this is also deprecated and I could not make it work.
Lastly, I could only make the KeyboardEvent
method work in XClarity, I could not get it to trigger in iDRAC.
Can we use the existing BMC JavaScript?
This is another avenue I very briefly explored - remote consoles usually have a virtual keyboard available and there could be existing code we could tap into, maybe a function used by an EventListener
or something similar.
The main issue is that we would need to write code per BMC implementation and keep up with any code changes on the vendor side.
Oh, and the Lenovo Virtual Keyboard code is ~9000 lines of this:
So while a JavaScript solution would be a cleaner option I’m going to leave it for now - I may revisit it in the future if I ever get that bored.
The PowerShell method works well and I can stick it in my sync’d profile to ensure I have it available wherever I need it.