使用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
,这是不行的,我还没有找到其他的东西 - 也就是动态参数中的错误抑制。
答案 0 :(得分:0)
我找到了一种方法,但不确定我是否真的推荐使用它,并且它有重复代码的一些缺点。也许有一种方法可以更好地解决这个问题,但如果能够做到这一点,我更多地将其作为一种练习。
代码 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 test
。\ Get-DynamicParamTestCustom.ps1 -Dynamic1 test -Verbpse
。\ Get-DynamicParamTestCustom.ps1 -Dynamic1 a