从VBA中的shell命令捕获输出值?

use*_*291 27 shell vba

找到此功能 http://www.cpearson.com/excel/ShellAndWait.aspx

但是还需要捕获shell输出的输出.任何代码建议?

Bri*_*rns 50

根据Andrew Lessard的回答,这是一个运行命令并将输出作为字符串返回的函数 -

Public Function ShellRun(sCmd As String) As String

    'Run a shell command, returning the output as a string

    Dim oShell As Object
    Set oShell = CreateObject("WScript.Shell")

    'run command
    Dim oExec As Object
    Dim oOutput As Object
    Set oExec = oShell.Exec(sCmd)
    Set oOutput = oExec.StdOut

    'handle the results as they are written to and read from the StdOut object
    Dim s As String
    Dim sLine As String
    While Not oOutput.AtEndOfStream
        sLine = oOutput.ReadLine
        If sLine <> "" Then s = s & sLine & vbCrLf
    Wend

    ShellRun = s

End Function
Run Code Online (Sandbox Code Playgroud)

用法:

MsgBox ShellRun("dir c:\")
Run Code Online (Sandbox Code Playgroud)

  • 你不需要在这里使用while循环,你可以从"Set oOutput = oExec.StdOut"行替换到该行的函数结尾:`ShellRun = oExec.StdOut.ReadAll` (9认同)
  • 我无法使用你的例子来解决这个问题.我需要`ShellRun("cmd.exe/c dir c:\")`.然后它完美地工作.谢谢. (5认同)
  • 我在最近的一篇[Python帖子](http://stackoverflow.com/questions/39516875/return-result-from-python-to-vba/39517658#39517658)中归功于你的这个伟大答案。请直接回答,我会删除我自己的。 (2认同)
  • 此外,如果你需要单独的行,那么你可以`ShellRun = Split(oExec.StdOut.ReadAll,vbCrLf)`,并将函数声明更改为`Public Function ShellRun(sCmd As String)As String()`.这给出了一个0索引的字符串数组. (2认同)
  • 谢谢你 - 我花了好几个小时绞尽脑汁试图找到一个解决方案来从 powershell 命令中获取返回值。无论如何,是否可以更改 Shell 以使其从视图中隐藏? (2认同)

Ale*_* K. 20

您可以CreateProcess将应用程序重定向StdOut到管道,然后直接读取该管道; http://pastebin.com/CszKUpNS

dim resp as string 
resp = redirect("cmd","/c dir")
resp = redirect("ipconfig","")
Run Code Online (Sandbox Code Playgroud)


Raf*_*iki 7

根据主要来自布莱恩·伯恩斯(Brian Burns)的各种答案,这里是一个经过测试且功能齐全的简短版本:

Function F_shellExec(sCmd As String) As String
    Dim oShell   As New WshShell 'requires ref to Windows Script Host Object Model
    F_shellExec = oShell.Exec(sCmd).StdOut.ReadAll
End Function
Run Code Online (Sandbox Code Playgroud)

它工作得很好而且速度很快。但是,如果输出太大(例如扫描整个 C: 驱动器sCmd = "DIR /S C:\"),ReadAll将会崩溃

所以我想出了下面的第二个解决方案,到目前为止,在这两种情况下都运行良好。请注意,第一次读取速度更快,如果崩溃,读取会从头开始,这样您就不会错过信息

Function F_shellExec2(sCmd As String) As String
    'Execute Windows Shell Commands
    Dim oShell  As New WshShell 'requires ref to Windows Script Host Object Model
    'Dim oExec   As WshExec 'not needed, but in case you need the type
    Dim oOutput As TextStream
    Dim sReturn As String
    Dim iErr    As Long
    
    'Set oExec = oShell.Exec(sCmd) 'unused step, for the type
    Set oOutput = oShell.Exec(sCmd).StdOut
    
    On Error Resume Next
    sReturn = oOutput.ReadAll
    iErr = Err.Number
    On Error GoTo 0
    
    If iErr <> 0 Then
        sReturn = ""
        While Not oOutput.AtEndOfStream
            sReturn = sReturn & oOutput.ReadLine & Chr(10)
        Wend
    End If
    
    F_shellExec2 = sReturn
    
End Function
Run Code Online (Sandbox Code Playgroud)

关于对 的引用Windows Script Host Object Model:您将需要添加对 的引用,以便了解Windows Script Host Object Model类型WshShell(和)。 (为此,请转到VBA IDE 菜单栏中的“工具” -> “参考” 。)WshExec


Mar*_*orf 6

根据Brian Burns 的回答,我在调用期间向可执行文件添加了传递输入(使用StdInput)。以防万一有人偶然发现并有同样的需求。

''' <summary>
'''   Executes the given executable in a shell instance and returns the output produced
'''   by it. If iStdInput is given, it is passed to the executable during execution.
'''   Note: You must make sure to correctly enclose the executable path or any given
'''         arguments in quotes (") if they contain spaces.
''' </summary>
''' <param name="iExecutablePath">
'''   The full path to the executable (and its parameters). This string is passed to the
'''   shell unaltered, so be sure to enclose it in quotes if it contains spaces.
''' </param>
''' <param name="iStdInput">
'''   The (optional) input to pass to the executable. Default: Null
''' </param>
Public Function ExecuteAndReturnStdOutput(ByVal iExecutablePath As String, _
                                 Optional ByVal iStdInput As String = vbNullString) _
                As String

   Dim strResult As String

   Dim oShell As WshShell
   Set oShell = New WshShell

   Dim oExec As WshExec
   Set oExec = oShell.Exec(iExecutablePath)

   If iStdInput <> vbNullString Then
      oExec.StdIn.Write iStdInput
      oExec.StdIn.Close    ' Close input stream to prevent deadlock
   End If

   strResult = oExec.StdOut.ReadAll
   oExec.Terminate

   ExecuteAndReturnStdOutput = strResult

End Function
Run Code Online (Sandbox Code Playgroud)

注意:您将需要添加Windows Script Host Object Model对类型WshShellWshExec已知的引用。
(要执行此操作,请转到VBA IDE 菜单栏中的Extras -> References。)

您可以使用以下小 C# 程序来测试来自 VBA 的调用。(如果您手边没有 Visual Studio (Express),您可以按照这些说明从一个简单的源文件快速编译它。):

using System;

class Program
{
   static void Main(string[] args)
   {
      // Read StdIn
      string inputText = Console.In.ReadToEnd();

      // Convert input to upper case and write to StdOut
      Console.Out.Write(inputText.ToUpper());
   }
}
Run Code Online (Sandbox Code Playgroud)

在 VBA 中,您可以运行以下方法,该方法将显示一个包含“ABCDEF”的消息框:

Public Sub TestStdIn()
   MsgBox ExecuteAndReturnStdOutput("C:\ConvertStdInToUpper.exe", "abcdef")
End Sub
Run Code Online (Sandbox Code Playgroud)


Lan*_*rts 5

您始终可以将shell输出重定向到文件,然后从文件中读取输出.


小智 5

Sub StdOutTest()
    Dim objShell As Object
    Dim objWshScriptExec As Object
    Dim objStdOut As Object
    Dim rline As String
    Dim strline As String

    Set objShell = CreateObject("WScript.Shell")
    Set objWshScriptExec = objShell.Exec("c:\temp\batfile.bat")
    Set objStdOut = objWshScriptExec.StdOut

    While Not objStdOut.AtEndOfStream
        rline = objStdOut.ReadLine
        If rline <> "" Then strline = strline & vbCrLf & CStr(Now) & ":" & Chr(9) & rline
       ' you can handle the results as they are written to and subsequently read from the StdOut object
    Wend
    MsgBox strline
    'batfile.bat
    'ping 1.1.1.1 -n 1 -w 2000 > nul
    'echo 2
    'ping 1.1.1.1 -n 1 -w 2000 > nul
    'echo 4
    'ping 1.1.1.1 -n 1 -w 2000 > nul
    'echo 6
    'ping 1.1.1.1 -n 1 -w 2000 > nul
    'echo 8
End Sub
Run Code Online (Sandbox Code Playgroud)


小智 5

对于那些预期回报较小的情况,这是我见过的最短的命令:

MsgBox CreateObject("WScript.Shell").Exec("C:\Windows\SysWOW64\WHOAMI.EXE /USER /FO CSV").StdOut.ReadAll
Run Code Online (Sandbox Code Playgroud)