2013-09-26 35 views
0

作爲此問題的附件:How do I force declared parameters to require explicit naming?我正在努力處理管道。假設我想要的行爲,這種聲明:參數列表和管道

param(
    $installdir, 
    $compilemode, 
    [Parameter(Position=0, ValueFromRemainingArguments=$true)] $files 
    ) 

即,我可以把我的腳本是這樣的:

c:\> MyScript -installdir c:\ file-1.txt file-2.txt file-3.txt 

,但現在我也想能夠做到這樣說:

c:\> gi file-*.txt |MyScript -installdir c:\ 

我可能會想增加一個裝飾的參數是這樣的:

param(
    $installdir, 
    $compilemode, 
    [Parameter(
     Position=0, 
     ValueFromRemainingArguments=$true, 
     ValueFromPipeline=$true 
    )] $files 
    ) 

但實際發生的是我只有1個參數到我的參數,而不是獲得一個數組與gi產生的所有文件,我只得到列表中的第一個。

我試圖這樣的第二種方式是通過使用$input變量(而不是使用ValueFromPipeline裝飾),但隨後在試圖調用腳本我得到的錯誤:

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.

在那裏我可以從去這裏?

回答

3

你可以聲明它沒有ValueFromRemainingArguments:

param(
    [Parameter(
     Position=0, 
     ValueFromPipeline=$true, 
     ValueFromPipelineByPropertyName=$true)] 
    [Alias('PSPath')] 
    [string[]] 
    $files, 
    $installdir, 
    $compilemode 
    ) 

然後在多個文件中使用逗號操作符如傳遞一個數組:

MyScript -installdir c:\ file-1.txt,file-2.txt,file-3.txt 

注:爲了接受類似的命令輸入Get-Item和Get-ChildItem,使用ValueFromPipelineByPropertyName並添加一個參數別名「PSPath」,它將在由Get-Item/Get-ChildItem輸出的對象上查找PSPath屬性。

我有測試此在ISE和正常工作:

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 

僅供參考,這是一個模板,我用所有的時間來創建能夠利用管道輸入或數組輸入,以及通配符路徑命令:

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 
    { 
    } 
} 
+0

是的。我可能必須這樣做。我不喜歡它,因爲本能說你用空格分隔列表。或者,也許我可以運行$ args變量,但它仍然讓我不得不聲明至少有一個參數與一個位置,以便其他名稱是必需的。嘆...... perl在這方面好得多 – ekkis

+0

我想這裏真正困擾我的是似乎在參數和管道對象之間存在混淆。管道輸入到我的腳本中的東西還不是我的參數,當我嘗試輸入管道時我的param()聲明失敗了,我不明白爲什麼......並且特別是當我聲明參數的位置爲0時 – ekkis

+0

在任何情況下,你的解決方案不起作用,因爲只要我聲明一個帶有位置值的參數,我似乎無法將任何東西傳入腳本(我不明白爲什麼) – ekkis