powershell - 如何提供 PowerShell 参数的自定义类型转换
问题描述
我有一个场景,我的 cmdlet 的参数之一是 CSV 文件名和列标题名称的元组。我想将其正确导入为 type 的元组[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]".
Microsoft 提供了有关此主题的一些文档,但老实说,我正在努力理解该示例中发生的事情。那里有很多我不熟悉的语法和命令,也不了解它们与类型转换过程的相关性。
我的问题是:有没有办法告诉 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
现在我们可以将 2 个字符串绑定到一个元组:
function Test-TupleBinding
{
param(
[Parameter(Mandatory = $true)]
[System.Tuple[System.IO.FileInfo,string]] $PathAndColumnName
)
$PathAndColumnName
}
参数绑定期间的转换魔法:
PS C:\> Test-TupleBinding -PathAndColumnName windows\system32\notepad.exe,ColumnNameGoesHere
Item1 Item2 Length
----- ----- ------
C:\windows\system32\notepad.exe ColumnNameGoesHere 2
推荐阅读
- python - 如何使用 python 更改 wikihow API 中的语言
- distance - 层次聚类规范表示?
- javascript - php中sessionStorage的等价物是什么?
- python - 如何从 Pandas 数据框中删除列标签包含唯一字符的所有列
- python - PyTorch:为什么要创建相同类型层的多个实例?
- java - 在实体中建立自动关系时错误事务中止
- java - 程序为给定的 N 行打印正方形图案(数字为奇数)
- typescript - useReducer 打字稿:状态类型
- d3.js - d3.js - 在条形图上方添加文本不显示
- java - 二叉树的高度:为什么这个解决方案没有通过hackerrank中的2/6测试用例?