Как найти код обновления для установленного файла MSI?

В некоторых случаях может возникнуть необходимость получить коды обновления MSI для развернутых пакетов.

Общие сценарии:

  • Я взял на себя какой-то проект MSI, и мне нужно определить, какие коды обновления использовались для предыдущих версий, которые уже находятся в дикой природе. Это необходимо для обработки сценариев обновления. У меня нет архива выпусков где-нибудь.
  • Я случайно менял код обновления для своего WiX-пакета несколько раз во время разработки, и мне нужно найти все версии Upgrade Code "в дикой природе". Я не знал, что коды обновления должны оставаться стабильными между версиями.

Это вопрос стиля Q/A.

Этот вопрос появился в разных воплощениях, но это не дубликат. Я размещаю способ сделать это, используя главный интерфейс автоматизации MSI (или, строго говоря, WMI). Он должен быть более надежным, чем подходы, основанные на реестре, из предыдущих ответов. В этом ответе также делается попытка обобщить другие методы поиска.

Ответ 1

Получение кода обновления MSI (через PowerShell/WMI)

PowerShell script ниже следует получить все связанные коды продуктов, коды обновления и названия продуктов. на вашем компьютере (выход таблицы).

Снимок экрана вывод (полный script ниже):

powerhell output

Это реальные, живые значения непосредственно из базы данных установщика Windows на рассматриваемой машине. Нет необходимости в каком-либо преобразовании или интерпретации. Мы проходим через соответствующие API.

Техническое примечание!. Помните, что проверка свойств непосредственно в исходном файле MSI (таблица свойств) или в исходном файле WiX может не соответствовать фактическим установленным значениям, поскольку свойства могут быть переопределены во время установки через transforms (подробнее см. ниже) - или значения свойств, указанные в командной строке. Мораль истории: извлекайте значения свойств непосредственно из системы, когда сможете.

Быстрая оговорка. В редких случаях запуск script может привести к самовосстановлению установщика Windows. Подробнее в разделе "отказ от ответственности" ниже. Просто потенциальная неприятность, но прочитайте отказ от ответственности.

В качестве отступления существует также однострочная команда PowerShell, которая будет получать коды продуктов и коды обновления только без включения имени пакета. Это может быть достаточно для некоторых пользователей (я бы рекомендовал, чтобы все script ниже). В разделе ниже показан снимок экрана этого однострочного изображения. Примечание: эта команда выглядит намного быстрее, чем больше script (поле "Значение" - это код обновления). Также обратите внимание: коды продуктов без соответствующих кодов обновления не будут отображаться, насколько я могу судить - они будут в более крупном script:

gwmi -Query "SELECT ProductCode,Value FROM Win32_Property WHERE Property='UpgradeCode'" | Format-Table ProductCode,Value

Чтобы запустить полный PowerShell script ниже:

  • Запустите PowerShell (нажмите и удерживайте клавишу Windows, коснитесь R, отпустите клавишу Windows, введите "powershell" и нажмите "ОК" или нажмите "Enter" ).
  • Скопируйте script ниже целиком, а затем просто щелкните правой кнопкой мыши внутри окна PowerShell.
  • Это должно начинаться с script и , для выполнения потребуется довольно много времени.
  • Сообщите о любых проблемах. Я не эксперт PowerShell. Я специалист по развертыванию, а не кодер, но script должен выполнить эту работу.
  • Заметка о производительности. Я просто получаю объект Win32_Product WMI
    • Свойства захвата черри, по-видимому, на самом деле делают ее медленнее (тест VBScript).
    • Думаю, нам все равно нужно собрать все строки, а вишневые колоды - просто лишний подъем?
    • Для Win32_Property мы фильтруем как строки, так и столбцы (код обновления - только один из многих типов строк). Будьте готовы к медленной работе, WMI очень медленный.
$wmipackages = Get-WmiObject -Class win32_product
$wmiproperties = gwmi -Query "SELECT ProductCode,Value FROM Win32_Property WHERE Property='UpgradeCode'"
$packageinfo = New-Object System.Data.Datatable
[void]$packageinfo.Columns.Add("Name")
[void]$packageinfo.Columns.Add("ProductCode")
[void]$packageinfo.Columns.Add("UpgradeCode")

