编写 SSH 脚本以重启 GrandStream 手机

Scripting SSH to reboot GrandStream phones

我在网络上使用数百个可通过 SSH 访问的独立设备。我在这里使用 GrandStream GXP2200 phone 作为示例,因为它最容易解释。

我们的 GrandStream GXP2200 phones 可以通过 SSH 访问,您可以通过 SSH 执行基本功能,例如重启或升级固件。使用 Putty 远程重启 phone 很容易;只需键入用户和密码,键入重启命令,按 y,然后回车。 phone 将尽职尽责地重新启动。

我需要能够编写脚本。理想情况下,我的脚本是一个批处理文件,每个设备一行,即

plink -t admin@172.27.4.0 -pw <password> -m commands.txt

plink -t admin@172.27.4.1 -pw <password> -m commands.txt

...等等

我可以有一个用于固件升级、重新启动或更改特定设置的脚本,然后能够将它部署到许多设备上。看起来这应该很容易,尤其是使用 Plink 之类的东西。我在 Windows 上有很多经验,但在 Linux 上没有那么多。我真的很想在 Windows 上完成此操作,但我不反对在需要时启动 Ubuntu 虚拟机。我已经阅读了使用 expect 脚本和 bash 脚本的示例,并且我已经阅读了有关管道字符串并将 unicode 字符代码放入文本文件并以各种方式重定向的信息......但是我试过的都不起作用。

主要问题是无法发送完成命令所需的击键。例如,当通过 SSH 将重启命令发送到 phone 时,它会询问您是否真的要重启,如果是,请按 y,然后输入。在 commands.txt 中,如果需要,我可以逐行列出一堆命令。但是,如果它们中的任何一个需要用户交互,它就会卡住。例如,当 phone 收到 reboot 命令时,它会提示您先按 y,然后再按 Enter。据我所知,Plink 无法发送这些击键,因为它正在等待 reboot 命令完成,然后再从 commands.txt.

发送下一行

第二个问题是,由于这些独立的网络设备相当简单,内置命令(如reboot)不支持选项,如/y。事实上,这些 phone 在检测到有效命令后完全停止解析来自终端的输入。例如,如果我使用 Putty 登录并键入我的命令,但在末尾添加了一堆随机垃圾,例如 rebootlkq2jq3pyjq 并按回车键,它的效果与我只键入 reboot 相同。

我可以用来远程重启 phones 的唯一方法是手动登录到 Web 界面并单击重启按钮。我可以弄清楚 HTML 但当涉及到 PHP 或 Java 或任何网络界面正在使用的内容时,我迷路了。我希望能够在 Web 界面上使用该按钮的代码。

TLDR:如何在通过脚本化 SSH 连接发送 reboot 命令后发送 yEnter?互联网上有很多人在寻找这个问题的解决方案。

:: 编辑 ::

看来我在这种情况下的最佳选择是 expect。它似乎是为解决这类问题而设计的。不幸的是,Windows 的 expect 是个笑话。

  1. 好的文档是不存在的。它要么太高级,要么太简单,要么不完整,要么过时。
  2. 有些下载或版本不包含所有需要的文件。
  3. tcl 无法找到 ssh (C:\Windows\System32\OpenSSH\ssh.exe),即使我可以在这台机器上的任何命令提示符下键入 ssh 并且它工作正常并且我已经添加了我的 tcl 我的用户 Path 和系统 Path 环境变量的路径并重新启动。
  4. tcl/expect 看起来它想与 plink 一起工作(它不会抱怨找不到文件),但无论我选择什么试试,它总是说 The request is not supported. 我试过的最后一个命令是 spawn plink -ssh 172.27.4.0,它返回 The request is not supported.

所以是的,我会尝试 Ubuntu。我会根据结果在编辑或答案中写下我的结果。

目标:使用自动脚本通过 SSH 远程重启网络设备。

解决方案:在Linux机器上使用expect脚本。

工作脚本:

#!/usr/bin/expect -f

set pass "password"
log_user 1

send_user "...... BEGIN EXPECT SCRIPT ......\n"

foreach arg $argv {

        send_user "\nStarting on $arg\n"
        spawn ssh -oKexAlgorithms=+diffie-hellman-group1-sha1 -oStrictHostKeyChecking=no admin@$arg
        
        expect {
            "assword: " {
                send -- "$pass\r"
                send_user "PASSWORD SENT\n"
            }
        }

        expect {
            ">" {
                send -- "reboot\r"
                send_user "REBOOT COMMAND SENT\n"
            }
                
            "denied" {
                send_user "\nBAD PASSWORD\n"
                continue
            }
        }

        expect {
            "continue" {
                send -- "y\r"
                send_user " Y KEYSTROKE SENT\n"
                sleep 2
            }

            "Rebooting..." {
                send_user "\nY NOT REQUIRED\n"
            }
            
            "Connection refused" {
                send_user "\nBROKEN CONNECTION ON $arg\n"
            }
        }

    send_user "Done with $arg\n.................................\n"

}

send_user "\n......  END EXPECT SCRIPT  ......\n"

exit

在 Ubuntu 上使用 expect 运行 感觉是最适合我的情况的解决方案。我今天花了大约 4 个小时试图让 expect 在 Windows 上工作(我非常不成功)。因此,我没有使用 Windows,而是启动了一个 Ubuntu 20 服务器虚拟机,安装了 expectsudo apt install expect,使用 autoexpect 生成了一个脚本,编辑了该脚本,我已经在不到 1 小时的时间内获得了一个可用的脚本模板。我在 Linux 版本中没有看到任何奇怪的环境问题或语法问题。我的 Linux-foo 不是很强大,但我很快就弄明白了。

我计划将其扩展到不仅用于重新启动,而且还用于在 IP 电话主机、网络交换机、网络摄像机和可能的一些 Linux 服务器上编写脚本设置更改。