9

How can I write a PowerShell script to automate this set of commands?

  • Telnet to a machine,
  • execute few commands,
  • analyze at the output in the telnet window,
  • based on that output, send few more commands
p.campbell
  • 98,673
  • 67
  • 256
  • 322
Guru Je
  • 91
  • 1
  • 1
  • 2
  • what's the server side? unix? osx? windows+telnetd? powershell v1 or v2? can you install stuff on the remote side? the client side? – x0n Apr 14 '10 at 01:20
  • powershell v2. I am writing the powershell script on a windows machine. Remote side can be, linux, windows. I can't install new stuff on the remote site – Guru Je Apr 14 '10 at 17:05

7 Answers7

5

Ok this isn't the most elegant solution, and it does rely on shudder VBscript but here it goes...

Create a VBScript to actually expedite the telnet session, this is an example

set oShell = CreateObject("WScript.Shell")
oShell.run("Telnet")
WScript.Sleep 1000
oShell.SendKeys("Open 127.0.0.1 23")
WScript.Sleep 1000
oShell.SendKeys("{Enter}")
WScript.Sleep 1000
oShell.SendKeys("n")
WScript.Sleep 1000
oShell.SendKeys("{Enter}")
WScript.Sleep 1000
oShell.SendKeys"MyName"
WScript.Sleep 1000
oShell.SendKeys("{Enter}")
WScript.Sleep 1000
oShell.SendKeys("MyPassword")
WScript.Sleep 1000
oShell.SendKeys("{Enter}")
WScript.Sleep 1000
oShell.SendKeys("MyCommand")
WScript.Sleep 1000
oShell.SendKeys("{Enter}")
WScript.Sleep 1000

Then use Powershell to invoke that script and pass it the commands you want executing, in the example below these commands are stored in a file called CommandList.txt

function Connect-MyTelnet{
Param(
 [string] $IPAddress,
 [string] $Port,
 [string] $UserName,
 [string] $Password,
 [string] $cmdlistPath
)
    ## - Setting default values:
    if($port -eq $null){ $Port = "23"; };
    if($cmdlistPath -eq $null) { $CmdlistPath = 'c:\temp\cmdlist.txt'; };

    ## create vbscript file: MyTelnetSession.vbs
    ## - For Microsoft Telnet:
    $MyVBScript = @"
                   set oShell = CreateObject("WScript.Shell")`r`n
                   oShell.run("Telnet")`r`n
                   WScript.Sleep 1000`r`n
                   oShell.SendKeys("Open $IPAddress $Port")`r`n
                   WScript.Sleep 1000`r`n
                   oShell.SendKeys("{Enter}")`r`n
                   WScript.Sleep 1000`r`n
                   oShell.SendKeys("n")`r`n
                   WScript.Sleep 1000`r`n
                   oShell.SendKeys("{Enter}")`r`n
                   WScript.Sleep 1000`r`n
                   oShell.SendKeys("$UserName")`r`n
                   WScript.Sleep 1000`r`n
                   oShell.SendKeys("{Enter}")`r`n
                   WScript.Sleep 1000`r`n
                   oShell.SendKeys("$Password")`r`n
                   WScript.Sleep 1000`r`n
                   oShell.SendKeys("{Enter}")`r`n
                   WScript.Sleep 1000`r`n
                 "@;

    ## - Get file with telnet commands:
    [array] $Cmdlist = Get-Content $cmdlistPath;

    ## loop through and build each telnet command line:
    foreach($cmd in $cmdlist)
    {
        ## - Build VBscript lines:
        $MyVBScript += 'oShell.SendKeys("'+$cmd+'")'+"`r`n";
        $MyVBScript += "WScript.Sleep 1000`r`n";
        $MyVBScript += 'oShell.SendKeys("{Enter}")'+"`r`n";
        $MyVBScript += 'WScript.Sleep 1000'+"`r`n";
    }

    ## - Close Telnet Session:
        $MyVBScript += 'oShell.SendKeys("  QUIT")'+"`r`n";
        $MyVBScript += "WScript.Sleep 1000`r`n";
        $MyVBScript += 'oShell.SendKeys("{Enter}")'+"`r`n";
        $MyVBScript += 'WScript.Sleep 1000'+"`r`n";

    ## - Save and execute generated VBscript:
    $MYVBScript | Out-File -FilePath c:\temp\MyTelnet.vbs -Encoding ASCII;
    & c:\temp\MyTelnet.vbs
}; Set-Alias ct Connect-MyTelnet;

And that should do what you are asking...

Note: Not my solution, found from this blog post and I have made use of it once or twice.

RAGNO
  • 507
  • 12
  • 20
3

Rather than try to automate a telnet executable, just create the socket and issue the commands, read them back, and make decisions based on that. Here is an oversimplified example connecting to my local web server:

