PowerShell is an incredibly powerful tool that can be used in a wide variety of ways. This tutorial will teach you how to create functions and the pipeline, which are two key PowerShell features that make it so useful.
A “powershell function” is a command-line tool that allows users to create functions. A function is a series of commands that are executed in order, and can be called by other commands or scripts.
One of the most essential (and valuable) components of the PowerShell shell and scripting language is the PowerShell pipeline. You can use its strength in your own functions after you grasp the fundamentals of how it operates and what it can do. You’ll learn how to accomplish precisely that in this guide!
The PowerShell pipeline enables you to connect commands together to create a single ‘pipeline,’ which simplifies coding and permits parallel processing, among other things. Let’s get started if you’re ready to learn about the pipeline and write your own functions to make use of it.
Prerequisites
This page will serve as a tutorial with full hands-on demonstrations. PowerShell v3+ is required if you want to follow along. Windows PowerShell v5.1 will be used in this lesson.
The PowerShell Pipeline: An Overview
A parameter is used to provide input to most PowerShell commands. The command takes an item as input and performs some action on it. The output may then optionally return an object.
Commands in a pipeline act like human runners in a relay race. Every runner in the race, except for the first & the last, accepts the baton (objects) from its predecessor and passes it to the next.
Everything You Need to Know About PowerShell Parameters is Related
The Stop-Service cmdlet, for example, contains an argument named InputObject. This argument enables you to supply Terminate-Service a specified kind of object that represents the Windows service you want to stop.
To utilize the InputObject argument, use Get-Service to get the service object and then send it to the InputObject parameter as shown below. This way of using the InputObject argument to provide input to the Stop-Service cmdlet works excellent and gets the job done.
Stop-Service -InputObject $service = Get-Service -Name ‘wuauserv’ $service
There are two phases to giving input to the Stop-Service command using this manner. Get-Service must be called first, the result saved to a variable, and then the value sent to Stop-Service through the InputObject argument.
Now, replace the preceding snippet with the one below, which accomplishes the same goal. It’s a lot easier since you don’t have to use the InputObject argument or construct a $services variable. Instead, PowerShell “knows” that the InputObject argument will be used. This is accomplished via the use of a concept known as parameter binding.
With the | operator, you’ve now “chained” instructions together. You’ve put together a pipeline.
Stop-Service | Get-Service -Name ‘wuauserv’
However, you don’t have to use just two instructions to build a pipeline; you may use as many as you like (if the command parameters support it). Consider the following code snippet:
- The Where-Object cmdlet receives all of the objects returned by the Get-Service cmdlet.
- After that, the Where-Object cmdlet examines each object’s Status field and returns only those that have a value of Running.
- The objects are then submitted to Select-Object, which only returns the objects’ Name and DisplayName fields.
- Because no other cmdlet takes the objects produced by Select-Object, the command returns them to the console.
The Where-Object and Select-Object cmdlets use a notion called parameter binding, which is covered in the following section, to understand how to handle pipeline input.
Get-Service | Select-Object Name, DisplayName | Where-Object Status -eq Running
Run the Get-Help about pipelines command to learn more about pipelines.
Binding of Pipeline Parameters
The pipeline may seem simple at first look. It’s only transferring things from one instruction to the next, after all. However, the pipeline is significantly more intricate in practice. Only parameters are accepted by commands. Even if you don’t explicitly declare a parameter, the pipeline must figure out which one to use.
The task of figuring out which parameter to use when a command receives input via the pipeline is known as parameter binding. To successfully bind an object coming in from the pipeline to a parameter, the incoming command’s parameter(s) must support it. Command parameters support Binding of Pipeline Parameters in one of two ways; ByValue and/or ByPropertyName.
ByValue
The parameter value for the command parameter is the whole received object. A ByValue parameter searches the incoming objects for an item of a certain type. If the object type matches, PowerShell thinks it was supposed to be bound to that argument and accepts it.
The Path argument of the Get-ChildItem cmdlet takes a string object type and pipeline input through ByValue. Because C:Windows is a string, doing something like ‘C:Windows’ | Get-ChildItem retrieves all files in the C:Windows directory.
ByPropertyName
The command argument accepts just a single attribute of an object, not the full object. It accomplishes it by looking at the property name rather than the object type.
The Name argument of the Get-Process cmdlet is configured to accept pipeline input byPropertyName. When you use [pscustomobject]@Name=’firefox’ | Get-Process to send an object containing a Name property to the Get-Process cmdlet, PowerShell matches or binds the Name property on the receiving object to the Name argument and uses that value.
Identifying Pipeline-Supporting Command Parameters
As previously stated, pipeline input is not supported by all commands. That functionality must be developed by the command author. The command must include at least one pipeline-supporting argument, such as ByValue or ByPropertyName.
How do you figure out which commands and arguments are compatible with pipeline input? You may attempt it by trial and error, but the Get-Help command from the PowerShell help system is a better option.
Get-Help in PowerShell is a related command.
Get-Help <COMMAND> -Parameter <PARAMETER>
Take a look at the Path argument of the Get-ChildItem cmdlet, for example. Both forms of pipeline input are supported, as you can see.
Input from the PowerShell pipeline is permitted.
Once you’ve figured out which command arguments enable pipeline input, you may take use of it, as illustrated below.
# This is a non-pipeline call. ‘C:Program Files’, ‘C:Windows’ Get-ChildItem -Path # ‘C:Program Files’, ‘C:Windows’ pipeline call | Get-ChildItem
On the other side, the Get-Service DisplayName argument does not accept pipeline input.
The use of PowerShell pipelines is not permitted.
Creating a Pipeline Function of Your Own
Even while pipeline input isn’t supported by the regular PowerShell cmdlets, it doesn’t imply you can’t use it. Fortunately, you can create functions that take pipeline input as well.
Associated: PowerShell Functions: A Beginner’s Guide
Let’s start with a pre-existing function named Get-ConnectionStatus to show.
- ComputerName is a single parameter (that does not receive pipeline input) that enables you to give one or more strings to this function. Because the ComputerName parameter isn’t declared as a parameter attribute ([Parameter()]), you can determine it doesn’t accept pipeline input.
- After that, the function reads each of those strings and performs the Test-Connection cmdlet on each of one.
- It then produces an object with a ComputerName and Status attribute for each string computer name supplied.
[CmdletBinding()] function Get-ConnectionStatus ([Parameter()]) param ([Parameter()]) param ([Parameter ## There is no pipeline input. [string[]] foreach($c in $ComputerName) in $ComputerName) in $ComputerName) in $ComputerName) in $ComputerName) in $Comput if(Test-Connection -ComputerName $c -Quiet -Count 1) if(Test-Connection -ComputerName $c -Quiet -Count 1) if(Test-Connection – otherwise if $status = ‘Ok’ $status = ‘There is No Connection’ [pscustomobject] $status ComputerName = $c ComputerName = $c ComputerName = $c ComputerName = $c ComputerName = $c ComputerName = $c ComputerName = $c ComputerName = $c
You’d next use the Get-ConnectionStatus cmdlet, supplying one or more hostnames or IP addresses to the ComputerName argument, as shown below.
Get-ConnectionStatus -ComputerName ‘127.0.0.1’, ‘192.168.1.100’ Get-ConnectionStatus -ComputerName ‘127.0.0.1’, ‘192.168.1.100’ Get-ConnectionSt
Allowing Pipeline Input is the first step.
You must first declare the necessary argument attribute for this function to take pipeline input. This attribute may be either ValueFromPipelineByPropertyName to accept pipeline input byPropertyName or ValueFromPipelineByValue to accept pipeline input byValue.
As seen below, inside the brackets of the [Parameter()] definition, add the ValueFromPipeline parameter attribute.
[Parameter(ValueFromPipeline)] [string[]] $ComputerName
That’s technically all you have to do at this point. Any string object given to the Get-ConnectionStatus method will now be bound to the ComputerName argument. However, just because argument binding is happening doesn’t guarantee the function will perform anything useful with it.
Step 2: Putting a Process Block in Place
You must then add a Process block to PowerShell in order for it to process all objects coming in through the pipeline. This command instructs PowerShell to process each item that enters the pipeline.
PowerShell will only process the first item from the pipeline if you don’t use a Process block. PowerShell is told to keep processing objects using the Process block.
Add a Process block to the function as shown below, containing all of the function’s logic.
function Get-ConnectionStatus { [CmdletBinding()] param ( [Parameter(ValueFromPipeline)] [string[]] $ComputerName ) Process ## New Process block { foreach($c in $ComputerName) { if(Test-Connection -ComputerName $c -Quiet -Count 1) { $status = ‘Ok’ } else { $status = ‘No Connection’ } [pscustomobject]@{ ComputerName = $c Status = $status } } } ## end Process block }
Send output from the Process block at all times. Sending output from the Process block to the pipeline “streams” the objects, enabling subsequent commands to receive them from the pipeline.
Using the PowerShell Pipeline to Pass Objects
Once you’ve established a Process block in the function above, you may use the pipeline to call the function, providing data to the ComputerName argument.
Get-ConnectionStatus -ComputerName ‘127.0.0.1’, ‘192.168.1.100’ Get-ConnectionStatus -ComputerName ‘127.0.0.1’, ‘192.168.1.100’ Get-ConnectionSt ## or ‘127.0.0.1’, ‘192.168.1.100’ | Get-ConnectionStatus
At this point, you may start using the pipeline’s true potential by adding additional instructions to the mix. For instance, suppose you have a text file named C:Testcomputers.txt that has a line of IP addresses separated by a new line, as seen below.
You could then retrieve each of those IP addresses from the text file using the Get-Content cmdlet and give them straight to the Get-ConnectionStatus function.
Get-Content: How to Read Text Files Like a Boss
Get-Content -Path C:Testcomputers.txt | Get-ConnectionStatus Get-Content -Path C:Testcomputers.txt Get-Content -Path C:Testcomputers.t
You could take this arrangement a step further and send the items returned by Get-ConnectionStatus straight to the ForEach-Object cmdlet.
The following is the code:
- The Get-ConnectionStatus function receives all computer names from the text file and feeds them to it.
- Each computer name is processed by Get-ConnectionStatus, which produces an object with the values ComputerName and Status.
- After that, Get-ConnectionStatus sends each object to the ForEach-Object cmdlet, which produces a single Cyan-colored string with a human-readable status.
Get-Content -Path C:Testcomputers.txt | Get-ConnectionStatus Get-Content -Path C:Testcomputers.txt Get-Content -Path C:Testcomputers.t | ForEach-Object { Write-Host “$($_.ComputerName) connection status is: $($_.Status)” -ForegroundColor Cyan }
PowerShell would not deliver any status to the console until all objects (IP addresses) were processed if pipeline input was not enabled on the ComputerName argument or if Get-ConnectionStatus did not return an object inside the Process block.
Binding Pipelines by Property Name
Until now, the Get-ConnectionStatus cmdlet has been configured to take pipeline input byValue (ValueFromPipeline), which accepts an array of strings like ‘127.0.0.1’ and ‘192.168.1.100’. Would this method operate the same way if the input was a CSV file instead of a text file containing IP addresses?
Perhaps you have a CSV file named C:Testpc-list.csv that looks like this.
192.168.1.100,Paris ComputerName,Location 127.0.0.1,London
The Get-ConnnectionStatus ComputerName argument has the same name as the ComputerName column in the CSV file.
If you import the CSV and feed it through the pipeline to Get-ConnectionStatus, you’ll get an unexpected response in the ComputerName field.
Using Import-Csv in PowerShell to Manage CSV Files
Import-Csv -Path ‘C:Testpc-list.csv’ | Import-Csv -Path ‘C:Testpc-list.csv’ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ No Connection @ComputerName=127.0.0.1; Location=London No connection (ComputerName=192.168.1.100; Location=Paris)
Are you able to figure out what went wrong? Why didn’t the PowerShell pipeline tie the output supplied by Import-CSV to the ComputerName argument on Get-ConnectionStatus? Because the argument ValueFromPipelineByPropertyName is required.
The ComputerName parameter of the method currently has a parameter declaration that looks like [Parameter(ValueFromPipeline)]. As a result, as shown below, you must add ValueFromPipelineByPropertyName to the ComputerName option to enable input byPropertyName.
[CmdletBinding()] ([Parameter(ValueFromPipeline,ValueFromPipelineByPropertyName)]) param ([Parameter(ValueFromPipeline,ValueFromPipelineByPropertyName)]) [string[]] $ComputerName))))))))))))))
You instruct PowerShell to start looking at the object property names and the object type once you have pipeline support ByPropertyName. You should now see the expected output once you’ve made this adjustment.
PS> Import-Csv -Path ‘C:Testpc-list.csv’ | Get-ConnectionStatus ComputerName Status ———— —— 127.0.0.1 Ok 192.168.1.100 No Connection
Summary
You learned how the PowerShell pipeline works, how it binds arguments, and even how to develop your own PowerShell pipeline-supporting function in this course.
Despite the fact that functions will run without the pipeline, they will not be able to “stream” objects from one command to the next, simplifying coding.
Is there a function you’ve written, or are planning to create, that might benefit from being pipeline ready?
The “powershell function with parameters and return value” is a PowerShell command that allows you to create functions. The “powershell function with parameters and return value” will allow users to add parameter values, as well as have a return value.
Frequently Asked Questions
What are pipeline functions in PowerShell?
A: A pipeline is a series of commands that are executed sequentially. Pipelines take input data and process it in the order they were specified, outputting the processed results.
How do you create a function in PowerShell?
A: When creating a function, it can be done through either using the New keyword or by adding your code inside of another PowerShell script.
New-Function -Name MyFunction
# Alternatively you could do this in one command:
& {
$myfunction = New-Object System.Management.Automation.CommandFunctions `
-ArgumentList (Get-Process) `
}
How do I use the pipe command in PowerShell?
A: The pipe command lets you send a text file to PowerShell. You can use this with the more or less commands.
Examples:
– more c:\windows\system32\cmd.exe | more >dumpsysinfo>c:\temp\dumpfile – less
Related Tags
- powershell pipeline function
- powershell function accept pipeline
- powershell function parameters
- powershell pipeline examples
- powershell pipe output to another command