【问题标题】:Parameter splatting with values read from a JSON config file使用从 JSON 配置文件中读取的值进行参数喷溅
【发布时间】:2021-07-12 15:47:31
【问题描述】:

使用 Splatting Hashtable 来设置参数并且效果很好。 我将作为New-ADUser @param 传递给函数,在 splatting 中设置的值将在 Active Directory 中创建。但是,我的脚本将在其他地方运行。 Json 文件将由用户操作。

如何将 Json 文件而不是 Splatting table 传递给这个 New-ADUser @param 函数。

感谢您的帮助。

【问题讨论】:

  • 使用ConvertFrom-Json将json转换为对象,并获取属性以创建一个飞溅的哈希表

标签: json powershell parameter-splatting


【解决方案1】:

注意:以下假设您的 JSON 配置文件:

  • 包含一个对象,其属性名称与目标cmdlet的参数名称匹配,New-ADUser
  • 并且属性 values 仅限于字符串、数字、布尔值和嵌套对象,PowerShell 可以根据 @ 中解释的约束cast 到参数的类型987654321@.

这些约束确保该对象的哈希表表示可以按原样用于参数splatting


如果您正在运行 PowerShell (Core) 7+,则可以利用 ConvertFrom-Json
-AsHashtable 参数

# Load JSON from file 'config.json' into a [hashtable] instance.
$params = Get-Content -Raw config.json | ConvertFrom-Json -AsHashtable

# Use the hashtable for splatting.
New-ADUser @params

Windows PowerShell(其最新和最终版本是 5.1)中,您必须手动转换 @ 返回的 [pscustomobject] 实例 987654334@ 转至hashtable

# Load JSON from file 'config.json' into a [pscustomobject] instance.
$paramsAux = Get-Content -Raw config.json | ConvertFrom-Json

# Convert the [pscustomobject] to a [hashtable] instance by 
# making its properties (name-value pairs) hashtable entries.
$params = @{}
foreach ($prop in $paramsAux.psobject.Properties) {
  $params[$prop.Name] = $prop.Value
}

# Use the hashtable for splatting.
New-ADUser @params

您在评论中提供的示例配置 JSON 表明顶部所述的先决条件满足,并且配置的自定义转换需要 JSON 才能映射到目标 New-ADUser 参数:

  • 更新:真正预期的目标 cmdlet 原来是 New-AzureADuser,其参数与下面的示例 JSON 的属性直接匹配,因此不需要自定义转换;希望所展示的技术对确实需要自定义转换的未来读者仍然有用。
# Create a sample JSON config file.
@'
{
  "GivenName": "Lili",
  "SurName": "Waters",
  "accountEnabled": true,
  "displayName": "Lili Waters",
  "mailNickname": "LiliW",
  "userPrincipalName": "liliw@mailcom",
  "passwordProfile": {
    "forceChangePasswordNextSignIn": true,
    "password": "xxyyzz"
  }
}
'@ > config.json

# Load JSON from file 'config.json' into a [pscustomobject] instance.
$paramsAux = Get-Content -Raw config.json | ConvertFrom-Json

# Convert the [pscustomobject] to a [hashtable] instance by 
# making its properties (name-value pairs) hashtable entries,
# applying custom transformations, as necessary.
$params = @{}
foreach ($prop in $paramsAux.psobject.Properties) {
  switch ($prop.Name) {
    # Map the JSON property names and values onto the appropriate 
    # New-ADUser parameters.
    'accountEnabled'  { $params['Enabled'] = $prop.Value }

    'mailNickname'    { $params['SamAccountName'] = $prop.Value  }

    'passwordProfile' { 
      $params['ChangePasswordAtLogon'] = $prop.Value.forceChangePasswordNextSignIn
      $params['AccountPassword'] = ConvertTo-SecureString -Force -AsPlainText $prop.Value.password
     }

    # All other properties directly map onto New-ADUser parameters.
    default           { $params[$prop.Name] = $prop.Value }
  }
}

# Use the hashtable for splatting.
# Note: To inspect the actual arguments being passed, use Write-Output in lieu
#       of New-ADUser, or just output the hashtable, $params, by itself.
New-ADUser @params

注意:我不确定mailNickname 属性映射到什么参数;我在上面假设了-SamAccountName;根据需要进行调整。

【讨论】:

  • @AshlyneB:这就是答案中的前两个代码 sn-ps 分别用于 PowerShell (Core) 7+ 和 Window PowerShell 的内容。
  • @AshlyneB:这是因为PasswordProfile 属性必须是具有forceChangePasswordNextSignIn 等属性的对象,而不是字符串。您之前提供的示例 JSON(现在是答案的一部分)显示了必要的结构。
  • 另请注意,您不能在 JSON 文本中执行诸如 $PasswordProfile 之类的变量扩展 - 该值按原样 使用,这就是你看到了。您可以在调用ConvertFrom-Json 之后 之后分配一个对象$param.PasswordProfile = $PasswordProfile
  • @AshlyneB,这听起来像是一个不相关的问题,与飞溅不同(以您的示例 JSON 为例,错误消息告诉您 liliw@mailcom 用户主体名称的 mailcom 部分是'不被识别为属于您组织的域名)。同样,我认为我们已经涵盖了所有一般角度,所以我再次鼓励您accept这个答案并询问新问题以了解任何后续/无关您可能遇到的问题。
【解决方案2】:

@mklement0 的回答很好,解释了一切。我目前被困在 ps5 世界中,所以我不得不求助于跳过 -ashashtable 选项。我想我会举一个小例子来说明我是如何做到的。这只是 @mklement0 的一个更简洁的版本。

我目前使用 oneliner 进行转换,如下面的 sql 示例:

#get all my settings
$cfg = Get-Content settings.json -Raw | ConvertFrom-Json

#convert the arguments i want to splat
$sqlargs = $cfg.sql.psobject.Properties|%{$h=@{}}{$h."$($_.Name)"=$_.Value}{$h}

#use args as splat
$dt = Invoke-Sqlcmd @sqlargs

settings.json 看起来像...

{
    "sql": {
        "QueryTimeout": 1800,
        "ConnectionString": "my connection string",
        "InputFile": "sqlfile.sql",
        "OutputAs": "DataTables"
    }
}

我在文件中有其他设置不需要作为 args 传递,因此我不需要转换整个文件,只需转换这一属性即可。

我考虑为此创建一个模块,因为我将它用于各种事情,但我 this 项目看起来在这种情况下可以解决问题。

【讨论】:

    猜你喜欢
    • 2013-09-23
    • 2012-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-22
    • 1970-01-01
    相关资源
    最近更新 更多