function test() {
  $msg = [System.Text.Encoding]::ASCII.GetBytes("GET / HTTP/1.0`r`nHost: localhost`r`n`r`n")
  $c = New-Object System.Net.Sockets.TcpClient("localhost", 80)
  $str = $c.GetStream()
  $str.Write($msg, 0, $msg.Length)
  $buf = New-Object System.Byte[] 4096
  $count = $str.Read($buf, 0, 4096)
  [System.Text.Encoding]::ASCII.GetString($buf, 0, $count)
  $str.Close()
  $c.Close()
}

Obviously you would need to change it from port 80, and pass a username/password instead of a web request header... but this should be enough to get you started.

Goyuix
  • 23,614
  • 14
  • 84
  • 128
  • Thanks for the sample. I am very new to powershell. I tried few things based to the above code but things didn't work, but I must be missing something. Here what I tring to do. telnet portnum // wait until the screen says BIOS START "esc crtl [" if I can do the above, rest of the script becomes quite easy. Again thanks for the input, I'll keep trying based on the above example. – Guru Je Apr 14 '10 at 21:02
  • wait, you're trying to telnet into a remote machine to capture the boot sequence?! tell me I'm wrong... – x0n Apr 14 '10 at 22:15
  • no, telnet captures the output of a development board through a serial port on the remote machine. I have anthor telnet session into the remote machine to send commands to the development board. So the idea is to capture the output from the first telnet session, figureout what is the state of the development board, send more commands to the development board through the second telnet window. – Guru Je Apr 15 '10 at 16:16
2

I wouldn't do anything with sockets here because you are going to need to implement at least parts of the telnet spec. If I remember, that spec is a bit funny. But there are some .NET telnet implementations listed here: C# Telnet Library that you can probably adapt or use directly from powershell in the same way that Goyuix is using the socket code in his answer.

Community
  • 1
  • 1
jeffesp
  • 337
  • 1
  • 13
1

I suggest you to use TeraTerm this free software. you can telnet to your machine, and then run a TTL script. it is very powerful and reliable. I am using it every day for my work. you can do more search if you are interested. example of TTL script:

i = 100
do while i>0
    sendln 'un 1357'
    wait '>'
    sendln '.w 4 42800024 0000000a'
    wait '>'
    sendln '.w 4 42800014 00000004'
    wait 'in service'
    sendln 'info'
    wait'>'
    sendln 'start'
    wait '20'#13#10'>' '0'#13#10'>'
    if result!=2 then 
        break
    endif
    i = i - 1
loop
Urosh T.
  • 3,336
  • 5
  • 34
  • 42
Leo Zhao
  • 11
  • 1
1

Here's a very basic Telnet client in PowerShell. It's essentially just the .net Framework's TcpClient, with some extra code to reject any IAC commands (i.e. when negotiating its abilities with the server it just says "I don't/won't do that" to all requests, ensuring that the most basic NVT implementation can be used).

Code maintained here: https://gist.github.com/JohnLBevan/e28fbb6c0dfdd45a21e03c104999c212

