2015-12-14 44 views
3

是否可以使用自定義函數和ValidateScript,其中函數稍後在腳本中定義。 此外,調用此函數時是否可以引用其他參數(即假設沒有循環依賴)?將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)" 
+2

我確定這已經發生在你身上了,但爲什麼不只是讓'Validate-Country'早些時候在另一個「主」腳本中找到?儘管爲了保持這一點,我完全理解你的請求的必要性。 – Matt

+0

謝謝@Matt;是的,這是一個好的解決方案;我只是希望將腳本保存到一個單獨的文件中,以便使用較少的技術能力(即不必提供將腳本放在相同路徑中的說明)輕鬆共享和使用腳本。 – JohnLBevan

+2

我明白。不要分心你的實際問題,但你可以有一個主腳本調用你的遠程腳本或在本地複製它們,但這確實增加了不必要的複雜程度。 – Matt

回答

0

從反饋到目前爲止,似乎在PowerShell v4中目前不可能實現我想要的功能。

我最終使用了一個簡單的解決方法來實現這個目標。它增加了一點開銷,但不是太痛苦。

  1. 從文件參數中刪除ValidateScript驗證。
  2. 創建一個新函數RUN,並精確複製文件的參數作爲該函數的參數。在函數出現的腳本中,只要它在被調用之前就沒有關係(參見步驟4)。
  3. 在此函數的定義中添加了ValidateScript段。
  4. 作爲腳本的最後一行,這個腳本叫做RUN函數傳遞所有參數(爲了簡化/減少維護使用@PSBoundParameters)。
  5. 將可能已放置在主文件中的所有其他腳本邏輯(不包括函數定義)移至RUN函數的process塊中。
  6. 當心疑難雜症:如果使用默認參數,您需要處理這些因爲默認情況下,他們將不會被包含在第4步欲瞭解更多信息提到@PSBoundParameters,看到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 
0

如果你想保持一個腳本,你都可以在一個腳本中的功能。我的意思是這樣的:

Function fun1 { 
     <code> 
     } 

    Function fun2 { 
     <code> 
     } 

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

    #start executing code 
    fun3 

這將使你從一個單一的文件運行腳本,也有你的功能除了腳本的驗證。這很漂亮嗎?不行嗎?是。過去我已經做了好幾次,並且工作得很好。您需要牢記的唯一事情就是您的腳本使用變量進行範圍設定。

+2

在OP的腳本開始處使用'param'關鍵字時,無法執行此操作。 – Matt

+0

正確,它需要修改代碼,但是它打破了OP想要什麼?我剛剛看到,將它放在單個文件中對於使用腳本調用腳本比較容易。完全取決於OP,只是提供不同的觀點。 –

+0

謝謝@POSHGeek;根據Matt的評論,我理想的是在文件本身的參數解決方案之後(儘管我沒有在問題中明確提到這一點)。對於函數參數,函數的順序無關緊要。 – JohnLBevan

相關問題