如何提供PowerShell参数的自定义类型转换



我有一个场景,其中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

最新更新