Function New-TelnetClient {
    [CmdletBinding()]
    Param (
        [Parameter()]
        [string]$ComputerName = '127.0.0.1'
        ,
        [Parameter()]
        [int]$PortNo = 23
        ,
        [Parameter()]
        [System.Text.Encoding]$Encoding = [System.Text.Encoding]::ASCII
        ,
        [Parameter()]
        [int]$BufferSize = 1024
    )
    [System.Net.Sockets.TcpClient]$telnet = New-Object 'System.Net.Sockets.TcpClient'
    try {
        $telnet.PSTypeNames.Add('ClearChannel.Net.Sockets.TelnetClient')
        $telnet | Add-Member -MemberType 'NoteProperty' -Name 'Encoding' -Value ($Encoding)
        $telnet | Add-Member -MemberType 'NoteProperty' -Name 'EndOfCommand' -Value ([System.Environment]::NewLine)
        $telnet | Add-Member -MemberType 'NoteProperty' -Name 'BufferSize' -Value ($BufferSize)
        $telnet.Connect($ComputerName, $PortNo)
        $telnet | Add-Member -MemberType 'NoteProperty' -Name 'Writer'      -Value (New-Object -TypeName 'System.IO.StreamWriter' -ArgumentList ($telnet.GetStream()))
        $telnet.Writer.AutoFlush = $true
        $telnet | Add-Member -MemberType 'ScriptMethod' -Name 'SendCommand' -Value ({
            Param([string]$CommandText)
            #$this.Writer.WriteLine($CommandText + $this.EndOfCommand) #writeline should stick the line endings in place anyway, but just to be sure, added this
            $this.Writer.WriteLine($CommandText)
            (New-Object -TypeName 'PSObject' -Property @{Direction='Input'; Value=$CommandText; When=((Get-Date).ToUniversalTime())})
        })
        $telnet | Add-Member -MemberType 'ScriptMethod' -Name 'HandleIac' -Value ({
            if ($this.Available) {
                [int]$byte = $this.GetStream().ReadByte()
                [byte]$defaultResponse = 254 # for most IAC requests, we'll respond with don't
                switch ($byte) {
                    -1 { # end of stream (shouldn't happen, but handled in case)
                        Write-Warning 'Unexpected end of stream whilst processing IAC'
                        return
                    }
                    255 { # Escaped IAC character
                        Write-Debug 'IAC Escaped'
                        return $byte
                    }
                    253 { #if we get a DO, change default response to WON'T instead of DON'T
                        $defaultResponse = 252
                        # do not break; continue to next case statement
                    }
                    {(251, 252, 253, 254) -contains $_} { # Will, Won't, Do, Don't
                        $byte = $this.GetStream().ReadByte() # this is the option we need to respond to; currently we just deny all options to get a raw NVT
                        switch ($byte) {
                            -1 {
                                Write-Warning 'Unexpected end of stream whilst processing IAC'
                            }
                            # if we want to handle specific IAC codes we can add support here
                            default {
                                $this.GetStream().WriteByte(255)              # IAC
                                $this.GetStream().WriteByte($defaultResponse) # Don't/Won't
                                $this.GetStream().WriteByte($byte)            # whatever you told me
                            }
                        }
                        return
                    }
                    default {
                        Write-Warning "$byte is not a control character, but was received after an IAC character"
                    }

                }
            }
        })
        $telnet | Add-Member -MemberType 'ScriptMethod' -Name 'GetBytes'   -Value ({
            Start-Sleep -Milliseconds 500 #added to get correct output; otherwise we seem to fly past the handshake :/
            while ($this.Available -gt 0) {
                [int]$byte = $this.GetStream().ReadByte() #held as int to allow -1 status code for end of stream
                switch ($byte) {
                    -1 { # end of stream
                        return
                    }
                    255 { #IAC control character received
                        Write-Verbose 'IAC Command Received'
                        $this.HandleIac()
                        break
                    }
                    {($_ -ge 0) -and ($_ -lt 255)} { # normal data (not sure if it's worth returning the 0s... haven't seen anything to suggest that they're special though, as -1 is the eof.
                        [byte]$byte
                        Write-Debug "found $byte"
                        break
                    }
                    default {
                        throw "Received value $_ when expecting a byte (0-255)"
                    }

                }
            }
        })
        $telnet | Add-Member -MemberType 'ScriptMethod' -Name 'GetOutput'   -Value ({
            [byte[]]$bytes = $this.GetBytes()
            if (($null -ne $bytes) -and ($bytes.Length -gt 0)) {
                Write-Verbose "raw output is $(($bytes | %{"$_"}) -join ', ')"
                $this.Encoding.GetString($bytes)
            } else {
                write-verbose 'no output this time'
            }
        })
        $telnet | Add-Member -MemberType 'ScriptMethod' -Name 'ReceiveThenSendCommands' -Value ({
            Param([string[]]$Commands)
            foreach ($commandText in $commands) {
                $this.GetOutput()
                $this.SendCommand($commandText)
            }
            $this.GetOutput()
        })
        if ($telnet.Connected) {
            $telnet
        } else {
            throw 'Failed to connect'
        }
    } catch {
        Remove-TelnetClient -TelnetClient $telnet
    }
}

Function Remove-TelnetClient {
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory = $true)]
        [AllowNull()]
        [PSObject]$TelnetClient
    )
    if ($null -ne $TelnetClient) {
        if ($TelnetClient.Connected) {
            $TelnetClient.GetStream().Close()
            $TelnetClient.Close()
        }
        if($TelnetClient.Dispose) {
            $TelnetClient.Dispose()
        }
    }
}

Here's an example of how it would be used in a normal scripted session:

# Example Usage

$telnet = New-TelnetClient -ComputerName 'TelnetServerNameFqdnOrIp'
try {
    $telnet.ReceiveThenSendCommands(@(
        'myTelnetUsername'
        'myPlaintextTelnetPassword'
        'DIR' #or whatever command I want to run
    )) | Format-List # show the output in a readable format, including when it contains new line characters
} finally {
    Remove-TelnetClient $telnet
}

But if you wanted to run it in interactive mode, just call SendCommand when you want to push commands to the server, and GetOutput to see results; e.g. you can run each line below one at a time.

$telnet = New-TelnetClient -ComputerName 'TelnetServerNameFqdnOrIp'
$telnet.GetOutput() # will probably display a welcome message & logon prompt
$telnet.SendCommand('myUsername') # send your username
$telnet.GetOutput() # will probably echo back your username then prompt for a password
$telnet.SendCommand('myPassword') # send your password
$telnet.GetOutput() # unlikely to output anything for a valid password; will give an error for an invalid one
$telnet.SendCommand('DIR') # send whatever commands you want to run
$telnet.GetOutput() # get the output of those commands
Remove-TelnetClient $telnet # once you're done, cleanly closes down the client
JohnLBevan
  • 22,735
  • 13
  • 96
  • 178
