2011-02-07 14 views
17

To jest przykład kodu VBScript, który pokazuje, jak wychwycić cokolwiek program wiersza poleceń wysyła na standardowe wyjście. Wykonuje polecenie xcopy /? i wyświetla dane wyjściowe w oknie komunikatu. Zanim pojawi się okno komunikatu, przez ułamek sekundy pojawi się okno konsoli.Kod VBscript do przechwytywania stdout, bez wyświetlania okna konsoli

Set objShell = WScript.CreateObject("WScript.Shell") 
Set objExec = objShell.Exec("xcopy /?") 
Do 
    line = objExec.StdOut.ReadLine() 
    s = s & line & vbcrlf 
Loop While Not objExec.Stdout.atEndOfStream 
WScript.Echo s 

Oto inny przykład kodu VBScript, który pokazuje, jak wykonać skrypt bez wyświetlania okna konsoli.

objShell.Run "c:\temp\mybatch.bat C:\WINDOWS\system32\cmd.exe", 0 

lub

objShell.Run "c:\temp\myscript.vbs C:\WINDOWS\system32\cscript.exe", 0 

Jak widać ma ona formę <script><space><executor>. Ostatni przykład używa objShell.Run zamiast objShell.Exec

Co nie wiem, jest to, jak wykonać program wiersza poleceń (jeśli to konieczne z pliku wsadowego), złapać standardowe wyjście, bez pokazywania okna konsoli. Jakieś pomysły?

Odpowiedz

3

Ten dowód koncepcji scenariusza:

' pocBTicks.vbs - poor man's version of backticks (POC) 

Option Explicit 

' Globals 

Const SW_SHOWMINNOACTIVE = 7 
Const ForReading   = 1 

Dim goFS : Set goFS = CreateObject("Scripting.FileSystemObject") 
Dim goWSH : Set goWSH = CreateObject("WScript.Shell") 

' Dispatch 
WScript.Quit demoBTicks() 

' demoBTicks - 
Function demoBTicks() 
    demoBTicks = 1 
    Dim aCmds : aCmds = Array(_ 
     "dir pocBTicks.vbs" _ 
    , "dur pocBTicks.vbs" _ 
    , "xcopy /?" _ 
) 
    Dim sCmd 
    For Each sCmd In aCmds 
     WScript.Echo "########", sCmd 
     Dim aRet : aRet = BTicks(sCmd) 
     Dim nIdx 
     For nIdx = 0 To UBound(aRet) 
      WScript.Echo "--------", nIdx 
      WScript.Echo aRet(nIdx) 
     Next 
    Next 
    demoBTicks = 0 
End Function ' demoBTicks 

' BTicks - execute sCmd via WSH.Run 
' aRet(0) : goWSH.Run() result 
' aRet(1) : StdErr/error message 
' aRet(2) : StdOut 
' aRet(3) : command to run 
Function BTicks(sCmd) 
    Dim aRet : aRet  = Array(-1, "", "", "") 
    Dim sFSpec2 : sFSpec2 = goFS.GetAbsolutePathName(".") 
    Dim sFSpec1 : sFSpec1 = goFS.BuildPath(sFSpec2, goFS.GetTempName()) 
       sFSpec2 = goFS.BuildPath(sFSpec2, goFS.GetTempName()) 

    aRet(3) = """%COMSPEC%"" /c """ + sCmd + " 1>""" + sFSpec1 + """ 2>""" + sFSpec2 + """""" 
    Dim aErr 
On Error Resume Next 
    aRet(0) = goWSH.Run(aRet(3), SW_SHOWMINNOACTIVE, True) 
    aErr  = Array(Err.Number, Err.Description, Err.Source) 
On Error GoTo 0 
    If 0 <> aErr(0) Then 
    aRet(0) = aErr(0) 
    aRet(1) = Join(Array(aErr(1), aErr(2), "(BTicks)"), vbCrLf) 
    BTicks = aRet 
    Exit Function 
    End If 

    Dim nIdx : nIdx = 1 
    Dim sFSpec 
    For Each sFSpec In Array(sFSpec2, sFSpec1) 
     If goFS.FileExists(sFSpec) Then 
     Dim oFile : Set oFile = goFS.GetFile(sFSpec) 
     If 0 < oFile.Size Then 
      aRet(nIdx) = oFile.OpenAsTextStream(ForReading).ReadAll() 
      goFS.DeleteFile sFSpec 
     End If 
     End If 
     nIdx = nIdx + 1 
    Next 
    BTicks = aRet 
End Function 

pokazuje jak używać .Run i pliki tymczasowe, aby coś podobnego backticks z ukrytej konsoli. Dobra obsługa plików, cytowanie w sCmd, czyszczenie zwróconych łańcuchów i radzenie sobie z kodowaniem będzie wymagało więcej pracy. Być może jednak możesz użyć tej strategii, aby zaimplementować coś, co pasuje do twoich potrzeb.

+0

Genialne rozwiązanie. Szkoda na temat plików tymczasowych. Ale spełnia wymagania, więc punkty są twoje. Dzięki, Marcel. – mgr326639

5

Aby przekierować dane wyjściowe do konsoli, uruchom skrypt za pomocą cscript, np .: c:\cscript myscript.vbs.

cscript ma kilka opcji wiersza poleceń. Najważniejszym (dla mnie) jest przełącznik // NOLOGO. Jeśli roczny go używać (cscript //nologo myscript.vbs) będzie pominąć Microsoft towar ...

13

Zwykle używam to:

Wscript.echo execStdOut("ping google.com") 

Function execStdOut(cmd) 
    Dim goWSH : Set goWSH = CreateObject("WScript.Shell") 
    Dim aRet: Set aRet = goWSH.exec(cmd) 
    execStdOut = aRet.StdOut.ReadAll() 
End Function 

dla bardziej zaawansowanych poleceń youc wrap do COMSPEC (CMD)

my res = execStdOut("%comspec%" & " /c " & """" & "dir /b c:\windows\*.exe" & """" & " && Echo. && Echo finished") 
+2

Pamiętaj, że to się zawiesi, jeśli twój program wyjdzie za dużo (około 4KB IIRC) i nie jest ukryty. –

+0

@CamiloMartin Skąd czerpiesz ograniczenie 4KB? Czy to ograniczenie 'StdOut.ReadAll()'. Właśnie użyłem 'StdOut.ReadLine()' na pliku 109 KB bez problemów na http://ss64.com/vb/stdoutread.html. Chociaż mogę potwierdzić obserwację "niewidoczną", czyniąc to rozwiązanie nieidealnym dla osób poszukujących "ukrytego okna" jako surowego wymogu, zgodnie z PO. – tresf

+0

@QZSupport Szczerze mówiąc, nie mam już najmniejszej wskazówki, ale prawdopodobnie wypróbowałem ją i coś wisiało po 4KB, potem przyszły dwie inne osoby i wznowiono ją, ponieważ coś wisiało za nimi. Jeśli to naprawdę działa, to po prostu upewnij się, że testujesz na wszystkich obsługiwanych wersjach systemu Windows. (Ponadto, należy zauważyć: jest to * bardzo prawdopodobne * "ReadAll" przeczyta wszystko w pamięci RAM i byłoby bardzo brzydkie samo w sobie - powiedziałbym, że powinieneś zamiast tego przesyłać strumień StdOut, ale znowu nie wiem jak; 'ReadLine' nie byłaby dobra dla wyjścia binarnego). –

0

Aby powrócić w języku VBA, wszystkie podfoldery w G: \ OF

podzielić podzielony ciąg na tablicę

sub M_snb() 
    sn=split(createobejct("wscript.Shell").exec("cmd /c Dir G:\OF\*. /s/b").stdout.readall,vbCrLf) 

    for j=0 to ubound(sn) 
    msgbox sn(j) 
    next 
End Sub 
+3

-1 dla: 'createobejct', brakującego cytatu przed' cmd', i nie adresowania specyfikacji "ukryty". –

-1

Zamiast WScript.Shell, należy rozważyć użycie przy użyciu Win32_Process z startupInfo.ShowWindow = 0 aby uruchomić proces SW_HIDE. Wysłałem szczegółowy przykład pod numerem VBS Run cmd.exe output to a variable; not text file.

+0

Interesujący kawałek kodu. Ale tak naprawdę nie widzę przewagi w tym przypadku, ponieważ nadal polegasz na pliku tymczasowym. – mgr326639

0

Jeśli nie przeszkadza mający przycisk pasku zadań pojawi się, można po prostu przenieść okno konsoli poza ekranem przed uruchomieniem go.

Jeśli istnieje klucz HKCU\Console\WindowPosition, system Windows użyje jego wartości, aby ustawić okno konsoli. Jeśli klucz nie istnieje, otrzymasz okno z systemem.

Więc zapisz oryginalną wartość tego klucza, ustaw własną wartość, aby ustawić go poza ekranem, zadzwoń pod numer Exec() i przechwytuj jego dane wyjściowe, a następnie przywróć oryginalną wartość klucza.

Klucz WindowPosition oczekuje wartości 32-bitowej. Wysokie słowo to współrzędna X, a niskie słowo to współrzędna Y (XXXXYYYY).

With CreateObject("WScript.Shell") 

    ' Save the original window position. If system-positioned, this key will not exist. 
    On Error Resume Next 
    intWindowPos = .RegRead("HKCU\Console\WindowPosition") 
    On Error GoTo 0 

    ' Set Y coordinate to something crazy... 
    .RegWrite "HKCU\Console\WindowPosition", &H1000, "REG_DWORD" 

    ' Run Exec() and capture output (already demonstrated by others)... 
    .Exec(...) 

    ' Restore window position, if previously set. Otherwise, remove key... 
    If Len(intWindowPos) > 0 Then 
     .RegWrite "HKCU\Console\WindowPosition", intWindowPos, "REG_DWORD" 
    Else 
     .RegDelete "HKCU\Console\WindowPosition" 
    End If 

End With 

Jeśli naprawdę chcesz się upewnić, że współrzędne są poza ekranem, można uzyskać wymiary ekranu poprzez VBScript za pomocą IE lub innych narzędzi.

Powiązane problemy