Function 是否可以在PowerShell函数中自动传递开关参数?
我从中获得了一些灵感,创建了一个函数 到目前为止,它的工作情况与预期一样,但只有在调用函数时提供了选项开关时才起作用。 我想做的就是在不提供开关的情况下输入“getexternalip”。然后,该功能应自动使用-All开关。我也不知道为什么所有的开关都能工作 我试图设置参数$All=$true,但它不起作用,VSCode告诉我无论如何都不推荐使用它 在没有任何参数的情况下调用函数时,是否有方法自动传递-All选项开关? 如果指定了-all开关,有人能解释为什么函数返回所有信息吗 谢谢 这是我的密码:Function 是否可以在PowerShell函数中自动传递开关参数?,function,powershell,parameters,switch-statement,Function,Powershell,Parameters,Switch Statement,我从中获得了一些灵感,创建了一个函数 到目前为止,它的工作情况与预期一样,但只有在调用函数时提供了选项开关时才起作用。 我想做的就是在不提供开关的情况下输入“getexternalip”。然后,该功能应自动使用-All开关。我也不知道为什么所有的开关都能工作 我试图设置参数$All=$true,但它不起作用,VSCode告诉我无论如何都不推荐使用它 在没有任何参数的情况下调用函数时,是否有方法自动传递-All选项开关? 如果指定了-all开关,有人能解释为什么函数返回所有信息吗 谢谢 这是我的密
function Get-ExternalIP {
[CmdletBinding()]
param (
[parameter(Mandatory = $false)][switch]$Ip,
[parameter(Mandatory = $false)][switch]$HostName,
[parameter(Mandatory = $false)][switch]$City,
[parameter(Mandatory = $false)][switch]$Region,
[parameter(Mandatory = $false)][switch]$Country,
[parameter(Mandatory = $false)][switch]$Location,
[parameter(Mandatory = $false)][switch]$Provider,
[parameter(Mandatory = $false)][switch]$PostalCode,
[parameter(Mandatory = $false)][switch]$TimeZone,
[parameter(Mandatory = $false)][switch]$All
)
$IpInfo = Invoke-RestMethod https://ipinfo.io/json
switch ($PSBoundParameters.Values) {
$Ip { $IpInfo.ip }
$HostName { $IpInfo.hostname }
$City { $IpInfo.city }
$Region { $IpInfo.region }
$Country { $IpInfo.country }
$Location { $IpInfo.loc }
$Provider { $IpInfo.org }
$PostalCode { $IpInfo.postal }
$TimeZone { $IpInfo.timezone }
Default { $IpInfo }
}
}
Get-ExternalIP
如果您打印出$psboundparameters.values是什么,当您不使用“-all”时,您将看到它是空的,否则它有一个值$true 您可以使用参数集默认设置为
All
选项:
[CmdletBinding(DefaultParameterSetName='Everything')]
param(
[Parameter(ParameterSetName='Something')][switch]$Ip,
[Parameter(ParameterSetName='Something')][switch]$HostName,
[Parameter(ParameterSetName='Something')][switch]$City,
[Parameter(ParameterSetName='Something')][switch]$Region,
[Parameter(ParameterSetName='Something')][switch]$Country,
[Parameter(ParameterSetName='Something')][switch]$Location,
[Parameter(ParameterSetName='Something')][switch]$Provider,
[Parameter(ParameterSetName='Something')][switch]$PostalCode,
[Parameter(ParameterSetName='Something')][switch]$TimeZone,
[Parameter(ParameterSetName='Everything')][switch]$All
)
# set up dictionary to hold the switch-name-to-ipinfo-names
$Options = [Ordered]@{
'Ip' = 'ip'
'HostName' = 'hostname'
'City' = 'city'
'Region' = 'region'
'Country' = 'country'
'Location' = 'loc'
'Provider' = 'org'
'PostalCode' = 'postal'
'TimeZone' = 'timezone'
}
$IpInfo = Invoke-RestMethod https://ipinfo.io/json
# Select all options
$selected = $Options.Keys
if($PSCmdlet.ParameterSetName -ne 'Everything'){
# 1 or more switches were passed, select only those options
$selected = $selected.Where({$PSBoundParameters[$_]})
}
# Create a new object with the selected options as properties
$properties = [ordered]@{}
foreach($prop in $selected){
$properties[$prop] = $IpInfo.($Options[$prop])
}
# return the new object
return [pscustomobject]$properties
通过使用参数集名称来确定是否输出所有内容(然后返回),无论用户是传递
-All
,还是根本不传递开关,行为都是相同的。我将使用$PSBoundParameters。键作为开关正确命名,以匹配返回的信息:
function Get-ExternalIP {
[CmdletBinding()]
param (
[parameter(Mandatory=$false)][switch]$Ip,
[parameter(Mandatory=$false)][switch]$HostName,
[parameter(Mandatory=$false)][switch]$City,
[parameter(Mandatory=$false)][switch]$Region,
[parameter(Mandatory=$false)][switch]$Country,
[parameter(Mandatory=$false)][switch]$Location,
[parameter(Mandatory=$false)][switch]$Provider,
[parameter(Mandatory=$false)][switch]$PostalCode,
[parameter(Mandatory=$false)][switch]$TimeZone,
[parameter(Mandatory=$false)][switch]$All
)
$IpInfo = Invoke-RestMethod https://ipinfo.io/json
if ($All) { return $IpInfo }
# exclude Common Parameters
$commonParams = 'Debug','ErrorAction','ErrorVariable','InformationAction','InformationVariable','OutVariable',
'OutBuffer','PipelineVariable','Verbose','WarningAction','WarningVariable','WhatIf','Confirm'
$items = (@($PSBoundParameters.Keys) | Where-Object { $commonParams -notcontains $_ }) -replace
'Location', 'loc' -replace 'Provider', 'org' -replace 'PostalCode', 'postal'
$IpInfo | Select-Object $items
}
如前所述,有一种比上面代码中显示的更好的方法来检索使用过的开关
与其过滤掉已知的公共参数,不如根据$IpInfo对象中返回的属性检查$PSBoundParameter键
$items = ($PSBoundParameters.Keys -replace 'Location', 'loc' -replace 'Provider', 'org' -replace 'PostalCode', 'postal').Where({ $_ -in $IpInfo.psobject.Properties.Name })
并提供优雅的解决方案;让我补充一下你的具体问题:
如果指定了-all
开关,有人能解释为什么函数返回所有信息吗
您的switch
语句有一个Default
分支,如果其他分支的条件都不满足,就会调用该分支由于-All
开关值没有分支,因此如果
-指定了所有
相反,如果不传递任何参数,则永远不会输入switch
语句,因为对于集合值输入,switch
语句隐式循环该集合的元素。
如果没有传递参数,$PSBoundParameters.Values
是一个空集合,因此没有要枚举的内容
Mathias答案中的参数集方法是这个问题的最简单解决方案,它的另一个优点是使-All
开关和特定属性名称开关相互排斥。做得很好;需要注意的一点是:如果传递了一个或多个开关,问题中的函数只输出值-它们没有包装在自定义对象中,这与函数所做的不同。这是不够的,因为公共参数也反映在$PSBoundParameters
中,因此,检查$PSBoundParameters.Count-eq 0
会给你一个错误的否定,如果说,-Verbose
是唯一通过的开关。我没有投反对票,但你应该写一个答案的大致描述,并详细说明。@WasifHasan投反对票的是我。虽然答案显然很容易解释,但它的主要问题是我指出的概念缺陷。@mklement0哦,是的,这是一个更好的方法。我甚至没想到。关于输出。OP想要什么还不是很清楚:一个值数组还是一个具有属性的对象。在他/她的代码中,返回值是一个值数组,除非使用默认选项。那么它就是一个物体。。就个人而言,我总是希望得到对象的结果。我同意包装器可能是更好的方法(除非典型的用例是只使用一个开关),但我认为当解决方案涉及到问题中代码的行为变化时,在答案中总是值得指出,甚至-也许特别是-如果这是一个更好的改变。P.S.:我刚刚注意到您的解决方案依赖于选择对象
的一个令人惊讶的、未记录的行为:使用一个空的属性数组来选择,它传递输入对象(如果没有传递与-All
相反的开关,则会发生这种情况);e、 例如,(gi/| select@()).GetType().FullName
感谢您抽出时间更改函数。就像我想的那样。我也试过Mathias R.Jessen发布的一个,它也对我有用。我将研究这两种变体,并决定哪一种最适合我的目的。谢谢。@mozzie谢谢你的反馈,谢谢你发布这个有趣的问题。谢谢你的精彩解释。现在一切都有意义了。