如何编写接受System.type类型参数的PowerShell CmdLet?
我想将如何编写接受System.type类型参数的PowerShell CmdLet?,powershell,types,parameters,parameter-passing,cmdlet,Powershell,Types,Parameters,Parameter Passing,Cmdlet,我想将类型传递给自定义CmdLet,如下所示: PS> "1" | My-CmdLet -Check [System.String] PS> My-CmdLet 1 -Check [System.String] 我想使用-Check参数作为我的CmdLet中-Is运算符的类型参数: Function My-CmdLet { param( ${Actual}, [System.String] ${Check}
类型
传递给自定义CmdLet,如下所示:
PS> "1" | My-CmdLet -Check [System.String]
PS> My-CmdLet 1 -Check [System.String]
我想使用-Check
参数作为我的CmdLet中-Is
运算符的类型参数:
Function My-CmdLet {
param(
${Actual},
[System.String]
${Check} # <-- I want to pass a type here
)
if (-not ($Actual -Is [Type] $Check)) {
# ...
}
}
导致错误的原因:
Cannot convert the "[System.String]" value of type "System.String" to type "System.Type". At MycmdLet.ps1:19 char:9
+ if (-not ($Actual -Is [Type] $ExpectedType)) {
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvalidCastFromStringToType
我尝试使用[System.String]
,[System.Type]
[System.Object]
,[System.RunTimeType]
作为Check
参数的类型,但这些似乎都不起作用
作为比较:
我可以向Where-Object cmdlet传递类型,如下所示:
PS> Get-Process | Where-Object StartTime -Is [System.Datetime]
PS> "1" -Is [System.String]
True
(在本例中,值“[System.DateTime]”传递给CmdLet参数$value
,该参数的类型为[System.Object]
)
我可以使用带有-Is
运算符的类型,如下所示:
PS> Get-Process | Where-Object StartTime -Is [System.Datetime]
PS> "1" -Is [System.String]
True
如何在我的CmdLet中声明-Check
参数?将参数声明为字符串并通过[type]强制转换它
例如:
$a=1
$b="System.Int32"
$a -is [type]$b
这应该返回$true。有没有理由不首先声明类型为System.type的参数
function Get-FullyQualifiedTypeName
{
param([System.Type]$Type)
Write-Host $Type.FullName
}
如果您传递了一个实际的类型
,它将被接受,否则,解析器将尝试为您将(部分)typename字符串解析为一个实际的[Type]
。不需要重新实现解析器已经为您做的事情
PS> Get-FullyQualifiedTypeName $([psobject])
System.Management.Automation.PSObject
PS> Get-FullyQualifiedTypeName string
System.String
所以在你的情况下,你会做一些
function Check-Type
{
param(
[Parameter(Mandatory,ValueFromPipeLine)]
[psobject]$Actual,
[Parameter(Mandatory)]
[System.Type]$Check
)
$Actual -is $Check
}
你应该得到你想要的:
PS> "1" |Check-Type -Check string
True
PS> "1" |Check-Type -Check int
False
PS> 1 |Check-Type -Check int
True
[System.String]
(请注意方括号)是一个表达式,因此,如果不包装在分组表达式()
或子表达式$()
中,它就不能作为参数值。它只是类似于[type]::GetType(“System.String”)
(c#中的typeof()
)的PowerShell快捷方式
System.String
但是,PowerShell的自动类型转换将成功地将该字符串转换为类型
-对象
function Test-Type
{
param(
[Parameter(Mandatory=$true,ValueFromPipeLine=$true)]
[PSObject]$Object,
[Parameter(Mandatory=$true)]
[System.Type]$Type
)
$Object -is $Type
}
Test-Type "c" -Type ([string])
1 | Test-Type -Type string
1 | Test-Type -Type ([int])
"1" | Test-Type -Type string
#Output
True
False
True
True
或者,您可以使用字符串参数,并在函数中自己将其转换为Type
-object。通过这种方式,您可以自己删除方括号以使类型转换正常工作。像这样:
function Test-Type
{
param(
[Parameter(Mandatory=$true,ValueFromPipeLine=$true)]
[PSObject]$Object,
[Parameter(Mandatory=$true)]
[string]$Type
)
#Remove square brackets and convert to type-object
$Type = [System.Type]($Type -replace '^\[(.*)\]$', '$1')
$Object -is $Type
}
Test-Type "c" -Type [string]
1 | Test-Type -Type string
1 | Test-Type -Type [int]
"1" | Test-Type -Type string
#Output
True
False
True
True
您可以检查这个答案:如果($check.StartsWith('[')-和$check.EndsWith(']'){$check=$check.Substring(1,$check.Length-2)}
原因是[System.String]
有效,因为类型运算符()设计为使用方括号表达式。但是,参数值不是。使用该CmdLet会导致无法将类型为“System.String”的“[System.String]”值转换为类型为“System.type”。
您使用的是哪个Powershell版本?-因为在我的例子中,无论我传入的是“System.Int32”
还是[System.Int32]
,都会比较目标类型。我正在使用Powershell 5.v5。当您直接执行示例中的代码时,它确实起作用,但当您将其设置为带有字符串参数的cmdlet并尝试使用[System.Int32]
调用它时,它就不起作用了。我明白您的意思。。。我有一个解决方法:$Actual-是[type]$Check.Replace(“[”,”).Replace(“]”,”)
-其中$Check被定义为[psobject],我也同意这个想法(从字符串中删除方括号),但感觉有点。。不自然。我希望有一个更好的答案..当你用“1”| Check Type-Check[System.String]
@oɔɯǝɹ来校准它时,仍然会失败。好吧,这就是解析器的工作方式。如果要将类型文字作为参数传递,则必须将其放入子表达式或变量中,以避免将整个内容解释为字符串。为什么违抗此行为如此重要?我不想“违抗”此行为,我希望我的sybntax与采用[Type]
参数的其他cmdlet和参数保持一致(例如Where-Object-is[Type]
)在这种情况下,@PetSerAl的注释非常准确,您需要接受一个字符串,然后在强制转换之前移除函数内部最外层的[]
(如果存在)(这正是对象内部所做的)