foreach ($package in $wmipackages) 
{
    $foundupgradecode = $false # Assume no upgrade code is found

    foreach ($property in $wmiproperties) {

        if ($package.IdentifyingNumber -eq $property.ProductCode) {
           [void]$packageinfo.Rows.Add($package.Name,$package.IdentifyingNumber, $property.Value)
           $foundupgradecode = $true
           break
        }
    }

    if(-Not ($foundupgradecode)) { 
         # No upgrade code found, add product code to list
         [void]$packageinfo.Rows.Add($package.Name,$package.IdentifyingNumber, "") 
    }

}

$packageinfo | Format-table ProductCode, UpgradeCode, Name

# Enable the following line to export to CSV (good for annotation). Set full path in quotes
# $packageinfo | Export-Csv "[YourFullWriteablePath]\MsiInfo.csv"

# copy this line as well

Работа на удаленных машинах

  • Должно быть относительно легко расширить script выше, чтобы работать на удаленных компьютерах, но я не настроен для его проверки в настоящий момент.
  • Информация ниже немного запуталась, сообщите мне, если это непонятно или неясно.
  • В реальном домене Windows он должен (теоретически) просто в том, чтобы добавлять удаленные машины к самим вызовам WMI (и перебирать список машин - см. ниже), И важно: вы должны использовать реальную учетную запись администратора домена для запуска запроса. Возможно, что изменения, перечисленные ниже, чтобы заставить работу WMI работать в среде рабочей группы также могут потребоваться для некоторых доменов, я не знаю (правило брандмауэра и настройки реестра UAC). Я бы предположил, что реальная учетная запись администратора домена должна иметь привилегии и доступ, необходимые, хотя.
  • Удаленные подключения в WMI затронуты (по крайней мере) параметрами Брандмауэр Windows, DCOM, Настройки CIMOM и Учетная запись пользователя Control (UAC) (плюс любые дополнительные факторы, отличные от Microsoft), например, реальные брандмауэры, сторонние программные брандмауэры, программное обеспечение безопасности различного рода и т.д.). Вот несколько деталей:
  • В не-доменных сетях (малый офис, домашний и т.д.) вам, вероятно, придется добавлять учетные данные пользователя непосредственно к вызовам WMI, чтобы заставить его работать. Вероятно, вы должны иметь "настоящие права администратора" на соответствующих машинах, чтобы запросы выполнялись удаленно в домашней сети (рабочей группе). Я слышал, что встроенная учетная запись администратора не имеет проблем с UAC, но я никогда не пробовал ее. По-моему: не используйте эту учетную запись.
    • В моем тестировании мне пришлось (1) обновить правила брандмауэра Windows и ( 2) отключить фильтрацию токенов удаленного доступа UAC и используйте реальную локальную учетную запись администратора на удаленной системе. Обратите внимание, что Я не рекомендую ни одно из этих изменений, просто сообщая, что сработало для меня.
    • Изменить 1: брандмауэр Windows, выполнить команду (cmd.exe, запустить как admin): netsh advfirewall firewall set rule group="windows management instrumentation (wmi)" new enable=yes ( source - см. эту ссылку для командной строки, чтобы снова отключить это новое правило, если вы просто проверяете. По сути просто установите enable = no). См. Связанный источник для потенциально более ограничительных правил, которые также могут работать.
    • Изменить 2. Отключить фильтрацию доступа к токену удаленного UAC: вам нужно установить следующее значение реестра: HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\ LocalAccountTokenFilterPolicy = 1 ( источник - средняя страница, вторая половина). Я установил 32-разрядный DWORD.

С этими изменениями в удаленной системе я также добавил учетные данные пользователя для каждого вызова, запросив пользователя $Cred = Get-Credential. Существуют также более расширенные параметры для определения учетных данных пользователя, как описано здесь: Передача пароля в -credentialздесь). Чтобы протестировать прогон, вот небольшой тест script. Скопируйте все строки ниже, измените имя удаленного компьютера и вставьте его в PowerShell, щелкнув правой кнопкой мыши (вам будут предложены учетные данные):