0

I have created a powershell script to telnet multiple stores from single host and has options to capture or no capture the tracert and ping command

Command to telnet multiple host and capture tracert and ping command

    #Mutlple Telneting guide

    #Created by : Mohit

    #How to use ? 
    #Step 1 : Add mutiple IPs in DestinationIP.csv 
    #Step 2 : Run Batch file TelnetMultipleHost.bat

    ####################################################################################################################
    $DestinationIP= Get-Content .\DestinationIP.csv
    $ipV4 = (Test-Connection -ComputerName (hostname) -Count 1).IPV4Address.IPAddressToString
    ####################################################################################################################

    write-host "-------------------Welcome to Multiple Telnet Host Panel-------------------------"
    write-host ""
    write-host ""
    write-host "IMPORTANT: Make sure you are running this tool from source IP which in this case is " $ipV4
    write-host ""
    $Ports = Read-Host -Prompt "Enter Destination Port No.(# for multple ports just seperate ports with ,)"
    write-host ""
    write-host "Port No. you entered:" $Ports
    write-host ""
    write-host "Select Option"
    write-host ""
    write-host "Type 1 for telnet Host WITH trace logs"
    write-host "Type 2 for telnet Host WITHOUT trace logs"
    write-host ""
    $option =Read-Host -Prompt "Type here"
    write-host ""
    Start-Transcript -Path .\TraceLogs_$ipV4.txt


    switch($option)
    {
    #Type 1 for telnet Host WITH trace logs
    1{
      foreach ($Destination in $DestinationIP) 
      {
            foreach ($Port in $Ports) {

                    # Create a Net.Sockets.TcpClient object to use for      # checking for open TCP ports.
                    $Socket = New-Object Net.Sockets.TcpClient
                    # Suppress error messages
                    $ErrorActionPreference = 'SilentlyContinue'
                    # Try to connect
                    $Socket.Connect($Destination, $Port)
                    # Make error messages visible again
                    $ErrorActionPreference = 'Continue'
                    # Determine if we are connected.
                    if ($Socket.Connected) {
                        "${Destination}: Port $Port is open"
                        $Socket.Close()
                    }
                    else {
                        "${Destination}: Port $Port is closed or filtered"

                        if (test-connection $Destination -count 1 -quiet) {
                                     write-host $Destination "Ping succeeded." -foreground green

                            } else {
                                     write-host $Destination "Ping failed." -foreground red
                                }

                        Test-NetConnection $Destination -TraceRoute

                    }
                    # Apparently resetting the variable between iterations is necessary.
                    $Socket = $null
           }
        }
    }
    # Type 2 for telnet Host WITHOUT trace logs
    2{
    foreach ($Destination in $DestinationIP) {
        foreach ($Port in $Ports) {

            # Create a Net.Sockets.TcpClient object to use for
            # checking for open TCP ports.
            $Socket = New-Object Net.Sockets.TcpClient

            # Suppress error messages
            $ErrorActionPreference = 'SilentlyContinue'

            # Try to connect
            $Socket.Connect($Destination, $Port)

            # Make error messages visible again
            $ErrorActionPreference = 'Continue'

            # Determine if we are connected.
            if ($Socket.Connected) {
                "${Destination}: Port $Port is open"
                $Socket.Close()
            }
            else {
                "${Destination}: Port $Port is closed or filtered"

                 }
            # Apparently resetting the variable between iterations is necessary.
            $Socket = $null
        }
     } 
    }
    }
    Stop-Transcript

Please note: TelnetMultipleHost.bat this batch is used to run the powershell command

Make sure we have bat, ps1 file in same directory

Code for batch file:

@echo off Powershell.exe -executionpolicy remotesigned -File .\TelnetMultipleHost.ps1 pause

0

i use below script for telnet to multiple ip's:

$server_list = @('1.1.1.1:443', '10.100.8.22:3389', '10.100.8.21:22')
Foreach ($t in $server_list)
{
  $source = $t.Split(':')[0]
  $port = $t.Split(':')[1]
  Write-Host "Connecting to $source on port $port" | Out-File 'output.txt' -Append
  try
  {
    $socket = New-Object System.Net.Sockets.TcpClient($source, $port)
  }
  catch [Exception]
  {
    Write-Host $_.Exception.GetType().FullName | Out-File 'output.txt' -Append
    Write-Host $_.Exception.Message | Out-File 'output.txt' -Append
  }
  Write-Host "Connected`n" | Out-File 'output.txt' -Append
}


when you are connected to ip's script show you you are connected to