通过ValidateScript属性

时间:2017-02-28 20:28:50

标签: validation powershell default-value

我有以下PowerShell代码将用户输入验证为路径,如果用户没有输入任何内容,我试图为它们分配默认值。但是,当我运行它时,$filePath变量不会被赋值任何值。

无论如何,我可以更改此设置,以便在验证过程中为其分配默认值吗?

以下代码:

function validatePath {
  Param
  (
      [ValidateScript({
        If ($_ -eq "" -or $_ -eq [String]::Empty) {
            $_ = "C:\Install"
            $True
        }
        ElseIf ($_ -match "^([a-z]:\\(?:[-\\w\\.\\d])*)") {
            $True
        } 
        Else {
            Write-Host "Please enter a valid path,$_ is not a valid path."
            Write-debug $_.Exception
        }
      })]
      [string]$filePath = "C:\Install"
  )
  Process
  {
      Write-Host "The path is "$filePath
  }
}

validatePath -filePath $args[0] 

2 个答案:

答案 0 :(得分:2)

我认为您可以删除验证脚本,而是在Begin块中执行此操作:

Begin{
    If ($filepath -eq "") {
        $filepath = "C:\Install"
    }
    ElseIf ($filepath -notmatch "^([a-z]:\\(?:[-\\w\\.\\d])*)") {
        Write-Error "Please enter a valid path,$filepath is not a valid path."
    }
}
Process{

答案 1 :(得分:0)

此答案首先讨论正确使用ValidateScript属性
之后将讨论无关的默认值问题,然后是参数splatting 的可选部分。

Matt在他对这个问题的评论中提供了很好的指示:

  • ValidateScript脚本块应输出仅布尔
    该布尔告诉PowerShell参数值是否被认为是有效的, it 会相应地采取行动。

    • 值得注意的是,脚本块意味着:

      • 直接分配给参数变量
      • 包含任何其他输出语句,例如Write-Host(您不应该使用它来报告错误)。
    • 如果脚本块输出(有效)$False ,脚本块会抛出异常 PowerShell:

      • 中止函数的调用
      • 报告 非终止错误
    • 如果脚本块输出$False,则会得到一般错误消息,其中包含脚本块的文字内容 (不包括封闭内容) {}) - 对于最终用户而言技术性太强

      • PowerShell 核心 ValidateScriptValidatePattern引入了 optional ErrorMessage = "..." field 属性;例如,
        [ValidateScript({ $_ % 2 -eq 0 }, ErrorMessage = "{0} is not an even number.")]

      • Windows Powershell 中,建议抛出异常,并提供用户友好的错误消息**,其中case PowerShell在其错误消息中包含异常文本。

  • 参数的默认值是按设计而不是检查验证脚本 - 您作为函数创建者承担责任默认为有效的值 - 请参阅this blog post

应用于您的示例:

请注意,我使用'^[a-z]:\\[-\w\d\\]*$'作为正则表达式,因为这是我认为您实际上要使用的内容。

function validatePath {
  Param
  (
    [ValidateScript({
      if ($_ -match '^[a-z]:\\[-.\w\d\\]*$') { return $True }
      Throw "'$_' is not a valid local path." 
    })]
    [string] $filePath = "C:\Install"
  )
  Process
  {
    "The path is: $filePath"
  }
}

现在所有3个调用方案都应按预期工作:

> validatePath                          # use default value
The path is: C:\Install

> validatePath -filePath C:\MyInstall   # valid path
The path is: C:\MyInstall

> validatePath -filePath NotAFullPath   # invalid path -> error with custom message
validatePath : Cannot validate argument on parameter 'filePath'.
'NotAFullPath' is not a valid local path.
At line:1 char:24
+ validatePath -filePath NotAFullPath   # invalid path
+                        ~~~~~~~~~~~~
    + CategoryInfo          : InvalidData: (:) [validatePath], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,validatePath

为什么默认参数值没有生效:

此问题与验证无关,并且源于您在$args[0]调用中传递validatePath这一事实:

  • 如果脚本本身没有收到任何参数, $args[0] $null,但仍然作为显式值传递< / em> ,因此它通过强制绑定到空字符串来绑定参数$filePath

  • 由于传递了显式参数值,因此未使用默认值$filePath最终包含空字符串。

由于这是参数绑定在PowerShell中的工作方式,我建议尝试在函数中解决,而是修复问题关于调用

if ([string] $args[0]) { # only true if $args[0] is neither $null nor the empty string
  validatePath -filePath $args[0]
} else {
  validatePath
}

请注意,通常最好明确声明您的参数,而不是使用$args

可选阅读:使用 splatting (有选择地)将参数传递给另一个命令:

作为在上述条件中使用两个单独调用的替代方法,请考虑使用parameter splatting,它允许您使用前缀为@的单个集合变量传递多个参数:

  • 表示多个位置参数的数组

  • 更常见,更强大,散列表代表多个命名的参数。

这允许您提前动态构建参数集合,并将集合作为一个整体传递给目标命令的单个调用。

在您的情况下,快速而肮脏的解决方法是使用使用所有参数进行展开,即通过$args(注意{{1} } sigil而不是@):

$

这将简单地传递所有参数,如果有任何,将脚本传递给validatePath @args ,就好像它们是单独指定的那样;如果没有参数传递给脚本,则不会传递任何内容,并且validatePath 中的-filePath默认值生效。

参数个人splatting 是另一种选择,是一种将选择参数传递给另一个命令的强大技术

validatePath

如果使用显式参数声明脚本(使用自己的# Define a hashtable to hold the parameters, if any, to pass through # to validatePath() via splatting. $htPassthruParams = @{} # If the first script argument is neither $null nor the empty string, # add a hashtable entry for it that will bind to the -filePath parameter. if ([string] $args[0]) { $htPassthruParams.Add('filePath', $args[0]) } # Pass the hashtable with `@`, the splatting operator, to validatePath() validatePath @htPassthruParams 块),可以通过使用自动param(...)字典来推广该方法确定参数是否绑定 ,这样就无需检查特定值:

$PSBoundParameters