【问题标题】:Pass array of CimInstance to CimMethod将 CimInstance 数组传递给 CimMethod
【发布时间】:2015-03-17 05:45:10
【问题描述】:

我正在通过 Cim cmdlet 使用 WMI API。问题是我不知道如何将 wmi 对象传递给接受 wmi 对象数组的 wmi 方法。

这里是方法参数定义:

Name                                            CimType Qualifiers
----                                            ------- ----------
Path                                             String {ID, in}
Permissions                               InstanceArray {EmbeddedInstance, ID, in}
ResetChildren                                   Boolean {ID, in}

PathResetChildren 是简单的参数。它们分别接受像"/path"$true 这样的简单值。但是Permissions参数有问题。

这是我的代码

#Acquiring object that I want to pass to method
$group = Get-CimInstance -Namespace "root\VisualSVN" -ClassName VisualSVN_Group -Filter "Name='Readers'"

#Acquiring object which method will be called
$repositories = Get-CimInstance -Namespace "root\VisualSVN" -ClassName VisualSVN_Repository

#Preparing method arguments
$args = @{
    Path = "/";
    Permissions = @($group[0]); #Trouble here
    ResetChildren = $true
}

#Invoking method with arguments
Invoke-CimMethod -InputObject ($repositories[0]) -MethodName SetSecurity -Arguments $args

执行这段代码会报错:

Invoke-CimMethod : Unable to cast object of type 'Microsoft.Management.Infrastructure.CimInstance' to type 'M
icrosoft.Management.Infrastructure.Native.InstanceHandle'.
Parameter name: value
At C:\somepath\script1.ps1:11 char:1
+ Invoke-CimMethod -InputObject ($repositories[0]) -MethodName SetSecurity -Argume ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Invoke-CimMethod], ArgumentException
    + FullyQualifiedErrorId : System.ArgumentException,Microsoft.Management.Infrastructure.CimCmdlets.Invoke
   CimMethodCommand

如果您更改代码

Permissions = @($group[0]); #Trouble here

编码

Permissions = $group; #Trouble here

那么错误信息也会改变:

Invoke-CimMethod : Unable to cast object of type 'Microsoft.Management.Infrastructure.Native.InstanceHandle'
to type 'System.Collections.IList'.
Parameter name: value
At C:\somepath\script1.ps1:11 char:1
+ Invoke-CimMethod -InputObject ($repositories[0]) -MethodName SetSecurity -Argume ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Invoke-CimMethod], ArgumentException
    + FullyQualifiedErrorId : System.ArgumentException,Microsoft.Management.Infrastructure.CimCmdlets.Invoke
   CimMethodCommand

任何想法如何将$group 正确传递给方法?

【问题讨论】:

  • 我没有安装 VisualSVN,所以无法测试,但是你的“$group[0]”对象有 Handle 属性吗?如果是,那么传递“$group[0].Handle”怎么样?
  • 我认为这个麻烦与VisualSVN没有直接关系。因此,您可以使用任何具有相似签名的 WMI 方法来重现它。方法必须接受一些 WMI 对象的数组。不幸的是,我的“$group[0]”既没有 Handle 属性,也没有与 InstanceHandle 相关的东西。 InstanceHandle 类与内部实现细节相关,没有任何公共文档。我猜想当 PowerShell 做一些魔术将 PowerShell 内部 WMI 对象表示转换为纯 WMI 对象时,会抛出异常。
  • 我明白这不是 VisualSVN 问题,重现错误就好了。这是另一个示例 [链接]powershell.com/cs/forums/p/13888/26108.aspx。不幸的是,我也无法复制它。我发现的一个“提示”是“CIM cmdlet 返回惰性对象”([链接]blogs.msmvps.com/richardsiddaway/category/powershellandwmi/page/…)它解释了 get-cmistance 返回的对象是没有任何方法的 WMI 对象的“惰性”副本。我会尝试使用 Get-WmiObject 重写代码,看看是否可以直接调用该方法。
  • 我编写了脚本,用于在计算机中搜索所有接受对象数组的 WMI 方法。 Get-Methods.ps1。希望这可以帮助您重现情况。

标签: powershell wmi


【解决方案1】:

VisualSVN_Repository::SetSecurity 方法我遇到了完全相同的问题。

