Piping to a script

Hi all,

I am trying to write a script that will accept input from the pipeline. I have found that if I pass multiple objects through the pipeline, only the last object is passed into the script.

For example,

[cmdletBinding()]
param
(
[Parameter(Mandatory=$True,ValueFromPipeline=$True)]
$variable
)

$variable

I save this as script.ps1, then run

get-process | .\script.ps1

The $variable contains only the last process in the list of processes, rather than the full list of processes that I was expecting.

Can anyone help me with why this happens?

When a script accepts pipeline input, it needs a PROCESS block:

[cmdletBinding[]]
param (
[Parameter[Mandatory=$True,ValueFromPipeline=$True]]
$variable
)
PROCESS {
$variable
}

$variable will contain one item at a time when input is piped in, and PROCESS will repeat once per piped-in object. However, were you to run:

.\MyScript.ps1 -Variable one,two,three

Then PROCESS would run once, and $variable would contain three objects. So it’s common to enumerate:

[cmdletBinding[]]
param (
[Parameter[Mandatory=$True,ValueFromPipeline=$True]]
$variable
)
PROCESS {
  foreach ($var in $variable) {
    $var
  }
}

That way $var will contain just one thing, no matter how the script is run. For lots more on this, see Learn PowerShell Toolmaking in a Month of Lunches. Walks through the whole thing.

Hi Don

Thanks for your reply, that was exactly what I needed and I’ve got my script working as excepted now. However, while running a few tests, I discovered some strange behaviour.
I put this basic script together, that contains a function and a process block for the script.

[CmdletBinding()]
Param
(
[parameter(Mandatory=$True,ValueFromPipeline=$True)]
$variable
)

Function MyFunction
{
[CmdletBinding()]
Param
(
[parameter(Mandatory=$True,ValueFromPipeline=$True)]
$variable
)
PROCESS
{}

}

PROCESS {
}

Anything piped to this script produces a Get-Process error, even though Get-Process does not appear anywhere in the script.
eg

$object | .\MyScript.ps1

Get-Process : Cannot evaluate parameter ‘Name’ because its argument is specified as a script block and there is no
input. A script block cannot be evaluated without input.
At C:\scripts\Untitled14.ps1:21 char:9

  • PROCESS {
  •     ~
    
    • CategoryInfo : MetadataError: (:slight_smile: [Get-Process], ParameterBindingException
    • FullyQualifiedErrorId : ScriptBlockArgumentNoInput,Microsoft.PowerShell.Commands.GetProcessCommand

It appears that the Process block in the script is trying to run Get-Process, and if I move the { from the script Process block on to its own line, the results of Get-Process are output by the script!
Is there any explanation for this?

Your parameter needs to be expecting like input. In other words if you are looking for names of the process then your foreach loop should process those by name.

Don said to add a Process block but you added one with empty curly braces. in those braces you need to write a foreach loop to handle whatever objects you wanted your script to process. (not only one but 2 empty process blocks)

Another issue is that you’re making it a function. Or you have added a function block, so therefore that block of code won’t even run unless you called the function by name at the bottom of your script outside the last curly brace.

Can you describe what you want your script to do with the Process objects being piped into it. Perhaps if we knew that we’d be able to help you better.

-VERN

I wasn’t expecting that script to do anything. I created an empty function in an empty script - but for some reason when I pipe something to it, it runs Get-Process, even though Get-Process doesn’t appear anywhere in the script. It doesn’t matter what I pipe to it, the result is the same, it produces output for Get-Process. It’s like a bug in Powershell

When you use BEGIN/PROCESS/END, you’re not supposed to have code - including function declarations - outside those blocks. You’re getting into a complex creature - it’s going to be a bit difficult to muddle through. Might want to invest in my Toolmaking book to make it a bit easier. Short answer, for this one, is to enclose your second function declaration in a BEGIN block.

Well once your variable contains something in the ISE editor that variable will persistently contain those objects until you close ISE and open a new one (there is CTRL+T but that’s a more advanced topic)

So it’s possible that what you’re experiencing may seem like a bug, but in fact it’s because that $variable in ISE still contains value until you set it to something else.

In your scripting if you ever run into that you may want to always set the variable to zero or $Null at the first few lines of your script.

$variable = $Null

You will still be able to add value later but adding that line ensures that ISE won’t exibit this “bug” you were seeing.

-VERN

double posted

@Don, I already have your Toolmaking book. I’m working my way through it and it’s really changing the way I think about my scripts. I’ve been applying some of the techniques to my existing scripts, which is how I ended up experimenting with functions (maybe I’m getting a bit ahead of myself). For the script that I was referring to in my original post I’ve created a BEGIN block that contains two functions, and then a PROCESS block that calls those functions as necessary. It’s working now, and everything is organised much better than before :slight_smile:

@Vern, whatever I do, that empty function tries to run get-process when I pipe something to it. I rebooted my machine, created a new variable, then piped that to the script, and got the same results - a get-process error, it’s very strange. It doesn’t really mater though, as per Don’s advice, when I use a PROCESS block, I won’t put anything else outside of a BEGIN/PROCESS/END block

You’ve stumbled across a really weird PowerShell feature. When you type a command that doesn’t exist, one of the last things PS does is try to prepend “Get-” to it, so you can type things like “Service” at a prompt and it’ll wind up running “Get-Service”. I don’t know why they did that, but it’s there.

When your code wasn’t organized properly into begin / process / end, you confused the parser into treating “Process” as a command instead of a keyword, which eventually wound up calling Get-Process through that other feature.

@Dave, that is a weird feature! Thanks for explaining