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.
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
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 $_
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With