How do I write a PowerShell script that accepts pipeline input?

Powershell

Powershell Problem Overview


I am trying to write a PowerShell script that can get pipeline input (and is expected to do so), but trying something like

ForEach-Object {
   # do something
}

doesn't actually work when using the script from the commandline as follows:

1..20 | .\test.ps1

Is there a way?

Note: I know about functions and filters. This is not what I am looking for.

Powershell Solutions


Solution 1 - Powershell

In v2 you can also accept pipeline input (by propertyName or byValue), add parameter aliases etc:

function Get-File{
    param(  
	[Parameter(
		Position=0, 
		Mandatory=$true, 
		ValueFromPipeline=$true,
		ValueFromPipelineByPropertyName=$true)
	]
	[Alias('FullName')]
	[String[]]$FilePath
    ) 

    process {
	   foreach($path in $FilePath)
	   {
	       Write-Host "file path is: $path"
	   }
    }
}


# test ValueFromPipelineByPropertyName 
dir | Get-File

# test ValueFromPipeline (byValue) 

"D:\scripts\s1.txt","D:\scripts\s2.txt" | Get-File

 - or -

dir *.txt | foreach {$_.fullname} | Get-File

Solution 2 - Powershell

This works and there are probably other ways to do it:

foreach ($i in $input) {
    $i
}

17:12:42 PS>1..20 | .\cmd-input.ps1
1
2
3
-- snip --
18
19
20

Search for "powershell $input variable" and you will find more information and examples.
A couple are here:
PowerShell Functions and Filters PowerShell Pro!
(see the section on "Using the PowerShell Special Variable “$input”")
"Scripts, functions, and script blocks all have access to the $input variable, which provides an enumerator over the elements in the incoming pipeline. "
or
$input gotchas « Dmitry’s PowerBlog PowerShell and beyond
"... basically $input in an enumerator which provides access to the pipeline you have."

For the PS command line, not the DOS command line Windows Command Processor.

Solution 3 - Powershell

You can either write a filter which is a special case of a function like so:

filter SquareIt([int]$num) { $_ * $_ }

or you can create a similar function like so:

function SquareIt([int]$num) {
  Begin {
    # Executes once before first item in pipeline is processed
  }

  Process {
    # Executes once for each pipeline object
    $_ * $_
  }

  End {
    # Executes once after last pipeline object is processed
  }
}

The above works as an interactive function definiton or if in a script can be dotted into your global session (or another script). However your example indicated you wanted a script so here it is in a script that is directly usable (no dotting required):

  --- Contents of test.ps1 ---
  param([int]$num)

  Begin {
    # Executes once before first item in pipeline is processed
  }

  Process {
    # Executes once for each pipeline object
    $_ * $_
  }

  End {
    # Executes once after last pipeline object is processed
  }

With PowerShell V2, this changes a bit with "advanced functions" which embue functions with the same parameter binding features that compiled cmdlets have. See this blog post for an example of the differences. Also note that in this advanced functions case you don't use $_ to access the pipeline object. With advanced functions, pipeline objects get bound to a parameter just like they do with a cmdlet.

Solution 4 - Powershell

The following are the simplest possible examples of scripts/functions that use piped input. Each behaves the same as piping to the "echo" cmdlet.

As Scripts:

####### Echo-Pipe.ps1

  Begin {
    # Executes once before first item in pipeline is processed
  }

  Process {
    # Executes once for each pipeline object
    echo $_
  }

  End {
    # Executes once after last pipeline object is processed
  }

####### Echo-Pipe2.ps1

foreach ($i in $input) {
    $i
}

As functions:

Function Echo-Pipe {
  Begin {
    # Executes once before first item in pipeline is processed
  }

  Process {
    # Executes once for each pipeline object
    echo $_
  }

  End {
    # Executes once after last pipeline object is processed
  }
}

Function Echo-Pipe2 {
  	foreach ($i in $input) {
    	$i
	}
}

E.g.

PS > . theFileThatContainsTheFunctions.ps1 # This includes the functions into your session
PS > echo "hello world" | Echo-Pipe
hello world
PS > cat aFileWithThreeTestLines.txt | Echo-Pipe2
The first test line
The second test line
The third test line

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJoeyView Question on Stackoverflow
Solution 1 - PowershellShay LevyView Answer on Stackoverflow
Solution 2 - PowershellBratchView Answer on Stackoverflow
Solution 3 - PowershellKeith HillView Answer on Stackoverflow
Solution 4 - PowershellsamthebestView Answer on Stackoverflow