$Cred = Get-Credential
gwmi -ComputerName RemoteMachineName -credential $Cred -Query "SELECT ProductCode,Value FROM Win32_Property WHERE Property='UpgradeCode'" | Format-Table ProductCode,Value
# copy this line too

Для большого PowerShell script выше, основные дополнения для удаленного запуска на нескольких машинах в домене Windows могут быть примерно такими (я не буду обновлять выше script с тех пор Я не могу это проверить правильно). Не забудьте обновить список имен удаленных компьютеров в верхней части script и запустить с учетной записью администратора домена:

# DOMAIN NETWORK: mock-up / pseudo snippet ONLY - lacks testing, provided "as is"
$ArrComputers = "Computer1", "Computer2", "Computer3"
foreach ($Computer in $ArrComputers) 
{
    # here we modify the WMI calls to add machine name
    $wmipackages = Get-WmiObject -Class win32_product -ComputerName $Computer
    $wmiproperties = gwmi  -ComputerName $Computer -Query "SELECT ProductCode,Value FROM Win32_Property WHERE Property='UpgradeCode'"

    # the rest of the above, large script here (minus the first 2 WMI lines)
}

Чтобы адаптировать один и тот же машинный цикл для не-доменной сети, вы можете добавить учетные данные для вызовов WMI. Что-то вроде этого (вам будет предложено ввести учетные данные для каждой машины, что может ввести в заблуждение). Не забудьте обновить список имен удаленных компьютеров в верхней части script и использовать учетную запись с правами локального администратора в целевом поле:

# WORKGROUP NETWORK: mock-up / pseudo snippet ONLY - lacks testing, provided "as is"
$ArrComputers = "Computer1", "Computer2", "Computer3"
foreach ($Computer in $ArrComputers) 
{
     $Cred = Get-Credential

     # here we modify the WMI calls to add machine name AND credentials
     $wmipackages = Get-WmiObject -Class win32_product -ComputerName $Computer -credential $cred
     $wmiproperties = gwmi  -ComputerName $Computer -credential $cred -Query "SELECT ProductCode,Value FROM Win32_Property WHERE Property='UpgradeCode'"

     # the rest of the above, large script here (minus the first 2 WMI lines) 
}

Настоящий ответ заканчивается здесь. Я полагаю, что вышеозначенный script должен охватывать большинство случаев использования, но я также оставлю содержимое ниже, так как он не устарел, но, вероятно, менее эффективен, чем предыдущий script. Чтение, вероятно, будет повторяющимся.

Сценарии ниже для получения отдельных кодов обновления, а не всего списка могут представлять интерес, если вы хотите получить один код обновления из своего собственного приложения во время выполнения. Я оставлю этот старый контент.

Отказ от ответственности. Вышеупомянутый script использует WMI, а при доступе к классу Win32_Product он запускает проверка целостности установленных пакетов. Это довольно медленно и может очень специальные случаи запускают саморемонт MSI. Это не хорошо, если вы возглавляя важную встречу:-). К счастью, вы должны уметь отменить любой вызванный самообслуживание (но ваш запрос, вероятно, не будет до тех пор, пока вы не закончите ремонт). Быстрая контекстная ссылка (для сохранения).

IMHO: не позволяйте этому останавливать вас от использования WMI - это просто раздражение. Примечание. Оба подхода PowerShell и VBScript, описанные ниже, используют WMI и могут также инициировать эту проблему.


Получение обновленных кодов для файлов MSI, которые не установлены

Если вам нужен код обновления для пакета MSI, который не установлен на вашем компьютере, ознакомьтесь с разделом "Ручной поиск обновленных кодов" внизу для нескольких параметров (по существу посмотрите в Файл MSI или его исходный файл, используемый для его компиляции).

Неверно получить код обновления для установленных пакетов из исходного файла установки MSI или из (WiX) источников, используемых для компиляции MSI, поскольку коды обновления могут быть переопределено во время установки с помощью transforms (подробности в тексте ниже - преобразования - это небольшие фрагменты базы данных, применяемые во время установки, см., что Symantec ссылка).

Программный поиск кодов обновления основан на WMI, и вы можете использовать либо PowerShell или VBScript для вызова WMI. Оба метода представлены ниже. По существу, выполняется следующий запрос WMI для извлечения кода обновления для указанного кода продукта:

SELECT * FROM Win32_Property WHERE Property='UpgradeCode' AND ProductCode='{YourProdGuid}'

Это тот же запрос, который используется как для VBScript, так и для PowerShell. Вы также можете запустить его как прямой запрос WMI с помощью инструмента, такого как WMIExplorer.exe. Очень полезный инструмент - очень рекомендуется. Я считаю, что это их сайт: https://github.com/vinaypamnani/wmie2/releases


Получить единый код обновления через PowerShell/WMI

Вместо того, чтобы выводить всю таблицу со всеми кодами продуктов и кодами обновления, вы можете получить один код обновления для указанного кода продукта. Это хорошо, если вы пытаетесь выполнить извлечение из своего собственного кода приложения (тогда это всего лишь стандартный запрос WMI и не имеет ничего общего с PowerShell).

Ниже приведен код восстановления одного кода с помощью PowerShell (для запуска PowerShell: нажмите и удерживайте клавишу Windows, коснитесь R, отпустите клавишу Windows, введите "powershell" и нажмите "ОК" или нажмите "Enter" ):

gwmi -Query "SELECT Value FROM Win32_Property WHERE Property='UpgradeCode' AND ProductCode='{YourGuid}'" | Format-Table Value

Результат должен быть примерно таким (может быть, немного трудно читать, я должен был использовать более крупные шрифты):

Получение кода обновления с помощью PowerShell - аннотированный

Код продукта, указанный в запросе выше, предназначен для "Windows SDK Intellidocs". Вы, очевидно, должны заменить его собственным кодом продукта. Чтобы найти код продукта, который необходимо передать, вы также можете использовать запрос PowerShell, как описано здесь: Как я могу найти GUID продукта установленной установки MSI?

Возвращенный код обновления поступает прямо из реальной базы данных реестра установщика Windows. Он не требует дальнейшей обработки или интерпретации или шагов ручного преобразования. Это также будет правильным, даже если преобразование изменило исходный код обновления при установке MSI (подробности о проблемах преобразования ниже).

Обновление, специальное уведомление: без излишних усложнений, я считаю, что я нашел ошибку в WMI, которая очень специфична. Когда исходный MSI не имеет установленного кода обновления, и вы добавляете его через преобразование, WMI, похоже, вообще не сообщает код обновления. Однако: если исходный MSI имеет код обновления, и вы переопределяете его в преобразовании, WMI сообщает код обновления преобразования (который ожидается). Я определенно видел это, но вам нужно будет проверить еще один тестовый пакет. Мораль истории: всегда устанавливайте код обновления в MSI! Тогда вы полностью исключаете проблему. И не сгенерируйте его автоматически - жестко запрограммируйте его (см. "Руководство по восстановлению кодов обновления" ниже для объяснения).


Получить единый код обновления с помощью VBScript/WMI (Legacy Approach)

Нет ничего плохого в решении VBScript, найденном ниже - он даже имеет некоторые преимущества по сравнению с PowerShell - несмотря на то, что VBScript является унаследованной технологией. Преимущества в том, что он должен работать на всех машинах, даже если инфраструктура .NET отсутствует (или заблокирована) и на машинах, где PowerShell отсутствует (или заблокирован). Это устаревшее, но жизнеспособное решение, достаточно гибкое (если VBScript также не заблокирован, но все современные версии ОС полностью поддерживают VBScript).

Чтобы сделать как можно проще, чтобы получить код обновления, я создал " bare-bone VBScript", который должен сделать трюк. Он не был протестирован для таргетинга на удаленные компьютеры, даже если WMI должен иметь возможность сделать это по дизайну. script предназначен для запуска в системе, где установлен ваш тайный MSI с неизвестным кодом обновления.

Для этого VBScript требуется код входного продукта (диалоговое окно ввода, отображаемое при запуске script), и затем он будет искать соответствующий код обновления (если есть). Как указано выше, чтобы найти код продукта для вашего MSI, вы можете использовать этот подход: Как я могу найти GUID продукта установленной установки MSI?. Когда у вас есть код продукта (guid), вы можете запустить этот VBScript на целевой машине, и вы получите код обновления, который будет возвращен вам через несколько секунд. Поиск WMI может быть очень медленным.

'
' Purpose: Barebone / minimal VBScript implementation to allow retrieval of MSI UpgradeCodes via WMI.
'
' Version: 0.2, September.2017 - Stein Åsmul.
'
' Notes:
'
'  - As it stands, this script is intended to be run interactively (WScript).
'  - Conversion to run via CScript should be trivial (nothing ever is...)
'  - The script will ask the user to provide a valid product GUID for an installed MSI.
'  - To find a valid product GUID for your system, perhaps see this SO answer: https://stackoverflow.com/a/29937569/129130
'  - The script does not RegEx anything to check for valid GUID format (this is barebone - as terse as possible,
'    with as little as possible included that can break).
'
' UPDATE: for information on remote running, check "Running on remote machines" section here:
' https://stackoverflow.com/a/46637095/129130 (firewall and registry change seems to be needed).

strComputer = "."
' Remote connections was NOT tested for this script. In principle you should just add the machine name to "strComputer" above.
' AFAIK you must have "real" admin rights on the box you try to connect to. Many users report intermittent problems running remote WMI.
' Remote connections in WMI are affected by the Windows Firewall, DCOM settings, and User Account Control (UAC).
'    - Setting up a Remote WMI Connection: https://msdn.microsoft.com/en-us/library/aa822854(v=vs.85).aspx
'    - Connecting to WMI on a Remote Computer: https://msdn.microsoft.com/en-us/library/aa389290(v=vs.85).aspx
'    - Perhaps useful: https://social.technet.microsoft.com/Forums/lync/en-US/05205b52-0e43-4ce3-a8b8-58ec4c2edea5/wmi-generic-failure-when-accessing-win32product-remotely?forum=winserverManagement
'    - Maybe it is also worth noting that I think WMI queries can be slow enough to trigger timeouts,
'      and then you have the old favorite: intermittent bugs.

Set owmi = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")

' User interaction
productcode = InputBox("Please paste or type in the product code for the product whose upgrade code you want " + _
                       "to retrieve (not case sensitive, a blank product code will abort the script)." + vbNewLine + vbNewLine + _
                       "Please note that the script can take up to a minute to run due to WMI slowness.", "UpgradeCode retrieval:")
If productcode = vbCancel Or Trim(productcode) = "" Then
   WScript.Quit(0)
End If

' Run WMI call and verify that it completes successfully.
On Error Resume Next
Set upgradecode = owmi.ExecQuery("SELECT Value FROM Win32_Property WHERE Property='UpgradeCode' AND ProductCode='" & productcode & "'")
If (Err.number <> 0) Then
   MsgBox "The WMI query failed, this is a critical error - aborting.", vbCritical, "Fatal error."
   WScript.Quit(2) ' Following exit code "standard" from MSI SDK automation samples
End If
On Error GoTo 0

' Report results.
Select Case upgradecode.count

   Case 0
       ' We have to provide a separate message for this state, since some packages may not have an UpgradeCode.
       ' However, the product GUID could also have been misspelled.
       MsgBox "No UpgradeCode was found, are you sure you entered the correct product GUID?" & vbNewLine & vbNewLine & _
              "Note: It is possible for a product to NOT have an UpgradeCode.", vbInformation, "No UpgradeCode found."

   Case 1
      ' The "default state" - should cover almost all normal packages.

      ' Only one upgrade code should have been retrieved, and it can be referenced by upgradecode.ItemIndex(0).Value on newer systems 
      ' (Vista and later), but on XP this apparently does not work (never tested by me), for compatibility we use a standard For Each 
      ' enumeration instead. Source: https://stackoverflow.com/info/2378723/get-first-record-from-wmi-execquery

      For Each u in upgradecode
        Msgbox "The Upgrade Code is: " & u.Value & vbNewLine & vbNewLine & _
              "Just press CTRL + C to copy all text in this dialog (then paste to notepad or similar to extract the GUID).", _
              vbInformation, "UpgradeCode found."
          ' Exit For
      Next

   Case Else
       ' Should never get here - let us know if you do get this message.
       MsgBox "An error occurred, the query returned more than one result. There can only be one UpgradeCode. " & _ 
              "Please report this error on StackOverflow", vbInformation, "Error while retrieving UpgradeCode."
