使用PowerShell自动化Telnet

时间:2010-04-13 23:58:04

标签: powershell automation

如何编写PowerShell脚本来自动执行这组命令?

  • Telnet到一台机器,
  • 执行一些命令,
  • 分析telnet窗口中的输出
  • 基于该输出,发送更多命令

6 个答案:

答案 0 :(得分:3)

好的,这不是最优雅的解决方案,它确实依赖于 不寒而栗 VBscript,但在这里它... ...

创建一个VBScript以实际加快telnet会话,这是一个例子

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

然后使用Powershell调用该脚本并将其传递给您想要执行的命令,在下面的示例中,这些命令存储在名为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;

那应该做你要问的......

注意:不是我的解决方案,从this blog post找到,我已经使用了一两次。

答案 1 :(得分:2)

我不会对这里的套接字做任何事情,因为你需要实现至少部分telnet规范。如果我记得那个规格有点搞笑。但是这里列出了一些.NET telnet实现:C# Telnet Library你可以直接从powershell改编或使用,就像Goyuix在他的答案中使用套接字代码一样。

答案 2 :(得分:1)

不要尝试自动化telnet可执行文件,只需创建套接字并发出命令,读取它们,然后根据它做出决定。以下是连接到本地Web服务器的简化示例:

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()
}

显然,您需要从端口80更改它,并传递用户名/密码而不是Web请求标头...但这应该足以让您入门。

答案 3 :(得分:0)

我创建了一个powershell脚本来从单个主机telnet多个商店,并且可以选择捕获或不捕获tracert和ping命令

telnet多个主机并捕获tracert和ping命令的命令

    #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

请注意:TelnetMultipleHost.bat此批处理用于运行powershell命令

确保我们在同一目录中有bat,ps1文件

批处理文件的代码:

@echo off Powershell.exe -executionpolicy remotesigned -File。\ TelnetMultipleHost.ps1 暂停

答案 4 :(得分:0)

我建议您使用TeraTerm这个免费软件。 您可以远程登录到您的计算机,然后运行TTL脚本。 它非常强大且可靠。我每天都在工作中使用它。 如果您有兴趣,可以进行更多搜索。 TTL脚本示例:

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

答案 5 :(得分:0)

这是PowerShell中非常基本的Telnet客户端。它实质上只是.net Framework的TcpClient,带有一些额外的代码来拒绝任何IAC命令(即,与服务器协商其功能时,它对所有请求都说“我不/不愿意这样做”),以确保基本的NVT实施都可以使用。)

代码在此处维护: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()
        }
    }
}

以下是在普通脚本会话中如何使用它的示例:

# 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
}

但是,如果您想以交互方式运行它,只需在要将命令推送到服务器时调用SendCommand,然后调用GetOutput即可查看结果。例如您可以一次将每一行打到下面。

$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