【问题标题】:Splatting a hashtable - Start-Process -ArgumentList散列表 - Start-Process -ArgumentList
【发布时间】:2018-02-27 14:40:57
【问题描述】:

我正在尝试使用 splatting 安装 .MSI:

$InstallerArgs @{
    "DATABASENAME" = "my_database";
    "LOCALIP" = "127.0.0.1";
    "USERNAME" = "username1";
    "/i" = "C:\Files\Installer.msi";
}

然后我打电话给Start-Process:

Start-Process -FilePath msiexec.exe -ArgumentList @InstallerArgs -Wait

这会返回错误:Missing an argument for parameter 'ArgumentList'. Specify a parameter of type 'System.String[]' and try again.

Start-Process不能使用splatting吗?

【问题讨论】:

  • 可以通过Start-Process 使用喷溅,但您不能以这种方式为 msi 安装程序提供选项。
  • 顺便说一句,对于那些想知道这里是否需要使用Start-Process的人:它,即确保同步(阻塞)在-Wait 开关的帮助下执行。 msiexec,尽管拥有丰富的 CLI,但不是 控制台应用程序,因此默认情况下异步执行(并且始终没有控制台输出) .
  • 如果您不是从脚本运行它,而只是想运行命令从 PowerShell 提示符卸载某些东西,我更喜欢异步,因为我得到了提示并且不必等待卸载完成。

标签: powershell


【解决方案1】:

Splatting (@<varName>) 不支持作为参数(参数);相反,散列表本身表示一组参数名称-值对

相比之下,

Olaf's helpful answer 演示了正确使用 splatting,其中哈希表包含 Start-Process 的参数名称-值对作为一个整体,通过- to-msiexec 参数指定为ArgumentList 哈希表条目中的数组。

如果您确实想在单独的数据结构中只保留传递到msiexec 的参数,请使用 数组按原样传递,鉴于-ArgumentList 确实需要一个字符串 array 作为其参数 ([string[]]):

$InstallerArgs = @(
    "DATABASENAME=my_database"
    "LOCALIP=127.0.0.1"
    "USERNAME=username1"
    "/i"
    "C:\Files\Installer.msi"
)

# Note: NO splatting
Start-Process -FilePath msiexec.exe -ArgumentList $InstallerArgs -Wait

以上内容最终执行以下操作:

msiexec.exe DATABASENAME=my_database LOCALIP=127.0.0.1 USERNAME=username1 /i C:\Files\Installer.msi

请注意,由于长期存在的错误任何需要双引号的值 - 通常是因为它们嵌入了空格 - 必须明确指定嵌入、转义双引号 (`");例如,

"`"C:\Files A\Installer.msi`""

这将导致msiexec ... "C:\Files A\Installer.msi" 被通过。

该问题在 PowerShell [Core] 7.0 中仍然存在,并且可能永远不会被修复以保持向后兼容性。但是,可以提供一个新参数来提供正确的行为 - 请参阅 GitHub issue #5576


警告与外部程序

当使用 hashtables(而不是数组)进行 splatting 时,PowerShell 将 hashtable 条目转换为
-<key>:<value> 参数
- 请注意 : - 效果很好使用 PowerShell 命令,但可能不符合 msiexec 等外部实用程序所期望的参数语法。
GitHub issue #9343 建议将格式更改为用 空格分隔/em>(使用单独的参数;-<key> <value>)。

一个简单的例子:

# Define hashtable with parameter name-value pairs.
$htParams = @{
   foo = 'bar none'  # parameter -foo with value 'bar none'
}

# Pass the hashtable via splatting (note the use of @ instead of $).
baz.exe @htParams

baz.exe 然后会看到以下参数:

-foo:"bar none"

【讨论】:

    【解决方案2】:

    这应该确实有效:

    $InstallerArgs = @{
        FilePath = 'msiexec.exe'
        ArgumentList = @(
            '/i',
            'C:\Files\Installer.msi',
            'LOCALIP="127.0.0.1"',
            'USERNAME="username1"'
        )
        Wait = $True
    }
    Start-Process @InstallerArgs
    

    【讨论】:

      【解决方案3】:

      您不一定需要Start-Process。记住:PowerShell 是一个外壳;它可以运行你输入的命令,就像cmd.exe

      msiexec /i C:\Files\Installer.msi DATABASENAME=my_database LOCALIP=127.0.0.1 USERNAME=username1
      

      如果任何参数包含空格,请将它们括在" 字符中。

      注意:这将异步运行msiexec(即,如果您在脚本中运行该命令,它将继续执行下一行脚本,而无需等待msiexec 完成)。如果您想在继续之前等待 msiexec 完成(即同步运行它),您可以使用 Start-Process-Wait 参数,如其他答案中所述。

      【讨论】:

        【解决方案4】:

        此解决方案仅在您有 key=value 对时才有效

        $params = [string]::Join(" ", ($parameters.GetEnumerator() | ForEach-Object { $_.Key + "=" + $_.Value }))
        Start-Process -FilePath msiexec.exe -ArgumentList @InstallerArgs -Wait
        

        我是 c# 开发者,所以它可能不是传统的 ps 样式

        【讨论】:

          猜你喜欢
          • 2015-08-12
          • 2018-11-02
          • 1970-01-01
          • 2020-08-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多