WMI - выбор из Win32_Product занимает много времени
Я перечисляю установленные приложения, используя WMI, и этот блок занимает относительно много времени, чтобы завершить, независимо от того, как я его структурирую. Это занимает 13 секунд в моей среде каждый раз. Есть ли лучший (более быстрый) способ проверить, установлена ли программа? (Я использую iTunes в качестве примера программы для проверки)
private static string Timestamp
{
get { return DateTime.Now.ToString("HH:mm:ss.ffff"); }
}
private static void LoadInstalledPrograms()
{
List<string> installedPrograms = new List<string>();
Console.WriteLine("0 - {0}", Timestamp);
ManagementObjectSearcher mos = new ManagementObjectSearcher("SELECT * FROM Win32_Product");
Console.WriteLine("1 - {0}", Timestamp);
ManagementObjectCollection managementObjectCollection = mos.Get();
Console.WriteLine("2 - {0}", Timestamp);
foreach (ManagementObject mo in managementObjectCollection)
{
installedPrograms.Add(mo["Name"].ToString());
}
Console.WriteLine("3 - {0}", Timestamp);
Console.WriteLine("Length - {0}", installedPrograms.Count);
}
ВЫБРАТЬ * ИЗ Win32_Product
0 - 08:08:51.3762
1 - 08:08:51.3942
2 - 08:08:51.4012
3 - 08:09:04.8326
Length - 300
SELECT * FROM Win32_Product WHERE name = 'iTunes'
0 - 08:14:17.6529
1 - 08:14:17.6709
2 - 08:14:17.6779
3 - 08:14:31.0332
Length - 1
ВЫБЕРИТЕ * ИЗ Win32_Product, ГДЕ НАМ НРАВИТСЯ "iTunes"
0 - 08:16:38.2719
1 - 08:16:38.2899
2 - 08:16:38.2999
3 - 08:16:51.5113
Length - 1
ВЫБЕРИТЕ имя ИЗ Win32_Product, ГДЕ имя НРАВИТСЯ "iTunes"
0 - 08:19:53.9144
1 - 08:19:53.9324
2 - 08:19:53.9394
3 - 08:20:07.2794
Length - 1
6 ответов
WMI не торопится, как вы уже заметили. Итерация по реестру может помочь вам.
Вы можете взглянуть на Получить установленные приложения в системе здесь на stackru, где упоминаются оба метода.
Если вы запросите "Win32_product", msi-installer проверяет и проверяет каждый продукт.
Статья базы знаний http://support.microsoft.com/kb/974524 показывает:
Класс Win32_product не оптимизирован для запросов. Такие запросы, как "выберите * из Win32_Product, где (например," Sniffer% ")", требуют, чтобы WMI использовал поставщика MSI для перечисления всех установленных продуктов, а затем последовательно анализировал полный список для обработки предложения "где". Этот процесс также инициирует проверку согласованности установленных пакетов, проверку и исправление установки. С учетной записью, имеющей только пользовательские привилегии, так как учетная запись пользователя может не иметь доступа к нескольким местоположениям, может вызвать задержку запуска приложения и событие 11708, сообщающее об ошибке установки.
Win32reg_AddRemovePrograms - намного более легкий и эффективный способ сделать это, который избегает вызовов для проверки устойчивости, особенно в закрытой среде. Поэтому при использовании Win32reg_AddRemovePrograms мы не будем вызывать msiprov.dll и не будем инициировать проверку устойчивости.
Так что будьте осторожны с "Win32_product".
Обновление: хорошая статья https://sdmsoftware.com/group-policy-blog/wmi/why-win32_product-is-bad-news/
Как упомянуто здесь, Реестр ненадежен, а WMI работает медленно. Таким образом, для меня лучшим вариантом было использование Windows Installer API. Добавьте msi.dll к вашим ссылкам, а затем адаптируйте следующий код к вашим потребностям:
public static string GetVersionOfInstalledApplication(string queryName)
{
string name;
string version;
Type type = Type.GetTypeFromProgID("WindowsInstaller.Installer");
Installer installer = Activator.CreateInstance(type) as Installer;
StringList products = installer.Products;
foreach (string productGuid in products)
{
string currName = installer.ProductInfo[productGuid, "ProductName"];
string currVersion = installer.ProductInfo[productGuid, "VersionString"];
if (currName == queryName)
{
name = currName;
version = currVersion;
return version;
}
}
return null;
}
Как указывает Бернхард, использование WMI Win32_Product инициирует проверку целостности состояния пакета и, следовательно, будет довольно медленным в использовании - и в особых случаях может вызвать самовосстановление MSI (я никогда не видел, чтобы это происходило на моих машинах),
Вместо WMI можно напрямую использовать интерфейс автоматизации MSI для перечисления приложений, установленных с помощью пакетов установщика Windows (файлы MSI) на компьютере. Это очень быстро и вообще не касается WMI.
Посмотрите этот пример: как узнать, какие продукты установлены - на более новый продукт уже установлены окна MSI (полнофункциональный, но простой и понятный пример VBScript - ознакомьтесь с ним). Есть много свойств, которые вы можете получить для каждого продукта, пожалуйста, обратитесь к документации MSDN для интерфейса автоматизации MSI. Надеюсь, что связанный пример кода VBScript и документация MSDN, взятые вместе, должны помочь вам быстро начать работу.
PS: я знаю, что это старый вопрос, но эта проблема продолжает появляться (особенно медлительность WMI) - просто для дальнейшего использования.
Вы должны использовать SELECT Name FROM Win32_Product
в WMI Query у меня работает
SELECT *
сделать загрузку всех членов данных, поэтому его использование занимает много времени
Powershell 5.1 вместо этого имеет «get-package».
get-package *chrome*
Name Version Source ProviderName
---- ------- ------ ------------
Google Chrome 109.0.5414.75 msi