【问题标题】:What's the proper way to pass an array to a WMI Method?将数组传递给 WMI 方法的正确方法是什么?
【发布时间】:2013-06-14 12:37:59
【问题描述】:

我正在用 C# 编写一个查询 WMI 的函数,它使用从 WMI 返回的对象作为不同 WMI 类中方法的参数。

private void InstallUpdates()
{
    ManagementScope sc = new ManagementScope(@"\\.\root\ccm\clientsdk");
    ManagementClass c = new ManagementClass(@"CCM_SoftwareUpdatesManager");
    ManagementObjectSearcher s = new ManagementObjectSearcher("SELECT * FROM CCM_SOFTWAREUPDATE WHERE COMPLIANCESTATE=0 AND EVALUATIONSTATE < 2");
    c.Scope = s.Scope = sc;

    ManagementObjectCollection col = s.Get();
    List<ManagementObject> lUpdates = new List<ManagementObject>();

    //Install each update individually and track progress
    int index = 1;
    foreach (ManagementObject o in col)
    {


        object[] args = { o };

        object[] methodArgs = { args, null };

        lblCurrentAction.Text = "Now running method: Install Updates " + o.Properties["Name"].Value + " EvalState=" + (UInt32)o.Properties["EvaluationState"].Value;

        c.InvokeMethod("InstallUpdates",methodArgs);

        lblCurrentUpdate.Text = "Now Installing Update " + index + " of " + col.Count + ": " + o.Properties["name"].Value;

        UInt32 intProgress = (UInt32)o.Properties["PercentComplete"].Value;

        UInt32 evalState = (UInt32)o.Properties["EvaluationState"].Value;

        lblCurrentAction.Text = lblCurrentAction.Text + " EvalState: " + evalState;

        while (evalState <=  7)
        {
            progressBar1.Value = (intProgress <= 100) ? (int)intProgress : 100;
            evalState = (UInt32)o.Properties["EvaluationState"].Value;
            intProgress = (UInt32)o.Properties["PercentComplete"].Value;
            lblCurrentAction.Text = lblCurrentAction.Text + " EvalState: " + evalState;
        }

        ++index;

    }





}

我粘贴了整个函数以供参考,但问题行是 foreach 循环内的 #1、2 和 4。从文档here 中,该方法将 ccm_softwareupdate 对象数组作为参数,我已经成功地从不同的类中查询了该数组(并且正在对集合运行 foreach),所以我知道这些对象存在。

任何,因为这些是系统更新,我想一次安装一个,至少在测试期间,但是当我将单个对象数组传递给方法时

object[] args = { o };

c.InvokeMethod("InstallUpdates", args);

我收到一个转换错误:

无法将“system.management.managementobject”类型的对象转换为 system.array

所以某处显然将我的数组视为一个对象。我知道它没有使用 WMI 方法,因为我没有看到更新开始安装。

从网上阅读,我也尝试了现在函数中的内容:

object[] args = { o };

object[] methodArgs = { args, null };

c.InvokeMethod("InstallUpdates", methodArgs);

这里的关键是创建一个 second 数组,其中包含第一个数组和一个空值作为第二个值。这实际上有效并且调用了 WMI 方法,但它从不从该方法返回,代码只是挂起。切换参数

object[] methodArgs = { null, args };

显示它实际上挂在 null 参数上,因为这里更新永远不会开始安装。我也试过这个作为健全性检查

object[] args = { o, o };

c.InvokeMethod("InstallUpdates", args);

但是我得到了同样的转换错误,所以我必须在正确的轨道上使用双数组方法。另外,使用

object[] methodArgs = { args, 0};

object[] methodArgs = { args };

不起作用。

重申一下,我正在寻找一种使用 C# 将数组传递给 WMI 方法的方法。


更新

这个 powershell 脚本做同样的事情,并且确实有效。唯一的区别是它的初始数组有多个对象,但这无关紧要。

    #    '=================================================================== 
