我有一个场景,其中cmdlet的参数之一是CSV文件名和列标题的名称的元组。我想将其正确地导入为类型为[System.Tuple[System.IO.FileInfo,String]]
的元组。完整的代码如下:
[Parameter(Mandatory=$false)]
[ValidateScript( {
if (-Not ($_.item1 | Test-Path) ) {
throw "File or folder does not exist"
}
if (-Not ($_.item1 | Test-Path -PathType Leaf) ) {
throw "The Path argument must be a file. Folder paths are not allowed."
}
return $true
})]
[System.Tuple[System.IO.FileInfo,String]]$SomePath
然而,当你提供一个像-SomePath book1.csv,'Some Column Header'
这样的参数时,你会得到:
Invoke-MyCmdlet.ps1: Cannot process argument transformation on parameter 'SomePath'. Cannot convert the "System.Object[]" value of type "System.Object[]" to type "System.Tuple`2[System.IO.FileInfo,System.String]".
微软提供了一些关于这个主题的文档,但如果我说实话,我很难理解这个例子中发生了什么。那里有很多语法和命令我不熟悉,也不理解它们与类型转换过程的相关性。
我的问题是:有没有一种方法可以告诉PowerShell如何正确执行类型转换?如果是,语法是什么?它在其他地方记录得更清楚了吗?我错过了吗?
您可以实现并注册自己的PSTypeConverter
(此处使用PowerShell类(:
class CustomTupleConverter : System.Management.Automation.PSTypeConverter
{
[bool]
CanConvertFrom([object]$value, [type]$targetType)
{
# We only convert TO [Tuple[FileInfo,string]]
if($targetType -ne [System.Tuple[System.IO.FileInfo,string]]){
return $false
}
# ... and only from 2-item arrays consisting of @([string],[string]) or @([FileInfo],[string])
if($value -is [array] -and $value.Length -eq 2){
if(($value[0] -is [string] -or $value[0] -is [System.IO.FileInfo]) -and $value[1] -is [string]){
return $true
}
}
return $false
}
[object]
ConvertFrom([object]$value, [type]$targetType, [IFormatProvider]$format, [bool]$ignoreCase)
{
# Resolve individual values in the input array
$fileInfo = if($value[0] -is [System.IO.FileInfo]){
$value[0]
}
else{
Get-Item -Path $value[0]
}
if($fileInfo -isnot [System.IO.FileInfo]){
throw "Path didn't resolve to a file."
}
$headerName = $value[1] -as [string]
# Create corresponding tuple and return
return [System.Tuple]::Create($fileInfo, $headerName)
}
[bool]
CanConvertTo([object]$value, [type]$targetType){
return $this.CanConvertFrom($value, $targetType)
}
[object]
ConvertTo([object]$value, [type]$targetType, [IFormatProvider]$format, [bool]$ignoreCase){
return $this.ConvertFrom($value, $targetType, $format, $ignoreCase)
}
}
一旦定义,我们需要将其注册为[System.Tuple[System.IO.FileInfo,string]]
:的可能类型转换器
$targetTypeName = [System.Tuple[System.IO.FileInfo,string]].FullName
$typeConverter = [CustomTupleConverter]
Update-TypeData -TypeName $targetTypeName -TypeConverter $typeConverter
现在我们可以将两个字符串绑定到一个元组:
function Test-TupleBinding
{
param(
[Parameter(Mandatory = $true)]
[System.Tuple[System.IO.FileInfo,string]] $PathAndColumnName
)
$PathAndColumnName
}
参数绑定过程中的隐藏魔法:
PS C:> Test-TupleBinding -PathAndColumnName windowssystem32notepad.exe,ColumnNameGoesHere
Item1 Item2 Length
----- ----- ------
C:windowssystem32notepad.exe ColumnNameGoesHere 2