Author Posts

November 13, 2015 at 3:27 am

I have written a simple function. It takes a computer name, and then in the Process {} block I use Invoke-Command to run an action on each machine. My parameter is created like this:
Param(
[Parameter(valuefrompipeline=$true,Position=0)]
[string[]]$ComputerName=$ThisServer,

So I can supply a single name, a list of names or get a list from the pipeline.
However, it appears that things get processed in different ways when they get to the Process{} block. A single name is OK, as is input from the pipeline. But a list of machine names fails. Is this because the list is an array, and this is handled differently? How do get round this in a simple way?

Thanks

November 13, 2015 at 3:55 am

Can you post the rest of your code? Just be sure to sanitize it so it doesn't contain any private information. It would be useful to see what the Function actually does instead of just seeing the Parameter.

November 13, 2015 at 4:03 am

Here you go Ed, nothing special.....

Function Stop-GEOService
{

[CmdletBinding()]
Param(
[Parameter(valuefrompipeline=$true)]
[string[]]$ComputerName=($servername.keys | %{if($servername.$_ -eq $env:computername){$_}})
)
Begin
{
"Preparing to stop service..."
}
Process
{
$geoServer= $($serverName[$($ComputerName)])
"Processing: $ComputerName System Name: $geoServer"
try
{
Invoke-Command -ComputerName $geoServer { Stop-Service -DisplayName "GEO*" -Confirm} -ErrorAction stop
Add-VSToolsLog -LogFile VSTools.log -LogText " services were stopped on $ComputerName"
}
Catch
{
Write-Host "An error occured"
$errorMessage = $_.Exception.Message
Write-Host $errorMessage
Add-VSToolsLog -LogFile VSTools.log -LogText "An error occurred trying to Stop GEO services for $ComputerName, the error was $errorMessage"
}
}
End
{
}
}

Thanks for your help.

November 13, 2015 at 6:32 am

SideNote: If you use the "pre" and "/pre" html tags around your code, it will put it in a pretty format like below, making it much easier t read in the post.

Here is an example of your issue.

Function Test {
    [CmdLetBinding()]
    Param(
        [Parameter(valuefrompipeline=$true)]
        [String[]]$ComputerName
    )
    Begin{}
    Process {
        Write-Host $ComputerName
    }
    End {}
}

$objects = @(
    [PSCustomObject]@{ComputerName = "Test1"; Date = (Get-Date).AddDays(-1)},
    [PSCustomObject]@{ComputerName = "Test2"; Date = (Get-Date).AddDays(-10)},
    [PSCustomObject]@{ComputerName = "Test3"; Date = (Get-Date).AddDays(-20)}
)

$objects | test
write-host "------------------------------------"
test -ComputerName $objects

Results:

@{ComputerName=Test1; Date=11/12/2015 08:21:25}
@{ComputerName=Test2; Date=11/03/2015 08:21:25}
@{ComputerName=Test3; Date=10/24/2015 08:21:25}
------------------------------------
@{ComputerName=Test1; Date=11/12/2015 08:21:25} @{ComputerName=Test2; Date=11/03/2015 08:21:25} @{ComputerName=Test3; Date=10/24/2015 08:21:25}

The reason for this difference is that when you are using the Pipeline, the Process{} script block acts like a foreach loop for the pipeline input, so each input object in processed one at a time. The Process{} block only does this for pipeline input. So when you pass the objects as a parameter, there is nothing looping through the objects individually to process them one at a time. Instead they are being processed as one single array of objects. Thus the result is different.

In order to handle multiple object as input by a parameter instead of via the pipeline, you need to add a foreach loop to the code like this.

Function Test {
    [CmdLetBinding()]
    Param(
        [Parameter(valuefrompipeline=$true)]
        [String[]]$ComputerName
    )
    Begin{}
    Process {
        ForEach ($Computer in $ComputerName) {
            Write-Host $Computer
        }
    }
    End {}
}

$objects = @(
    [PSCustomObject]@{ComputerName = "Test1"; Date = (Get-Date).AddDays(-1)},
    [PSCustomObject]@{ComputerName = "Test2"; Date = (Get-Date).AddDays(-10)},
    [PSCustomObject]@{ComputerName = "Test3"; Date = (Get-Date).AddDays(-20)}
)

$objects | test
write-host "------------------------------------"
test -ComputerName $objects

Results:
@{ComputerName=Test1; Date=11/12/2015 08:28:32}
@{ComputerName=Test2; Date=11/03/2015 08:28:32}
@{ComputerName=Test3; Date=10/24/2015 08:28:32}
————————————
@{ComputerName=Test1; Date=11/12/2015 08:28:32}
@{ComputerName=Test2; Date=11/03/2015 08:28:32}
@{ComputerName=Test3; Date=10/24/2015 08:28:32}

November 13, 2015 at 8:22 am

Great, thanks for the help.