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

时间:2015-12-14 19:16:30

标签: validation powershell parameters powershell-v4.0

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

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

e.g。

#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属性中,并且仍然可以在脚本中稍后访问该函数; e.g:

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)"

2 个答案:

答案 0 :(得分:1)

到目前为止,根据反馈,似乎在PowerShell v4中目前无法完成我想要的工作。

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

  1. 从文件的参数中删除了ValidateScript验证。
  2. 创建了一个新函数RUN,并将文件的参数完全复制为此函数的参数。只要在它被调用之前它出现在脚本中的哪个位置并不重要(参见步骤4)。
  3. ValidateScript部分添加到此功能的定义中。
  4. 作为脚本的最后一行,调用此新RUN函数传递所有参数(使用@PSBoundParameters以简化/减少维护)。
  5. 将原本放在主文件中的所有其他脚本逻辑(不包括函数定义)移动到process函数的RUN块。
  6. 注意问题:如果您使用默认参数,则需要处理这些参数,因为默认情况下它们不会包含在步骤4中提到的@PSBoundParameters中。有关详细信息,请参阅{{ 3}}。如果将默认逻辑与其他参数信息一起复制到函数定义中,则不会出现此问题。
  7. #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
    

答案 1 :(得分:0)

如果你想保留一个脚本,你可以在脚本中使用所有功能。我的意思是这样的:

    Function fun1 {
       <code>
       }

    Function fun2 {
       <code>
       }

    Function fun3 {
       Param (
          Validatescript({
                  fun1
                  })$Param1
           )
        <code>
        }

    #start executing code
    fun3

这使您可以从单个文件运行脚本,但也可以将您的功能作为脚本验证的一部分。它漂亮吗?不,它有用吗?是。我过去曾多次这样做,并且效果很好。您需要记住的唯一事情是您的脚本使用变量进行范围设定。