Reputation: 10226
as an adjunct to this issue: How do I force declared parameters to require explicit naming? I am struggling with pipelines. Suppose I want the behaviour that this declares:
param(
$installdir,
$compilemode,
[Parameter(Position=0, ValueFromRemainingArguments=$true)] $files
)
namely, that I can call my script like this:
c:\> MyScript -installdir c:\ file-1.txt file-2.txt file-3.txt
but now I want to also be able to do it this way:
c:\> gi file-*.txt |MyScript -installdir c:\
I might think of adding a decoration to the parameter like this:
param(
$installdir,
$compilemode,
[Parameter(
Position=0,
ValueFromRemainingArguments=$true,
ValueFromPipeline=$true
)] $files
)
but what actually happens is I only get 1 argument into my parameter i.e. instead of getting an array with all the files that gi
produced, I get only the first in the list.
A second way I attempted this was by using the $input
variable (instead of using the ValueFromPipeline
decorator), but then in trying to call the script I get the error:
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.
where can I go from here?
Upvotes: 0
Views: 1858
Reputation: 201602
You could declare it without ValueFromRemainingArguments:
param(
[Parameter(
Position=0,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[Alias('PSPath')]
[string[]]
$files,
$installdir,
$compilemode
)
And then pass in multiple files as an array using the comma operator e.g.:
MyScript -installdir c:\ file-1.txt,file-2.txt,file-3.txt
Note: In order to accept input from commands like Get-Item and Get-ChildItem, use ValueFromPipelineByPropertyName and add a parameter alias "PSPath" that will find the PSPath property on the objects output by Get-Item/Get-ChildItem.
I have test this in ISE and it works fine:
function foo
{
param(
[Parameter(
Position=0,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[Alias('PSPath')]
[string[]]
$files,
$installdir,
$compilemode
)
process {
foreach ($file in $files) {
"File is $file, installdir: $installdir, compilemode: $compilemode"
}
}
}
foo a,b,c -installdir c:\temp -compilemode x64
ls $home -file | foo -installdir c:\bin -compilemode x86
FYI, this is a template I use all the time to create commands that take pipeline input or array input, as well as wildcard paths:
function Verb-PathLiteralPath
{
[CmdletBinding(DefaultParameterSetName="Path",
SupportsShouldProcess=$true)]
#[OutputType([output_type_here])] # Uncomment this line and specify the output type of this
# function to enable Intellisense for its output.
param(
[Parameter(Mandatory=$true,
Position=0,
ParameterSetName="Path",
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true,
HelpMessage="Path to one or more locations.")]
[ValidateNotNullOrEmpty()]
[SupportsWildcards()]
[string[]]
$Path,
[Alias("PSPath")]
[Parameter(Mandatory=$true,
Position=0,
ParameterSetName="LiteralPath",
ValueFromPipelineByPropertyName=$true,
HelpMessage="Literal path to one or more locations.")]
[ValidateNotNullOrEmpty()]
[string[]]
$LiteralPath
)
Begin
{
Set-StrictMode -Version Latest
}
Process
{
if ($psCmdlet.ParameterSetName -eq "Path")
{
if (!(Test-Path $Path)) {
$ex = new-object System.Management.Automation.ItemNotFoundException "Cannot find path '$Path' because it does not exist."
$category = [System.Management.Automation.ErrorCategory]::ObjectNotFound
$errRecord = new-object System.Management.Automation.ErrorRecord $ex, "PathNotFound", $category, $Path
$psCmdlet.WriteError($errRecord)
}
# In the -Path (non-literal) case, resolve any wildcards in path
$resolvedPaths = $Path | Resolve-Path | Convert-Path
}
else
{
if (!(Test-Path $LiteralPath)) {
$ex = new-object System.Management.Automation.ItemNotFoundException "Cannot find path '$LiteralPath' because it does not exist."
$category = [System.Management.Automation.ErrorCategory]::ObjectNotFound
$errRecord = new-object System.Management.Automation.ErrorRecord $ex, "PathNotFound", $category, $LiteralPath
$psCmdlet.WriteError($errRecord)
}
# Must be -LiteralPath
$resolvedPaths = $LiteralPath | Convert-Path
}
foreach ($rpath in $resolvedPaths)
{
if ($pscmdlet.ShouldProcess($rpath, "Operation"))
{
# .. process rpath
}
}
}
End
{
}
}
Upvotes: 3