使用 CIM 方法参数时,您必须将 ANY 数组参数 转换为 [CimInstance[]]

例如,这对我有用:

$Everyone = Get-CimInstance -Namespace root/VisualSVN -ClassName VisualSVN_Everyone
# Grant Everyone a Read/Write access:
$AccessRule = New-CimInstance -Namespace root/VisualSVN -ClassName VisualSVN_PermissionEntry -ClientOnly -Property @{ Account = $Everyone; AccessLevel = [UInt32]2 }
$SvnRepo = Get-CimInstance -Namespace root/VisualSVN -ClassName VisualSVN_Repository -Filter "Name='MY_REPOSITORY_NAME'"

Invoke-CimMethod -InputObject $SvnRepo -MethodName SetSecurity -Arguments @{ 
    Path = '/';
    Permissions = [CimInstance[]]$AccessRule;
    ResetChildren = $true
} | Out-Null

您必须将数组参数转换为 [CimInstance[]],即使它只是一个项目。

P.S.:也要小心Ref 数组参数:您必须先将其转换为[CimInstance[]],然后再转换为[ref[]]。比如调用VisualSVN_Group::Create方法时:

[CimInstance[]] $SvnUsers = [CimInstance[]]($ArrayOf_VisualSVN_User_Objects)

Invoke-CimMethod -ClassName VisualSVN_Group -Namespace root/VisualSVN -MethodName Create -Arguments @{
    Members = [ref[]]$SvnUsers;
    Name = 'MY_NEW_GROUP_NAME'
} | Out-Null

另请参阅:Tip#5: Passing ref and embedded instances on PowerShell Blog.

【讨论】:

    【解决方案2】:

    如果你有一个不依赖于我没有安装的软件的复制品,我可以明确回答,所以我会根据我从你的问题中推断出的情况做出最好的尝试。

    要使您分配给Permissions 的内容成为一个数组,并且您只分配一个值,请在前面使用逗号。

    Permissions = ,$group

    这是一些示例脚本和要演示的输出。

    脚本

    $var1 = "any value"
    $var2 = ,$var1
    
    $var1.GetType()
    $var2.GetType()
    $var2.Count
    $var2[0]
    

    输出

    IsPublic IsSerial Name      BaseType
    -------- -------- ----      --------
    True     True     String    System.Object
    True     True     Object[]  System.Array
    1
    any value
    

    【讨论】:

      【解决方案3】:

      基于 CIM 是惰性对象的“提示”,一个可能的解决方案(它对我有用,导致我出现在这里的类似问题)。在我的情况下,它以脚本方式安装 SCCM 更新,同时允许在更新需要时重新启动,并在整个过程花费超过一定时间时停止(不超过可用的维护窗口)。

      我将 CIMUpdate 对象传递给 powershell 函数以执行更新,以便在更新之间必要时允许重新启动(一次执行一个更新,验证是否需要重新启动,然后尝试下一次更新)。

      强制转换为 [CIMInstance[]] 时,CIM 对象出现类型不匹配错误,如果根本不转换,我将收到相同的 Unable to cast object of type 'Microsoft.Management.Infrastructure.CimInstance' to type 'Microsoft.Management.Infrastructure.Native.InstanceHandle' 错误消息。

      解决方案是使用 CIMUpdate 并重新查询以在函数中获取对象的 live 版本,然后使用该新对象作为 CIMMethod 的参数。

      【讨论】:

        【解决方案4】:

        到目前为止,它对我有用,我正在处理的案例是将 New-ScheduledTaskTrigger 实例传递给函数。

        我将CimInstance 传递给函数并将其作为PSCustomObject 类型接收。

        1. 作为 [PSCustomObject] 发送 CimInstance 接收 -> 在目标上它仍然是 CimInstance 对象类型
        2. 作为 [CimInstance] 发送 CimInstance 接收 -> 在目标上它仍然是 CimInstance 对象类型
        3. 发送CimInstance 接收为 [CimInstance[]] -> 在目标它转向CimInstance 数组类型

        【讨论】:

          猜你喜欢
          • 2020-08-27
          • 2020-08-05
          • 2020-07-28
          • 2014-01-14
          • 1970-01-01
          • 2013-02-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多