【问题标题】:When using Powershell's Dynamic parameters can I suppress Errors?使用 Powershell 的动态参数时,我可以抑制错误吗?
【发布时间】:2017-01-31 00:50:50
【问题描述】:

当使用 Powershell 的动态参数时,我可以抑制错误吗?

具体的错误是:

 f foo
Search-FrequentDirectory : Cannot validate argument on parameter 'dirSearch'. The argument "foo" does not belong to the set
"bin,omega,ehiller,psmodules,deploy,gh.riotgames.com,build-go,vim74,cmder,dzr,vimfiles,src,openssh,git" specified by the ValidateSet attribute. Supply an argument
that is in the set and then try the command again.
At line:1 char:3
+ f foo
+   ~~~
    + CategoryInfo          : InvalidData: (:) [Search-FrequentDirectory], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Search-FrequentDirectory

动态参数为:

DynamicParam {
$dirSearch = new-object -Type System.Collections.ObjectModel.Collection[System.Attribute]

# [parameter(mandatory=...,
#     ...
# )]
$dirSearchParamAttribute = new-object System.Management.Automation.ParameterAttribute
$dirSearchParamAttribute.Mandatory = $true
$dirSearchParamAttribute.Position = 1
$dirSearchParamAttribute.HelpMessage = "Enter one or more module names, separated by commas"
$dirSearch.Add($dirSearchParamAttribute)    

# [ValidateSet[(...)]
$dirPossibles = @()

$historyFile = (Get-PSReadlineOption).HistorySavePath
# directory Seperating character for the os; \ (escaped to \\) for windows (as C:\Users\); / for linux (as in /var/www/);
# a catch all would be \\\/  ; but this invalidates the whitespace escape character that may be used mid-drectory.
$dirSep = "\\"
# Group[1] = Directory , Group[length-1] = lowest folder
$regex = "^[[:blank:]]*cd ([a-zA-Z\~:]+([$dirSep][^$dirSep]+)*[$dirSep]([^$dirSep]+)[$dirSep]?)$"
# original: ^[[:blank:]]*cd [a-zA-Z\~:\\\/]+([^\\\/]+[\\\/]?)*[\\\/]([^\\\/]+)[\/\\]?$
# test for historyFile existance
if( -not (Test-Path $historyFile )){ 
    Write-Warning "File $historyFile not found, unable to load command history. Exiting."; 
    return 1; 
}
$historyLines = Get-Content $historyFile
# create a hash table, format of ;;; [directory path] = [lowest directory]
$searchHistory = @{}
# create a hash table for the count (number of times the command has been run)
$searchCount = @{}
ForEach ( $line in $historyLines ) {
    if( $line -match $regex ){
        try {
            # since the matches index can change, and a hashtable.count is not a valid way to find the index...
            # I need this to figure out the highest integer index
            $lowestDirectory = $matches[($matches.keys | sort -Descending | Select-Object -First 1)]
            $fullPath = $matches[1]
            if($searchHistory.keys -notcontains $matches[1]){
                $searchHistory.Add($matches[1],$lowestDirectory)
            }
            $searchCount[$fullPath] = 1
        } catch {
            $searchCount[$fullPath]++
        }
    }
}
# this helps with hashtables
# https://www.simple-talk.com/sysadmin/powershell/powershell-one-liners-collections-hashtables-arrays-and-strings/

$dirPossibles = ( $searchHistory.values | Select -Unique )

$modulesValidated_SetAttribute = New-Object -type System.Management.Automation.ValidateSetAttribute($dirPossibles)
$dirSearch.Add($modulesValidated_SetAttribute)

# Remaining boilerplate
$dirSearchDefinition = new-object -Type System.Management.Automation.RuntimeDefinedParameter("dirSearch", [String[]], $dirSearch)

$paramDictionary = new-object -Type System.Management.Automation.RuntimeDefinedParameterDictionary
$paramDictionary.Add("dirSearch", $dirSearchDefinition)

return $paramDictionary
}

该功能有效,当我在场景中时,一切都很好。当我弄错或其他什么时,我会得到一个相当不愉快的外观(非用户友好的错误)——我想设置它的样式。

有没有办法做到这一点?抑制错误?我尝试了try / catch,但没有成功,我还没有找到更多关于此的其他内容 - 即动态参数中的错误抑制。

【问题讨论】:

  • 没有提供足够的代码来理解问题,也没有足够的输入工作或失败。
  • 我不认为整个代码是必要的——这不是导致错误的原因——它是有效参数集之外的任何东西 触发它。但是我已经包含了所有的 DynamicParameter 代码,以防万一它有帮助。我还添加了错误。

标签: function powershell parameters powershell-cmdlet


【解决方案1】:

