none
script hangs when reading output of command inside vbscript RRS feed

  • Question

  • Following code hangs  after the line "4 Go" but only on windows 2003.

    Set objShell = CreateObject("WScript.Shell")
    wscript.echo "2 Go"
    backupstate = "wmic PATH WIN32_SERVICE where (name='vss') GET state"
    wscript.echo "3 Go"
    Set objExecObject = objShell.Exec(backupstate)
    wscript.echo "4 Go"
    With objExecObject
    Do While .Status=0
    Wscript.Sleep 10
    Do While Not .StdOut.AtEndOfStream
    strText = .StdOut.ReadLine()
    If Not .StdErr.AtEndOfStream Then
    .StdErr.ReadLine
    End If
    Loop
    Loop
    End With

    Same code works perfectly fine on Windows 2008 and above.

    Any suggestion?


    -KAKA-


    • Edited by KAKA_2 Tuesday, November 4, 2014 3:01 PM code correction
    Tuesday, November 4, 2014 2:59 PM

Answers

  • Look at your original script.  It is written badly.

    The script I posted works every time on all systems.  Your script has loops inside of loops that ar just causing issues.

    "ReadAll()" wiil work when the called program closes the handle.  If you search you will find KB articles describing why this fails and why, when it fails, it will always fail.  It is caused by a race condition.  IPCONFIG does not use the handle in that way.

    The best solution is to NOT use WMIC fro VBSCRIPT although my version works on all systems I have ever used it on.

    Pick the onethat worked for you.  Mark it as an answer and avoid Exec if possible. 

    I posted the link to the learning resources because there are correct examples of using redirected IO since the one you used was so badly damaged.


    ¯\_(ツ)_/¯

    • Marked as answer by KAKA_2 Wednesday, November 5, 2014 11:49 AM
    Wednesday, November 5, 2014 10:36 AM

All replies

  • Why are you running WMIC from VBScript? Just talk to WMI directly.


    Dim WMI, Services, Service
    Set WMI = GetObject("winmgmts:root/CIMV2")
    Set Services = WMI.ExecQuery("select State from Win32_Service where Name='vss'")
    For Each Service In Services
      WScript.Echo Service.State
    Next
    

    Even easier is to use PowerShell:


    get-wmiobject Win32_Service -filter 'name="vss"'
    


    -- Bill Stewart [Bill_Stewart]

    Tuesday, November 4, 2014 3:22 PM
    Moderator
  • Look closely at your writing Kaka.  It is easier to understand if you format it.

    Set objShell = CreateObject("WScript.Shell")
    wscript.echo "2 Go"
    
    backupstate = "wmic PATH WIN32_SERVICE where (name='vss') GET state"
    wscript.echo "3 Go"
    
    Set objExecObject = objShell.Exec(backupstate)
    wscript.echo "4 Go"
    
    With objExecObject
    
         Do While .Status=0
              Wscript.Sleep 10
              Do While Not .StdOut.AtEndOfStream
                    strText = .StdOut.ReadLine()
                    If Not .StdErr.AtEndOfStream Then
                        .StdErr.ReadLine
                     End If
              Loop
         Loop
    
    End With

    Go back and read how to start a process and monitor it.

    With script we would use WMI andnot WMIC.  Look up how to do that with Win32_Service in WMI.


    ¯\_(ツ)_/¯

    • Proposed as answer by jrv Tuesday, November 4, 2014 8:17 PM
    Tuesday, November 4, 2014 3:22 PM
  • Simplify first:

    Set objShell = CreateObject("WScript.Shell")
    
    backupstate = "wmic PATH WIN32_SERVICE where (name='vss') GET state"
    
    Set p = objShell.Exec(backupstate)
    
    While p.Status = 0
         Wscript.Sleep 100
    Wend
         
    Do While Not p.StdOut.AtEndOfStream
         WScript.Echo p.StdOut.ReadLine()
    Loop


    ¯\_(ツ)_/¯


    • Edited by jrv Tuesday, November 4, 2014 3:27 PM
    • Proposed as answer by jrv Tuesday, November 4, 2014 4:56 PM
    Tuesday, November 4, 2014 3:26 PM
  • Same thing with WMI:

    'OLD COMMAND WIN32_SERVICE where (name='vss') GET state
    Set vss = GetObject("winmgmts:\\.\root\CimV2:Win32_Service.Name='vss'")
    WScript.Echo "VSS is:" & vss.State
    


    ¯\_(ツ)_/¯

    • Proposed as answer by jrv Tuesday, November 4, 2014 4:56 PM
    • Unproposed as answer by jrv Tuesday, November 4, 2014 8:17 PM
    • Proposed as answer by jrv Tuesday, November 4, 2014 8:17 PM
    • Unproposed as answer by jrv Wednesday, November 5, 2014 10:01 AM
    • Proposed as answer by jrv Wednesday, November 5, 2014 10:02 AM
    Tuesday, November 4, 2014 3:32 PM
  • of course one can not write similar to other. i really like the replacement

    Set vss = GetObject("winmgmts:\\.\root\CimV2:Win32_Service.Name='vss'")
    WScript.Echo "VSS is:" & vss.State
    

    and thank you for suggesting neat and clean way.

    however my question remain same, why does those codes hang on windows 2003. moreover they were recommended in a microsoft article.

    https://support.microsoft.com/kb/960246?wa=wsignin1.0

    -KAKA-


    -KAKA-

    Tuesday, November 4, 2014 4:51 PM
  • Tuesday, November 4, 2014 4:56 PM
  • Why does the script hang when you ask for the VSS service's state? Is that what you're asking?

    There's not a way for us to know the answer to that question. Perhaps there is a problem with the computer's WMI service.

    Does the command window hang when you enter this command at a command prompt?


    sc.exe query vss

    If not, then perhaps something is wrong with WMI. You'll need to check the event logs and do your own troubleshooting with that. This wouldn't be a scripting issue.


    -- Bill Stewart [Bill_Stewart]


    Tuesday, November 4, 2014 5:53 PM
    Moderator
  • however my question remain same, why does those codes hang on windows 2003.

    Your script hangs (or more precisely: it keeps looping) because the Exec method of of the Shell object is notoriously unreliable when it comes to detecting the status of the executable it invokes. You can easily find out by placing the line

    wscript.echo "Status=" & objExecObject.status

    inside your loop. This only works properly if you run the script with cscript.exe.


    Tuesday, November 4, 2014 7:46 PM

  • Your script hangs (or more precisely: it keeps looping) because the Exec method of of the Shell object is notoriously unreliable when it comes to detecting the status of the executable it invokes. You can easily find out by placing the line

    wscript.echo "Status=" & objExecObject.status

    inside your loop. This only works properly if you run the script with cscript.exe.


    As Frederik says. :)

    To explicitly answer why that MSKB article suggests continually emptying the error buffer, it's because doing so is better than not doing so.

    Another workaround I use in preference to embedding the console tool within a WSH script is to factor out the tool so I don't have to manipulate it internally; instead I pipe the output in to the script.

    For example, suppose your script is named ProcessWmicOutput.vbs. within the script you would do something like this:

    data = WScript.Stdin.ReadAll

    to get all the data from wmic into a variable named data . Alternatively, you would do something like this, line by line (I'm making the script just relay StdOut from wmic):

    Do While Not WScript.StdIn.AtEndOfStream
         WScript.StdOut.WriteLine WScript.StdIn.ReadLine()
    Loop

    To run the script, getting wmic data, you would do this at a command prompt:

    wmic PATH WIN32_SERVICE where (name='vss') GET state | cscript ProcessWmicOutput.vbs

    Tuesday, November 4, 2014 8:11 PM
  • Note that this was fixed early this morning via a call to GetObject.

    The issue was only bad code and had nothing to do with exccec not working.  Exec has always worked well if you know hpw to use it.


    ¯\_(ツ)_/¯

    Tuesday, November 4, 2014 8:17 PM
  • Why does the script hang when you ask for the VSS service's state? Is that what you're asking?

    There's not a way for us to know the answer to that question. Perhaps there is a problem with the computer's WMI service.

    Does the command window hang when you enter this command at a command prompt?


    sc.exe query vss

    If not, then perhaps something is wrong with WMI. You'll need to check the event logs and do your own troubleshooting with that. This wouldn't be a scripting issue.


    -- Bill Stewart [Bill_Stewart]



    Niether it is about WMIC nor the loop. even the below code hangs on Windows 2003 machines.

    Set objShell = CreateObject("WScript.Shell")
    backupstate = "wmic PATH WIN32_SERVICE where (name='vss') GET state"
    Set objExecObject = objShell.Exec(backupstate)
    strText = objExecObject.StdOut.ReadAll()

    and it hang when it execute

    strText = objExecObject.StdOut.ReadAll()
    it hangs even if you replace the WMIC command with any simplest command.

    -KAKA-


    • Edited by KAKA_2 Wednesday, November 5, 2014 8:56 AM correction
    Wednesday, November 5, 2014 8:56 AM
  • There is a link: http://technet.microsoft.com/en-us/scriptcenter/dd793612.aspx

    Good Luck.


    ¯\_(ツ)_/¯

    Thanks for the link. I know one day i will have to learn powershell but current version of product/tool i am using does not support powershell as embedded script. i have only two option VBScript or Perl.

    There are already enhancement request for vendor to let us use powershell.


    -KAKA-


    • Edited by KAKA_2 Wednesday, November 5, 2014 9:09 AM correction
    Wednesday, November 5, 2014 8:59 AM
  • Why does the script hang when you ask for the VSS service's state? Is that what you're asking?

    it hangs even if you replace the WMIC command with any simplest command.

    -KAKA-

    I gave you a recipe to find out exactly where the code loops. Why not try it?
    Wednesday, November 5, 2014 9:52 AM
  • There is a link: http://technet.microsoft.com/en-us/scriptcenter/dd793612.aspx

    Good Luck.


    ¯\_(ツ)_/¯

    Thanks for the link. I know one day i will have to learn powershell but current version of product/tool i am using does not support powershell as embedded script. i have only two option VBScript or Perl.

    There are already enhancement request for vendor to let us use powershell.


    -KAKA-



    The link also has learning resources for VBScript.  Read more completely.

    ¯\_(ツ)_/¯

    Wednesday, November 5, 2014 9:59 AM
  • Why does the script hang when you ask for the VSS service's state? Is that what you're asking?

    it hangs even if you replace the WMIC command with any simplest command.

    -KAKA-

    I gave you a recipe to find out exactly where the code loops. Why not try it?

    the problem was solved.  Please read the whole thread.  I gave three solutions a day ago and all work.

    The ReadAll will not work the way it was used and cannot be made to work. It is in the basic behavior of the Exec method.


    ¯\_(ツ)_/¯

    Wednesday, November 5, 2014 10:01 AM
  • The ReadAll will not work the way it was used and cannot be made to work. It is in the basic behavior of the Exec method.


    ¯\_(ツ)_/¯

     So if it can not be made to work why does it work on windows 2008 R2 servers?

    another article in which output of ipconfig was read in the same way.

    http://technet.microsoft.com/en-us/library/ee692837.aspx

    Set objShell = CreateObject("WScript.Shell")
    Set objWshScriptExec = objShell.Exec("ipconfig")
    Set objStdOut = objWshScriptExec.StdOut
    strOutput = objStdOut.ReadAll
    WScript.Echo strOutput


    -KAKA-


    • Edited by KAKA_2 Wednesday, November 5, 2014 10:25 AM link added
    Wednesday, November 5, 2014 10:18 AM
  • Look at your original script.  It is written badly.

    The script I posted works every time on all systems.  Your script has loops inside of loops that ar just causing issues.

    "ReadAll()" wiil work when the called program closes the handle.  If you search you will find KB articles describing why this fails and why, when it fails, it will always fail.  It is caused by a race condition.  IPCONFIG does not use the handle in that way.

    The best solution is to NOT use WMIC fro VBSCRIPT although my version works on all systems I have ever used it on.

    Pick the onethat worked for you.  Mark it as an answer and avoid Exec if possible. 

    I posted the link to the learning resources because there are correct examples of using redirected IO since the one you used was so badly damaged.


    ¯\_(ツ)_/¯

    • Marked as answer by KAKA_2 Wednesday, November 5, 2014 11:49 AM
    Wednesday, November 5, 2014 10:36 AM
  • This also demonstrates the importance of asking your question correctly.

    Rather than using the Exec method, I recommend using the WshShell object's Run method, redirecting the output to a temporary file, and then reading the output. In this way you don't have to worry about the output buffering issues. You can also hide the console window that appears if you happen to run the script using wscript.exe.


    -- Bill Stewart [Bill_Stewart]

    Wednesday, November 5, 2014 3:47 PM
    Moderator
  • FYI, I finally tracked down a conversation I remembered from a few years ago about the potential problems with using Exec this way:

    https://groups.google.com/forum/#!topic/microsoft.public.scripting.wsh/kIvQsqxSkSk

     It's not a bug, really, more of a catch-22 situation. It might explain the original problem (and could be tested with appropriately place WScript.Echos to see where execution halts), but that seems a bit much trouble to go to when there's a simpler reliable solution.

    Wednesday, November 5, 2014 5:10 PM
  • I remember similar threads, back in the day...


    -- Bill Stewart [Bill_Stewart]

    Wednesday, November 5, 2014 5:21 PM
    Moderator