Reputation: 29123
E.g. I want something like head
that either accepts an array piped to it and then does select-object -first
, or, receives a list of file names as parameters and outputs the first lines of each. So cat $filename | head
should work like head $filename
Here's what I've tried so far:
Function head( )
{
param (
[switch] $help = $false,
[parameter(mandatory=$false,ValueFromPipeline=$true)] [object[]] $inputs,
[parameter(ValueFromRemainingArguments=$true)] [String[]] $files
)
If( $help )
{
Write-Host "usage: $($MyInvocation.MYCommand) [<file>] <numLines>"
return
}
$lines = 0
if ($files -and [int]::TryParse($files[0], [ref]$lines)) {
$null,$files = $files
} else {
$lines = 10
}
$input | select-object -First $lines
if ($files) {get-content -TotalCount $lines $files}
}
But this causes the function to ignore the first parameter:
C:\Users\idror.TLV-WPVAJ> head C:\temp\now.ps1
C:\Users\idror.TLV-WPVAJ> head C:\temp\now.ps1 C:\temp\now.ps1
Function head( )
{
param (
[switch] $help = $false,
[parameter(mandatory=$false,ValueFromPipeline=$true)] [object[]] $input,
[parameter(ValueFromRemainingArguments=$true)] [String[]] $files
)
If( $help )
{
C:\Users\idror.TLV-WPVAJ> $a | head
1
2
3
C:\Users\idror.TLV-WPVAJ> $a | head 1
head : The input object cannot be bound to any parameters for the command either because the command does not take
pipeline input or the input and its properties do not match any of the parameters that take pipeline input.
At line:1 char:6
+ $a | head 1
+ ~~~~~~
+ CategoryInfo : InvalidArgument: (1:Int32) [head], ParameterBindingException
+ FullyQualifiedErrorId : InputObjectNotBound,head
Upvotes: 2
Views: 63
Reputation: 47792
You can achieve this using Parameter Sets:
function head {
[CmdletBinding()]
param(
[Parameter(
ParameterSetName = 'Content',
ValueFromPipeline = $true,
Mandatory = $true
)]
[String[]]
$Content ,
[Parameter(
ParameterSetName = 'File',
ValueFromRemainingArguments = $true ,
Mandatory = $true
)]
[String[]]
$Path,
[Parameter()]
[uint64]
$Count = 5
)
Begin {
Write-Verbose "Parameter Set Name: $($PSCmdlet.ParameterSetName)"
}
Process {
Write-Verbose "Content: $Content"
Write-Verbose "Path: $Path"
Write-Verbose "Count: $Count"
}
}
First, take a look at the help output of this by running Get-Help head
:
NAME head SYNTAX head -Content <string[]> [-Count <uint64>] [<CommonParameters>] head -Path <string[]> [-Count <uint64>] [<CommonParameters>]
You can see that it interprets 2 different sets, and each parameter is mandatory in its own set.
You can also call it with -Verbose
to see a demonstration of how this is working:
# Content by pipeline
'one','two','three' | head -Verbose
# Files as an array
head -Verbose 'file1','file2','file3'
# Files as remaining arguments
head -Verbose 'file1' 'file2' 'file3'
Upvotes: 1