Auto-update
Once a product is installed, its new versions have to reach the computers it is on. Cobalt Installer puts a small Update.exe beside the program. It reads a file each build writes, sees there is a newer version, shows what is new in it, downloads it, checks that it is exactly the file you published and that it is signed by you, and installs it over the old one with the same answers. You only put two files on your site.
How it works
- The build writes
Product.updates.jsonbeside the setup: the version, the setup's file name, its size and SHA-256, the date, and what is new. The versions the last file had are kept in it. - You publish the setup and the updates file in one folder on your site, or as files of a GitHub release.
- Update.exe — a copy of the installer's engine in the install folder, about 620 KB — reads the updates file: on a schedule, when your program asks, or when the user picks Check for updates in Start.
- When there is a newer version for this computer, it shows what is new, downloads the setup (going on where a broken download stopped), checks it, and runs it.
- The new setup updates by the rules of Version upgrades: the same folder and answers, the program closed while its files are replaced and opened again after.
The section is under Release, in Add a feature. Turn on Look for new versions on the users' computers; everything else has a value to start with.
Where the updates are
| Where | What you give | What Update.exe reads |
|---|---|---|
| Your site | The folder's address: https://example.com/download/ | https://example.com/download/Product.updates.json |
| GitHub Releases | The project: owner/project | https://github.com/owner/project/releases/latest/download/Product.updates.json |
On a site, put the setup and the updates file in the same folder; a second address can be given, asked when the first does not answer. On GitHub, add both files to each release: GitHub gives the latest release's files at one address that never changes, so no server of your own is needed.
Only https. Over http anyone on the way — a café's Wi-Fi, a proxy — could hand out another file. For a try on your own computer, http://127.0.0.1:… and http://localhost:… are taken too.
The addresses take the project's values: https://example.com/{ProductName}/.
The updates file
{
"product": "Tiny App",
"id": "{6F1C2A7E-…}",
"publisher": "Cobaltsmith",
"versions": [
{
"version": "1.1.0",
"channel": "stable",
"date": "2026-11-10",
"file": "TinyApp-1.1.0-Setup.exe",
"size": 1570608,
"sha256": "d918f79c…",
"critical": false,
"rollout": 100,
"notes": { "en": "- Batch rename by a pattern\n- JPEG XL and AVIF" }
}
]
}
| Field | What it is |
|---|---|
id | The product's code from Version upgrades: an updates file of another product is not taken. |
file / url | The setup beside the updates file, or a full address of its own. |
size, sha256 | What the downloaded file must be, to the byte. |
critical | It can't be put off or skipped. |
rollout | The share of computers, 1–100, it is offered to. |
minimum | Not written by the build: the oldest version this setup can update; older ones get another version first. |
notes | What is new, by the installer's language. |
The file can be changed by hand after the build: to stop a version found to be wrong (rollout lowered, or the entry taken out), or to mark it critical.
What is new
From the changelog, or written in the section. A changelog is read by its headings: the part of version 1.4.0 goes from a heading with it — ## 1.4.0, ## [1.4.0] - 2026-11-10, ### v1.4 — to the next heading as high. The file chosen is in the installer's default language; CHANGELOG.de.md beside it gives the German text, and so on. Lists, headings and bold are shown as plain lines.
When the changelog has no part for the version being built, Problems says so.
When it looks
| How | What it is |
|---|---|
| From your program | It runs Update.exe --check --background as it starts. Twice a day at the most; a window only when there is a new version. |
| On a schedule | A Windows task, as the user. Off by default — see below. |
| Before installing | An old setup asks first whether there is a newer version than itself, 3 s at the most, and offers it. |
| Check for updates | An item in Start beside the program's shortcut, when asked for. |
The schedule has what Task Scheduler has:
| Repeat | For example |
|---|---|
| Every N days | every day; every 3rd day |
| Weekdays, every N weeks | every Monday; Tuesdays and Thursdays; Fridays every 2nd week |
| Days of the month | the 10th; the 1st and the 15th; the last day, whatever its number |
| A weekday's place in the month | the 2nd Tuesday; the last Friday |
| Months | any of them: every month, or only March, June, September, December |
Then the time, by the computer's clock, and a spread — none, 15 minutes, an hour, four hours — over which each computer's time falls at random, so a thousand of them don't come to your server in the same minute. A time missed while the computer was off comes as soon as it is on. At the user's sign-in too adds a look two minutes after each sign-in. Under the schedule the editor shows its next three times — the same Windows will keep.
Why the schedule is off by default
A task that starts a program at sign-in or at set times is also how malware keeps itself on a computer. Microsoft Defender judges such a task by who signed the program: while the setup is unsigned, or signed by a certificate Windows does not trust (one made by yourself), it is likely to put Update.exe in quarantine and delete the task. With a code signing certificate from a known authority this does not happen. Until then, let your program run Update.exe --check --background as it starts: nothing stays on the computer to look like that.
What it does with a new version
| Choice | What the user sees |
|---|---|
| Ask | A window: the version, what is new, its size and date; Update, Remind me tomorrow, Skip this version. A critical version has Update only. |
| Install by itself | Nothing until it is done: downloaded and installed quietly while the program is closed, then a notification. Installed for everyone, a second task runs as SYSTEM on the schedule, so no one is asked for rights. |
| Only tell | A Windows notification; the window opens when it is clicked. |
This version — said of the version being built, in the updates file:
- Critical: it can't be put off or skipped — a security fix, a server that changed.
- Offered first to 10%, 25%, 50% or all of the computers. Each computer's place among them stays the same for the version, so the first 10% are the same computers each time it is looked at. Found a problem — lower it, or take the version out of the updates file, and the rest won't get it.
The check
What is downloaded is installed only if all of this holds:
- Its size and SHA-256 are those in the updates file.
- It is signed by the same publisher as Update.exe itself. The same publisher, not the same certificate: certificates are renewed every year, the company's name stays.
- Windows trusts the signature, revoked certificates included.
It can't be turned off. While the setup is not signed, only the SHA-256 is checked — and a setup changed on the server together with the updates file would go through; Problems says so.
Administrators and your program
| Command | What it does |
|---|---|
setup.exe /S UPDATES=0 | Installs with updates off on that computer; the next versions keep it so. UPDATES=1 turns them on again. |
HKLM\Software\Policies\Publisher\Product Updates = 0 | Off on every computer the policy reaches. |
HKLM\Software\Policies\Publisher\Product Url | Another updates file: the company's own server, with the versions it has tried. |
Update.exe --check --background | For your program as it starts: twice a day at the most, a window only when there is a new version. |
Update.exe --check | Check for updates in your program's menu: the window, or the newest version when there is none. |
Update.exe --check --quiet | No window. Exit code 0 — none newer, 1 — there is one (a line of JSON about it on the output), 2 — no network. |
Update.exe --install | Downloads, checks and installs the newest version with no window. |
// C#: Help → Check for updates
var update = Path.Combine(AppContext.BaseDirectory, "Update.exe");
Process.Start(update, "--check");
Update.exe writes what it did to %TEMP%\Product Update.log.