Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set Timeout On Remote WMI when RPC Server Is Unavailable

Tags:

c#

timeout

wmi

I have the following code that checks the status of a service on a remote computer. The problem is that if the remote computer can't be found (it's down or something), then the ManagementObjectSearcher.Get() method takes 20 seconds to throw an error of "The RPC Server Is Unavailable". In cases where the server is unavailable, I want to explicitly state that I only want it to try for a short period of time (like 3 seconds). I have followed the post here, but it states to use the Timeout option on ManagementObjectSearcher, but my code seems to ignore that value (as it states it's not relevant on collections). Is there something I'm overlooking on these options? I have tried using the ReturnImmediatly property as well to no avail.

public static void WmiServiceCheck()
    {
        try
        {
            var computerName = "SomeInvalidComputer";
            var serviceName = "Power";
            var managementScope = new ManagementScope(string.Format(@"\\{0}\root\cimv2", computerName));
            var objectQuery = new ObjectQuery(string.Format("SELECT * FROM Win32_Service WHERE Name = '{0}'", serviceName));
            var searcher = new ManagementObjectSearcher(managementScope, objectQuery);
            searcher.Options.Timeout = new TimeSpan(0, 0, 0, 3); // Timeout of 3 seconds
            var managementObjectCollection = searcher.Get();
            var serviceState = managementObjectCollection.Cast<ManagementObject>().ToList().Single()["State"].ToString();
            /// Other stuff here
        }
        catch (Exception ex)
        {
        }
    }
like image 768
bigmac Avatar asked Aug 12 '14 23:08

bigmac


2 Answers

Yes, not that one. You want to set the ConnectionOptions.Timeout:

  var managementScope = new ManagementScope(...);
  managementScope.Options.Timeout = TimeSpan.FromSeconds(3);

Worked well when I tested it.

Do keep in mind that 3 seconds is on the low end, the server may well have to swap a lot of code into RAM to handle the request if it hasn't been queried for a while. That's not necessarily a speedy operation if the server is otherwise keeping the disk drive hoppin'. Only pick it if you don't mind the occasional false alarm. I personally never go below 10 seconds on a workstation, learned in the School of Hard Knocks. 20 seconds for a server class machine is safe.

like image 142
Hans Passant Avatar answered Sep 23 '22 10:09

Hans Passant


I realize this is an old question, but it never got resolved. This is my workaround.

Dim wmiScope As New Management.ManagementScope("\\" & HOST_COMPUTER_HERE & "\root\cimv2")
Dim exception As Exception = Nothing
Dim timeRan As Integer = 0
Dim wmiThread As Threading.Thread = New Threading.Thread(Sub() Wmi_Connect(wmiScope))
    wmiThread.Start()
    While wmiThread.ThreadState = Threading.ThreadState.Running
        Threading.Thread.Sleep(1000)
        timeRan += 1000
'WmiThreadTimeout is a global variable set to 10,000 miliseconds.
            If timeRan >= WmiThreadTimeout Then
                wmiThread = Nothing
                    exception = New Exception(HostName & " could not be connected to within the timeout period.")
                End If
                Exit While
            End If
        End While

Here's the thread.

Private Sub Wmi_Connect(ByRef wmiScope As Management.ManagementScope)
    Try
        wmiScope.Connect()
    Catch ex As System.Runtime.InteropServices.COMException
    End Try
End Sub

As I said, it's a workaround. It doesn't kill the thread, just stops it from blocking. (I do realize setting the Thread object to Nothing doesn't kill the thread.)

like image 24
Tyler Montney Avatar answered Sep 22 '22 10:09

Tyler Montney