End Select

Получение всех кодов обновления и кода продукта на машине

Я должен упомянуть, что у меня есть большой VBScript, который будет генерировать всеобъемлющий HTML-отчет для всех установленных пакетов MSI на машина работает на. Это включает в себя все код обновления и список связанных коды продуктов (коды продуктов, которые имеют один и тот же код обновления). Однако я не очень доволен кодом (я специалист по развертыванию, а не кодер). scriptслишком велико, слишком медленно и слишком непроверено для использования, поэтому я создаю найденный выше голый костяной VBScript, чтобы выполнить поиск для одного упаковка только. Этот script гораздо проще проверить и изменить для вашего собственное использование. Я могу предоставить этот большой VBScript для тестирования, если это интересно. Он доступен только для чтения, кроме одного выходного файла HTML в "Мои документы". Необходимо также адаптировать этот script для использования на удаленных компьютерах.

Существует команда one-line PowerShell для получения всех кодов продуктов и связанных с ними кодов обновления, но на этом выходе нет названия продуктов. Я включаю его здесь для полноты:

gwmi -Query "SELECT ProductCode,Value FROM Win32_Property WHERE Property='UpgradeCode'" | Format-Table ProductCode,Value

Выход будет похож на это (поле "Значение" - это код обновления - коды продуктов без соответствующих кодов обновления не будут отображаться, насколько я могу судить):

вывод всех кодов обновления и кодов продуктов


Ручной поиск обновленных кодов

В этом разделе перечислены некоторые "ручные способы" для извлечения кодов обновления, которым не нужны никакие кодировки или командные строки. Эти ручные подходы не рекомендуемые. Я включаю их только потому, что пытается стать " справочным ответом". Необходимо предоставить несколько различных вариантов. Моя рекомендация заключается в использовании PowerShell или VBScript, приведенных выше.

Как говорится, коды обновления, как правило, никогда не изменяются в разных версиях вашего продукта, поэтому есть вероятность, что вы можете попробовать тот, который вы найдете в самом файле MSI, или в источнике, используемом для его компиляции, как описано ниже. Проблема, о которой уже упоминалось несколько раз, заключается в том, что преобразование может изменить коды обновления во время установки, поэтому вам необходимо получить код обновления программно, если вы хотите убедиться, что нашли правильный. Если вы не пытаетесь получить код обновления из MSI, который не установлен в вашей системе. Тогда вам просто нужен просмотрщик файлов MSI, как описано ниже в пункте 1 маркировки.

A transform - это просто фрагмент базы данных с изменениями, которые применяются к исходному MSI во время установки. Это инструмент, который в основном используется для упаковки корпоративных приложений для изменения инсталляторов без изменения файлов MSI напрямую. Преобразования имеют расширение .mst. Изменение кода обновления с помощью преобразования является необычным, но не неслыханным - особенно для корпоративной переупаковки. В редких случаях упаковщики приложений могут преднамеренно изменить руководство по обновлению, чтобы позволить им доставлять собственные обновления для установленных пакетов (вместо того, чтобы напрямую ссылаться на обновления поставщика). Редкий, но я видел это. Является ли это хорошо или не очень спорно.

