编辑:根据 cmets,听起来您真正的问题是:
如何验证我是否能够使用Add-Member 将新属性附加到输入对象?
为此,您需要排除两种输入值:
-
值类型的对象(数值类型,
[datetime]'s,任何在 .NET 中通过值传递的东西)
- 字符串
(作为mklement0's excellent answer shows,可以将属性添加到这些类型的本地副本中 - 但当在管道中的相邻命令之间传递值时,PowerShell 无法预测地“复活”它们,以及其他怪癖)
您可以验证输入对象不属于这些存储桶之一,如下所示:
[ValidateScript({$null -ne $_ -and $_.GetType().IsValueType -and $_ -isnot [string]})]
[psobject[]]$InputObject
PSObject 是一种通用包装类型,PowerShell 在内部使用它来跟踪附加到现有对象的扩展属性和成员。
因此,任何对象都可以隐式转换为PSObject——事实上,每当一个对象在管道语句中通过|从一个命令传递到另一个命令时,PowerShell都会这样做——并且在强制执行特定的输入对象特征方面没有实际影响。
如果要确保对象具有特定属性,最好的选择是使用 class 关键字定义特定数据类型:
class MyParameterType
{
[string]$Name
[int]$Value
}
function Test-MyParameterType
{
param(
[MyParameterType[]]$InputObject
)
$InputObject |ForEach-Object {
$_.GetType() # this will output `[MyParameterType]`
$_.Name # now you can be sure this property exists
}
}
您现在可以将声明类型的实例传递给函数参数:
$mpt = [MyParameterType]::new()
$mpt.Name = 'Name goes here'
Test-MyParameterType -InputObject $mpt
但如果自定义对象具有匹配的属性,PowerShell 也可以将它们隐式转换为所需的目标类型:
$arg = [pscustomobject]@{
Name = 'A name'
Value = Get-Random
}
# This will return [PSCustomObject]
$arg.GetType()
# But once we reach `$_.GetType()` inside the function, it will have been converted to a proper [MyParameterType]
Test-MyParameterType -InputObject $arg
如果您想验证特定属性的存在及其可能的值无需显式输入,您必须在验证脚本中访问对象的隐藏 psobject 成员集 - 请注意它'将一次验证一项:
function Test-RequiredProperty
{
param(
[ValidateScript({ $_ -is [PSObject] -and ($prop = $_.psobject.Properties['RequiredProperty']) -and $null -ne $prop.Value })]
[PSObject[]]$InputObject
)
}
现在,如果我们传递一个带有 RequiredProperty 属性的对象,该属性具有某些值,则验证成功:
$arg = [pscustomobject]@{
RequiredProperty = "Some value"
}
# This will succeed
Test-RequiredProperty -InputObject $arg
# This will fail because the property value is $null
$arg.RequiredProperty = $null
Test-RequiredProperty -InputObject $arg
# This will fail because the property doesn't exist
$arg = [pscustomobject]@{ ADifferentPropertyName = "Some value" }
Test-RequiredProperty -InputObject $arg