Перейти к основному содержимому

Как сделать установщик

Разработчику

Готовая программа редко состоит из одного .exe. Обычно нужны папка с файлами, ярлык, запись об установке и возможность удалить всё без ручной охоты по Program Files. Установщик автоматизирует этот сценарий: пользователь запускает один файл — и через минуту может работать.

Загрузка мастера установки…

См. также: Исполняемые файлы (в т.ч. MSI и установочные пакеты), Архивы и установочные пакеты, Распространение десктопных приложений, Microsoft Store и MSIX, Electron — сборка установщика.


Содержание


Что такое установщик

Установочный файл (часто Setup.exe, MyApp-1.0.0-installer.exe) — программа, которая разворачивает ваше приложение на компьютере пользователя. Внутри неё обычно лежит сжатый набор файлов (как в архиве) и логика: куда копировать, что проверить, что записать в систему.

Установочный пакет — более широкое понятие: сам дистрибутив плюс метаданные (версия, зависимости, права). Примеры форматов пакетов без «своего» GUI: .msi (Windows Installer), .deb / .rpm (Linux), .msix (Store). Примеры собственного мастера установки: Inno Setup, NSIS, WiX, скрипт на PowerShell/Python, приложение на C#.

Главная цель для пользователя и разработчика одна: быстро и предсказуемо получить рабочую копию программы — без ручного копирования десятков файлов и без гадания «куда положить DLL».

Как это выглядит для пользователя

  1. Скачал один файл с сайта или получил по ссылке.
  2. Запустил (Windows может спросить права администратора).
  3. Прошёл мастер: папка → компоненты → «Установить».
  4. Появился ярлык; приложение запускается.
  5. При необходимости — «Удалить программу» в параметрах Windows (если установщик зарегистрировал деинсталлятор).

Что такое setup.exe

Имя setup.exe — устоявшееся соглашение, не отдельный формат. Это обычный PE-исполняемый файл (исполняемые файлы), внутри которого может быть:

  • оболочка Inno Setup / NSIS / InstallShield;
  • bootstrap Visual Studio (vs_setup.exe);
  • ваш скрипт, упакованный через PyInstaller;
  • MSI, переименованный или обёрнутый в EXE (редко, но встречается).

Антивирусы и SmartScreen смотрят на подпись издателя и репутацию файла, а не на слово setup в имени.

Отличие от «просто ZIP»

Архив только распаковывает файлы. Установщик ещё проверяет ОС, создаёт ярлыки, пишет ключ в реестр для удаления и может поставить зависимости (runtime). Подробнее — в статье «Архивы и установочные пакеты».


Архитектура: что обязан делать установщик

Минимальная логика любого приличного установщика:

ЭтапЗадача
До установкиПроверить ОС (64-bit?), свободное место, не занята ли ли уже другая версия
Выбор путиПапка по умолчанию (%ProgramFiles%\Vendor\App) и возможность изменить
КопированиеФайлы приложения, ресурсы, конфиги по умолчанию
ИнтеграцияЯрлыки (меню «Пуск», при необходимости рабочий стол), ассоциации файлов
РегистрацияЗапись в «Приложения и компоненты» — чтобы работало удаление
После установкиОпционально: запуск приложения, открытие README
ДеинсталляторСкрипт или unins000.exe, который удаляет скопированное и чистит записи

Права администратора

Установка в C:\Program Files требует повышения прав (UAC). Если ставите только в профиль пользователя (%LocalAppData%\Programs\MyApp), админ часто не нужен — так делают многие «портативные» и Electron-сборки.

Куда ставимТипичные права
Program FilesАдминистратор
%LocalAppData%Обычный пользователь
Запись в HKLM (машина)Администратор
Запись в HKCU (текущий пользователь)Обычный пользователь

Проверка папки

Перед копированием стоит убедиться:

  • путь существует или его можно создать;
  • на диске достаточно места;
  • нет конфликта с запущенным процессом (файлы не заблокированы);
  • при обновлении — корректно перезаписать или сначала остановить старую версию.

Деинсталлятор

