Processing a pipeline and parameter input in a Powershell function

I am confused by what I saw in the Learn PowerShell book for the month of lunch. In chapter 21, when the author discusses functions that accept input through parameter bindings or pipelines, he gives two patterns.

First of all should

function someworkerfunction { # do some work } function Get-SomeWork { param ([string[]]$computername) BEGIN { $usedParameter = $False if($PSBoundParameters.ContainsKey('computername')) { $usedParameter = $True } } PROCESS { if($usedParameter) { foreach($computer in $computername) { someworkerfunction -computername $comptuer } } else { someworkerfunction -comptuername $_ } } END {} } 

Second like this

 function someworkerfunction { # do stuff } function Get-Work { [CmdletBinding()] param( [Parameter(Mandatory=$True, ValueFromPipelineByPropertyName=$True)] [Alias('host')] [string[]]$computername ) BEGIN {} PROCESS { foreach($computer in $computername) { someworkerfunction -comptuername $computer } } END {} } 

I know that the second sample is a standard Powershell 2.0 Advanced feature. My question is Powershell 2.0 support for the cmdletbinding directive if you want to use the first template. Is this just a legacy of Powershell 1.0? Basically, there has ever been a time using Powershell 2.0 that I would like to use with the first template when the second template is so cleaner.

Any insight would be appreciated.

Thanks.

+6
source share
5 answers

If you want to handle the input of the pipeline in your function, but do not want to add all the attributes of the parameters or want backward compatibility with cmdletbinding less.

If you want to use additional features of the PowerShell script cmdlets, such as parameter attributes, parameter sets, etc., then go to the second one.

+3
source

No, the first example is not just a legacy. To create a PowerShell function that uses an array parameter and accepts an input stream, you need to do some work.

I even guess that the second example does not work. At least I couldn't get it to work.

Take this example ...

 function PipelineMadness() { [cmdletbinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline=$true)] [int[]] $InputArray ) Write-Host ('$InputArray.Count {0}' -f $InputArray.Count) Write-Host $InputArray Write-Host ('$input.Count {0}' -f $input.Count) Write-Host $input if($input) { Write-Host "input is true" } else { Write-Host "input is false" } } 

results...

 PS C:\Windows\system32> 1..5 | PipelineMadness $InputArray.Count 1 5 $input.Count 5 1 2 3 4 5 input is true PS C:\Windows\system32> PipelineMadness (1..5) $InputArray.Count 5 1 2 3 4 5 $input.Count 1 input is false 

Note that when using the pipeline, the $InputArray variable represents a single value of 5 ...

Now with BEGIN and PROCESS blocks

 function PipelineMadnessProcess() { [cmdletbinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline=$true)] [int[]] $InputArray ) BEGIN { Write-Host 'BEGIN' Write-Host ('$InputArray.Count {0}' -f $InputArray.Count) Write-Host $InputArray Write-Host ('$input.Count {0}' -f $input.Count) Write-Host $input if($input) { Write-Host "input is true" } else { Write-Host "input is false" } } PROCESS { Write-Host 'PROCESS' Write-Host ('$InputArray.Count {0}' -f $InputArray.Count) Write-Host $InputArray Write-Host ('$input.Count {0}' -f $input.Count) Write-Host $input if($input) { Write-Host "input is true" } else { Write-Host "input is false" } } } 

Now this is where it gets weird

 PS C:\Windows\system32> 1..5 | PipelineMadnessProcess BEGIN $InputArray.Count 0 $input.Count 0 input is false PROCESS $InputArray.Count 1 1 $input.Count 1 1 input is true PROCESS $InputArray.Count 1 2 $input.Count 1 2 input is true ... PROCESS $InputArray.Count 1 5 $input.Count 1 5 input is true 

The BEGIN block contains no data at all. And the process block works well if you have foreach , as in the example that it will actually work, but it will run foreach with 1 input X times. Or, if you pass in an array, it will run foreach once with a full set.

So, I assume that technically this example will work, but it may not work as you expect.

Also note that even if the BEGIN block had no data, the function passed the syntax check.

+2
source

To answer your question, I would say that the first template is just a legacy from PowerShell 1.0, you can also use $input in classic functions without a Process script block. As much as you can write PowerShell 2.0 code, you can forget it.

As for pipeline functions, in PowerShell V1.0 they can be processed using filters .

you just need to know that it was done this way when you take samples from the network or when you need to debug old Powerhell code.

Personally, I still use the old functions and filters inside my modules. I reserve cmdletbinding for export functions or profile functions.

Powershell is a bit like lego blocks, you can do many things in different ways.

+1
source

If someone wants a very, very simple explanation of how to read data from the input channel, see

How do you write a powershell function that reads using an input stream?

If this ^ existed when I had this question, I would save a lot of time because this thread is quite complex and does not really explain how to handle pipelined input to a function.

+1
source

The first form expects one or more computer names as string arguments either from the argument list or from the pipeline.

The second form expects either an array of string arguments from the argument list, or input objects from the pipeline with computer names as a property.

0
source

Source: https://habr.com/ru/post/910127/


All Articles