我找到了一种方法,但不确定我是否真的推荐使用它,而且它有一些重复代码的缺点。也许有办法更好地解决这个问题,但我这样做更多是为了练习是否可以做到。

代码 Get-DynamicParamTestCustom.ps1

<#
Reference: http://blog.enowsoftware.com/solutions-engine/bid/185867/Powershell-Upping-your-Parameter-Validation-Game-with-Dynamic-Parameters-Part-II
#>

[CmdletBinding()]
param (
)

DynamicParam {
    function New-ValidationDynamicParam {
        [CmdletBinding()]
        [OutputType('System.Management.Automation.RuntimeDefinedParameter')]
        param (
            [Parameter(Mandatory)]
            [ValidateNotNullOrEmpty()]
            [string]$Name,

            [ValidateNotNullOrEmpty()]
            [Parameter(Mandatory)]
            [array]$ValidateSetOptions,

            [Parameter()]
            [switch]$Mandatory = $false,

            [Parameter()]
            [string]$ParameterSetName = '__AllParameterSets',

            [Parameter()]
            [switch]$ValueFromPipeline = $false,

            [Parameter()]
            [switch]$ValueFromPipelineByPropertyName = $false
        )

        $AttribColl = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
        $ParamAttrib = New-Object System.Management.Automation.ParameterAttribute
        $ParamAttrib.Mandatory = $Mandatory.IsPresent
        $ParamAttrib.ParameterSetName = $ParameterSetName
        $ParamAttrib.ValueFromPipeline = $ValueFromPipeline.IsPresent
        $ParamAttrib.ValueFromPipelineByPropertyName = $ValueFromPipelineByPropertyName.IsPresent
        $AttribColl.Add($ParamAttrib)
        $AttribColl.Add((New-Object System.Management.Automation.ValidateSetAttribute($Param.ValidateSetOptions)))
        $RuntimeParam = New-Object System.Management.Automation.RuntimeDefinedParameter($Param.Name, [string], $AttribColl)

        $RuntimeParam
    }

    function Get-ValidValues
    {
        # get list of valid values
        $validValues = @()
        $validValues += 'a'
        $validValues += 'b'
        $validValues += 'c'

        $validValues += $global:dynamic1Value


        $validValues
    }

    # coerce the current passed value into our list, and we detect later
    # to customize message
    # the heart of this problem is getting the param from the Call Stack
    # and stashing it away (a hack, but it IS a solution).
    $line = (Get-PSCallStack | Select -First 1 | Select *).InvocationInfo.Line
    # parse this for the command line arg
    # TODO: make this more robust
    $null = $line -match "-Dynamic1 (.*?)(\s+|$)"
    $global:dynamic1Value = $Matches[1]

    $ParamOptions = @(
        @{
        'Name' = 'Dynamic1';
        'Mandatory' = $true;
        'ValidateSetOptions' =  Get-ValidValues
        }
    )

    $RuntimeParamDic = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
    foreach ($Param in $ParamOptions) 
    {
        $RuntimeParam = New-ValidationDynamicParam @Param
        $RuntimeParamDic.Add($Param.Name, $RuntimeParam)
    }

    return $RuntimeParamDic
}


begin 
{
    $PsBoundParameters.GetEnumerator() | foreach { New-Variable -Name $_.Key -Value $_.Value -ea 'SilentlyContinue'}
} 

process 
{
    # not sure how else to write this because the function needs to be inside
    # DynamicParam{} block for its usage, and here for 'process' usage.
    function Get-ValidValuesReal
    {
        # get list of valid values
        $validValues = @()
        $validValues += 'a'
        $validValues += 'b'
        $validValues += 'c'

        $validValues
    }

    function foo
    {
    }

    Write-Output "global:dynamic1Value is: '$($global:dynamic1Value)'."
    Write-Output "Dynamic1 is: '$($Dynamic1)'."
    $realValues = Get-ValidValuesReal
    if ($global:dynamic1Value -notin $realValues)
    {
        Write-Error "Hey, '$global:dynamic1Value' is not allowed."
    }
    else
    {
        Write-Output "Dynamic1 is: '$($Dynamic1)' and is cool."
    }

}

end {}

测试用例

.\Get-DynamicParamTestCustom.ps1 -Dynamic1 t

.\Get-DynamicParamTestCustom.ps1 -Dynamic1 测试

.\Get-DynamicParamTestCustom.ps1 -Dynamic1 test -Verbpse

.\Get-DynamicParamTestCustom.ps1 -Dynamic1 a

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-07-31
    • 1970-01-01
    • 2020-12-20
    • 1970-01-01
    • 1970-01-01
    • 2013-01-08
    • 1970-01-01
    相关资源
    最近更新 更多