Powershell:使用 json 中的值作为参数默认值

Powershell: use values from json as parameter defaults

我想编写一个带参数的脚本,这些参数的默认值存储在 json 文件中。不幸的是,如果它不是脚本中的第一行代码,Powershell 无法识别 param()

当然如果是脚本的第一行,就不能提前加载配置,并使用它的值作为默认值。所以我很生气。

config.json:

{"defaultValue":"Default"}

powershell 脚本:

$configPath = "config.json"
$configPath = Join-Path $PSScriptRoot $configPath

# read config
$config = Get-Content $configPath | ConvertFrom-Json

write-host $config.defaultValue

param($myparam = $config.defaultValue)

write-host $myparam

我是 powershell 的新手,有没有办法在脚本后面设置参数的默认值?或者,稍后将参数读入脚本?

让我们假设您的 config.json 看起来像这样:

{
    "Name": "Earthling",
    "Color": "Pink"
}

根据您的实际情况,您可以将 config.json 的路径作为参数传递,并将所有其他参数设为可选。

在脚本中加载配置并为脚本调用中未设置的所有参数提供默认值:

[CmdletBinding()]
param (
    [Parameter()]
    [string]
    $Name,

    [Parameter()]
    [string]
    $Color,

    [Parameter()]
    [string]
    $ConfigPath
)

    if ($ConfigPath -in  $PSBoundParameters.Keys) {

        $config = Get-Content $ConfigPath | ConvertFrom-Json

        if ('Name' -notin  $PSBoundParameters.Keys) {
            $Name = $config.Name
        } 
        if ('Color' -notin  $PSBoundParameters.Keys) {
            $Color = $config.Color
        } 
    }

    Write-Host "$Name your favourite color is $Color"

您可以这样调用脚本:

PS> ./script.ps1  -ConfigPath ./config.json -Color Blue

Earthling your favourite color is Blue

缺点是不能将参数声明为强制参数。另一种允许将参数声明为强制参数的方法是将配置通过管道传输到您的脚本中:

[CmdletBinding()]
param (
    [Parameter(ValueFromPipelineByPropertyName,Mandatory)]
    [string]
    $Name,

    [Parameter(ValueFromPipelineByPropertyName,Mandatory)]
    [string]
    $Color
)

    Write-Host "$Name your favourite color is $Color"

调用将是:

PS> Get-Content ./params.json | ConvertFrom-Json | ./script.ps1 -Color Red

Earthling your favourite color is Red

您可能想为此使用 DynamicParam { } 块和 Set-Variable cmdlet。
缺点是您无法设置相关变量(如 $Name),但可以使用 $PSBoundParameters[$Name] 代替或在 Begin 块中分配裸变量名称。
快速而肮脏的示例(不检查例如相关参数是否确实存在):

Function Test {
    [CmdletBinding()] param (
        [Parameter()][string]$Name,
        [Parameter()][string]$Color
    )
    DynamicParam {
        $Defaults = ConvertFrom-Json -AsHashTable '{
            "Name": "Earthling",
            "Color": "Pink"
        }'
        ForEach ($Key in $Defaults.get_Keys()) { 
            if (!$PSBoundParameters.ContainsKey($Key)) { $PSBoundParameters[$Key] = $Defaults[$Key] }
        }
    }
    Begin {
        ForEach ($Key in $PSBoundParameters.get_Keys()) { Set-Variable $Key $PSBoundParameters[$Key] }
    }
    Process {
        Write-Host 'Name:' $Name
        Write-Host 'Color:' $Color
    }
}

Test -Name Jim
Name: Jim
Color: Pink

我建议使用 PSDefaultParameterValues;因此您可以在脚本开始时将 JSON 文件加载到此哈希表中。

为了避免 param 需要位于脚本的开头,并为您提供一个函数名称以在 PSDefaultParameterValues 哈希表中使用,您可以定义脚本的核心逻辑在脚本内的函数定义中。然后脚本本身只做了 3 件事:

  • 读取 JSON 文件并设置 PSDefaultParameterValues
  • 定义函数
  • 调用函数

我认为这种方法比 DynamicParams 更简单,并且鼓励将代码封装到可重用函数中的良好实践,而脚本实际上只是调用所述函数的包装器。

参数默认值可以通过任意命令分配,只要您的默认值是参数特定的并且不依赖于其他参数的值(或稍后在脚本中定义的变量),使用 self -包含确定默认值的命令是一个可行的选项:

param(
  $myparam = (ConvertFrom-Json (Get-Content -Raw $PSScriptRoot/config.json)).defaultValue
)

# Output the parameter value for diagnostic purposes.
"[$myparam]"

唯一的潜在问题是,如果您想以这种方式分配多个参数的默认值,则必须复制此命令的(变体):

  • 性能方面,我怀疑这不会有问题(除非 JSON 文件很大并且有很多参数)。

  • 如果您出于维护原因不喜欢重复方面,请使用基于 automatic $PSBoundParameters variable, as shown in .

    的事后方法