#    ' DISCLAIMER: 
#    '------------------------------------------------------------------- 
#    ' 
#    ' This sample is provided as is and is not meant for use on a  
#    ' production environment. It is provided only for illustrative  
#    ' purposes. The end user must test and modify the sample to suit  
#    ' their target environment. 
#    '  
#    ' Microsoft can make no representation concerning the content of  
#    ' this sample. Microsoft is providing this information only as a  
#    ' convenience to you. This is to inform you that Microsoft has not  
#    ' tested the sample and therefore cannot make any representations  
#    ' regarding the quality, safety, or suitability of any code or  
#    ' information found here. 
#    '  
#    '=================================================================== 

# This is a simpple get of all instances of CCM_SoftwareUpdate from root\CCM\ClientSDK 
$MissingUpdates = Get-WmiObject -Class CCM_SoftwareUpdate -Filter ComplianceState=0 -Namespace root\CCM\ClientSDK 

# The following is done to do 2 things: Get the missing updates (ComplianceState=0)  
# and take the PowerShell object and turn it into an array of WMI objects 
$MissingUpdatesReformatted = @($MissingUpdates | ForEach-Object {if($_.ComplianceState -eq 0){[WMI]$_.__PATH}}) 

# The following is the invoke of the CCM_SoftwareUpdatesManager.InstallUpdates with our found updates 
# NOTE: the command in the ArgumentList is intentional, as it flattens the Object into a System.Array for us 
# The WMI method requires it in this format. 
$InstallReturn = Invoke-WmiMethod -Class CCM_SoftwareUpdatesManager -Name InstallUpdates -ArgumentList (,$MissingUpdatesReformatted) -Namespace root\ccm\clientsdk 

【问题讨论】:

  • 您对InstallUpdates 方法本身了解吗?很明显,您所指的转换错误是该方法出于某种原因想要接收数组的结果。如果对InvokeMethod 的调用永远不会返回,那么我认为在某种程度上正在消耗一个异常。你知道那可能是什么吗?
  • 你是对的,你需要额外的数组,因为 p1 是一个数组。我在想 null 是这里的实例对象,应该首先出现,您可以尝试 c.CreateInstance() 而不是 null。 (但挂起也可能是由于其他原因,比如范围)
  • @ebyrob put c.CreateInstance() first 再次给了我一个演员错误,把它放在第二个给了我同样的挂起。我已经发布了一个实际有效的 powershell 脚本,我只是不知道如何在 c# 中做同样的事情。
  • @MDMoore313 什么是强制转换异常?它应该告诉你预期的第一个参数是什么......
  • 您也可以尝试捕获 SMS 错误类型,但不确定您是否已经捕获或只是捕获一般异常。请参阅此处了解您可以捕获的 SMS 异常类型,这些类型可能会提供更多详细信息。 msdn.microsoft.com/en-us/library/hh949216.aspx

标签: c# arrays methods wmi


【解决方案1】:

我在寻找触发 CCM 代理安装更新的 C# 方法时遇到了这个问题。这是我在生产应用程序中运行的内容。

using (var searcher = new ManagementObjectSearcher(string.Format(@"\\{0}\root\CCM\ClientSDK", strComputerName), string.Format("SELECT * FROM CCM_SoftwareUpdate WHERE Name=\"{0}\"", strUpdateName)))
foreach (var obj in searcher.Get())
    using (var mInv = new ManagementClass(string.Format(@"\\{0}\root\CCM\ClientSDK", strComputerName), "CCM_SoftwareUpdatesManager", null))
        mInv.InvokeMethod("InstallUpdates", new object[] { new ManagementBaseObject[] { obj } });

【讨论】:

  • 嵌套数组看起来不错,虽然我不再从事 SCCM 业务,但我仍然在 C# 业务中。为您的努力获得一些代表。
猜你喜欢
  • 2016-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-20
  • 1970-01-01
  • 2020-11-10
  • 1970-01-01
相关资源
最近更新 更多