Как скачать установщик MSI с аргументом для идентификатора пользователя

У меня есть приложение.NET C#, обернутое в установщик MSI - "myprogram.exe". У меня есть веб-сайт PHP и определенная страница, где пользователь может скачать программу по ссылке.

Я хотел бы иметь возможность отслеживать определенные события в приложении.NET. Например - "Программа открыта".

На мой сервер легко отправлять события, однако как мне получить идентификатор пользователя с сервера php, чтобы я мог знать, какой пользователь что делал в приложении.NET?

Я думал о передаче аргумента (идентификатора пользователя) установщику MSI, но не смог найти путь к этому.

Как связать между идентификатором пользователя PHP и приложением.NET?

Пояснение -

Многие люди предлагали использовать систему входа в систему для связи между сервером и приложением.

Это действительно самое простое решение, однако на моем веб-сайте я не вынуждаю пользователя войти в систему, чтобы загрузить приложение (и не запрашиваю данные для входа в приложение.NET - это необязательно). Если нам не нужно запрашивать данные для входа, я думаю, что нет, пользовательский опыт будет намного лучше (гораздо меньше шагов для использования приложения) - у пользователя будет больше шансов загрузить и использовать приложение Desktop.

Учтите, что текущий поток -> веб-страница - загрузка клика - запуск - использование приложения (занимает 10 секунд)

При входе в систему -> Веб-страница - Зарегистрироваться (подтвердить адрес электронной почты?) - Перенаправить - Загрузить Нажмите - Запустить - Вход в приложение - Использовать приложение (пользователю требуется 60-120 секунд)

3 ответа

Решение

Вход из программы

Лучший способ - позволить пользователю войти в систему с теми же учетными данными в вашей программе. Таким образом, ваша программа может использовать безопасную аутентификацию OAuth2 для взаимодействия с вашим внутренним API. Это также делает прозрачным для пользователя, что программа общается с Интернетом.

Включить идентификатор пользователя в имя файла

Другой способ - добавить идентификатор пользователя к имени файла программы установки во время загрузки и извлечь его при запуске программы установки. Вам нужно будет проверить, позволяет ли это ваш установщик. Кроме того, делайте это только в том случае, если вы используете UUID или что-то подобное, поскольку вы не хотите, чтобы пользователь угадывал другие идентификаторы.

App.config

Третий вариант - добавить идентификатор пользователя к App.config файл. Есть два способа сделать это:

  1. Создайте свой MSI с App.config без сжатия добавьте настройку идентификатора пользователя с фиксированным UUID. Ваш скрипт PHP может найти UUID и заменить его в двоичном файле MSI перед отправкой пользователю. Смотрите фрагмент кода под MST-преобразованием.
  2. Сборка.msi по требованию с обычаем App.config, Это будет работать только в том случае, если ваш веб-сервер работает в Windows или у вас есть удаленный сервер сборки Windows, который может выполнить эту работу.

MST преобразование

Вы также можете использовать MST-преобразование и использовать тот же трюк двоичной замены, который я объяснил для пункта 1 в App.config.

Для обоих вариантов вы можете использовать PHP-скрипт, который использует бинарно-безопасные функции для замены значений в установщике и отправляет файл пользователю для загрузки:

<?php
$userId = // TODO get userId from the session or database
$data = file_get_contents("./my-installer.msi");
// I would use UUID's for template and userId, this way the size of the installer remains the same after replace
$data = str_replace("{fe06bd4e-4bed-4954-be14-42fb79a79817}", $userId, $data);
// Return the file as download
header("Cache-Control: public"); // needed for i.e.
header('Content-Disposition: attachment; filename=my-installer.msi');
header('Content-Type: application/x-msi');
header("Content-Transfer-Encoding: Binary");
echo $data;
?>

Серийный номер

Последний способ, о котором я могу подумать, - это позволить программе запрашивать серийный номер при первом запуске и позволить вашему веб-сайту генерировать уникальный серийный номер для каждого пользователя.

Хм, пожалуйста, обратите внимание, очень вероятно, что это не то, что вы хотите сделать. Тем не менее, я объясню пару способов сделать это..

Использование файлов MST с MSI:

Вы можете создавать MST-файлы со свойством user-id и генерировать их для каждого пользователя, когда они загружают MSI, и заставляют их устанавливать MSI с преобразованием:

msiexec -i c:\temp\The.msi transforms=c:\temp\YourPerso.mst

См. Дополнительную информацию здесь: Установите преобразование с помощью командной строки.

Вы видите, что файлы MST часто используются в крупных организациях, где все MSI имеют файлы MST со встроенными серийными номерами и т. Д.

Для создания MST-файла вам необходимо скачать и установить Microsoft Orca Tool, входящую в состав Microsoft Windows SDK.

Откройте Orca и создайте файл MST из файла MSI. В основном вы открываете MSI-файл, переходите к таблице "Свойство", там вы видите список параметров. Обратите внимание, что в файле MSI вы увидите параметры, которые требуют значения по умолчанию.

Прежде чем добавлять / изменять параметры, создайте новое Преобразование, щелкнув в меню "Преобразование" -> "Новое преобразование".

После этого вы можете изменить параметры или добавить новые, как вы хотите. Когда вы закончите изменения параметров, используйте функцию "Generate Transform" в меню "Transform" для генерации MST-файла.

Если вы затем откроете файл MST с помощью HexEditor, вы увидите только что добавленное свойство:

Вы можете редактировать файл для каждой загрузки, просто редактируя значение, например:

Конечно, вы можете (и, вероятно, должны) сделать это надлежащим образом, используя API-интерфейс WindowsInstaller.Installer. Вот пример:

private function createTransform(mstfile, msi, config)
    writeLog InfoLog, "Generating transform " & mstfile

    dim vars: set vars = configvars(config)

    dim createPropertyTable: createPropertyTable = "create table `Property` " & _
        "(`Property` char(72) not null, `Value` longchar localizable " & _
        "primary key `Property`)"
    dim addProperty: addProperty = "insert into `Property` (`Property`, `Value`) values (?, ?)"
    dim updateProperty: updateProperty = "update `Property` set `Value` = ? where `Property` = ?"

    dim wi: set wi = createObject("WindowsInstaller.Installer")
    dim base: set base = wi.openDatabase("base.msi", msiOpenDatabaseModeCreate)
    base.openview(createPropertyTable).execute
    dim tgt: set tgt = wi.openDatabase("tgt.msi", msiOpenDatabaseModeCreate)
    tgt.openview(createPropertyTable).execute
    dim props: set props = createObject("scripting.dictionary")
    dim view: set view = msi.openView("select `Property`, `Value` from `Property`") 
    view.execute        
    dim record: set record = view.fetch
    while not record is nothing
        props(record.stringdata(1)) = true
        base.openview(addProperty).execute record
        tgt.openview(addProperty).execute record    
        set record = view.fetch
    wend

    set record = wi.createRecord(2)
    dim prop
    for each prop in properties_
        on error resume next
        dim val: val = expand(vars, prop(DepPropertyValueIdx))
        if err then
            writeLog ErrorLog, err.description
            exit function
        end if
        on error goto 0
        writeLog InfoLog, "Property " & prop(DepPropertyNameIdx) & "=" & val
        if props.exists(prop(DepPropertyNameIdx)) then
            record.stringdata(2) = prop(DepPropertyNameIdx)
            record.stringdata(1) = val
            tgt.openview(updateProperty).execute record
        else
            record.stringdata(1) = prop(DepPropertyNameIdx)
            record.stringdata(2) = val
            tgt.openview(addProperty).execute record
        end if
    next
    if not tgt.generateTransform(base, mstfile) then
        writeLog ErrorLog, "Failed to create transform"
        exit function
    end if
    tgt.createTransformSummaryInfo msi, mstfile, 0, 0
    createTransform = true
end function

Подсказка: чтобы сделать это с помощью управляемого кода, лучше всего использовать Microsoft.Deployment.WindowsInstaller.dll это доступно как часть http://wix.codeplex.com/


Создайте MSI для каждого пользователя:

ИМХО, было бы намного проще сделать это с помощью Nullsoft (WiX, InstallShield, INNO и т. Д.) И создать MSI для каждого пользователя. Для этого вы должны встраивать уникальный идентификатор пользователя, например, в скрипт nsi, и запускать сборку MSI для каждой загрузки. Во время установки уникальный идентификатор пользователя будет храниться в файле, разделе реестра и т. Д. Я предлагаю вам попробовать, используя этот редактор NSIS Wizard, чтобы быстро создать базовый сценарий установки NSI и построить MSI с помощью командной строки: makensis.

Примечание. Хотя "Включение идентификатора пользователя в имя файла MSI" проще, чем создание MSI для каждого пользователя, пользователи могут легко изменить имя файла. Гораздо менее вероятно, что пользователь будет проверять MSI с помощью Orca, чтобы найти встроенный идентификатор пользователя.


Самый простой и логичный способ:

На мой сервер легко отправлять события, однако как мне получить идентификатор пользователя с сервера php, чтобы я мог знать, какой пользователь что делал в приложении.NET?

Сделайте то, что @Jhuliano Moreno, а затем @WouterHuysentruit рекомендовал:

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

Когда файл вызывается, отправьте параметр UserID, если вы используете MVC-фреймворк в вашем PHP, вам понадобится новый контроллер, который получает MSI-файл и переименовывает его в name-userID.exe, а затем возвращает файл для загрузки. через браузер.

Другие вопросы по тегам