Function 使用Powershell时';s动态参数我可以抑制错误吗?

Function 使用Powershell时';s动态参数我可以抑制错误吗?,function,powershell,parameters,cmdlet,Function,Powershell,Parameters,Cmdlet,使用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,vim

使用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
,但这是不可能的,我在这方面找不到太多其他的东西,也就是说,动态参数中的错误抑制。

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

代码Get-DynamicParamTestCustom.ps1


[CmdletBinding()]
param(
)
动态存储器{
新函数ValidationDynamicParam{
[CmdletBinding()]
[OutputType('System.Management.Automation.RuntimeDefinedParameter')]
param(
[参数(强制性)]
[ValidateNotNullOrEmpty()]
[字符串]$Name,
[ValidateNotNullOrEmpty()]
[参数(强制性)]
[阵列]$validateStoptions,
[参数()]
[开关]$Mandatory=$false,
[参数()]
[string]$ParameterSetName='\uu所有参数集',
[参数()]
[开关]$ValueFromPipeline=$false,
[参数()]
[开关]$ValueFromPipelineByPropertyName=$false
)
$AttribColl=新对象System.Collections.ObjectModel.Collection[System.Attribute]
$ParamAttrib=新对象System.Management.Automation.ParameterAttribute
$paramatrib.Mandatory=$Mandatory.IsPresent
$ParamAttrib.ParameterSetName=$ParameterSetName
$ParamAttrib.ValueFromPipeline=$ValueFromPipeline.IsPresent
$ParamAttrib.ValueFromPipelineByPropertyName=$ValueFromPipelineByPropertyName.IsPresent
$AttribColl.Add($paramatrib)
$AttribColl.Add((新对象系统、管理、自动化、ValidateStatAttribute($Param.validateStoptions)))
$RuntimeParam=新对象System.Management.Automation.RuntimeDefinedParameter($Param.Name,[string],$AttribColl)
$RuntimeParam
}
函数获取有效值
{
#获取有效值的列表
$validValue=@()
$validValues+=“a”
$validValues+=“b”
$validValues+=“c”
$validValues+=$global:dynamic1Value
$validvalue
}
#强制将当前传递的值放入我们的列表中,然后我们检测
#自定义消息的步骤
#这个问题的核心是从调用堆栈中获取参数
#并把它藏起来(一个黑客,但这是一个解决方案)。
$line=(Get PSCallStack | Select-First 1 | Select*).InvocationInfo.line
#为命令行arg解析此参数
#TODO:让它更健壮
$null=$line-match“-Dynamic1(.*)(\s+|$)”
$global:dynamic1Value=$Matches[1]
$ParamOptions=@(
@{
'Name'=“Dynamic1';
“必需”=$true;
“ValidateStoptions”=获取有效值
}
)
$RuntimeParamDic=新对象System.Management.Automation.RuntimeDefinedParameterDictionary
foreach($ParamOptions中的Param)
{
$RuntimeParam=newvalidationdynamicparam@Param
$RuntimeParamDic.Add($Param.Name,$RuntimeParam)
}
返回$RuntimeParamDic
}
开始
{
$PsBoundParameters.GetEnumerator()| foreach{New Variable-Name$\.Key-Value$\.Value-ea'SilentlyContinue'}
} 
过程
{
#不确定该如何编写,因为函数需要在内部
#DynamicParam{}块的用法,这里是“进程”用法。
函数获取有效值real
{
#获取有效值的列表
$validValue=@()
$validValues+=“a”
$validValues+=“b”
$validValues+=“c”
$validvalue
}
函数foo
{
}
写入输出“全局:dynamic1Value为:“$($global:dynamic1Value)”
写入输出“Dynamic1为:“$($Dynamic1)”
$realValues=获取有效值real
如果($global:dynamic1Value-notin$realValues)
{
写入错误“嘿,$global:dynamic1Value”是不允许的
}
其他的
{
写入输出“Dynamic1是:“$($Dynamic1)”并且很酷。”
}
}
结束{}
测试用例

.\Get-DynamicParamTestCustom.ps1-Dynamic1 t

.\Get-DynamicParamTestCustom.ps1-Dynamic1测试

.\Get-DynamicParamTestCustom.ps1-Dynamic1测试-Verbpse


.\Get-DynamicParamTestCustom.ps1-Dynamic1 a

没有提供足够的代码来理解问题,也没有提供足够的输入工作或失败。我认为没有必要完整的代码-问题不是导致错误的原因-触发错误的是有效参数集之外的任何东西。但我已经包含了所有DynamicParameter代码,以防它确实有用。我还添加了错误。
<#
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 {}