13

I have batch file for telnet a server automatically, I want to do the same thing with PowerShell

Batch File named Script.bat :

:: Open a Telnet window
 start telnet.exe 10.84.10.85
:: Run the script
 cscript SendKeys.vbs

Command File named SendKeys.vbs :

set OBJECT=WScript.CreateObject("WScript.Shell")
 WScript.sleep 1000
 OBJECT.SendKeys "myPassword{ENTER}"
 WScript.sleep 1000
 OBJECT.SendKeys "7{ENTER}"
 WScript.sleep 1000
 OBJECT.SendKeys "1{ENTER}"
 WScript.sleep 1000
 OBJECT.SendKeys "{ENTER}"
 WScript.sleep 1000
 OBJECT.SendKeys "{ENTER}"
 WScript.sleep 1000
 OBJECT.SendKeys "Y{ENTER}"
 WScript.sleep 3000
 OBJECT.SendKeys ""
6
  • 2
    start-process path\telnet.exe -argumentlist 10.84.10.85 to start telnet, $obj = New-Object -com Wscript.Shell to create the object, $obj.SendKeys("x") to send the keys, sleep -ms 1000to sleep
    – SimonS
    Sep 13, 2017 at 12:44
  • that's what I'm looking for exact !! merci :)
    – yazan
    Sep 13, 2017 at 13:41
  • @SimonS please make an aswer from your comment.
    – JosefZ
    Sep 13, 2017 at 16:10
  • 1
    Just chiming into what others give you. Avoid COM at all costs, unless there is no other choice. Use the offered up .Net namespace as your default. This [void] [System.Reflection.Assembly]::LoadWithPartialName("'System.Windows.Forms"), in PowerShell is really legacy stuff. The current way is via the Add-Type cmdlet. Add-Type -AssemblyName Microsoft.VisualBasic, PresentationCore. SendKeys has gotcha's, so, really look at stuff like AutoIT and Selenium for this kind of thing.
    – postanote
    May 29, 2021 at 4:13
  • 1
    @not2qubit - It's all about how SendKeys work. Its performance is directly impacted by the environment in which it is executed. Just because it runs as expected on your machine or another, does not mean in will perform as expected on other systems. There are many articles on the topic. 'why sendkeys is problematic'
    – postanote
    May 20, 2023 at 9:21

4 Answers 4

25

PowerShell has no built-in functionality to emulate keystrokes.

Practically, you have two options: COM-Automation and Interop.

  1. SendKeys via COM

Like in VB(S) you can create a Shell-Object and SendKeys. Here is the PowerShell way to do it.

$wshell = New-Object -ComObject wscript.shell;
$wshell.SendKeys('a')

If you would like to send a keystroke to a window, you have to activate it first:

$wshell = New-Object -ComObject wscript.shell;
$wshell.AppActivate('title of the application window')
Sleep 1
$wshell.SendKeys('~')

Some keystrokes have special variables like ~ for RETURN. Here is a complete list.
After activating a window it's often necessary to wait a second until it becomes responsive, otherwise it'll send the key to the PowerShell window, or to nowhere. The scripting Host's SendKeys method can be unreliable, but luckily there is a better approach.

  1. SendKeys via Interop

Like in C#, you can use the SendWait method from the .NET Framework in PowerShell.

[void] [System.Reflection.Assembly]::LoadWithPartialName("'System.Windows.Forms")
[System.Windows.Forms.SendKeys]::SendWait("x")

If you want to activate a window, it can be done like this:

[void] [System.Reflection.Assembly]::LoadWithPartialName("'Microsoft.VisualBasic")
[Microsoft.VisualBasic.Interaction]::AppActivate("Internet Explorer - Windows")

To Sleep, you can use the Start-Sleep Cmdlet.

Regarding your original problem, I would suggest the following solution:

# Open a Telnet window
Start-Process telnet.exe -ArgumentList 10.84.10.85
# Run the keystrokes
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.SendKeys]::SendWait('myPassword{ENTER}')
Start-Sleep 1
[System.Windows.Forms.SendKeys]::SendWait('7{ENTER}')
Start-Sleep 1
[System.Windows.Forms.SendKeys]::SendWait('1{ENTER}')
Start-Sleep 1
[System.Windows.Forms.SendKeys]::SendWait('{ENTER}')
Start-Sleep 1
[System.Windows.Forms.SendKeys]::SendWait('{ENTER}')
Start-Sleep 1
[System.Windows.Forms.SendKeys]::SendWait('Y{ENTER}')
Start-Sleep 1
[System.Windows.Forms.SendKeys]::SendWait('')

WARNING: Be extra careful if you're using this method to send a password because activating a different window between invoking AppActivate and invoking SendKeys will cause the password to be sent to that different window in plain text (e.g. your favorite messenger)!

2
  • 1
    "PowerShell has no built-in functionality to emulate keystrokes." - just import Windows-DLLs and call API? Dec 8, 2022 at 9:54
  • @TheincredibleJan This seems to be still true. powershellgallery.com also has no suitable Cmdlet to send keystrokes.
    – wp78de
    Dec 8, 2022 at 16:58
3
function Do-SendKeys {
    param (
        $SENDKEYS,
        $WINDOWTITLE
    )
    $wshell = New-Object -ComObject wscript.shell;
    IF ($WINDOWTITLE) {$wshell.AppActivate($WINDOWTITLE)}
    Sleep 1
    IF ($SENDKEYS) {$wshell.SendKeys($SENDKEYS)}
}
Do-SendKeys -WINDOWTITLE Print -SENDKEYS '{TAB}{TAB}'
Do-SendKeys -WINDOWTITLE Print
Do-SendKeys -SENDKEYS '%{f4}'
1
  • Short, simple, versatile -- for those systems where $wshell.SendKeys works. See wp78de answer for the Interop alternative. Sep 17, 2021 at 0:54
1

I did some of modification in the script, I have a list of IP server which have the same password and I want to telnet the list automatically and sendKey for deactivate or activate the FTP server .

my script is :

  ## - List of IP
  $printers = get-content "C:\Dir2\servers.txt"

  foreach ($IPAddress in $printers){

   ## - Start Telnet Session:
     start-process C:\Windows\System32\telnet.exe -argumentlist $IPAddress

   ## - SendKey for each IP
     $obj = New-Object -com Wscript.Shell
     sleep -s 3
     $obj.SendKeys("MyPassword{ENTER}")
     sleep -s 3
     $obj.SendKeys("7{ENTER}")
     sleep -s 3
     $obj.SendKeys("1{ENTER}")
     sleep -s 3
     $obj.SendKeys("{ENTER}")
     sleep -s 3
     $obj.SendKeys("{ENTER}")
     sleep -s 3
     $obj.SendKeys("Y{ENTER}")
     sleep -s 3
     $obj.SendKeys("{ENTER}")
     sleep -s 3
     }
0

Here's a function that will run SendKeys and clean up the COM object when it's done. It's not perfect, but it works.

The -Delay parameter gives you some time to switch focus to another application before it sends the keys.

function Send-Keystrokes ([string] $Keys, [int] $Delay = 0)
{
    try
    {
        Start-Sleep -Seconds $Delay
        $wshell = New-Object -ComObject WScript.Shell
        $wshell.SendKeys($Keys)
        Start-Sleep -Seconds 1
    }
    finally
    {
        try
        {
            [System.Runtime.InteropServices.Marshal]::ReleaseComObject([System.__ComObject]$wshell) | Out-Null
            [System.GC]::Collect()
            [System.GC]::WaitForPendingFinalizers()
        }
        catch { }
    }
}
1
  • The cleanup isn't necessary. When .NET GC's a wrapped COM object, it will call Release. In PS, calling Remove-Variable is adequate.
    – McGuireV10
    Nov 27, 2023 at 16:04

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .