简体   繁体   English

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

[英]Is it possible to automatically pass along a switch parameter in a PowerShell Function?

I created a function with some inspiration from here .我从这里获得了一些灵感,创建了一个函数。

It's working as expected so far but only when an Option Switch is provided when calling the function.到目前为止,它按预期工作,但只有在调用函数时提供了选项开关。 What I want to do is just be able type "Get-ExternalIP" without providing a switch.我想要做的只是能够在不提供开关的情况下输入“Get-ExternalIP”。 The function should then automatically use the -All switch.然后该函数应自动使用 -All 开关。 Also I'm not sure why the -All switch even works...另外我不确定为什么 -All 开关甚至可以工作......

I've tried to set the Parameter $All = $true it's not working and VSCode tells me that it's not recommended anyways.我试图设置参数 $All = $true 它不起作用并且 VSCode 告诉我无论如何都不推荐它。

Is there a way to automatically pass along the -All Option Switch when the function is called without any parameters?有没有办法在不带任何参数的情况下调用函数时自动传递 -All 选项开关? Would somebody be able to explain why the function returns all info if the -All switch is specified?如果指定了 -All 开关,有人能解释为什么该函数返回所有信息吗?

Thanks!谢谢!

Here's my code:这是我的代码:

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

You could use parameter sets to default to the All option:您可以使用参数集默认为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

By using the parameter set name to determine whether to output everything (and then return), the behavior is the same regardless of whether the user passes -All , or no switches at all.通过使用参数集名称来确定是否输出所有内容(然后返回),无论用户是否通过-All或根本没有开关,行为都是相同的。

I would use the $PSBoundParameters.Keys as your switches are properly named to match the returned info:我会使用$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
}

As mklement0 commented, there is a much better way of retrieving the used switches than shown in the above code.正如mklement0评论的那样,有一种比上面代码中显示的更好的检索使用的开关的方法。

Instead of filtering out the known Common Parameters, it makes more sense to check the $PSBoundParameter keys against the properties returned in the $IpInfo object.与其过滤掉已知的通用参数,不如根据 $IpInfo 对象中返回的属性检查 $PSBoundParameter 键更有意义。

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

Mathias R. Jessen's answer and Theo's answer provide elegant solutions; Mathias R. Jessen 的回答Theo 的回答提供了优雅的解决方案; let me complement them with an answer to your specific question:让我用你的具体问题的答案来补充它们:

Would somebody be able to explain why the function returns all info if the -All switch is specified?如果指定了-All开关,有人能解释为什么该函数返回所有信息吗?

Your switch statement has a Default branch, which is invoked if none of the other branches' conditions are met;你的switch语句有一个Default分支,如果其他分支的条件都不满足,就会调用它; since you don't have a branch for the -All switch value, the Default handler kicks in if由于您没有用于-All开关值的分支,因此Default处理程序将启动,如果
-All was specified . -All被指定

By contrast, if you don't pass any argument, the switch statement is never entered , because, for collection-valued input, the switch statement implicitly loops over the elements of that collection.相比之下,如果您不传递任何参数,则永远不会输入switch语句,因为对于集合值输入, switch语句隐式地遍历该集合的元素。 With no arguments passed, $PSBoundParameters.Values is an empty collection , so there is nothing to enumerate.没有传递参数, $PSBoundParameters.Values是一个空集合,所以没有什么可枚举的。

The parameter-set approach in Mathias' answer is the simplest solution to this problem, which has the added advantage of making the -All switch and the specific property-name switches mutually exclusive. Mathias 回答中的参数集方法是解决此问题的最简单方法,它具有使-All开关和特定属性名称开关互斥的额外优势。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM