编写 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
命令后发送 y
和 Enter
?互联网上有很多人在寻找这个问题的解决方案。
:: 编辑 ::
看来我在这种情况下的最佳选择是 expect
。它似乎是为解决这类问题而设计的。不幸的是,Windows 的 expect
是个笑话。
- 好的文档是不存在的。它要么太高级,要么太简单,要么不完整,要么过时。
- 有些下载或版本不包含所有需要的文件。
tcl
无法找到 ssh (C:\Windows\System32\OpenSSH\ssh.exe
),即使我可以在这台机器上的任何命令提示符下键入 ssh
并且它工作正常并且我已经添加了我的 tcl
我的用户 Path
和系统 Path
环境变量的路径并重新启动。
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 服务器虚拟机,安装了 expect
和 sudo apt install expect
,使用 autoexpect
生成了一个脚本,编辑了该脚本,我已经在不到 1 小时的时间内获得了一个可用的脚本模板。我在 Linux 版本中没有看到任何奇怪的环境问题或语法问题。我的 Linux-foo 不是很强大,但我很快就弄明白了。
我计划将其扩展到不仅用于重新启动,而且还用于在 IP 电话主机、网络交换机、网络摄像机和可能的一些 Linux 服务器上编写脚本设置更改。
我在网络上使用数百个可通过 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
命令后发送 y
和 Enter
?互联网上有很多人在寻找这个问题的解决方案。
:: 编辑 ::
看来我在这种情况下的最佳选择是 expect
。它似乎是为解决这类问题而设计的。不幸的是,Windows 的 expect
是个笑话。
- 好的文档是不存在的。它要么太高级,要么太简单,要么不完整,要么过时。
- 有些下载或版本不包含所有需要的文件。
tcl
无法找到 ssh (C:\Windows\System32\OpenSSH\ssh.exe
),即使我可以在这台机器上的任何命令提示符下键入ssh
并且它工作正常并且我已经添加了我的tcl
我的用户Path
和系统Path
环境变量的路径并重新启动。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 服务器虚拟机,安装了 expect
和 sudo apt install expect
,使用 autoexpect
生成了一个脚本,编辑了该脚本,我已经在不到 1 小时的时间内获得了一个可用的脚本模板。我在 Linux 版本中没有看到任何奇怪的环境问题或语法问题。我的 Linux-foo 不是很强大,但我很快就弄明白了。
我计划将其扩展到不仅用于重新启动,而且还用于在 IP 电话主机、网络交换机、网络摄像机和可能的一些 Linux 服务器上编写脚本设置更改。