Function 使用Powershell时';s动态参数我可以抑制错误吗?
使用Powershell的动态参数时,我可以抑制错误吗 具体而言,错误是: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
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 {}