繁体   English   中英

如何正确验证 powershell 中的参数?

[英]How to correctly validate parameter in powershell?

团队!

我的高级 function 中有类型为 PSObject[] 的变量。

[Parameter( Mandatory = $false, Position = 0, HelpMessage = "PsObject data." )]
[PSobject[]] $data,
...

但有时我输入的 [string[]] 类型的 $data 正在转换为 [PSObject[]] 并且我在使用 object 属性时遇到错误。

我试图通过脚本验证它

[Parameter( Mandatory = $false, Position = 0, HelpMessage = "PsObject data." )]
[ValidateScript({ ( ( $_ -is [PSobject] ) -or ( $_ -is [PSobject[]] )  -or ( $_ -is [System.Object[]] ) ) })]
 $data,

但它没有效果,我看到类型为 [string[]] 的 $data,我继续 cath 错误。

怎么了?

编辑:根据评论,听起来您真正的问题是:

如何验证我是否能够使用Add-Member将新属性附加到输入对象?

为此,您需要排除两种输入值:

  • 值类型的对象(数值类型, [datetime]的,任何在 .NET 中按值传递的东西)
  • 字符串

(正如mklement0 的出色回答所示,可以将属性添加到这些类型的本地副本中 - 但 PowerShell 在管道中的相邻命令之间传递值时无法预测地“复活”它们,以及其他怪癖)

您可以验证输入对象不属于这些桶之一,如下所示:

[ValidateScript({$null -ne $_ -and $_.GetType().IsValueType -and $_ -isnot [string]})]
[psobject[]]$InputObject

PSObject是一种通用包装器类型,PowerShell 在内部使用它来跟踪附加到现有对象的扩展属性和成员。

出于这个原因,任何 object都可以隐式转换为PSObject - 事实上,每次 object 从一个命令传递到另一个命令时,PowerShell 都会这样做| 在管道语句中 - 它在强制执行特定输入 object 特征方面没有实际效果。

如果要确保 object 具有特定属性,最好的选择是使用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
  }
}

您现在可以将已声明类型的实例传递给 function 参数:

$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 

如果您想在不显式键入的情况下验证特定属性及其潜在值的存在,您必须在验证脚本中访问 object 的隐藏psobject成员集 - 请注意,它将一次验证一个项目:

function Test-RequiredProperty
{
  param(
    [ValidateScript({ $_ -is [PSObject] -and ($prop = $_.psobject.Properties['RequiredProperty']) -and $null -ne $prop.Value })]
    [PSObject[]]$InputObject
  )
}

现在,如果我们传递一个 object 和一个具有某些值的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

补充Mathias R. Jessen 的有用答案

虽然不建议通过Add-Member使用ETS(扩展类型系统)属性修饰.NET 值类型字符串的实例,但可以使用以下习惯用法来实现。

# Works with any non-$null object.
# Note the use of -PassThru
# Add -Force to override an existing property.
$decoratedObject = $object | Add-Member -PassThru foo bar 

注意: Add-Member调用是以下简称: Add-Member -PassThru -NotePropertyName foo -NotePropertyValue bar 也就是说,添加了一个名为.foo且值为'bar'的属性。

-PassThru仅在$object字符串(类型[string] )时才严格需要。

展示:

$decoratedNumber = 42 | Add-Member -PassThru foo bar1 
$decoratedString = 'baz' | Add-Member -PassThru foo bar2
# Access the .foo property on each:
($decoratedNumber, $decoratedString).foo # -> 'bar1', 'bar2'

为什么不建议这样做:

装饰属性:

  • 在将修饰值类型实例传递或强制转换为相同类型的参数或修改变量值时被丢弃

     PS> ++$decoratedNumber; $decoratedNumber.foo + '.'. #.: Property was discarded. PS> & { param([int] $num) $num.foo + '!' } $decoratedNumber ! # !! Property was discarded. # Only *untyped* parameters preserve the decorations: PS> & { param($num) $num.foo + '!' } $decoratedNumber bar1!
  • 可以意外地出现在序列化上下文中; 例如:

     PS> $decoratedNumber | ConvertTo-Json -Compress {"value":42,"foo":"bar1"} # Casting to the original type helps: PS> [int] $decoratedNumber | ConvertTo-Json -Compress 42

此外,具体对于[int]实例, 0100之间的值由 PowerShell 内部缓存(出于性能原因),因此装饰可能会意外地出现在稍后的无关变量中:

 PS> $decorated = 42 | Add-Member -PassThru foo bar1; $other = 42; $other.foo
 bar1 # !! Unrelated use of 42 is decorated too.

有关详细信息,请参阅此答案

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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