我正在使用 powershell 脚本自动执行无人值守检索和安装指定的 .msi 包,但是如果命令调用时出现语法错误,则 msiexec 将无限期地等待在其帮助显示屏上单击“确定”,尽管存在 /quiet 和/或 /passive。
目前我正在用以下方式调用它:
(start-process -FilePath "msiexec" -ArgumentList "/i <path_to_package> /quiet /passive" -PassThru -Wait).ExitCode
有什么方法可以禁用 msiexec 帮助显示?
答案1
遗憾的是,我认为避免帮助显示的唯一方法是......
...不要犯任何拼写错误/语法错误。
我希望我能为您提供更好的答案,但是......
答案2
对于包含语法错误的命令,无法禁用此行为msiexec
。您可以将命令包装成类似以下内容。它使用 .NET Automation 查找“使用情况”窗口并在脚本中处理它。
Add-Type -AssemblyName UIAutomationClient
Add-Type -AssemblyName UIAutomationTypes
# Note the invalid argument '/badswitch'
$mse = Start-Process -FilePath 'msiexec' -ArgumentList "/i package.msi /badswitch /quiet /passive" -PassThru
# Let msiexec at least get off the ground
[void] $mse.WaitForInputIdle()
# Create an AutomationElement from $mse's handle
$mseAuto = [Windows.Automation.AutomationElement]::FromHandle($mse.MainWindowHandle)
# A PropertyCondition for findAll()
$pane = New-Object Windows.Automation.PropertyCondition -ArgumentList (
[Windows.Automation.AutomationElement]::ControlTypeProperty,
[Windows.Automation.ControlType]::Pane
)
# Search for a child $pane element.
$findResult = $mseAuto.FindFirst(
[System.Windows.Automation.TreeScope]::Children,
$pane
)
# If there's a pane element in $mseAuto, and it contains "usage" string, it's an msiexec syntax issue, so close $mse's window.
if ( $findResult.Current.Name -match 'msiexec /Option <Required Parameter>' ) {
[void] $mse.CloseMainWindow()
} else {
# You should put something more sane here to handle waiting for "good" installs to complete.
$mse.WaitForExit()
}
$mse.ExitCode
这也有问题。/quiet
安装过程中仍会显示进度对话框。您可以考虑使用/qn
隐藏所有msiexec
UI 元素。此外,MSI 可能会触发其他未处理的错误,从而暂停执行不忠诚。也许包括超时值?从 CustomAction 表启动的外部进程又如何?抱歉,我现在快要说废话了……
答案3
我只是想避免使用 msiexec.exe。这可以通过Windows 安装程序 API使用脚本或代码。
您可以使用 VBScript / VBA / VB 进行 COM 自动化,或者使用 DTF(Windows Installer API 的 .NET 包装器),更易于通过 .NET 语言(例如 C#)使用。
您甚至可以直接通过 C++ 转到原始 Win32 API 调用,但这只是浪费时间,因为您拥有 COM 和 .NET 等效物,它们将调用原始 Win32 API 作为其操作的一部分。
解决方案 1:VBScript 和 COM 自动化
如果使用自动化是一种选择,你应该能够通过Windows Installer COM 自动化并以此方式自动执行安装/卸载。以下是您可以放入文件并运行的 VBScript(显然要更新 MSI 路径名):
Const msiUILevelEndDialog = 128
Set msi = CreateObject("WindowsInstaller.Installer")
msi.UILevel = msiUILevelEndDialog
msi.InstallProduct( "C:\msifile.msi")
Set msi = Nothing
解决方案 2:DTF - 部署工具基础 - .NET
差分复用技术(部署工具基础)本质上是 Windows Installer API 的 .NET 包装器 - 它具有如此强大的 .NET 程序集集合,可直接与 Windows Installer 的各个方面配合使用,我只想在这里添加它,以供那些寻找具有大量细粒度部署控制的解决方案来解决其管理问题的人参考。C# 应用程序中非常简单的代码可以完全控制安装过程。这是一个粗略的模型:
using Microsoft.Deployment.WindowsInstaller.Installer;
Installer.SetInternalUI(InstallUIOptions.Silent);
Installer.InstallProduct(msiFilename, "ACTION=INSTALL ALLUSERS=1");
您可以通过以下方式获取 DTFWIX 工具包- 这是从 XML 源文件创建 MSI 文件的整体解决方案。您将在以下位置找到出色的文档:数据保护手册和DTFAPI说明实际文件位于主安装文件夹中。最后两个通常是您需要的:
- 微软部署压缩.dll- 档案打包和解包的框架。
- 微软部署压缩Cab.dll- 实现文件压缩包的打包和解包。
- 微软部署资源.dll- 用于在可执行文件中读取和写入资源数据的类。
- 微软部署.WindowsInstaller.dll- 完整的 Windows Installer API 类库。
- 微软部署.WindowsInstaller.Package.dll- 用于处理 Windows Installer 安装和修补程序包的扩展类。
只需创建一个 C# 项目,引用这些文件,然后使用您想要和需要的任何控件编写您自己的部署应用程序。我目前还没有为 DTF 设置工具,但请参阅此样本了解 C# 程序的工作原理。
解决方案 3:C++ 安装程序函数
我只是觉得我应该添加这一点——我认为这与系统管理员基本无关,但它可能有助于更好地理解 MSI 技术。除了 COM 自动化之外,还有一个具有可通过 C++ 访问的函数的 Win32 API。当然,性能要好得多(COM 自动化显然在后台调用这些 Win32 函数 - COM 当然只是这些“真实”函数之上的一个包装器)。
我现在没有任何可用的 C++ 示例,但是这里是 SDK 文档:Windows 安装程序参考. 并直接链接到实际安装程序功能列表。这个功能列表应该能让您快速了解使用这项技术的感觉。
更新:我添加了一个 C++ 代码片段示例这个 stackoverflow 回答了有关卸载 MSI 包的不同方法(答案底部的第 14 部分)。
系统管理员不会使用此选项,但商业工具会使用此选项来访问系统的 MSI 数据库(存储在注册表中的几个位置,并在磁盘上有一个缓存文件夹 - %SystemRoot%\Installer
- 以及一些“工作文件夹”)。例如,您的 SCCM 或类似的部署系统将在“后台”使用它们。
解决方案 4:WMI
只需添加一些 WMI 类即可用于自动化和查询 MSI。Win32_产品以及其他一些。
答案4
您尝试过 /qn 开关吗?它应该会抑制所有用户界面提示。
http://technet.microsoft.com/en-us/library/cc759262(v=ws.10).aspx#BKMK_SetUI