Set timeout for WMI query

I have some code that pings a system. If it's online, it checks what OS is on it. However, some systems randomly have problems with the WMI and will lock up my code. I need a way of setting some sort of at timeout so that it will skip to the next step if it sits for more than 10 seconds.
If PingComputer(strcomputer) = True Then
                Dim ooss As Object
                Dim oos
                Dim sos As String
                Dim OSTXT = ""

                    ooss = GetObject("winmgmts:\\" & strcomputer).InstancesOf("Win32_OperatingSystem")

                    For Each oos In ooss

                        sos = oos.Name
                        Dim sp
                        Dim pos As Integer
                        Dim trimnull
                        pos = InStr(sos, "|")

                        If pos Then
                            trimnull = Microsoft.VisualBasic.Left(sos, pos - 1)
                            sp = oos.ServicePackMajorVersion
                            OSTXT = trimnull & " SP " & sp
                        End If


                Catch ex As Exception
                End Try
            End If

Open in new window

Who is Participating?

Improve company productivity with a Business Account.Sign Up

apresenceConnect With a Mentor Commented:
I apologize, I had a major brain lapse when I first looked at your question.  Whenever I see something relating to WMI, I automatically assume VBScript, but I can see now you are working with VB.NET.  That makes things a lot easier...

Create a thread that does the WMI stuff, and wait for it to complete within a certain timeout value. If the timeout is reached, terminate the thread.

Drop the attached code into a module or class, and replace the contents between the Try and Catch statements of DoWMIStuff with the WMI code provided in your question. You can put your output variable in oargs.stroutput, or create additional output variables in the WMIStuffArgs class.

If you're running this test on multiple computers, you can even create several threads at a time so that you can go through your whole list of computers faster.

NOTE: This is NOT the best way to do this if you're trying to create a high-performance application.  A better way is to use the APM (Asynchronous Programming Model) feature of .NET.  But, using this method is a bit more complicated and I'm not sure if it will fit well in the program you are writing/using.

Output of testing the code (uncomment the appropriate line to test):
MAIN   Starting worker thread
THREAD Started with argument: remote_computer
MAIN   Worker thread terminated with exception: System.Exception: foo at ThreadTimeout_VB.Module1.DoWMIStuff(Object state) in C:\LocalWork\Dev\ThreadTimeout_VB\ThreadTimeout_VB\Module1.vb:line 21
MAIN   Application completed

MAIN   Starting worker thread
THREAD Started with argument: remote_computer
MAIN   Timeout waiting for worker thread to complete; Terminating
MAIN   Worker thread terminated
MAIN   Application completed

MAIN   Starting worker thread
THREAD Started with argument: remote_computer
THREAD Completed with success
MAIN   Worker thread terminated with success; Output=[remote_computer_from_thread]
MAIN   Application completed

Class WMIStuffArgs
        Public strcomputer As String
        Public success As Boolean
        Public e As Exception
        Public stroutput As String

        Public Sub New()
            strcomputer = Nothing
            success = False
            e = Nothing
        End Sub
    End Class

    Sub DoWMIStuff(ByVal state As Object)
        Dim oargs As WMIStuffArgs : oargs = state

            Console.WriteLine("THREAD Started with argument: {0}", oargs.strcomputer)
            '- Note: Uncomment next line to test exception handling
            'Throw New Exception("foo")
            '- Note: Uncomment next line to cause a timeout
            '- Note: Uncomment next line to complete with success
            oargs.stroutput = oargs.strcomputer & "_from_thread"
            oargs.success = True
            Console.WriteLine("THREAD Completed with success")
        Catch e As Exception
            oargs.e = e
        End Try
    End Sub

    Sub Main()
        Dim wmiThread As System.Threading.Thread
        Dim wmiArgs As WMIStuffArgs

        wmiThread = New System.Threading.Thread(AddressOf DoWMIStuff)
        wmiArgs = New WMIStuffArgs

        Console.WriteLine("MAIN   Starting worker thread")
        wmiArgs.strcomputer = "remote_computer"

        If (Not wmiThread.Join(10000)) Then
            Console.WriteLine("MAIN   Timeout waiting for worker thread to complete; Terminating")
            Console.WriteLine("MAIN   Worker thread terminated")
            If (Not (wmiArgs.e Is Nothing)) Then
                Console.WriteLine("MAIN   Worker thread terminated with exception: {0}", wmiArgs.e.ToString)
            ElseIf (wmiArgs.success) Then
                Console.WriteLine("MAIN   Worker thread terminated with success; Output=[{0}]", wmiArgs.stroutput)
                Console.WriteLine("MAIN   Worker thread terminated with failure")
            End If
        End If

        Console.WriteLine("MAIN   Application completed")
    End Sub

Open in new window

WMI depends on DCOM, and there's some registry setting you can use to control the timeout for DCOM calls, but I don't remember it off the top of my head.  Perhaps someone else does.  In the meantime, I'm searching around for it...
jcampingAuthor Commented:
From what I can tell, the DCOM setting you are referring to would have to be set on every machine. I'm just looking for a way to programmatically time out a piece of code after a designated amount of time. It seems like this would be something that would be possible. Is it?
Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Oddly enough, there isn't a good way to set the DCOM timeout...   WMI *does* have a "dead man switch" to terminate a call if it takes too long.  But that doesn't come into play until after the connection is sucessfully made.
If you're interested in some cool WMI examples, take a look at the downloadable source code at:
jcampingAuthor Commented:
OK, so if there is no way to kill the code, is there a way to check to see if WMI is functioning before trying to connect to it?
Nope, not really...  that's a catch 22... you need WMI to be able to determine if WMI is running OK !
I generally do a "ping" first, and then attempt to do a WMI connection.   If it times out, it times out... and I move on to the next one in the list..   For example, during lunch today, I polled about 400 PCs via WMI.  Yeah, sure... some of them didn't answer a ping or didn't respond to a WMI query, but I've only had a lockup about two times in about 10 years of doing this.
... oops, I hit submit too quickly
So, let's concentrate on what's going on that can cause a lockup.  Have you been able to isolate a "test case" where a PC is the cause of the lockup?
jcampingAuthor Commented:
That's awesome. I've looked everywhere for something easy to follow like this! Thanks so much apresence!
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.