validation - 将 ValidateScript 与稍后在脚本中定义的自定义函数一起使用

标签 validation powershell parameters powershell-4.0

是否可以通过 ValidateScript 使用自定义函数? ,该函数稍后在脚本中定义。
此外,在调用此函数时是否可以引用其他参数(即假设没有循环依赖)?

我理解为什么这可能是不可能的,但由于它很有用,我希望 MS 实现一些特殊规则,以允许在验证参数发生之前读取脚本并提供函数定义。

例如

#Run-DemoScript.ps1
param (
    [Parameter(Mandatory = $true)]
    [string]$DbInstance 
    ,
    [Parameter(Mandatory = $true)]
    [string]$DbCatalog 
    ,
    [Parameter(Mandatory = $true)]

    #
    # Is this possible; i.e.
    # - Validate-Country is not defined until later in this script
    # - DbInstance and DbCatalog parameters are defined alongside Country
    [ValidateScript({Validate-Country -Country $_ -DbInstance $DbInstance -DbCatalog $DbCatalog})] 
    #


    [string]$Country
)

#returns $true if the country is in the database's country table; otherwise false
function Validate-Country {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$DbInstance
        ,
        [Parameter(Mandatory = $true)]
        [string]$DbCatalog
        ,
        [Parameter(Mandatory = $true)]
        [string]$Country
    )
    process {
        $Country = $Country -replace "'","''"
        ((Execute-SQLQuery -DbInstance $DbInstance -DbCatalog $DbCatalog -Query "select top 1 1 x from dbo.Country where Name = '$Country'") | Measure-Object | Select -ExpandProperty Count) -gt 0
    }
}

function Execute-SQLQuery {
    #...
}

"Script ran with Country $Country"

更新

看来您可以将整个函数定义移到 ValidateScript 中属性,并且仍然可以稍后在脚本中访问该函数;例如:
param(
    [Parameter(Mandatory = $true)]
    [ValidateScript({
        function IsValid ($test) {
            $test -eq 'test'
        }
        IsValid $_
    })]
    [string]$x
)


"Output: $x"
"Is Valid? $(IsValid $x)"

然而这相当痛苦。它也不允许引用兄弟参数(例如下面)
param(
    [Parameter(Mandatory = $true)]
    [string]$y
    ,
    [Parameter(Mandatory = $true)]
    [ValidateScript({
        function IsValid ($a,$b) {
            $a -eq $b
        }
        IsValid $_, $y
    })]
    [string]$x 
)


"X: $x"
"Y: $Y"
"Is Valid? $(IsValid $x $y)"

最佳答案

从目前的反馈来看,目前在 PowerShell v4 中似乎无法完全按照我的意愿行事。

我最终使用了一个简单的解决方法来实现这一目标。它增加了一点开销,但并不太痛苦。

  • 删除了 ValidateScript从文件的参数验证。
  • 创建了一个新函数,RUN , 并将文件的参数完全复制为该函数的参数。该函数出现在脚本中的哪个位置并不重要,只要它在被调用之前即可(参见步骤 4)。
  • 添加了 ValidateScript部分到这个函数的定义。
  • 正如脚本的最后一行调用了这个新的 RUN传递所有参数的函数(使用 @PSBoundParameters 为简单起见/减少维护)。
  • 将所有其他可以放在主文件中的脚本逻辑(不包括函数定义)移动到 process RUN块功能。
  • 当心陷阱:如果您使用默认参数,您将需要处理它们,因为默认情况下它们不会包含在 @PSBoundParameters 中。在步骤 4 中提到。有关更多信息,请参阅 Parameters with default value not in PsBoundParameters? .如果您将默认逻辑与其他参数信息一起复制到函数定义中,这不是问题。

  • .
    #Run-DemoScript.ps1
    param (
        [Parameter(Mandatory = $true)]
        [string]$DbInstance 
        ,
        [Parameter(Mandatory = $true)]
        [string]$DbCatalog 
        ,
        [Parameter(Mandatory = $true)]
        #[ValidateScript({Validate-Country -Country $_ -DbInstance $DbInstance -DbCatalog $DbCatalog})] 
        [string]$Country
    )
    
    #move all logic from main script into here
    #copy parameters from file's param definition, only add in validation
    function RUN {
        param (
            [Parameter(Mandatory = $true)]
            [string]$DbInstance 
            ,
            [Parameter(Mandatory = $true)]
            [string]$DbCatalog 
            ,
            [Parameter(Mandatory = $true)]
            [ValidateScript({Validate-Country -Country $_ -DbInstance $DbInstance -DbCatalog $DbCatalog})] 
            [string]$Country
        )
        process {
            "Script ran with Country $Country"
        }
    }
    
    #returns $true if the country is in the database's country table; otherwise false
    function Validate-Country {
        [CmdletBinding()]
        param (
            [Parameter(Mandatory = $true)]
            [string]$DbInstance
            ,
            [Parameter(Mandatory = $true)]
            [string]$DbCatalog
            ,
            [Parameter(Mandatory = $true)]
            [string]$Country
        )
        process {
            $Country = $Country -replace "'","''"
            ((Execute-SQLQuery -DbInstance $DbInstance -DbCatalog $DbCatalog -Query "select top 1 1 x from dbo.Country where Name = '$Country'") | Measure-Object | Select -ExpandProperty Count) -gt 0
        }
    }
    
    function Execute-SQLQuery {
        #...
    }
    
    RUN @PSBoundParameters #remember to handle default parameters: https://stackoverflow.com/questions/2808973/parameters-with-default-value-not-in-psboundparameters
    

    关于validation - 将 ValidateScript 与稍后在脚本中定义的自定义函数一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34274871/

    相关文章:

    validation - Vue js vee 使用自定义组件验证密码确认

    php - 创建自定义 codeigniter 验证规则

    jquery - PreventDefault 不适用于 Zurb 验证(遵守)

    windows - 使用 PowerShell 加载文件文件?

    amazon-web-services - AWS-CDK 和 Powershell Lambda

    c++ - 使 GUI 从 Windows 命令行运行

    javascript - 正则表达式(替换所有非数字字符并强制执行 2 个小数位数字)

    powershell - 在Powershell Invoke-Expression中转义飞溅的变量

    perl - 从 Mojolicious Controller 内省(introspection)占位符变量的名称

    c++ - 对象作为参数传递,就像传递构造函数值一样