Powershell 检查变量是否为对象

Gos*_*ega 3 powershell

[在两个答案都说不清楚之后编辑] 我的目标:根据传递给函数的内容是“对象”类型的东西(例如数组、哈希表)还是简单的“字符串”类型的东西,执行不同的操作。如果它只是一个字符串,我会简单地将它包含在电子邮件正文中。如果它是一个数组或哈希表,我需要对其进行一堆处理才能将其转换为 HTML 表。

[原始问题文本] 我将一个变量传递$body给一个函数Email-Report,该函数可以是一个简单的字符串或一个对象(例如一个哈希表或数组)。我想检查是否$body是一个对象并根据情况做不同的事情。我的问题是$body几乎可以是任何东西,而不仅仅是字符串或哈希表。所以我不能只是检查是否$body.GetType().Name -eq String

我试过$body.GetType().Name哪个返回

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Hashtable                                System.Object
Run Code Online (Sandbox Code Playgroud)

然而,如果变量是一个数组BaseTypeSystem.Array,所以我不能过滤器上该属性,也如上所述$body变量可能并不总是一个散列表或阵列。如果它是一个哈希表,则$var.GetType()返回 BaseType System.Object,但是我似乎无法引用 BaseType 属性。 ($hash.GetType()).BaseType返回另一个对象本身,它本身具有一个空白的 BaseType 属性。

我也试过$body.IsObject$body.IsObject()但这些方法似乎不存在。我也试过$body -eq [System.Object]我期望的$true,但它返回$false

不知道从哪里开始 - 我想我遗漏了一些明显的东西或有一个逻辑错误。

Mat*_*sen 10

从这个问题中并不完全清楚你的目标或动机是什么,但这里是:

System.Object由于 .NET 类型系统的性质,PowerShell 中的每个对象最终都继承自,因此尝试对其进行类型标识比较有点愚蠢,因为您可以简单地执行以下操作:

function Test-IsObject
{
    param(
        [AllowNull()]
        $InputObject
    )

    return $null -ne $InputObject
}
Run Code Online (Sandbox Code Playgroud)

如果要测试所讨论的对象是否不是值类型(即不是结构体或整型,而是类),请检查IsValueType该类型的属性:

function Test-IsRefType
{
    param(
        [AllowNull()]
        $InputObject
    )

    return ($null -ne $InputObject -and -not $InputObject.GetType().IsValueType)
}
Run Code Online (Sandbox Code Playgroud)

如果你想要一个通用的解决方案来测试某个类型是否出现在一个对象的类型层次结构中,有三种通用方法:

  1. 依靠 PSTypeNames
  2. 使用-is运算符
  3. 自己解析所有基本类型

PS 类型名称

PowerShell 中的所有对象都有一个名为的特殊属性PSTypeNames,该属性包含底层对象的类型层次结构中所有类型的类型名称 +(可选)PowerShell 定义的类型扩展名称——这就是 PowerShell 区分不同 CIM 类实例的格式的方式,例如.

由于PSTypeName可以由用户直接操作,这本质上是“不安全的”,但在大多数情况下都有效:

function Test-IsType
{
    param(
        [object]$InputObject,
        [string]$TypeName
    )

    return $InputObject.PSTypeNames -contains $TypeName 
}
Run Code Online (Sandbox Code Playgroud)

内置类型运算符

从 PowerShell 3.0 开始,我们有两个新的类型运算符:-is和它的否定对应-isnot. 这些实际上检查底层 .NET 对象的运行时类型,因此它们比检查合成PSTypeNames属性更安全:

$Object -is [System.Object]   # $true for any value assigned to $Object
"" -is [string]               # $true
5 -is [int]                   # $true
Run Code Online (Sandbox Code Playgroud)

-is自动测试基本类型和接口(下面的所有语句都是$true):

$strings = 'a', 'b', 'c' -as [string[]]
$strings -is [array]
$strings -is [System.Collections.Generic.IEnumerable[string]]
$strings -is [object]
Run Code Online (Sandbox Code Playgroud)

这些运算符以及相关的-as运算符记录在about_Type_Operators帮助主题中。

手动解析类型层次结构

最后,如果我们想进一步探索,我们可以通过简单地取消引用来手动解析类型层次结构,GetType().BaseType直到我们点击System.Object。下面是一个简单的辅助函数,它发出所有基本类型,然后我们可以进行比较:

function Get-BaseType
{
    param(
        [type]$Type,
        [switch]$IncludeLeaf
    )

    if($IncludeLeaf){
        # We're "walking backwards", so we'll start by emitting the type itself
        $Type
    }

    # Now go through the BaseType references
    # At some point we'll reach System.Object and (BaseType -eq $null) 
    while($BaseType = $Type.BaseType){
        ($Type = $BaseType)
    }
}

function Test-IsType
{
    param(
        [object]$InputObject,
        [type]$TypeName
    )

    return $TypeName -in (Get-BaseType -Type $InputObject.GetType() -IncludeLeaf)
}
Run Code Online (Sandbox Code Playgroud)

请注意,您可以只使用-is代替Test-IsType,除非您特别想仅测试基类,而不是接口。


Adm*_*ngs 7

如果您只想测试对象的类型,可以使用-is运算符将变量或值与类型进行比较。

# String test

PS > $str = "a string"
PS > $str -is [String]
True

PS > $str -is [Int]
False

PS > $str.gettype().Name
String

# Array Test

PS > $arr = @(1,2,3)
PS > $arr.GetType().Name
Object[]

PS > $arr -is [Object[]]
True

# Hashtable Test

PS > $hash = @{property='Value'}
PS > $hash.GetType().Name
Hashtable
PS > $hash -is [Hashtable]
True
PS > $hash -is [Object[]]
False
PS > $hash -is [String]
False
Run Code Online (Sandbox Code Playgroud)

您分配的几乎所有变量都将是对象或对对象的引用。因此,[object]将任何东西作为一种类型进行测试几乎总是True.

但是为了更安全,在进行类型比较时应该依赖类型的全名,因为并非所有类型都有类型加速器。下面以ArrayList类型为例。类型名称可能是 ArrayList,但由于没有调用类型加速器[ArrayList]并且它不是直接脱离 System 命名空间,因此检查将在没有完整类型名称的情况下抛出错误。您可以随时离开 System,即[String][System.String].

# Bad ArrayList Test

PS > $e = @(1,2) -as [Collections.ArrayList]
PS > $e.GetType().Name
ArrayList
PS > $e -is [ArrayList]
Unable to find type [ArrayList].
At line:1 char:8

# Good Arraylist Test

PS C:\temp\test1> $e.GetType().FullName
System.Collections.ArrayList
PS > $e -is [System.Collections.ArrayList]
True
Run Code Online (Sandbox Code Playgroud)