如何从WMI获取方法 [英] How to get methods from WMI

查看:104
本文介绍了如何从WMI获取方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

tl;dr What should I SELECT instead of * in order to get the methods?

更多信息:

这是一个例子:

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

如果我只想要一个属性,那还不够-在尝试obj.InvokeMethod(...);时会遇到异常.

If I just ask for one property it's not enough - I get an exception when trying obj.InvokeMethod(...);.

如果我要求*就足够了,但我宁愿避免这种情况.

If I ask for * it is enough but I rather avoid this if possible.

在WMI类的文档中,我没有看到用于获取方法(-DisableEnable,...)的任何属性.如果列表中不是 -*的工作原理是什么?

I don't see any property for getting the methods (-Disable, Enable,...) in the docs for WMI classes. And if it's not on the list - how come * works? Isn't it just supposed to ask for all of those on the list?

编辑

有人建议使用 ManagementClass 而不是ManagementObjectSearcher.是否会加载所有属性,例如*? (如果不是,那是一个很好的答案.尽管在我的实际情况中,除了需要具有调用方法的能力外,我还需要一个属性.而且我的理论问题仍然存在-是*而不是 all .)

Someone suggested using ManagementClass instead of ManagementObjectSearcher. Does this load all properties like *? (If not, that's a good answer. Though in my actual case I need a property besides the ability to call a method. And my theoretical questions remains - is * more than just all.)

推荐答案

就标题和TL; DR的要求而言,无法通过SELECT查询方法,但可以使用

As far as what the title and TL;DR are asking, methods cannot be queried via SELECT but you can use the ManagementClass.Methods property to inspect those provided by that management class. For example, this code...

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}");
        }
    }

...产生此输出...

...produces this output...

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属性.我相信这是您的另一个问题, WMI为什么通过搜索而不是直接通过搜索工作?

Unless "get methods" has a different meaning than I think it does (distinct from calling methods), the rest of the question seems to be dealing with something else entirely, which is the necessity of populating Key properties before invoking a method. I believe this is addressed in another question of yours, Why does WMI work through a search but not directly?

如果您真正询问的是如何确定为调用方法而需要选择的最小属性集?",则可以使用ManagementClass完成该操作, 也.该最小属性集是所有具有 Key限定符的属性,因此您可以使用 Properties属性来查找 Qualifiers属性包含带有"Key" Name .

If what you're really asking is "How can I determine the minimum set of properties I need to select in order to invoke a method?", then you can accomplish that with ManagementClass, too. That minimum set of properties are all properties with a Key qualifier, so you would use the Properties property to find any property whose Qualifiers property contains a qualifier with a Name of "Key".

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

Consider the Win32_Product class, which represents products installed by Windows Installer and (as determined on my Windows 10 system, differing from the documentation) has these Key properties...

  • IdentifyingNumber
  • Name
  • Version
  • IdentifyingNumber
  • Name
  • Version

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

Let's say you want to retrieve these properties to display...

  • PackageName
  • Vendor
  • Version
  • PackageName
  • Vendor
  • Version

...,然后为具有<<的产品调用 Uninstall()方法 "Microsoft .NET Framework 4.8 SDK"的c18>.以下代码显示了尝试此任务的三种不同方式...

...and then call the Uninstall() method for a product with a Name of "Microsoft .NET Framework 4.8 SDK". The following code shows three different ways to attempt this task...

  1. 选择所有属性并调用该方法.
  2. 仅选择要显示的属性并调用该方法.
  3. 选择要显示的属性以及Key属性,然后调用该方法.
  1. Select all properties and invoke the method.
  2. Select only the properties you want to display and invoke the method.
  3. Select the properties you want to display plus the Key properties and invoke the method.

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();
                    }
            }
        }
    }
}

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

...and produces this output...

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.

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

Here are the takeaways from those three attempts...

  1. 选择所有属性当然会导致成功的方法调用,但是最终我们获得了比我们想要的更多的属性.
  2. 精确选择我们想要的属性-但不是全部Key属性-导致方法调用失败.
    • 请注意,尽管Key属性之一Version是我们查询的一部分,但
  1. Selecting all properties, of course, results in a successful method invocation, but we end up with way more properties than we wanted.
  2. Selecting exactly the properties we want - but not all Key properties - results in a failed method invocation.
    • Notice that even though one of the Key properties, Version, was part of our query, the searchResult.Path property is empty in this case, a sure sign that something isn't quite right with our result object.
  • If we have a collection of properties we want (i.e. displayProperties) and a collection of Key properties (i.e. keyProperties), the Union() LINQ method makes it easy to combine them to get the minimum properties to select.

这篇关于如何从WMI获取方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