自动安装 .msi

Automate .msi installs

我正在尝试一个接一个地批量安装一堆 .msi。但是当我 运行 我的 powershell 脚本 msiexec /?好像我的论点是错误的。我在这里错过了什么?

$Path = Get-ChildItem -Path *my path goes here* -Recurse -Filter *.MSI
foreach ( $Installer in ( Get-ChildItem -Path $Path.DirectoryName -Filter *.MSI ) ) {
    Start-Process -Wait -FilePath C:\windows\system32\msiexec.exe -ArgumentList "/i '$Installer.FullName'"
}

语法"/i '$Installer.FullName'"不正确。在您的代码中应该是 "/i", $Installer.FullName

用双引号将 PowerShell 对象括起来会触发字符串扩展。当发生这种情况时,只有变量本身被替换为它的值,然后其余不属于名称的字符被视为字符串。当您 运行 以下片段时,您可以看到该对象执行了 ToString() ,然后将字符串 .FullName 添加到其中。

foreach ( $Installer in ( Get-ChildItem -Path $Path.DirectoryName -Filter *.MSI ) ) {
     "/i $Installer.FullName"
}

如果您必须使用双引号,那么解决它的方法是使用 sub-expression 运算符 $()。解析器将内部的任何内容视为表达式。所以更详细的 "/i '$($Installer.FullName)'" 在技术上是可行的。

完整代码应该是:

$Path = Get-ChildItem -Path *my path goes here* -Recurse -Filter *.MSI
foreach ( $Installer in ( Get-ChildItem -Path $Path.DirectoryName -Filter *.MSI ) ) {
    Start-Process -Wait -FilePath C:\windows\system32\msiexec.exe -ArgumentList "/i", $Installer.FullName
}

包含很好的建议,但让我试着从概念上归纳一下:

您的尝试有两个不相关的问题:

  • 内部可扩展字符串("...")只能使用简单变量引用($Installer)as-is; 表达式 ($Installer.FullName) 需要 $()subexpression operator: $($Installer.FullName) - see this answer 以获得 PowerShell 中可扩展字符串(字符串插值)的概述。

  • 由于您通过 -ArgumentListmsiexec 的参数作为 单个字符串 传递,因此仅嵌入 支持双引号"...",不支持'...'(单引号)。

因此,使用以下内容(为简洁起见,-FilePath-ArgumentList 参数按 位置 传递给 Start-Process):

Get-ChildItem $Path.DirectoryName -Recurse -Filter *.MSI | ForEach-Object {
  Start-Process -Wait C:\windows\system32\msiexec.exe "/i `"$($_.FullName)`""
}

注:

-ArgumentList参数是数组类型的([string[]])。理想情况下,您会因此将参数 单独 作为数组的元素传递:'/i', $_.FullName,这不需要您考虑 embedded 单个 字符串中引用。

不幸的是,Start-Process doesn't handle such individually passed arguments properly if they contain embedded spaces,所以可靠的解决方案是使用 单个 -ArgumentList 包含 所有参数 个参数,根据需要 嵌入 double-quoting,如上所示。

有关更详细的讨论,请参阅

在 Powershell 5.1 中,使用 msi,您还可以:

install-package $installer.fullname