API WMI зависают при вводе неверных учетных данных - PullRequest
1 голос
/ 18 октября 2011

Я нашел несколько онлайновых руководств по установке WMI-соединений с удаленными компьютерами с помощью c #. Эти учебные пособия описывают процесс, подобный следующему:

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 () зависает (по-видимому) бесконечно. Аналогичным образом, вызов функции Connect () в ManagementScope зависает аналогичным образом.

У нас есть похожая логика для выполнения эквивалентных команд WMI в c ++, и я могу сообщить, что они возвращаются почти немедленно, если предоставлены неправильные учетные данные. Соответствующее сообщение «Отказано в доступе» возвращается. Хосты, которые я сейчас использую для тестирования, те же самые, которые мы используем при тестировании нашей существующей логики c ++, поэтому у меня нет оснований полагать, что WMI неправильно настроен в нашей среде.

Я искал проблемы тайм-аута, связанные с соединениями WMI в c #. Я исследовал свойство Timeout в ConnectionOptions и moSearcher.Options. Я также рассмотрел свойство ReturnImmediately объекта EnumerationOptions, которое можно связать с экземпляром ManagementObjectSearcher. Эти параметры не дали желаемого эффекта для меня.

Полагаю, я мог бы выполнить эти команды WMI в отдельном потоке и окружить поток кодом мониторинга, который убивает его, если он не вернулся в течение разумного периода времени. Это похоже на изрядное количество работы, которая будет проделана всем потребителям подпрограмм c # WMI, и я надеюсь, что есть более простой способ. Кроме того, я не уверен, что уничтожение выдающегося потока таким образом правильно очищает соединение WMI.

Проверка связи с удаленным хостом не приносит мне никакой пользы, потому что знание того, что хост запущен и работает, не говорит мне, соответствуют ли мои учетные данные (и если вызовы c # WMI будут зависать). Есть ли другой способ проверки учетных данных на удаленном хосте?

Всегда возможно, что я пропускаю очевидный флаг или API, потому что я думаю, что другие столкнулись с этой проблемой. Любая информация / помощь будет принята с благодарностью. Спасибо за чтение этого длинного поста.

Ответы [ 2 ]

0 голосов
/ 19 октября 2011

Я принял предложение jp, чтобы окружить вызовы API WMI в отдельном потоке, который можно было бы уничтожить, если они превысили тайм-аут. При тестировании отдельный поток генерировал исключение типа 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;
}

(обратите внимание, что выражение catch System.Runtime.InteropServices.COMException уже существовало в моем коде)

Я не знаю, почему это исключение не генерируется (или, по крайней мере, не доводится до сведения пользователя через VS 2010 IDE) при выполнении в качестве части родительского потока. В любом случае, это именно то, что я искал, и это согласуется с поведением подпрограмм подключения WMI в c ++.

0 голосов
/ 18 октября 2011

Я не знаю, каковы все ваши специальные функции, но вот небольшая подпрограмма, которая поможет вам устранить неполадки, которые должны быть в состоянии обернуть вашу подпрограмму в поток и дать ей 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");
  }
}

Надеюсь, что это помогает или дает вам некоторые идеи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...