В Windows список «Установка и удаление программ» питается из реестра:

  • HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall\{GUID} — для всех пользователей;
  • HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall\{GUID} — только для текущего.

Ключевые поля: DisplayName, UninstallString, InstallLocation, DisplayVersion, Publisher.

Без этой записи пользователь будет удалять папку вручную — и часто оставит мусор в реестре и в %AppData%.

Что ещё учесть

  • Зависимости: .NET, VC++ Redistributable, WebView2 — либо включить в установщик, либо проверить и скачать (self-contained сборка .NET).
  • Обновления: тот же GUID в Uninstall, инкремент версии, опция «удалить старую перед копированием».
  • Подпись кода: Authenticode снижает предупреждения SmartScreen (дистрибуция).
  • Тихая установка: ключи /SILENT, /VERYSILENT (Inno), /quiet (MSI) — для IT и CI.

Публикация в Microsoft Store — отдельный путь через MSIX, без классического setup.exe: 117.


Inno Setup

Inno Setup — бесплатный установщик для Windows с декларативным скриптом .iss и визуальным мастером Inno Setup Compiler. Подходит, когда нужен привычный мастер «Далее → Далее → Готово» без написания GUI на C#.

Плюсы: быстрый старт, встроенное сжатие LZMA, деинсталлятор, локализация, тихий режим.
Минусы: только Windows; сложная кастомная логика — через Pascal-скрипты в [Code].

Минимальный пример MyApp.iss:

#define MyAppName "My Demo App"
#define MyAppVersion "1.0.0"
#define MyAppPublisher "IT Universe"
#define MyAppExeName "MyApp.exe"

[Setup]
AppId={{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppPublisher={#MyAppPublisher}
DefaultDirName={autopf}\{#MyAppName}
DefaultGroupName={#MyAppName}
OutputBaseFilename=MyApp-{#MyAppVersion}-setup
Compression=lzma2
SolidCompression=yes
PrivilegesRequired=admin

[Languages]
Name: "russian"; MessagesFile: "compiler:Languages\Russian.isl"

[Files]
Source: "publish\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs

[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon

[Tasks]
Name: "desktopicon"; Description: "Ярлык на рабочем столе"; GroupDescription: "Дополнительно:"

[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "Запустить {#MyAppName}"; Flags: nowait postinstall skipifsilent

Сборка: положите результат dotnet publish или Release-сборку в папку publish\, откройте .iss в Inno Setup Compiler → Compile. На выходе — один MyApp-1.0.0-setup.exe.

Официальная документация и примеры — на jrsoftware.org.


Скрипт на PowerShell

Скриптовый установщик уместен для внутренних утилит, CI и админов: без GUI, зато прозрачная логика в репозитории. Запуск: правый клик → «Выполнить с PowerShell» или powershell -ExecutionPolicy Bypass -File install.ps1.

Структура проекта:

installer/
install.ps1
payload/ ← сюда кладёте собранное приложение
MyApp.exe
appsettings.json

Пример install.ps1 (упрощённо, без GUI):

#Requires -RunAsAdministrator
$ErrorActionPreference = "Stop"

$AppName = "MyDemoApp"
$Version = "1.0.0"
$InstallRoot = Join-Path $env:ProgramFiles $AppName
$PayloadDir = Join-Path $PSScriptRoot "payload"
$UninstallKey = "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\$AppName"

if (-not (Test-Path $PayloadDir)) {
throw "Не найдена папка payload рядом со скриптом."
}

$requiredMb = 50
$drive = (Split-Path $InstallRoot -Qualifier)
$freeMb = (Get-PSDrive ($drive.TrimEnd(':'))).Free / 1MB
if ($freeMb -lt $requiredMb) {
throw "Недостаточно места на диске (нужно ~$requiredMb МБ)."
}

if (Test-Path $InstallRoot) {
Write-Host "Обновление: удаляем предыдущую копию..."
Remove-Item $InstallRoot -Recurse -Force
}
New-Item -ItemType Directory -Path $InstallRoot -Force | Out-Null
Copy-Item -Path (Join-Path $PayloadDir "*") -Destination $InstallRoot -Recurse -Force

$exePath = Join-Path $InstallRoot "MyApp.exe"
$uninstallScript = Join-Path $InstallRoot "uninstall.ps1"
@'
Remove-Item -LiteralPath $PSScriptRoot -Recurse -Force
Remove-Item -Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\MyDemoApp" -ErrorAction SilentlyContinue
'@ | Set-Content -Path $uninstallScript -Encoding UTF8

New-Item -Path $UninstallKey -Force | Out-Null
Set-ItemProperty -Path $UninstallKey -Name DisplayName -Value $AppName
Set-ItemProperty -Path $UninstallKey -Name DisplayVersion -Value $Version
Set-ItemProperty -Path $UninstallKey -Name Publisher -Value "IT Universe"
Set-ItemProperty -Path $UninstallKey -Name InstallLocation -Value $InstallRoot
Set-ItemProperty -Path $UninstallKey -Name UninstallString -Value "powershell.exe -ExecutionPolicy Bypass -File `"$uninstallScript`""

$WshShell = New-Object -ComObject WScript.Shell
$Shortcut = $WshShell.CreateShortcut("$env:ProgramData\Microsoft\Windows\Start Menu\Programs\$AppName.lnk")
$Shortcut.TargetPath = $exePath
$Shortcut.WorkingDirectory = $InstallRoot
$Shortcut.Save()

Write-Host "Установлено в $InstallRoot"

Ограничения: Execution Policy, предупреждения SmartScreen для неподписанных .ps1, слабее UX, чем у Inno. Для обучения и автоматизации — отличный первый шаг. См. PowerShell в терминале.


Скрипт на Python и PyInstaller

Python удобен, когда установщик должен быть кроссплатформенным (Windows / macOS / Linux): одна логика на pathlib и shutil, разные пути по умолчанию.

Пример installer.py (консольный, без GUI):

#!/usr/bin/env python3
"""Простой установщик: копирует payload/ в каталог приложения."""

from __future__ import annotations

import argparse
import platform
import shutil
import sys
from pathlib import Path

APP_NAME = "MyDemoApp"
VERSION = "1.0.0"


def default_install_dir() -> Path:
system = platform.system()
if system == "Windows":
base = Path.home() / "AppData" / "Local" / "Programs"
elif system == "Darwin":
base = Path.home() / "Applications"
else:
base = Path.home() / ".local" / "share"
return base / APP_NAME


def install(target: Path, payload: Path) -> None:
if not payload.is_dir():
raise FileNotFoundError(f"Нет папки payload: {payload}")
if target.exists():
shutil.rmtree(target)
target.parent.mkdir(parents=True, exist_ok=True)
shutil.copytree(payload, target)
print(f"{APP_NAME} {VERSION} установлен в {target}")


def main() -> int:
parser = argparse.ArgumentParser(description=f"Установщик {APP_NAME}")
parser.add_argument(
"--dir",
type=Path,
default=default_install_dir(),
help="Каталог установки",
)
args = parser.parse_args()
script_dir = Path(__file__).resolve().parent
payload = script_dir / "payload"
try:
install(args.dir.resolve(), payload)
except OSError as exc:
print(f"Ошибка: {exc}", file=sys.stderr)
return 1
return 0


if __name__ == "__main__":
raise SystemExit(main())

Рядом с скриптом — папка payload/ с MyApp.exe или всей сборкой.

Один файл для Windows: PyInstaller

Чтобы раздать пользователю один .exe без установленного Python:

pip install pyinstaller
pyinstaller --onefile --noconsole installer.py
  • --onefile — всё в одном исполняемом файле (при старте распаковка во временную папку).
  • --noconsole — без чёрного окна (для GUI-установщика; для отладки уберите флаг).

Артефакт: dist/installer.exe. Его можно положить на сайт как «портативный установщик». Для полноценного мастера с шагами позже тот же скрипт оборачивают в tkinter / PyQt или собирают Inno поверх папки payload.

Связь с упаковкой Python-приложений: раздел про PyInstaller в Исполняемых файлах.


Установщик на C# (WinForms / WPF)

Когда нужен свой интерфейс (брендинг, лицензия, выбор компонентов, прогресс-бар с логом) — пишут отдельное desktop-приложение-установщик на .NET. Обычно это WinForms (быстрее для простого мастера) или WPF (гибче вёрстка). См. WinForms, WPF, примеры в Lab.

Типичная архитектура:

  1. UI — несколько страниц (UserControl / Page): приветствие → путь → прогресс → готово.
  2. InstallService — копирование, проверки, запись в реестр (класс без привязки к UI).
  3. Rollback — при ошибке на середине удалить уже скопированное.

Фрагмент сервиса установки (ядро логики):

using System.IO;
using Microsoft.Win32;

public sealed class InstallService
{
private const string UninstallKeyPath =
@"Software\Microsoft\Windows\CurrentVersion\Uninstall\MyDemoApp";

public void Install(string sourceDir, string targetDir, string publisher, string version)
{
if (!Directory.Exists(sourceDir))
throw new DirectoryNotFoundException(sourceDir);

Directory.CreateDirectory(targetDir);
CopyAll(new DirectoryInfo(sourceDir), new DirectoryInfo(targetDir));

using var key = Registry.LocalMachine.CreateSubKey(UninstallKeyPath, true);
key.SetValue("DisplayName", "My Demo App");
key.SetValue("DisplayVersion", version);
key.SetValue("Publisher", publisher);
key.SetValue("InstallLocation", targetDir);
key.SetValue("UninstallString", $"\"{Path.Combine(targetDir, "uninstall.exe")}\"");
}

private static void CopyAll(DirectoryInfo source, DirectoryInfo target)
{
target.Create();
foreach (var file in source.GetFiles())
file.CopyTo(Path.Combine(target.FullName, file.Name), overwrite: true);
foreach (var dir in source.GetDirectories())
CopyAll(dir, target.CreateSubdirectory(dir.Name));
}
}

Деинсталлятор — отдельный маленький проект Uninstall.exe (или тот же код с флагом --uninstall), который читает InstallLocation, удаляет дерево файлов и ветку реестра.

Сборка release:

dotnet publish installer/Installer.csproj -c Release -r win-x64 --self-contained false

Для распространения без установленного .NET на машине пользователя добавьте --self-contained true или положите VC++ / .NET runtime в Inno Setup.

WinForms-мастер: форма с Button «Далее», TextBox для пути (FolderBrowserDialog), ProgressBar + фоновый Task.Run для копирования (не блокировать UI — см. 112).


Повторное использование демо в других статьях

Тот же мастер можно вставить в гайды по установке IDE, runtime или первой программы — с другими текстами через props:

import InstallerWizardPlay from '@site/src/components/InstallerWizardPlay.jsx';

<InstallerWizardPlay
appName="Установка Visual Studio"
productName="Visual Studio Community"
welcomeText="Мастер установит среду разработки и выбранные рабочие нагрузки."
/>

Доступные props: appName, productName, welcomeText, pathDescription, defaultPath, extraOptionsLabel, cardTitle, cardSubtitle, showCard (если false — только окно мастера без обёртки карточки).


Сравнение подходов

ПодходСложностьGUIКроссплатформаТипичное применение
Inno SetupНизкаяГотовый мастерWindowsРелизы Win32/.NET для сайта
PowerShellНизкаяНет (можно дописать)В основном WindowsIT, внутренние tools
Python + PyInstallerСредняяПо желанию (tkinter)ДаУтилиты, прототипы
C# WinForms/WPFВысокаяПолный контрольWindows (.NET)Бренд, сложные сценарии
MSI / MSIXСредняя–высокаяСтандарт WindowsWindowsКорпорации, Store (117)
electron-builderСредняяЗависит от toolWin/mac/LinuxElectron-приложения (114)

Чек-лист перед релизом

  • Установка на чистой VM / виртуалке без SDK
  • Запуск приложения после установки и после перезагрузки
  • Удаление через «Приложения» — папка и ярлыки исчезли
  • Повторная установка поверх старой версии (обновление)
  • Путь с пробелами и кириллицей в имени пользователя
  • Подпись установщика (желательно для внешних пользователей)
  • README: системные требования и что делать при ошибке

Связанные материалы