是否可以在PowerShell函数中自动传递开关参数



我从这里获得了一些灵感,创建了一个函数。

到目前为止,它按预期工作,但只有在调用函数时提供了选项开关时才能工作。我想做的只是能够在不提供交换机的情况下键入"GetExternalIP"。然后,该功能应自动使用-All开关。我也不知道为什么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.Keys,因为您的交换机已正确命名以匹配返回的信息:

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
}

正如mklement0所评论的,有一种比上面代码中显示的更好的方法来检索使用过的开关。

与其过滤掉已知的Common Parameters,不如根据$IpInfo对象中返回的属性检查$PSBoundParameter键。

$items = ($PSBoundParameters.Keys -replace 'Location', 'loc' -replace 'Provider', 'org' -replace 'PostalCode', 'postal').Where({ $_ -in $IpInfo.psobject.Properties.Name })

您可以使用参数集默认为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还是根本不通过开关,行为都是相同的。

Mathias R.Jessen的答案和Theo的答案提供了优雅的解决方案;让我用你的具体问题的答案来补充它们:

如果指定了-All开关,有人能解释为什么函数会返回所有信息吗?

您的switch语句有一个Default分支,如果其他分支的条件都不满足,就会调用该分支由于-All开关值没有分支,因此如果指定了
-All
,则Default处理程序将启动

相反,如果不传递任何参数,则永远不会输入switch语句,因为对于集合值输入,switch语句隐式地循环该集合的元素。在不传递任何参数的情况下,$PSBoundParameters.Values是一个空集合,因此没有什么可枚举的。

Mathias的答案中的参数集方法是解决这个问题的最简单的方法,它还具有使-All开关和特定属性名称开关互斥的优点。

如果您打印出$psboundparameters.values是什么,当您不使用"-all"时,您会看到它是空的,否则它只有一个值$true。

最新更新