如何编写接受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的注释非常准确,您需要接受一个字符串,然后在强制转换之前移除函数内部最外层的
[]
(如果存在)(这正是
对象内部所做的)