powershell - Powershell - 如何使用“WindowsInstaller.Installer”在 MSI 中插入属性值 - REBOOT = Force
问题描述
我正在尝试在 Powershell 中完成此操作,我发现它很难做到。这是我发现做类似事情的最接近的代码。我还发现了这个类似的例子,但在 VBScript 中。我已经将所有这些加上几个小时的谷歌搜索编译成这个:
$com_object = New-Object -com WindowsInstaller.Installer
[int]$msiOpenDatabaseMode = 0
$database = $com_object.GetType().InvokeMember(
"OpenDatabase",
"InvokeMethod",
$Null,
$com_object,
@("C:\XXX.msi", $msiOpenDatabaseMode)
)
$View = $database.GetType().InvokeMember('OpenView', 'InvokeMethod', $null, $database,
("INSERT INTO Property (Property, Value) VALUES ('REBOOT', 'Force')"))
$View.GetType().InvokeMember('Execute', 'InvokeMethod', $null, $View, $null) | Out-Null
$View.GetType().InvokeMember('Close', 'InvokeMethod', $null, $View, $null) | Out-Null
但是,当我运行它时,我得到以下信息:
使用“5”参数调用“InvokeMember”的异常:“Execute,Params”在 C:\XXX\Example.PS1:15 char:5 $View.GetType().InvokeMember('Execute', 'InvokeMethod', $null, $V ...
CategoryInfo : NotSpecified: (:) [], MethodInvocationException FullyQualifiedErrorId : COMException
而且我不知道为什么,有人知道为什么这不会运行吗?我的真正问题是我看不到问题的根源,所有 COMExceptions 似乎都没有返回任何真实信息,这使得弄清楚 COM 调用失败的原因非常困难,有没有更好的方法那个也是?
解决方案
读/写:
[int]$msiOpenDatabaseMode = 0
这会以只读方式打开 MSI 数据库 - 非常常见的故障。这需要纠正,但也可能存在其他故障。我只是基于下面示例的现有脚本。提醒:请记住,某些属性不应被创作到属性表中。我现在唯一能想到的是: FASTOEM, ADDLOCAL - 还有其他的。从技术上讲,REBOOT 应该没问题 - 我认为 - 但是请阅读下一点 - 这不是一个好习惯。
重启警告:
ScheduleReboot
当 MSI 在静默模式下运行时,MSI 标准操作会触发系统自发重启。我刚刚验证了这种方法会发生同样的事情(REBOOT = Force
在属性表中)。要静默安装 MSI,请从提升的cmd.exe
命令提示符运行此命令:msiexec /i Setup.msi /qn
.
DTF:我还想提一下为与 MSI API 交互而编写的部署工具基础 .NET 类。使用此 dll,您不必处理 COM 互操作。这些 DLL 随 WiX 工具包一起安装。以下是 dll 系列的简要概述。
Powershell 不是我的菜——你必须是埃及人才能喜欢那些象形文字(尽可能强大)——但也许你可以试试下面的脚本(更新$MsiFilePath
)。对高线噪音说不!
- 此脚本假定属性表中没有预先存在的
REBOOT
条目 - 运行两次将触发错误。 - 如果您遇到问题 - 并且您已经运行了许多测试 - 尝试使用您的测试 MSI 的新副本或完全切换到另一个 MSI。
- 您可以通过自动化测试进入一些奇怪的“肮脏状态”。
- 当文件损坏时,避免将头撞到脚本上(只是为了说明这一点)。
实际脚本:
$Installer = new-object -comobject WindowsInstaller.Installer
$MSIOpenDatabaseModeTransact = 1
$MsiFilePath = "C:\Users\UserName\Desktop\MyTest.msi"
$MsiDBCom = $Installer.GetType().InvokeMember(
"OpenDatabase",
"InvokeMethod",
$Null,
$Installer,
@($MsiFilePath, $MSIOpenDatabaseModeTransact)
)
$Query1 = "INSERT INTO ``Property`` (``Property``,``Value``) VALUES ('REBOOT','Force')"
$Insert = $MsiDBCom.GetType().InvokeMember(
"OpenView",
"InvokeMethod",
$Null,
$MsiDBCom,
($Query1)
)
$Insert.GetType().InvokeMember("Execute", "InvokeMethod", $Null, $Insert, $Null)
$Insert.GetType().InvokeMember("Close", "InvokeMethod", $Null, $Insert, $Null)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Insert) | Out-Null
$MsiDBCom.GetType().InvokeMember("Commit", "InvokeMethod", $Null, $MsiDBCom, $Null)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($MsiDBCom) | Out-Null
推荐阅读
- python - 如何在 tkinter 中的面板内设置标签的大小 - python
- php - 我怎么能在 laravel 中传递这个查询?
- griddb - 为什么我的 TQL 查询使用 LIKE 没有返回结果?
- c - 如果找到大写字母,函数不会获取字符串的其余部分
- blazor - 如何在 WebAssembly 中执行 Blazor OpenID Connect 身份验证工作流
- sml - 带有 step 参数的 sml 中的 range 函数
- python - Python:如何比较卡片数组中的元素
- docker - 如何在两台服务器上同步 Docker 容器
- javascript - Vue NodeJs API 随机 ERR_TIMED_OUT
- frameworks - 将 EF 重新映射到应用程序