使用invoke-command时如何将xml元素传递给scriptBlock

时间:2013-07-05 13:53:31

标签: xml powershell invoke-command

使用PowerShell 3.0,我使用Invoke-Command cmdlet将xmlElement传递给scriptblock。问题是我认为scriptBlock是作为arrayList而不是xmlElement接收参数(实际上,我知道在我注销ArrayList时收到的参数是$service.GetType()

这是我的XMLElement:

<Service>
    <ServiceName>Spooler</ServiceName>
    <Startup>Disabled</Startup>
</Service>

这是我的scriptBlock:

$scptModifyService = {
    param (
        $service
    );
    Set-Service -Name $service.ServiceName -StartupType $service.Startup;
}

这是我调用scriptBlock的代码:

## Modify remote Services:
foreach($service in $XML.QCSettings.Services.Service) {
    Invoke-Command -ScriptBlock $scptModifyService -ComputerName $ComputerName -ArgumentList $service;
}

据我所知,Invoke-Command cmdlet(get-help invoke-command)是ArguementList可以将一个对象作为输入,所以我认为这不是我如何调用scriptblock的问题上面的'foreach'循环。希望这是有道理的。

有没有人对如何将我的scriptblock中的param捕获为xmlElement而不是ArrayList有任何想法?

我已经尝试了几件事(在我的scriptblock中):

param( $service = [xml]Get-Content args[0] );

该代码的其他变体。

2 个答案:

答案 0 :(得分:1)

从你所展示的内容来看,我看不到scriptblock是如何获得ArrayList的,但你仍然能够做到这一点。 ArrayList是否包含正确的XmlElements?如果是这样,您只需处理一个或多个服务条目就可以使您的功能更加健壮:

$scptModifyService = {
    param (
        [Xml.XmlElement[]]$service
    );

    foreach ($s in $service) {
        Set-Service -Name $s.ServiceName -StartupType $s.Startup;
    }
}

然后你应该可以这样称呼它:

Invoke-Command -ScriptBlock $scptModifyService -ComputerName $ComputerName -ArgumentList $XML.QCSettings.Services.Service

答案 1 :(得分:0)

使用PowerShell的[xml]加速器和动态属性时必须小心。看起来像普通的XML文档对象模型会被转换为ArrayList和其他令人讨厌的对象。

果然,当我将XML加载到DOM中,并在GetType()元素上调用Service时,我得到Object[]

> $xml = [xml]'<QCSettings><Services><Service /><Service /></Services></QCSettings>'
> $xml.QCSettings.Services.Service.GetType()
IsPublic IsSerial Name                                     BaseType            
-------- -------- ----                                     --------            
True     True     Object[]                                 System.Array        

由于您使用的是PowerShell 3,因此可以使用using范围来引用远程脚本块中的XML块:

$services = $xml.QCSettings.Services.Service
Invoke-Command -ScriptBlock { 
    $using:services | ForEach-Object {
        Set-Service $_.ServiceName -StartupType $_.StartupType
    }
}

由于此代码传递了所有服务对象,因此您只需登录一次计算机,而在此之前,您每个服务都登录一次。

如果您无法使用using范围,我会使用ArrayList并编写您的脚本块以接受对象列表:

$scptModifyService = {
    param (
        [Object[]]
        $service
    );
    $service | ForEach-Object {
        Set-Service -Name $_.ServiceName -StartupType $_.StartupType
    }
}

$XML.QCSettings.Services.Service |
    ForEach-Object {
        Invoke-Command -ScriptBlock $scptModifyService -ComputerName $ComputerName -ArgumentList $_
    }