3

我正在使用 InstallShield 2013 为需要Windows Platform Update KB2670838的应用程序制作基本 MSI 安装程序。

对于 .NET 框架和其他要求,我在 InstallShield 的 Redistributables 部分中选择它们。KB2670838 不可用。

如果我从 Microsoft 下载 KB2670838,我会得到一个.msu文件。是否可以以某种方式将其包含在安装程序中,以便在需要时自动安装?如果没有,有没有办法停止安装并告诉用户“需要 KB2670838 但未安装。在此处获取...”?

4

5 回答 5

3

注册表中的添加/删除程序列表可以帮助您大致了解已安装的内容:

  • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall

似乎这并没有提供已安装内容的完整列表:http: //social.technet.microsoft.com/Forums/windows/en-US/d913471a-d7fb-448d-869b-da9025dcc943/where-does- addremove-programs-get-its-information-from-in-the-registry?forum=w7itprogeneral

另一种方法可能是使用知识库文章 中的文件信息:http: //support.microsoft.com/kb/2670838/en(更多信息:文件信息)并使用 WIX / MSI 的AppSearch / LaunchCondition功能。这应该可以解决问题,尽管我发现语法有点违反直觉。

另一种方法是编写自定义操作并结合这两个源(添加/删除条目和文件信息)。这样的自定义操作不会对系统进行任何更改,因此比导致回滚问题的其他自定义操作问题更少。我发现测试和维护自定义操作更容易,以防在某些时候需要进一步的先决条件。不过,这是一个口味问题。我只是发现针对选择的文件运行先决条件脚本以测试它是否正确识别它们并按预期运行比为每个测试继续运行 MSI 文件更容易。

这是一个类似的问题,来自 superuser.com 的一些指针: https ://superuser.com/questions/521175/determine-if-windows-hotfix-has-been-applied

还有另一个指向 serverfault.com(系统管理站点)的链接。使用PowerShell的好方法当然可以迁移到自定义操作: https ://serverfault.com/questions/312778/determine-if-user-has-hotfix-981889-installed

更多涉及update.exeWMI和 Powershell 脚本的serverfault.com 内容,用于查看所有已安装的修补程序https ://serverfault.com/questions/263847/how-can-i-query-my-system-via-command-在线查看,如果-a-kb-patch-is-installed推荐阅读。微软:http ://technet.microsoft.com/en-us/library/hh849836.aspx

PSInfo似乎能够显示已安装的修补程序:http ://technet.microsoft.com/en-us/sysinternals/bb897550

于 2014-03-13T21:20:47.173 回答
3

在 InstallShield 中,您通常应该将此类更新作为先决条件(工具 > 先决条件编辑器)或作为套件中包含的包([SystemFolder]wusa.exe安装.msu文件的参考)提供。在这两种情况下,这使可再发行安装在逻辑上与您的软件包安装分开,同时为您的用户提供单一的安装程序体验。

Glytzhkof 提到了几个关于如何确定是否已安装更新的非常好的观点。您将希望将这些合并到您的条件中(在先决条件或套件包上),并且还希望在您的.msi包中检测更新或缺少更新,以便如果在启动时尚未安装所需的更新,它可以中止.msi

于 2014-03-14T12:41:55.633 回答
2

@Glytzhkof 好点。那么如何让 InstallShield 中止并给用户一个好消息,让他们知道该怎么做呢?– 鞋垫 1 小时前

然后我将添加一个新答案 - 太长了,无法在评论中写。

  • 在此 kdb 文章的“更多信息:文件信息”下找到您需要扫描 的文件详细信息:http: //support.microsoft.com/kb/2670838/en
  • 在 Installshield 中选择一些文件进行扫描并添加为文件搜索(见下面的屏幕截图)。您为每个文件(FILE1FOUND、FILE2FOUND、FILE3FOUND 等)指定一个属性,如果搜索与文件详细信息(版本、大小、日期等)匹配,则该属性设置为文件的完整路径文件。否则,该属性未定义或设置为默认值(屏幕截图显示预定义搜索,而不是文件搜索,但您明白了)。
  • 最后,您为每个文件添加LaunchCondition条目,以确保您选择检查的所有文件都是正确的版本或更高版本。我想这是在先决条件或类似情况下 - 我不记得了。打开已编译的 MSI 并检查它是否看起来像LaunchConditon 表

Installshield 的搜索视图

备案:(不是上述建议的一部分)

就我个人而言,我赞成为这样的复杂逻辑编写单个脚本,以确保逻辑可以作为一个整体进行检查,并在 MSI 文件之外作为一个整体进行关键测试。向此类代码添加注释以解释脚本正在检查的内容以及原因(有助于企业部署)也很好。一个脚本可以直接在机器上运行几十个测试,而无需重新编译 MSI。如果逻辑复杂,这可以节省大量时间。如果您编写已编译的 dll,您可以显示一个消息框并将 Visual Studio 调试器附加到 msiexec.exe 进程(客户端或服务器,具体取决于您的自定义操作在哪个上下文中运行),并在嵌入 MSI 时单步执行代码,但这似乎超出了您的方案的范围。只是想为可能阅读本文的其他人提及它。还要检查 Stefan Kruger 的installsite.com以获取有关此类复杂设置调试的更多信息。

重要的是要注意,对于脚本对系统进行更改的情况,通常不建议使用脚本编写 - 如果有内置的 MSI 方法可以实现相同的结果。这样做的原因是,对机器进行更改的脚本将需要为其指定单独的回滚操作,以便 MSI 遵循最佳实践。要做到正确,这可能需要大量的工作和复杂性。上面的脚本只会检查系统条件,所以不需要回滚支持。

于 2014-03-16T00:57:09.623 回答
1

让我尝试添加一个参考风格的答案,因为我的其他答案在这一点上至少可以说有点有机 - 我将把它留在里面,因为它包含一个 MSI 讨论。请参阅下面中间部分的 MSI 建议

西米

wmic qfe where "HotfixID = 'KB973687'"

PowerShell:(只是获取完整列表的修补程序)

get-hotfix | findstr "981889"

SystemInfo(删除列表格式的参数):

systeminfo /fo csv

PSInfo(似乎没有列出所有机器上的所有内容,并且可能无法正常运行):

PSinfo -h

注册表(显然不是完整的修补程序列表):

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall

对于 MSI custom action use,我实际上会使用一个自定义操作来检查文件版本,如我的其他答案中所述。非常可靠,并且考虑到在文件仍然是最新的情况下可能会弃用修补程序。


参考资料

于 2014-03-14T16:54:56.240 回答
0

有同样的问题并通过添加 PowerShell 脚本的先决条件和批处理文件来执行它来解决它。

pre.ps1文件如下所示

function TestConnection
{
    Test-Connection -ComputerName "8.8.8.8" -Quiet
}

get-hotfix -id KB2670838
if(!$?){
    #SourceURI = "https://download.microsoft.com/download/1/4/9/14936FE9-4D16-4019-A093-5E00182609EB/Windows6.1-KB2670838-x64.msu";
    #$FileName = $SourceURI .Split('/')[-1]
    #$BinPath = Join-Path $DownloadPath -ChildPath $FileName
    Invoke-Webrequest -Uri $SourceURI -OutFile $BinPath
    #Start-Process -FilePath $BinPath -ArgumentList "/q /norestart" -Wait -NoNewWindow
}

pre.cmd文件如下所示:

@echo off
::set PS_FILE=%~dp0Prerequisite.ps1
set PS_FILE=%~dpn0.ps1
set PS_EXEC_PATH=%SystemRoot%\sysnative\WindowsPowerShell\v1.0\
set PS_EXEC_PATH=%SystemRoot%\System32\WindowsPowerShell\v1.0\
::set PS_EXEC_PATH=%SystemRoot%\SysWOW64\WindowsPowerShell\v1.0\
set PS_EXEC_PATH=
set PS_EXEC=%PS_EXEC_PATH%powershell.exe
echo %PS_EXEC%
echo %PS_FILE%

::%PS_EXEC% -file %PS_FILE% set-executionpolicy remotesigned
::%PS_EXEC% -NoProfile -ExecutionPolicy Bypass -Command "& '%PS_FILE%'"
::This is with admin rights
%PS_EXEC% -NoProfile -Command "& {Start-Process PowerShell.exe -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File ""%PS_FILE%""' -Verb RunAs}"

::pause
于 2017-02-19T09:08:06.317 回答