如何在Shell中运行SSH以将值返回到VBA变量?

卢克霍克

我正在尝试运行ssh命令,并将输出捕获到VBA中的变量(使用OpenSSH)。我可以在命令行中使其正常工作:

ssh user @ ip python C:\ Temp \ Remote.py

结果是返回到命令行窗口的值的列表。我想将此读入VBA变量。

我发现了这个这个这个前两个代码似乎无法正确发送或接收命令,因为代码已挂在oShell.Exec(...)上。Shell看起来像正在执行,但只是挂了。如果关闭挂起的命令窗口,则VBA中的结果为空白。

Dim sCmd As String
sCmd = "ssh user@ip python C:\Temp\Remote.py"

Dim oShell As Object
Set oShell = CreateObject("WScript.Shell")
Dim oExec As Object
Dim oOutput As Object
Set oExec = oShell.Exec(sCmd)
Set oOutput = oExec.StdOut

Dim s As String
Dim sLine As String

While Not oOutput.AtEndOfStream
    sLine = oOutput.ReadLine
    If sLine <> "" Then s = s & sLine & vbCrLf
Wend

第三个似乎部分起作用(使用'retVal = Shell("ssh user@ip python C:\Temp\Remote.py", vbNormalFocus)'),但我无法获得价值。我可以看到命令窗口已打开,值又回来了,但是我在retVal中得到了一些整数。

有什么帮助吗?

mklement0

WScript.Shell对象的.Exec()方法是运行一个被设计成(a)所述方法控制台命令/应用,和(b)捕获其输出经由的属性WshScriptExec返回实例。

在这一点上,为什么ssh基于命令的命令不起作用是一个谜,您的代码通常可以与控制台命令一起使用。

也就是说,还有一个使用的原因.Exec(),当从GUI应用程序(例如VBA托管应用程序)运行时,控制台窗口始终在执行过程中可见,这可能在视觉上造成破坏。

以下替代方法(可选)允许隐藏运行命令(不显示可见窗口),但请注意,这两种方法均不直接支持捕获已调用命令的输出

  • VBA自己的Shell()函数,但是总是不变地异步执行,因此确定命令何时完成比较麻烦。

  • WScriptShell对象的.Run()方法,其任选地允许等待的命令来完成。

获得不可见的执行输出捕获,您可以:

  • 结合WScriptShell对象的.Run()方法
  • 通过将命令的输出发送到临时文件
  • 命令完成后,将临时文件读入内存。
Dim cmd as String
Dim exitCode As Integer
Dim tempFile As String
Dim capturedOutput As String

' Construct the name of a temporary file to capture the command's stdout output in.
tempFile = Environ$("TEMP") & "\" & CreateObject("Scripting.FileSystemObject").GetTempName()

' Define the command to invoke.
cmd = "ssh user@ip python C:\Temp\Remote.py"

' Use .Run() to invoke the command.
'  - In order to use output redirection, the command must be prefixed with 'cmd /c '.
'  - Setting the last argument to `True` makes the invocation synchronous.
'  - Replace vbNormalFocus with vbHidden to run the command *invisibly*.
exitCode = CreateObject("WScript.Shell").Run("cmd /c " & cmd & " >" & tempFile, vbNormalFocus, True)
If exitCode = 0 Then ' Command succeeded.

    ' Read the output file, then delete the temporary file.
    capturedOutput = CreateObject("Scripting.FileSystemObject").OpenTextFile(tempFile).ReadAll()
    CreateObject("Scripting.FileSystemObject").DeleteFile(tempFile)

    ' Display the output.
    MsgBox "Captured Output:" & vbNewLine & capturedOutput

Else ' Command indicated failure.

    MsgBox "An unexpected error occurred.", vbExclamation

End If

这是基于Shell()此实现启发替代方法

如您所见,进行Shell()同步需要付出更多的努力,并且需要使用Windows API:

Private Declare Function OpenProcess Lib "kernel32.dll" (ByVal dwDesiredAccessas As Long, ByVal bInheritHandle As Long, ByVal dwProcId As Long) As Long
Private Declare Function CloseHandle Lib "kernel32.dll" (ByVal hObject As Long) As Long
Private Declare Function WaitForSingleObject Lib "kernel32.dll" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Private Declare Function GetExitCodeProcess Lib "kernel32.dll" (ByVal hProcess As Long, ByRef lpExitCodeOut As Long) As Integer

