我的 powershell 函式應該接受混合檔案和/或目錄的有效路徑串列作為命名引數或通過管道,過濾與模式匹配的檔案,并回傳檔案串列。
$Paths = 'C:\MyFolder\','C:\MyFile'
這有效:Get-Files -Paths $Paths這不:$Paths | Get-Files
$PSDefaultParameterValues = @{
"Get-Files:Paths" = ( Get-Location ).Path
}
[regex]$DateRegex = '(20\d{2})([0-1]\d)([0-3]\d)'
[regex]$FileNameRegex = '^term2-3\.7_' $DateRegex '\.csv$'
Function Get-Files {
[CmdletBinding()]
[OutputType([System.IO.FileInfo[]])]
[OutputType([System.IO.FileInfo])]
param (
[Parameter(
Mandatory = $false, # Should default to $cwd provided by $PSDefaultParameterValues
ValueFromPipeline,
HelpMessage = "Enter filesystem paths that point either to files directly or to directories holding them."
)]
[String[]]$Paths
)
begin {
[System.IO.FileInfo[]]$FileInfos = @()
[System.IO.FileInfo[]]$SelectedFileInfos = @()
}
process { foreach ($Path in $Paths) {
Switch ($Path) {
{ Test-Path -Path $Path -PathType leaf } {
$FileInfos = (Get-Item $Path)
}
{ Test-Path -Path $Path -PathType container } {
foreach ($Child in (Get-ChildItem $Path -File)) {
$FileInfos = $Child
}
}
Default {
Write-Warning -Message "Path not found: $Path"
continue
}
}
$SelectedFileInfos = $FileInfos | Where-Object { $_.Name -match $FileNameRegex }
$FileInfos.Clear()
} }
end {
Return $SelectedFileInfos | Get-Unique
}
}
我發現如果我洗掉默認引數值,這兩個版本都可以作業。為什么?
當引數在 PSDefaultParameterValues 中定義了默認值時,為什么通過管道傳遞引數會導致錯誤,有沒有辦法解決這個問題?
uj5u.com熱心網友回復:
Mathias R. Jessen在評論中提供了關鍵指標:
$PSDefaultParameterValues通過存盤在首選項變數中的字典中的條目系結的引數在它可能通過管道系結之前被系結,就像顯式傳遞引數值一樣,作為引數。一旦給定引數以這種方式系結,它就不能通過管道再次系結,從而導致錯誤:
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.如您所見,不幸的是,此訊息并未涵蓋手頭的特定問題 -已系結的引數。未說出口的部分是,一旦給定引數已被引數系結(可能是 via ),它將從輸入可以系結到的候選管道系結引數集中洗掉,如果沒有剩余候選,則會發生錯誤。
$PSDefaultParameterValues
覆寫預設值的唯一方法
$PSDefaultParameterValue是使用(顯式)引數。
對相關 GitHub 問題的此評論提供了有關引數系結順序的詳細資訊。
重現問題的簡化方法:
& {
# Preset the -Path parameter for Get-Item
# In any later Get-Item calls that do not use -Path explicitly, this
# is the same as calling Get-Item -Path /
$PSDefaultParameterValues = @{ 'Get-Item:Path' = '/' }
# Trying to bind the -Path parameter *via the pipeline* now fails,
# because it has already been bound via $PSDefaultParameterValues.
# Even without the $PSDefaultParameterValues entry in the picture,
# you'd get the same error with: '.' | Get-Item -Path /
'.' | Get-Item
# By contrast, using an *argument* allows you to override the preset.
Get-Item -Path .
}
uj5u.com熱心網友回復:
這里發生了什么事?!
這是一個時間問題。
PowerShell嘗試按以下順序系結和處理引數引數:
- 明確命名的引數引數是系結的(例如。
-Param $value) - 位置引數是系結的(
abcinWrite-Host abc) - 默認引數值適用于在前兩個步驟中未處理的任何引數- 請注意,適用
$PSDefaultParameterValues始終優先于引數塊中定義的默認值 - 決議引數集,驗證所有強制引數都有值(只有在管道中沒有上游命令時才會失敗)
- 呼叫
begin {}管道中所有命令的塊 - 對于管道下游的任何命令:等待輸入,然后開始將其系結到之前步驟中尚未處理
process {}的最合適的引數,并在管道中的所有命令上呼叫塊
如您所見,您分配給的值$PSDefaultParameterValues在步驟 3 中生效 - 早在 PowerShell 甚至有機會-Paths在步驟 6 中開始將管道字串值系結到 之前。
*) 這是一個嚴重的過度簡化,但要點仍然存在:必須在管道系結開始之前處理默認引數值。
如何解決它?
鑒于上述程序,我們應該能夠通過顯式命名我們想要將管道輸入系結到的引數來解決此問題。
但是如何-Paths與管道輸入結合呢?
通過提供延遲系結腳本塊(或有時稱為“管道系結引數運算式”):
$Paths | Get-Files -Paths { $_ }
這將導致 PowerShell-Paths在上面的第 1 步中進行識別,此時會跳過默認值分配。
一旦命令開始接收輸入,它就會轉換輸入值并將結果值系結到-Paths,通過執行{ $_ }塊 - 因為我們只是按原樣輸出專案,所以效果與管道輸入被隱式系結時完全相同。
深層發掘
如果您想了解更多關于“幕后”發生的事情,最好的工具是Trace-Command:
$PSDefaultParameterValues['Get-Files:Paths'] = $PWD
Trace-Command -Expression { $Paths |Get-Files } -Name ParameterBinding -PSHost
我應該提到ParameterBinding跟蹤器非常冗長- 這對于推測正在發生的事情非常有用 - 但輸出可能有點壓倒性,在這種情況下,您可能需要替換-PSHost引數-PSPath .\path\to\output.txt以將跟蹤輸出寫入檔案
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/412553.html
標籤:
