管道到用户函数参数问题
Pipeline to user function parameter problems
出于某种原因,我的程序拒绝在这种情况下工作:
- 由于缺乏灵活性,我有一个自定义函数,用于替换 cmdlet
- 我正在通过管道
向此函数传递一个文件或文件夹对象
这是函数:
function Get-ChildItemCustom {
Param(
[Parameter(ValueFromPipeline=$true)]
[System.IO.FileSystemInfo] $item,
[Parameter(ValueFromPipeline=$false)]
[string] $archive_path
)
Process {
Get-ChildItem $item
}
}
我希望能够像 Get-ChildItem
一样使用此功能:输入一个 [System.IO.FileSystemInfo]
对象,并获取所有子项(使用我未在此处包含的一些额外条件进行排序)作为输出。
我是这样调用函数的:
Get-ChildItem $parentfolder_path |
Get-ChildItemCustom |
Do-SomethingElse
错误 returns 说明 Get-ChildItem
的结果(可验证类型 [System.IO.FileSystemInfo]
)被视为字符串。
Cannot convert the "E:\Data\VHG-ITC-Test\New folder\archive" value of type "System.String" to type "System.IO.FileSystemInfo".
参数前面的类型并不总是存在。当 $item
没有明确的类型时,函数会误读输入(据说只将 Name
属性 作为输入):
Get-ChildItem : Cannot find path 'C:\Windows\system32\New folder' because it does not exist.
所以该函数似乎无法正确接受对象输入。我想不惜一切代价避免使用字符串,而只是移动对象。我是不是参数设置错了?我能做什么?
问题不完全在于你的函数,而是在于 Get-ChildItem
处理参数的方式(正如 Moerwald 在他的回答中已经怀疑的那样)。
当您使用 FileInfo
对象作为未命名参数调用 Get-ChildItem
时,该参数被传递给第一个位置参数 (-Path
),它需要一个字符串数组作为输入,所以对象被转换为字符串。但是,在某些情况下,将 FileInfo
对象转换为字符串会扩展 FullName
属性,而在其他情况下,它只会扩展 Name
属性(我不能不过,请解释 PowerShell 如何决定何时选择哪个)。后者是你的情况。由于 Get-ChildItem
只看到一个名称,而不是完整路径,它正在寻找当前工作目录中的项目,但失败了。
有多种方法可以避免此问题,Moerwald 已经展示了其中一种方法。其他是:
使用管道将 $item
传递给 Get-ChildItem
:
function Get-ChildItemCustom {
Param(
[Parameter(ValueFromPipeline=$true)]
[IO.FileSystemInfo]$item,
[Parameter(ValueFromPipeline=$false)]
[string]$archive_path
)
Process {
$item | Get-ChildItem
}
}
通过按名称映射 属性 来传递完整路径:
function Get-ChildItemCustom {
Param(
[Parameter(
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true
)]
[string[]]$FullName,
[Parameter(ValueFromPipeline=$false)]
[string]$archive_path
)
Process {
Get-ChildItem $FullName
}
}
就个人而言,我更喜欢最后一种变体(通过 属性 名称传递)。
出于某种原因,我的程序拒绝在这种情况下工作:
- 由于缺乏灵活性,我有一个自定义函数,用于替换 cmdlet
- 我正在通过管道 向此函数传递一个文件或文件夹对象
这是函数:
function Get-ChildItemCustom {
Param(
[Parameter(ValueFromPipeline=$true)]
[System.IO.FileSystemInfo] $item,
[Parameter(ValueFromPipeline=$false)]
[string] $archive_path
)
Process {
Get-ChildItem $item
}
}
我希望能够像 Get-ChildItem
一样使用此功能:输入一个 [System.IO.FileSystemInfo]
对象,并获取所有子项(使用我未在此处包含的一些额外条件进行排序)作为输出。
我是这样调用函数的:
Get-ChildItem $parentfolder_path |
Get-ChildItemCustom |
Do-SomethingElse
错误 returns 说明 Get-ChildItem
的结果(可验证类型 [System.IO.FileSystemInfo]
)被视为字符串。
Cannot convert the "E:\Data\VHG-ITC-Test\New folder\archive" value of type "System.String" to type "System.IO.FileSystemInfo".
参数前面的类型并不总是存在。当 $item
没有明确的类型时,函数会误读输入(据说只将 Name
属性 作为输入):
Get-ChildItem : Cannot find path 'C:\Windows\system32\New folder' because it does not exist.
所以该函数似乎无法正确接受对象输入。我想不惜一切代价避免使用字符串,而只是移动对象。我是不是参数设置错了?我能做什么?
问题不完全在于你的函数,而是在于 Get-ChildItem
处理参数的方式(正如 Moerwald 在他的回答中已经怀疑的那样)。
当您使用 FileInfo
对象作为未命名参数调用 Get-ChildItem
时,该参数被传递给第一个位置参数 (-Path
),它需要一个字符串数组作为输入,所以对象被转换为字符串。但是,在某些情况下,将 FileInfo
对象转换为字符串会扩展 FullName
属性,而在其他情况下,它只会扩展 Name
属性(我不能不过,请解释 PowerShell 如何决定何时选择哪个)。后者是你的情况。由于 Get-ChildItem
只看到一个名称,而不是完整路径,它正在寻找当前工作目录中的项目,但失败了。
有多种方法可以避免此问题,Moerwald 已经展示了其中一种方法。其他是:
使用管道将
$item
传递给Get-ChildItem
:function Get-ChildItemCustom { Param( [Parameter(ValueFromPipeline=$true)] [IO.FileSystemInfo]$item, [Parameter(ValueFromPipeline=$false)] [string]$archive_path ) Process { $item | Get-ChildItem } }
通过按名称映射 属性 来传递完整路径:
function Get-ChildItemCustom { Param( [Parameter( ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true )] [string[]]$FullName, [Parameter(ValueFromPipeline=$false)] [string]$archive_path ) Process { Get-ChildItem $FullName } }
就个人而言,我更喜欢最后一种变体(通过 属性 名称传递)。