Sub Main()

    Dim cmd As String
    Dim taskId As Integer
    Dim exitCode As Integer
    Dim tempFile As String
    Dim capturedOutput As String

    ' Construct the name of a temporary file to capture the command's stdout output in.
    tempFile = Environ$("TEMP") & "\" & CreateObject("Scripting.FileSystemObject").GetTempName()

    ' Define the command to run.
    cmd = "ssh user@ip python C:\Temp\Remote.py"

    ' Use the SyncShell() helper function defined below to invoke the command
    ' synchronously and to obtain its exit code.
    '  - In order to use output redirection, the command must be prefixed with 'cmd /c '.
    '  - Add a 3rd argument with a timeout value in seconds if you don't want to wait
    '    indefinitely for the process to complete.
    '  - Replace vbNormalFocus with vbHidden to run the command *invisibly*.
    exitCode = SyncShell("cmd /c " & cmd & " >" & tempFile, vbNormalFocus)
    If exitCode = 0 Then ' Command succeeded.

        ' Read the output file and delete the temporary file.
        capturedOutput = CreateObject("Scripting.FileSystemObject").OpenTextFile(tempFile).ReadAll()
        CreateObject("Scripting.FileSystemObject").DeleteFile (tempFile)

        ' Display the output.
        MsgBox "Captured Output:" & vbNewLine & capturedOutput

    Else ' Command indicated failure.

        MsgBox "An unexpected error occurred.", vbExclamation

    End If

End Sub

' Helper function
Private Function SyncShell(ByVal cmd As String, Optional ByVal windowStyle As VbAppWinStyle = vbMinimizedFocus, Optional ByVal timeoutInSecs As Double = -1) As Long

    Dim pid As Long ' PID (Process ID) as returned by Shell().
    Dim h As Long ' Process handle
    Dim sts As Long ' WinAPI return value
    Dim timeoutMs As Long ' WINAPI timeout value
    Dim exitCode As Long

    ' Invoke the command (invariably asynchronously) and store the PID returned.
    ' Note that the invocation may fail.
    pid = Shell(cmd, windowStyle)

    ' Translate the PIP into a process *handle* with the SYNCHRONIZE and PROCESS_QUERY_LIMITED_INFORMATION access rights,
    ' so we can wait for the process to terminate and query its exit code.
    h = OpenProcess(&H100000 Or &H1000, 0, pid) ' &H100000 == SYNCHRONIZE, &H1000 == PROCESS_QUERY_LIMITED_INFORMATION
    If h = 0 Then Err.Raise vbObjectError + 1024, , "Failed to obtain process handle for process with ID " & pid & "."

    ' Now wait for the process to terminate.
    If timeoutInSecs = -1 Then
        timeoutMs = &HFFFF ' INFINITE
    Else
        timeoutMs = timeoutInSecs * 1000
    End If
    sts = WaitForSingleObject(h, timeoutMs)
    If sts <> 0 Then Err.Raise vbObjectError + 1025, , "Waiting for process with ID " & pid & " to terminate timed out, or an unexpected error occurred."

    ' Obtain the process's exit code.
    sts = GetExitCodeProcess(h, exitCode) ' Return value is a BOOL: 1 for true, 0 for false
    If sts <> 1 Then Err.Raise vbObjectError + 1026, , "Failed to obtain exit code for process ID " & pid & "."

    CloseHandle h

    ' Return the exit code.
    SyncShell = exitCode

End Function

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何在vim中运行shell命令并将结果字符串返回到VimScript变量中?

如何将HttpRequest中的值直接返回到变量中

如何将变量的值返回到 Flutter 中的上一个类?

如何将状态代码从远程运行的Shell脚本返回到本地Shell脚本

如何将列中的值从 StarBasic 返回到 Calc

如何将值返回到方法中?

变量在 Perl 中返回到以前的值

如何使用评估方法将值填充到 VBA 数组中并将它们返回到 Excel 工作表?

将目录中的文件数返回到shell scrtpt中的变量

如何将值返回到数组

将值返回到列表中

如何将命令行变量的值返回到立即窗口

将多个值从Shell脚本返回到C程序

SQL Server中如何将存储过程的输出返回到字符串变量中

VBA函数无法将值返回到主子项

如何将Firebase中的snapshot.val()返回到变量?

如何将变量从 AsyncTask 返回到 Android 中的 Google Map 活动

如何在运行的shell中编辑变量?

如何将多列中的最大值返回到pandas df中的新列

如何将 LINQ 中的值返回到参数中?C#

如何将值从JavaScript中的函数返回到HTML中的文本框

如何在laravel 5.4中将两个变量从同一方法/函数返回到一个视图?

如何在 VBA 中将对象返回到 UiPath?

如何将变量返回到表单onsubmit事件?

如何将PowerShell变量返回到VBScript

如何使用猫鼬将查询结果返回到变量

Odoo,如何将变量从模型返回到弹出窗口

Postgres 函数将表返回到变量中

将更新的列返回到数组变量中