Question

Using PowerShell 3.0, I am using the Invoke-Command cmdlet to pass an xmlElement to a scriptblock. The problem is that I think the scriptBlock is receiving the parameter as an arrayList and not as an xmlElement (actually, I know that the received param is an ArrayList as I logged out $service.GetType() ).

Here is my XMLElement:

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

Here is my scriptBlock:

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

Here is my code calling the scriptBlock:

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

From what I understand about the Invoke-Command cmdlet (get-help invoke-command) is that the ArguementList can take an object as input, so I don't think that is is an issue with how I call the scriptblock in the 'foreach' loop above. Hopefully that makes some sense.

Does anyone have any ideas about how capture the param in my scriptblock as an xmlElement and not as an ArrayList?

I have tried several things already (in my scriptblock):

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

And other variations on the that code.

Was it helpful?

Solution

From what you've shown I don't see how the scriptblock is getting an ArrayList but you can still make this work. Does the ArrayList contain the correct XmlElements? If so, you can make your function more robust by just handling one or more service entries like so:

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

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

Then you should be able to call it like so:

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

OTHER TIPS

You have to be careful when using PowerShell's [xml] accelerator and dynamic properties. What looks like a normal XML document object model gets casted around to ArrayList and other unsavory objects.

Sure enough, when I load your XML into a DOM, and call GetType() on the Service element, I get an Object[]:

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

Since you're using PowerShell 3, you can use the using scope to reference the XML block inside your remote script block:

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

Since this code passes in all the service objects, you're only logging into each computer once, whereas before, you were logging in once per service.

If you can't use the using scope, I would just live with the ArrayList and write your script block to accept a list of objects:

$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 $_
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top