【问题标题】:How to get methods from WMI如何从 WMI 获取方法
【发布时间】:2018-04-12 14:12:55
【问题描述】:

tl;dr 我应该用SELECT 而不是* 来获取方法?

更多信息:

这是一个例子:

using (var s = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM someClass"))
    foreach (var obj in s.Get())

如果我只要求一个属性是不够的 - 我在尝试 obj.InvokeMethod(...); 时遇到异常。

如果我要求 * 就足够了,但如果可能的话,我宁愿避免这样做。

我在 WMI 类的文档中看不到任何用于获取方法(-DisableEnable、...)的属性。如果列表中没有 - * 怎么会起作用?它不应该只是询问所有列表中的人吗?

编辑

有人建议使用ManagementClass 而不是ManagementObjectSearcher。这会加载像* 这样的所有属性吗? (如果不是,这是一个很好的答案。虽然在我的实际情况下,除了调用方法的能力之外,我还需要一个属性。我的理论问题仍然存在 - * 不仅仅是 all。)

【问题讨论】:

  • WMI 很难找到你需要的东西,但这个工具对我了解它是如何工作的很有帮助。 microsoft.com/en-us/download/details.aspx?id=8572.
  • 看起来他们把它拿下了……如果你愿意,我还有它,我可以托管它并提供下载链接。
  • @SamMarion 谢谢。我已经在某处拥有该工具。 (至少我认为我这样做)但我的问题不仅仅是如何获得这些方法。我的问题是如何使用* 获得它们不使用
  • 该工具会生成不使用星号的代码,如果我没记错的话,它会告诉你哪些方法是可用的。不是吗?
  • 没关系,我似乎记得微软提供的工具在所有查询中都使用了 *,抱歉。

标签: c# .net methods wmi system.management


【解决方案1】:

就标题和 TL;DR 的要求而言,无法通过 SELECT 查询方法,但您可以使用 ManagementClass.Methods property 来检查该管理类提供的方法。比如这段代码……

using (ManagementClass processClass = new ManagementClass("Win32_Process"))
    foreach (MethodData method in processClass.Methods)
    {
        bool isStatic = method.Qualifiers
            .Cast<QualifierData>()
            .Any(qualifier => string.Equals(qualifier.Name, "Static", StringComparison.OrdinalIgnoreCase));

        Console.WriteLine($"{method.Origin}.{method.Name}() [{(isStatic ? "static" : "instance")}]");
        if (method.InParameters != null && method.InParameters.Properties.Count > 0)
        {
            Console.WriteLine("\tInput parameters:");
            foreach (PropertyData parameterProperty in method.InParameters.Properties)
                Console.WriteLine($"\t\t{parameterProperty.Type} {parameterProperty.Name}");
        }
        if (method.OutParameters != null && method.OutParameters.Properties.Count > 0)
        {
            Console.WriteLine("\tOutput parameters:");
            foreach (PropertyData parameterProperty in method.OutParameters.Properties)
                Console.WriteLine($"\t\t{parameterProperty.Type} {parameterProperty.Name}");
        }
    }

...产生这个输出...

Win32_Process.Create() [static]
    Input parameters:
        String CommandLine
        String CurrentDirectory
        Object ProcessStartupInformation
    Output parameters:
        UInt32 ProcessId
        UInt32 ReturnValue
Win32_Process.Terminate() [instance]
    Input parameters:
        UInt32 Reason
    Output parameters:
        UInt32 ReturnValue
Win32_Process.GetOwner() [instance]
    Output parameters:
        String Domain
        UInt32 ReturnValue
        String User
...

除非“获取方法”的含义与我认为的不同(不同于 调用 方法),否则问题的其余部分似乎完全是在处理其他事情,这是在调用方法之前填充Key 属性。我相信这在你的另一个问题中得到了解决,Why does WMI work through a search but not directly?

如果您真的要问的是“我如何确定我需要选择的最小属性集才能调用一个方法?”,那么您可以使用ManagementClass 来完成它, 也。该最小属性集是所有带有Key qualifier 的属性,因此您可以使用Properties property 来查找其Qualifiers property 包含带有Name"Key" 的限定符的任何属性。

考虑 Win32_Product class,它代表由 Windows Installer 安装的产品并且(在我的 Windows 10 系统上确定,与文档不同)具有这些 Key 属性...

  • IdentifyingNumber
  • Name
  • Version

假设您要检索这些属性以显示...

  • PackageName
  • Vendor
  • Version

...然后调用Uninstall() method 获取Name"Microsoft .NET Framework 4.8 SDK" 的产品。以下代码显示了尝试此任务的三种不同方式...

  1. 选择所有属性并调用该方法。
  2. 只选择要显示的属性并调用该方法。
  3. 选择要显示的属性以及Key 属性并调用该方法。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;

namespace SO49798851
{
    static class Program
    {
        static void Main()
        {
            // Win32_Product is slow to query, so be patient!
            const string className = "Win32_Product";
            const string condition = "Name = 'Microsoft .NET Framework 4.8 SDK'";
            string[] allProperties = new string[] { "*" };
            string[] displayProperties = new string[] { "PackageName", "Vendor", "Version" };
            string[] keyProperties = GetKeyPropertyNames(className);
            string[] displayPlusKeyProperties = displayProperties.Union(keyProperties).ToArray();
            // When run as a non-administrator, the Uninstall() method
            // still returns 0 despite not (appearing to) do anything
            const string methodName = "Uninstall";
            object[] methodArguments = Array.Empty<object>();

            Console.WriteLine($"Key properties for class {className}: {string.Join(", ", keyProperties)}");
            Console.WriteLine();

            FindAndInvoke(className, condition, allProperties,            methodName, methodArguments);
            FindAndInvoke(className, condition, displayProperties,        methodName, methodArguments);
            FindAndInvoke(className, condition, displayPlusKeyProperties, methodName, methodArguments);
        }

        static string[] GetKeyPropertyNames(string className)
        {
            using (ManagementClass managementClass = new ManagementClass(className))
            {
                return managementClass.Properties
                    .Cast<PropertyData>()
                    .Where(
                        property => property.Qualifiers
                            .Cast<QualifierData>()
                            .Any(qualifier => string.Equals(qualifier.Name, "Key", StringComparison.OrdinalIgnoreCase))
                    )
                    .Select(property => property.Name)
                    .ToArray();
            }
        }

        static void FindAndInvoke(
            string className,
            string condition,
            string[] selectedProperties,
            string methodName,
            object[] methodArguments
        )
        {
            if (selectedProperties == null)
                selectedProperties = Array.Empty<string>();

            ObjectQuery query = new SelectQuery(className, condition, selectedProperties);
            bool allPropertiesSelected = selectedProperties.Length < 1
                || selectedProperties.Any(propertyName => propertyName == "*");

            Console.WriteLine(query.QueryString);
            Console.WriteLine(new string('=', query.QueryString.Length));

            using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(query))
            using (ManagementObjectCollection searchResultCollection = searcher.Get())
            {
                // ManagementObjectCollection doesn't support indexing; this is the
                // least-ugly, least-verbose way to enumerate it with an index variable
                ManagementObject[] searchResultArray = searchResultCollection.Cast<ManagementObject>().ToArray();

                for (int i = 0; i < searchResultArray.Length; i++)
                    using (ManagementObject searchResult = searchResultArray[i])
                    {
                        Console.WriteLine($"{className}[{i}].Path.RelativePath: {searchResult.Path.RelativePath}");
                        Console.WriteLine($"{className}[{i}].Properties.Count: {searchResult.Properties.Count}");
                        foreach (PropertyData property in searchResult.Properties)
                            if (allPropertiesSelected
                                    || selectedProperties.Contains(property.Name, StringComparer.OrdinalIgnoreCase)
                            )
                            {
                                object displayValue = property.Value ?? "<null>";

                                Console.WriteLine($"{className}[{i}].Properties[\"{property.Name}\"]: {displayValue}");
                            }

                        try
                        {
                            object methodResult = searchResult.InvokeMethod(methodName, methodArguments);

                            Console.WriteLine($"{className}[{i}].{methodName}() completed with result {methodResult}.");
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine($"{className}[{i}].{methodName}() failed with {ex}.");
                        }
                        Console.WriteLine();
                    }
            }
        }
    }
}

...并产生此输出...

Key properties for class Win32_Product: IdentifyingNumber, Name, Version

select * from Win32_Product where Name = 'Microsoft .NET Framework 4.8 SDK'
===========================================================================
Win32_Product[0].Path.RelativePath: Win32_Product.IdentifyingNumber="{949C0535-171C-480F-9CF4-D25C9E60FE88}",Name="Microsoft .NET Framework 4.8 SDK",Version="4.8.03928"
Win32_Product[0].Properties.Count: 27
Win32_Product[0].Properties["AssignmentType"]: 1
Win32_Product[0].Properties["Caption"]: Microsoft .NET Framework 4.8 SDK
Win32_Product[0].Properties["Description"]: Microsoft .NET Framework 4.8 SDK
Win32_Product[0].Properties["HelpLink"]: <null>
Win32_Product[0].Properties["HelpTelephone"]: <null>
Win32_Product[0].Properties["IdentifyingNumber"]: {949C0535-171C-480F-9CF4-D25C9E60FE88}
Win32_Product[0].Properties["InstallDate"]: 20191001
Win32_Product[0].Properties["InstallDate2"]: <null>
Win32_Product[0].Properties["InstallLocation"]: <null>
Win32_Product[0].Properties["InstallSource"]: C:\ProgramData\Microsoft\VisualStudio\Packages\Microsoft.Net.4.8.SDK,version=4.8.3928.1\
Win32_Product[0].Properties["InstallState"]: 5
Win32_Product[0].Properties["Language"]: 1033
Win32_Product[0].Properties["LocalPackage"]: C:\WINDOWS\Installer\34d24bd7.msi
Win32_Product[0].Properties["Name"]: Microsoft .NET Framework 4.8 SDK
Win32_Product[0].Properties["PackageCache"]: C:\WINDOWS\Installer\34d24bd7.msi
Win32_Product[0].Properties["PackageCode"]: {CC6C9CC4-DDCD-4C14-81E1-4007EE49D7C0}
Win32_Product[0].Properties["PackageName"]: sdk_tools48.msi
Win32_Product[0].Properties["ProductID"]: <null>
Win32_Product[0].Properties["RegCompany"]: <null>
Win32_Product[0].Properties["RegOwner"]: <null>
Win32_Product[0].Properties["SKUNumber"]: <null>
Win32_Product[0].Properties["Transforms"]: <null>
Win32_Product[0].Properties["URLInfoAbout"]: <null>
Win32_Product[0].Properties["URLUpdateInfo"]: <null>
Win32_Product[0].Properties["Vendor"]: Microsoft Corporation
Win32_Product[0].Properties["Version"]: 4.8.03928
Win32_Product[0].Properties["WordCount"]: 0
Win32_Product[0].Uninstall() completed with result 0.

