Как запустить SSH в Shell для возврата значений в переменную VBA?

Я пытаюсь запустить команду ssh и захватить вывод в переменную в VBA (используя OpenSSH). Я могу заставить это работать нормально в командной строке:

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

Результатом является список значений, возвращаемых в окно командной строки. Я хотел бы прочитать это в переменной VBA.

Я нашел это , это и это . Первые два, кажется, не посылают или не получают команду правильно, так как код получает зависание на oShell.Exec (…). Оболочка выглядит так, как будто она выполняется, но ее просто повесили. Если я закрою окно командной строки, результаты в VBA будут пустыми.

Dim sCmd As String sCmd = "ssh [email protected] 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 [email protected] python C:\Temp\Remote.py", vbNormalFocus)' ), но я не могу получить значение. Я вижу, что окно команды открыто, значения возвращаются, но я возвращаю целое число в retVal.

Любая помощь?

    WScript.Shell .Exec() объекта .Exec() – это метод, который предназначен для (a) запуска консольной команды / приложения и (b) захвата его вывода через свойства экземпляра WshScriptExec он возвращает.

    На данный момент загадка, почему ваша команда на основе ssh не работает – ваш код обычно работает с консольными командами.

    Тем не менее, есть еще одна причина не использовать .Exec() , при запуске из приложения GUI , например приложения VBA-хостинга, окно консоли всегда отображается во время исполнения, что может быть визуально разрушительным.

    Следующие альтернативы (необязательно) позволяют запустить скрытую команду (без видимого окна), но обратите внимание, что ни одна из них напрямую не поддерживает захват вывода из вызываемой команды:

    • Собственная функция Shell() VBA, которая, однако, неизменно выполняется асинхронно , поэтому очень сложно определить, когда команда завершается.

    • Метод WScriptShell .Run() объекта WScriptShell объекта, который по выбору позволяет дождаться завершения команды.

    Чтобы получить как невидимое выполнение, так и вывод , вы можете:

    • скомбинировать метод WScriptShell .Run() объекта WScriptShell
    • с отправкой вывода команды во временный файл ,
    • и, после завершения команды, прочитайте временный файл в памяти.
     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 [email protected] 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 [email protected] 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 

    Я думаю, вы должны попробовать использовать «command spec» в начале команды. На вашей машине это можно получить в VBA с VBA.Environ$("comspec") который на моей машине возвращает C:\WINDOWS\system32\cmd.exe

    Поэтому постарайтесь

      sCmd = VBA.Environ$("comspec") & " /C " & " ssh [email protected] python C:\Temp\Remote.py" 

    Спецификация команды требует в некоторых случаях переключателей cmd

    У меня нет Python, поэтому я не могу проверить.

    Interesting Posts

    Excel Average с несколькими диапазонами и критериями

    выделить ячейку на основе значения, массив поиска mulptie

    Как удалить ячейки, содержащие формулы, но не данные (т.е. они выглядят пустыми, но не являются)

    Excel / VBA / SQL – обновление не работает

    Таблица Excel VBA Import Word с объединенными ячейками в Excel

    Использовать Явные имена рабочих листов, когда RSR RSR RSR RDS RDS в Excel

    csv file print columnwise raw значения для значений больше 0,5

    Broken Macro – найдите последнюю строку и добавьте данные

    VBA Excel: созданный макросом график с динамическим диапазоном

    Получить последнюю строку с данными из таблицы Excel

    Как экспортировать электронные письма по строкам в excel с помощью c #?

    Как получить таблицу, на которую ссылается формула ячейки

    Отношения «один ко многим»

    Условное форматирование в листах – форматирование двух ячеек на основе одного

    Данные электронной почты, экспортированные в Excel – Сортировка по Полученной Дате

    Давайте будем гением компьютера.