简体   繁体   中英

How to write a PowerShell CmdLet that will accept a parameter of type System.Type?

I want to pass a Type to a custom CmdLet, as follows:

PS> "1" | My-CmdLet -Check [System.String]

I want to use the -Check parameter as the type argument for the -Is operator in my CmdLet:

Function My-CmdLet {
    param(
        ${Actual},

        [System.String]
        ${Check}           # <-- I want to pass a type here
    )

    if (-not ($Actual -Is [Type] $Check)) {
        # ... 
    }
}

When called as follows:

PS> My-CmdLet 1 -Check [System.String]

Results in the error:

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

I tried using [System.String] , [System.Type] [System.Object] , [System.RunTimeType] as the type for the Check parameter, but none of those seem to be working.

For comparison:

I can pass a type to the Where-Object cmdlet like this:

PS> Get-Process | Where-Object StartTime -Is [System.Datetime]

(In this case the value "[System.DateTime]" gets passed on to the CmdLet parameter $Value which is of type [System.Object] )

I can use a Type with the -Is operator like this:

PS> "1" -Is [System.String]
True

How do i declare the -Check parameter in my CmdLet?

Any reason you wouldn't just declare the parameter of type System.Type in the first place?

function Get-FullyQualifiedTypeName
{
    param([System.Type]$Type)

    Write-Host $Type.FullName
}

If you pass an actual Type , it will be accepted, otherwise, the parser will try to resolve your (partial) typename string to an actual [type] for you. No need to re-implement something that the parser already does for you!

PS> Get-FullyQualifiedTypeName $([psobject])
System.Management.Automation.PSObject
PS> Get-FullyQualifiedTypeName string
System.String

So in your case, you'd do something like

function Check-Type
{
    param(
        [Parameter(Mandatory,ValueFromPipeLine)]
        [psobject]$Actual,
        [Parameter(Mandatory)]
        [System.Type]$Check
    )

    $Actual -is $Check
}

Should get you what you want:

PS> "1" |Check-Type -Check string
True
PS> "1" |Check-Type -Check int
False
PS> 1 |Check-Type -Check int
True

[System.String] (notice the square brackets) is an expression and because of that it can't be as a parameter value without being wrapped in a grouping expression () or a subexpression $() . It is simply a PowerShell shortcut for something like [type]::GetType("System.String") ( typeof() in c#).

System.String however is a string which PowerShell's automatic type conversion will successfully convert to a Type -object.

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

As an alternative, you can use a string-parameter and convert it to Type -object yourself inside your function. This way you can remove the square-brackets yourself to make the type conversion work. Like this:

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

Declare the parameter as string and cast it via [type].

For example:

$a=1
$b="System.Int32"
$a -is [type]$b

This should return $true.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM