Excel VBA调用PLink实现SSH/Telnet:解决单命令登录延迟或维持会话执行多查询问题
Excel VBA调用PLink实现SSH/Telnet:解决单命令登录延迟或维持会话执行多查询问题
我太懂你这种痛苦了——每次跑命令都要重新建立SSH连接,光握手、验证就占了4秒,成千上万次下来不仅耗时惊人,还把电脑卡得没法用。下面针对你的问题逐一给出解决方案:
一、用PLink解决延迟问题:必须复用会话!
完全可以避免这个延迟!你当前的核心问题是每次执行命令都新建一个SSH连接,登录、密钥验证这些固定开销占了绝大多数时间。只要复用同一个SSH会话,后续命令的执行速度会快到几乎可以忽略。
二、维持会话批量执行命令的具体实现
这里给你两种可行的方法,第一种是基于你现有代码的轻量化修改,第二种是进阶方案:
方法1:用WshShell交互模式维持PLink会话
这种方式不需要额外依赖,直接用你已经在使用的Windows Script Host对象就能实现。核心思路是:
- 先启动一个PLink交互进程(不附加命令参数,让它进入远程SSH shell)
- 通过
StdIn发送命令,通过StdOut读取输出 - 识别远程主机的提示符(比如
user@linuxbox:~$)来判断命令是否执行完成
修改后的VBA代码示例
首先在模块顶部声明全局变量,避免会话进程被意外销毁:
Option Explicit Private oShell As WshShell Private oExec As WshExec Private strPrompt As String ' 远程主机的命令提示符,比如 "user@yourbox:~$ " ' 初始化SSH会话(只需要执行一次) Sub InitSSHConnection() Dim plinkPath As String Dim sshUser As String Dim sshHost As String Dim sshPassword As String ' 替换成你的实际参数 plinkPath = "C:\Tools\plink.exe" ' PLink的安装路径 sshUser = "your_username" sshHost = "10.10.10.10" sshPassword = "your_password" strPrompt = sshUser & "@yourbox:~$ " ' 登录后看到的命令行提示符 ' 启动PLink交互会话(不要加命令参数,进入远程shell) Dim cmd As String cmd = """" & plinkPath & """ -ssh " & sshUser & "@" & sshHost & " -pw " & sshPassword Set oShell = New WshShell Set oExec = oShell.Exec(cmd) ' 等待会话建立,跳过登录输出直到出现提示符 Dim output As String Do While InStr(output, strPrompt) = 0 Do While oExec.StdOut.AtEndOfStream = False output = output & oExec.StdOut.ReadAll Loop DoEvents ' 避免Excel假死,让电脑可以正常操作 Loop Debug.Print "SSH会话已成功建立!" End Sub ' 发送单个命令并返回清理后的结果 Function SendSSHCommand(strCmd As String) As String If oExec Is Nothing Then MsgBox "请先运行InitSSHConnection初始化会话!", vbExclamation Exit Function End If ' 发送命令(加换行符模拟回车键) oExec.StdIn.WriteLine strCmd ' 读取输出直到再次出现提示符(说明命令执行完成) Dim output As String output = "" Do While InStr(output, strPrompt) = 0 Do While oExec.StdOut.AtEndOfStream = False output = output & oExec.StdOut.ReadAll Loop DoEvents Loop ' 清理输出:去掉命令本身、提示符和多余换行 SendSSHCommand = CleanRawOutput(output, strCmd) End Function ' 辅助函数:提取纯命令结果 Private Function CleanRawOutput(rawOutput As String, sentCmd As String) As String Dim startPos As Long, endPos As Long ' 跳过发送的命令行 startPos = InStr(rawOutput, sentCmd) + Len(sentCmd) + 2 ' +2跳过命令后的换行 ' 找到提示符位置,截断结果 endPos = InStr(rawOutput, strPrompt) - 1 ' 提取并去除前后空白 CleanRawOutput = Trim(Mid(rawOutput, startPos, endPos - startPos)) End Function ' 关闭SSH会话 Sub CloseSSHConnection() If Not oExec Is Nothing Then oExec.StdIn.WriteLine "exit" ' 发送退出命令 oExec.Terminate ' 强制终止进程 Set oExec = Nothing End If Set oShell = Nothing Debug.Print "SSH会话已关闭!" End Sub ' 测试批量命令执行 Sub BatchTestCommands() ' 初始化会话(只运行一次) InitSSHConnection ' 批量执行你的测试命令 Dim testCmds(1 To 5) As String testCmds(1) = "databaseread -t Tag1.Value" testCmds(2) = "databaseread -t Tag2.Value" testCmds(3) = "databaseread -t Tag3.Value" testCmds(4) = "databaseread -t Tag4.Value" testCmds(5) = "databaseread -t Tag5.Value" Dim i As Integer For i = 1 To UBound(testCmds) Debug.Print "正在执行:" & testCmds(i) Debug.Print "结果:" & SendSSHCommand(testCmds(i)) Debug.Print "------------------------" Next i ' 执行完毕关闭会话 CloseSSHConnection End Sub
关键注意事项:
- 一定要替换代码中的路径、账号、主机地址和提示符为你的实际信息
- 第一次运行前,建议手动用PLink连接一次目标主机,接受主机密钥(避免会话卡在密钥确认步骤);或者提前执行一次
plink.exe -ssh user@10.10.10.10 -batch -pw password exit,自动保存密钥 DoEvents的作用是让Excel在等待输出时不会假死,保证你可以正常操作电脑
方法2:PLink本地端口转发(进阶)
如果交互模式的输出处理太繁琐,你可以用PLink建立本地端口转发,把远程SSH会话映射到本地端口,然后用VBA的Socket控件(比如MSCOMCTL.Socket)连接本地端口发送命令。不过这种方式需要一定的网络编程基础,适合对稳定性要求更高的场景。
三、其他可选方案
如果PLink的方式还是不够灵活,你可以考虑这些替代方案:
- PowerShell SSH模块:Windows 10+自带OpenSSH客户端,PowerShell可以用
New-SSHSession建立持久会话,VBA调用PowerShell脚本传递命令并获取结果,无需依赖PLink - 第三方SSH控件:比如Chilkat SSH控件,提供原生VBA接口,直接在代码中建立会话、发送命令,稳定性更好但属于付费软件(有免费试用版)
- Excel Power Query:如果你的查询可以结构化,Power Query支持通过SSH连接Linux主机,批量执行命令并将结果导入Excel,无需编写VBA
最后总结
对你的场景来说,方法1的PLink交互会话复用是最直接的解决方案,基于你现有代码修改即可,能把单命令执行时间从4秒压缩到毫秒级,同时避免电脑假死。
备注:内容来源于stack exchange,提问作者Scott
相关产品推荐
相关产品推荐