select PackageName,Vendor,Version from Win32_Product where Name = 'Microsoft .NET Framework 4.8 SDK'
====================================================================================================
Win32_Product[0].Path.RelativePath: 
Win32_Product[0].Properties.Count: 3
Win32_Product[0].Properties["PackageName"]: sdk_tools48.msi
Win32_Product[0].Properties["Vendor"]: Microsoft Corporation
Win32_Product[0].Properties["Version"]: 4.8.03928
Win32_Product[0].Uninstall() failed with System.InvalidOperationException: Operation is not valid due to the current state of the object.
   at System.Management.ManagementObject.InvokeMethod(String methodName, Object[] args)
   at SO49798851.Program.FindAndInvoke(String className, String condition, String[] selectedProperties, String methodName, Object[] methodArguments) in ...\Program.cs:line 90.

select PackageName,Vendor,Version,IdentifyingNumber,Name from Win32_Product where Name = 'Microsoft .NET Framework 4.8 SDK'
===========================================================================================================================
Win32_Product[0].Path.RelativePath: Win32_Product.IdentifyingNumber="{949C0535-171C-480F-9CF4-D25C9E60FE88}",Name="Microsoft .NET Framework 4.8 SDK",Version="4.8.03928"
Win32_Product[0].Properties.Count: 5
Win32_Product[0].Properties["IdentifyingNumber"]: {949C0535-171C-480F-9CF4-D25C9E60FE88}
Win32_Product[0].Properties["Name"]: Microsoft .NET Framework 4.8 SDK
Win32_Product[0].Properties["PackageName"]: sdk_tools48.msi
Win32_Product[0].Properties["Vendor"]: Microsoft Corporation
Win32_Product[0].Properties["Version"]: 4.8.03928
Win32_Product[0].Uninstall() completed with result 0.

以下是这三个尝试的收获...

  1. 当然,选择所有属性会导致方法调用成功,但我们最终会得到比我们想要的更多的属性。
  2. 准确选择我们想要的属性——但不是所有Key 属性——会导致方法调用失败。
    • 请注意,尽管Key 属性之一Version 是我们查询的一部分,但在这种情况下searchResult.Path property 是空的,这肯定表明我们的结果对象有些地方不太对劲。
  3. 准确选择我们想要的属性加上Key 属性会导致成功的方法调用没有多余的属性。
    • 如果我们有一组我们想要的属性(即displayProperties)和一组Key 属性(即keyProperties),Union() LINQ method 可以很容易地组合它们以获得最少的属性来选择.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多