Powershell检查变量是否为对象
[在两个答案都表示不清楚后进行编辑] 我的目标是:根据传递给函数的是“对象”类型(例如数组、哈希表)还是简单的“字符串”类型,执行不同的操作。如果它只是一个字符串,我会简单地将其包含在电子邮件的正文中。如果它是一个数组或哈希表,我需要对其进行大量处理,以将其转换为HTML表 [问题原文] 我正在将变量Powershell检查变量是否为对象,powershell,Powershell,[在两个答案都表示不清楚后进行编辑] 我的目标是:根据传递给函数的是“对象”类型(例如数组、哈希表)还是简单的“字符串”类型,执行不同的操作。如果它只是一个字符串,我会简单地将其包含在电子邮件的正文中。如果它是一个数组或哈希表,我需要对其进行大量处理,以将其转换为HTML表 [问题原文] 我正在将变量$body传递给函数电子邮件报告,该函数可以是简单字符串或对象(例如哈希表或数组)。 我想检查$body是否是一个对象,并根据需要执行不同的操作。 我的问题是,$body几乎可以是任何东西,而不仅仅
$body
传递给函数电子邮件报告
,该函数可以是简单字符串或对象(例如哈希表或数组)。
我想检查$body
是否是一个对象,并根据需要执行不同的操作。
我的问题是,$body
几乎可以是任何东西,而不仅仅是字符串或哈希表。所以我不能只检查$body.GetType().Name-eq String
我尝试了$body.GetType().Name
,返回
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Hashtable System.Object
但是,如果变量是数组BaseType
则变为System.array
,因此无法对该属性进行筛选,同样如上所述,$body
变量可能并不总是哈希表或数组。
如果它是一个哈希表,$var.GetType()
返回一个System.Object
的BaseType,但是我似乎无法引用BaseType属性。
($hash.GetType()).BaseType
返回另一个对象本身,该对象本身的BaseType属性为空
我还尝试了$body.IsObject
和$body.IsObject()
,但这些方法似乎不存在。我还尝试了$body-eq[System.Object]
,我希望它是$true
,但它返回$false
不确定从这里走到哪里-我想我遗漏了一些明显的东西或有逻辑错误。如果您只是想测试对象的类型,您可以使用
-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
几乎所有指定的变量都是对象或对象的引用。因此,将任何东西作为类型[object]
进行测试几乎总是正确的
不过,为了更安全,在进行类型比较时应该依赖于类型的全名,因为并非所有类型都有类型加速器。以下面的ArrayList类型为例。类型名可能是ArrayList,但由于没有名为[ArrayList]
的类型加速器,并且它不是直接从系统命名空间中删除的,因此检查将抛出一个没有完整类型名的错误。您可以随时关闭系统,即[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
这个问题并不完全清楚你的目标或动机是什么,但这里有:
由于.NET类型系统的性质,PowerShell中的每个对象最终都继承自System.object
,因此尝试对其使用类型标识比较有点愚蠢,因为您可以简单地执行以下操作:
function Test-IsObject
{
param(
[AllowNull()]
$InputObject
)
return $null -ne $InputObject
}
如果要测试所讨论的对象不是值类型(即不是结构或整型,而是类),请检查类型的
IsValueType
属性:
function Test-IsRefType
{
param(
[AllowNull()]
$InputObject
)
return ($null -ne $InputObject -and -not $InputObject.GetType().IsValueType)
}
如果您想要一个通用解决方案来测试某个类型是否出现在对象的类型层次结构中,有三种通用方法:
PSTypeNames
-is
运算符PSTypeNames PowerShell中的所有对象都有一个名为
PSTypeNames
的特殊属性,该属性包含基础对象+(可选)PowerShell定义的类型扩展名的类型层次结构中所有类型的类型名称-例如,这就是PowerShell区分不同CIM类实例格式的方式
由于用户可以直接操纵PSTypeName
,这本身就是“不安全的”,但在大多数情况下都会起作用:
function Test-IsType
{
param(
[object]$InputObject,
[string]$TypeName
)
return $InputObject.PSTypeNames -contains $TypeName
}
内置类型运算符
自从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
-is
也会自动测试基本类型和接口(下面的所有语句都是$true
):
这些运算符以及相关的-as
运算符记录在帮助主题中
手动解析类型层次结构
最后,如果我们想进一步探索,我们可以手动解析类型层次结构,只需取消引用GetType().BaseType
,直到点击System.Object
。下面是一个简单的helper函数,它发出所有的基类型,然后我们可以与之进行比较:
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)
}
请注意,您可以只使用
-is
而不是测试IsType
,除非您特别希望只测试基类,而不测试接口。基类将告诉您当前对象的继承来源。因此,哈希表和字符串的基础是system.object。你的目标是什么?是否要查看主类型是否为System.Object?您想看看它是字符串、数组还是哈希表吗?我想看看变量是字符串还是对象。但是,我现在从下面的两个答案中了解到,在Powershell中,甚至字符串也被视为对象。如果我能找到一种不影响人们已经回答的一般要点的方法,我将尝试编辑我的问题以使其清晰。我还在GitHub上打开了一个文档问题,要求改进:谢谢,两个答案非常相似。我了解到,Powershell中几乎所有变量都被视为对象。您让我使用“-is[string]检查变量是否为字符串,因此我将其标记为答案。
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)
}