Powershell - 如何使用 "WindowsInstaller.Installer" 在 MSI 中插入 属性 值 - REBOOT = Force

Powershell - How to use "WindowsInstaller.Installer" to Insert a Property Value in a MSI - REBOOT = Force

我正在尝试 accomplish this in Powershell, I've found it to very difficult to do. This is the closest bit of code I've found that does something similar. I've also found this example 这很相似,但在 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

但是当我 运行 它时我得到以下信息:

Exception calling "InvokeMember" with "5" argument(s): "Execute,Params" At C:\XXX\Example.PS1:15 char:5 $View.GetType().InvokeMember('Execute', 'InvokeMethod', $null, $V ...

CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
FullyQualifiedErrorId : COMException

而且我不明白为什么,有谁知道为什么这不会 运行?我真正的问题是我看不到问题的根源,所有的 COMExceptions 似乎都没有 return 任何真实信息,这使得弄清楚为什么 COM 调用失败非常困难,有没有还有更好的方法吗?

Read / Write: [int]$msiOpenDatabaseMode = 0 this opens the MSI database read-only - very common glitch. This needs to be corrected, but there could be other glitches as well. I just based myself on an existing script for the sample below.

Heads-up: Keep in mind that some properties should not be authored into the Property table. The only ones I can think of right now are: FASTOEM, ADDLOCAL - there are others. REBOOT should be OK technically - I think - however read the next point - it is not good practice.

Warning on Reboot: The ScheduleReboot MSI standard action triggers a spontaneous reboot of the system when an MSI is run in silent mode. I just verified that the same thing happens with this approach (REBOOT = Force in property table). To install MSI silently, run this command from an elevated cmd.exe command prompt: msiexec /i Setup.msi /qn.

  • Ethics of rebooting (no less).
  • Another issue: (you are asked to reboot after every operation - modify, repair, upgrade, uninstall, etc...).

DTF:我还想提一下Deployment Tools Foundation .NET classes written to interact with the MSI API. Using this dll you don't have to deal with COM Interop. These DLLs come installed with the WiX toolkit. Here is a brief overview of the dll family.


Powershell 不是我的菜 - 你必须是埃及人才能喜欢那些象形文字(尽可能强大) - 但也许你可以尝试下面的脚本(更新 $MsiFilePath )。对高线噪音说不!

  • 此脚本假定在 属性 table - 运行ning 两次中没有预先存在的 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

WiX 拥有 DTF 库,可让您在托管代码中完成所有这些工作。有一个 powershell cmdlet 可以做很多事情但不能编辑数据库。这可能是值得一看的好代码,以了解该怎么做。

https://github.com/heaths/psmsi

这是我的 MSFT 员工写的。

PS- 为什么要编辑 MSI?如果这样做,您将破坏它的数字签名。如果您希望它始终重新启动,通常您只需说 MSIEXEC /I FOO.MSI REBOOT=F。