【问题标题】:WMI APIs hang when supplied incorrect credentials提供不正确的凭据时 WMI API 挂起
【发布时间】:2011-12-09 15:28:15
【问题描述】:

我找到了多个使用 c# 建立与远程计算机的 WMI 连接的在线教程。这些教程描述了如下过程:

ConnectionOptions cOpts = new ConnectionOptions();
ManagementObjectCollection moCollection;
ManagementObjectSearcher moSearcher;
ManagementScope mScope;
ObjectQuery oQuery;

mScope = new ManagementScope(String.Format("\\\\{0}\\{1}", host.hostname, "ROOT\\CIMV2"), cOpts);
oQuery = new ObjectQuery("Select * from Win32_OperatingSystem");
moSearcher = new ManagementObjectSearcher(mScope, oQuery);

moCollection = moSearcher.Get();

快乐路径案例 - 连接到本地主机,或使用适当的凭据连接到远程主机 - 工作正常。我正在做一个项目,当当前登录的帐户无权访问我们尝试连接的远程主机时,我们需要支持这种情况。也就是说,我们需要抓住这种情况,提醒用户注意错误的凭据,并提示他们再次提供凭据。

当我在我的 ConnectionOptions 对象中指定在远程计算机上没有上下文的凭据时,我对 moSearcher.Get() 的调用会无限期地挂起(似乎)。同样,对 ManagementScope 中的 Connect() 函数的调用以相同的方式挂起。

我们有类似的逻辑来在 c++ 中执行等效的 WMI 命令,我可以报告如果提供了不正确的凭据,这些命令几乎会立即返回。返回适当的“访问被拒绝”消息。我现在用于测试目的的主机与我们在测试现有 c++ 逻辑时使用的主机相同,因此我没有理由相信 WMI 在我们的环境中配置不正确。

我已经在 c# 中搜索了围绕 WMI 连接的超时问题。我已经探索了 ConnectionOptions 和 moSearcher.Options 的 Timeout 属性。我还查看了可以与 ManagementObjectSearcher 实例关联的 EnumerationOptions 对象的 ReturnImmediately 属性。这些选项对我来说没有达到预期的效果。

我想我可以在一个单独的线程中执行这些 WMI 命令,并用监视代码包围该线程,如果它在合理的时间内没有返回,则将其杀死。这似乎是相当多的工作将推给 c# WMI 例程的所有消费者,我希望有一种更简单的方法。另外,我不确定以这种方式杀死一个未完成的线程是否会正确清理 WMI 连接。

ping 远程主机对我没有任何好处,因为知道主机已启动并正在运行并不能告诉我我拥有的凭据是否合适(以及 c# WMI 调用是否会挂起)。还有其他方法可以针对远程主机验证凭据吗?

总是有可能我缺少一个明显的标志或 API,因为我认为其他人已经遇到了这个问题。任何信息/帮助将不胜感激。感谢您阅读这篇冗长的文章。

【问题讨论】:

    标签: c# wmi


    【解决方案1】:

    我不知道你所有的特殊功能是什么,但这里有一个小例程可以帮助你排除故障,它应该能够将你的例程包装在一个线程中并给它 5 秒的时间来执行:

    void Fake() {
      bool ok = false;
      ConnectionOptions cOpts = new ConnectionOptions();
      ManagementObjectCollection moCollection;
      ManagementObjectSearcher moSearcher;
      ManagementScope mScope;
      ObjectQuery oQuery;
      if (cOpts != null) {
        mScope = new ManagementScope(String.Format("\\\\{0}\\{1}", host.hostname, "ROOT\\CIMV2"), cOpts);
        if (mScope != null) {
          oQuery = new ObjectQuery("Select * from Win32_OperatingSystem");
          if (oQuery != null) {
            moSearcher = new ManagementObjectSearcher(mScope, oQuery);
            if (moSearcher != null) {
              ManualResetEvent mre = new ManualResetEvent(false);
              Thread thread1 = new Thread(() => {
                moCollection = moSearcher.Get();
                mre.Set();
              };
              thread1.Start();
              ok = mre.WaitOne(5000); // wait 5 seconds
            } else {
              Console.WriteLine("ManagementObjectSearcher failed");
            }
          } else {
            Console.WriteLine("ObjectQuery failed");
          }
        } else {
          Console.WriteLine("ManagementScope failed");
        }
      } else {
        Console.WriteLine("ConnectionOptions failed");
      }
    }
    

    希望对您有所帮助或提供一些想法。

    【讨论】:

    • 感谢 jp 的快速回复。该单独的线程代码是一种选择。让我感觉更好的是发现其他人在以我的方式使用这些 API 时遇到了同样的问题。
    • 还要注意,错误检查一直在通知您,开发人员,有些地方出了问题。如果您的代码通过错误检查步骤一直到moCollection = moSearcher.Get() 行,那么您可能需要查找Get() 函数以查看它是否提供了任何重载或错误代码。希望对您有所帮助。
    • 例如这个链接>> msdn.microsoft.com/en-us/library/67a77ef1.aspx Full trust for the immediate caller. This member cannot be used by partially trusted code.”
    • 在这种情况下,错误检查并不能救我。也就是说,没有一个对象在其构造函数之后为空。看来我得走单独的线程路线了。希望遇到此问题的其他人可以从这篇文章中受益并节省时间。感谢 jp 的输入。
    【解决方案2】:

    我接受了 jp 的建议,将 WMI API 调用包含在一个单独的线程中,如果它们超过超时,则可能会被终止。测试时,单独的线程抛出了 System.UnauthorizedAccessException 类型的异常。我删除了线程逻辑并添加了一个 catch 语句来处理这种异常类型。果然,在调用 ManagementObjectSearcher.Get() 之后几乎立即捕获到异常。

    try
    {
        moCollection = moSearcher.Get();
    }
    
    catch (System.UnauthorizedAccessException)
    {
        return Program.ERROR_FUNCTION_FAILED;
    }
    
    catch (System.Runtime.InteropServices.COMException)
    {
        MessageBox.Show("Error, caught COMException.");
        return Program.ERROR_FUNCTION_FAILED;
    }
    

    (请注意,我的代码中已经存在 System.Runtime.InteropServices.COMException catch 语句)

    我不知道为什么在作为父线程的一部分执行时没有抛出这个异常(或者至少没有通过 VS 2010 IDE 引起用户的注意)。无论如何,这正是我所寻找的,并且与 C++ 中 WMI 连接例程的行为一致。

    【讨论】:

      猜你喜欢
      • 2013-03-10
      • 1970-01-01
      • 2012-04-01
      • 1970-01-01
      • 2019-12-22
      • 2013-09-15
      • 2011-03-13
      • 2012-09-19
      • 1970-01-01
      相关资源
      最近更新 更多