我找到了多个在线教程,用于使用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,因为我认为其他人已经遇到了这个问题。任何信息/协助将不胜感激。感谢您阅读这篇冗长的文章。
答案 0 :(得分:0)
我不知道你的所有特殊功能是什么,但是这里有一个小例程来帮助你排除故障,应该能够将你的例程包装在一个线程中并给它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");
}
}
希望有助于或给你一些想法。
答案 1 :(得分:0)
我接受了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连接例程的行为一致。