Простые, ручные способы, чтобы найти коды обновления MSI:

  • Хотя оскорбительно очевидно, самый простой способ найти код обновления - открыть оригинальный MSI, используемый для установки продукта, и найти код обновления в таблице свойств. Все, что вам нужно - это инструмент, способный открывать файлы MSI. Вот некоторые инструменты: Какой установочный продукт использовать? InstallShield, WiX, Wise, Advanced Installer и т.д., Самая быстрая ставка - это, скорее всего, Orca, если у вас установлена ​​Visual Studio (поиск Orca-x86_en-us.msi и ее установка - это официальный Microsoft, официальный просмотрщик и редактор MSI) или Super Orca, если у вас нет установленной Visual Studio (следуйте приведенному выше ссылку, чтобы найти его).

  • Если вы являетесь разработчиком с использованием WiX (или любого другого инструмента развертывания), вы можете явно легко найти код обновления в исходном файле WiX, который использовался для компиляции вашего MSI (или Installshield source, Advanced Installer source или любой другой инструмент развертывания, который вы используете).

    • Не позволяйте нам сбрасывать ручку здесь со слишком значимым советом, который загромождает основную проблему, но вы должны явно жестко кодировать код обновления в своем источнике, а никогда не автогенерировать это
    • Коды обновления определяют " семейства связанных продуктов" и должны оставаться стабильными в версиях (версиях). В большинстве случаев он должен оставаться стабильным и в языковых версиях. Точная настройка зависит от требований к развертыванию.
    • Если продукты должны быть в состоянии существовать бок о бок, у вас обычно есть разные коды обновления для продуктов, которые должны сосуществовать.
    • Правило большого пальца: сохраняйте коды обновления стабильными как можно дольше, когда это возможно. Измените их, когда требования абсолютно требуются.
    • Чтобы обернуть вещи: никогда не используйте один и тот же код обновления для разных продуктов, у которых есть свой " жизненный цикл" и никакого реального отношения друг к другу. Они не связаны. Это так же важно, как сохранение стабильного кода обновления для связанных продуктов. Подумайте " жизненный цикл" и " отношение семейного отношения" и " сосуществование".
    • Это было большое отступление, вернувшись к проблеме: найти коды обновления.
  • Даже если у вас нет оригинальной MSI, даже можно найти кешированный MSI из исходной установки в папке %SystemRoot%\Installer. Файлы MSI здесь имеют загадочное шестнадцатеричное имя, но это всего лишь копии исходных файлов MSI, используемых для установки различных продуктов - кэшированных в безопасном месте, чтобы быть доступными для операций по модификации, ремонту и деинсталляции. Что бы вы ни делали, не вмешивайтесь в эту папку. Никогда, никогда ничего не удаляйте. Вы можете найти MSI, который установил ваш продукт, выбрав первый файл MSI и проверив строку состояния Windows Explorer, что имя продукта для старой версии Windows. В Windows 10 кажется, что вы можете навести курсор мыши на MSI с указателем, и вы получите всплывающее окно с некоторыми подробностями MSI. Затем вы просто щелкаете по списку, пока не найдете нужный продукт, и откройте MSI и найдите код обновления в таблице свойств.

  • Некоторые люди используют реестр для чтения кодов обновления: Как найти код обновления для установленного приложения на С#?. По-моему, это не очень хороший подход, есть лучшие способы - например, использование PowerShell, как описано выше. Нет необходимости в этом преобразовании и интерпретации упакованных GUID (это формат GUID, используемый в базе данных реестра установщика Windows).

Это должно завершить основные "ручные методы", чтобы быстро получить код обновления. Просто некоторые методы для арсенала, которые иногда достаточно хороши. Возможно, еще несколько способов забыть.

Предпочитаете программные подходы, но если вы находитесь в спешке и работаете без использования всех ваших инструментов, некоторые ручные опции хороши. Однако некоторые из этих ручных методов требуют больше инструментов, чем командная строка PowerShell (вам нужен просмотрщик файлов MSI, который не всегда доступен в поле, если вы находитесь в "службе поддержки" кому-то). Пришло время использовать PowerShell (да, я тоже устарел).

Кстати, файлы MSI по существу удаляются из баз данных SQL Server, хранящихся в виде файлов хранения в формате COM (формат файлов MS Office). По существу файловая система в файле с потоками хранения различных типов.

Если вы застряли на машине без средства просмотра MSI, вы можете запросить кэшированные базы данных MSI непосредственно из PowerShell: