Complete annotated example
This file contains a production-grade, copy-paste-ready MPDEV package for the fictional "My Application" desktop app. It is assembled in one place with line-by-line commentary.
The package builds both an MSI and an MSIX from a single JSON file, signed with Azure Trusted Signing, with a branded MSI dialog, an auto-updater, dependency checks, file associations, services, firewall rules, the works.
Project layout
My Application/
├── package.json
├── source/ ← application files (built by your CI)
│ ├── MyApp.exe
│ ├── My Application.Service.exe
│ ├── My CompanyShellExt.dll
│ └── docs/
│ └── README.txt
├── installer-assets/ ← installer-only resources
│ ├── icon.ico
│ ├── eula.rtf
│ └── third-party-licenses.txt
└── ca/ ← custom action sources
└── InitializeDatabase.ps1
The full package.json
JSON does not support comments. Strip the
// …lines if you copy this verbatim into a real file. They are here purely to explain the package as you read top-to-bottom.
{
// ──────────────────────────────────────────────────────────────
// $schema enables IDE autocomplete (VS Code, JetBrains, etc.)
// ──────────────────────────────────────────────────────────────
"$schema": "https://www.masterpackager.com/support-master-packager-dev/mpdev-schema.json",
// ──────────────────────────────────────────────────────────────
// COMMON SECTION – applies to BOTH the MSI and the MSIX builds
// ──────────────────────────────────────────────────────────────
"outputTypes": ["msi", "msix"],
"outputDirectory": "build-output",
"outputFileName": "$.packageName_$.version_$.platform",
"compressionLevel":"Normal",
"packageName": "My Application",
"publisher": "My Company Name Ltd.",
"version": "1.0.0",
"platform": "x64",
"installDir": "%ProgramFiles%\\My Application",
"icon": "installer-assets\\icon.ico",
// Files shipped to BOTH outputs
"fileSystemEntries": [
{ "sourcePath": "source",
"targetPath": "$.installDir" },
{ "sourcePath": "installer-assets\\eula.rtf",
"targetPath": "$.installDir\\eula.rtf" },
{ "sourcePath": "installer-assets\\third-party-licenses.txt",
"targetPath": "$.installDir\\licenses\\THIRD-PARTY.txt" }
],
// Start menu shortcut (MSIX requires at least one)
"shortcuts": [
{ "target": "$.installDir\\MyApp.exe",
"name": "My Application",
"description": "Take notes the My Company way",
"icon": "installer-assets\\icon.ico" }
],
// URL shortcut
"urlShortcuts": [
{ "name": "My Application - Documentation",
"url": "https://docs.MyCompany.example.com" }
],
// Registry writes (MSI: live registry, MSIX: virtualized)
"registries": [
{ "key": "HKEY_LOCAL_MACHINE\\SOFTWARE\\My Application",
"value": "My Application" },
{ "key": "HKEY_LOCAL_MACHINE\\SOFTWARE\\My Application",
"name": "ExpandableValue",
"type": "ExpandString",
"value": "65,00,78,00,70,00,61,00,6e,00,64,00,61,00,62,00,6c,00,65,00,00,00" },
{ "key": "HKEY_LOCAL_MACHINE\\SOFTWARE\\My Application",
"name": "Telemetry",
"type": "DWord",
"value": "0" }
],
// Environment variable on PATH
"environmentVariables": [
{ "name": "PATH",
"value": "[INSTALLDIR]",
"msi": {
"type": "System",
"onInstall": "CreateOrUpdate",
"onUninstall": "Remove",
"valueAction": "AppendEnd"
}
}
],
// Open .myapp files with My Application
"fileAssociations": [
{ "fileType": "myapp",
"executable": "$.installDir\\MyApp.exe",
"icon": "installer-assets\\icon.ico",
"verbs": [
{ "name": "Open", "arguments": "\"%1\"" }
]
}
],
// Right-click "Open with My Application" on any file
"contextMenu": [
{ "fileType": "*",
"executable": "$.installDir\\MyApp.exe",
"name": "Open with My Application",
"icon": "$.installDir\\MyApp.exe",
"arguments": "\"%1\"" }
],
// Background service for the updater
"services": [
{ "name": "My ApplicationSync",
"displayName": "My Application Sync",
"executable": "$.installDir\\My Application.Service.exe",
"startAccount": "LocalService",
"startupType": "Auto",
"description": "Syncs notes to the cloud." }
],
// Auto-launch app at user logon (minimised)
"startup": [
{ "type": "OnLogin",
"executable": "$.installDir\\MyApp.exe",
"arguments": "--minimised" }
],
// Outbound TCP for the sync service
"firewallExceptions": [
{ "name": "My Application Sync - Outbound",
"path": "$.installDir\\My Application.Service.exe",
"bound": ["out"],
"profile": ["domain", "private"],
"protocol": "tcp" }
],
// Sign EVERYTHING with Azure Trusted Signing
// (Set AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET in env first)
"digitalSignature": {
"signWith": "AzureTrustedSigning",
"endpoint": "https://eus.codesigning.azure.net",
"codeSigningAccountName": "MyCompanySigningAccount",
"certificateProfileName": "MyCompanyProductionProfile",
"timestampServer": "http://timestamp.acs.microsoft.com",
"exclusions": [
"source\\\\third-party\\\\already-signed\\.dll$"
]
},
// ──────────────────────────────────────────────────────────────
// MSI-ONLY SECTION
// ──────────────────────────────────────────────────────────────
"msi": {
"outputDirectory": "build-output\\msi",
"upgradeCode": "{A11C9F73-7B6E-4A63-8DC9-F5DE4F1A2B0C}",
// Custom MSI properties (overridable on msiexec command line)
"properties": [
{ "name": "TELEMETRY_ENABLED", "value": "1" },
{ "name": "API_ENDPOINT", "value": "https://api.MyCompany.example.com" }
],
// Branded install dialog with EULA, release notes, accent color
"installDialog": {
"packageDescription": "My Application – the modern way to take notes.",
"publisherUrl": "https://MyCompany.example.com",
"releaseNotesUrl": "https://MyCompany.example.com/release-notes",
"eulaUrl": "https://MyCompany.example.com/eula",
"primaryAccent": "#01787B",
"promptAppsAfterInstall": [
{ "displayName": "Launch My Application",
"file": "$.installDir\\MyApp.exe" }
]
},
// Detect helper exes that may be running
"detectRunningProcesses": [
"MyApp.exe",
"My Application.Service.exe",
"My Application.Tray.exe"
],
// Check for .NET 8, install via WinGet if missing
"packageDependencies": [
{ "displayName": ".NET 8 Desktop Runtime (x64)",
"namePattern": "^Microsoft Windows Desktop Runtime\\s-\\s8.*(x64)",
"minVersion": "8.0.0",
"install": {
"winGet": { "id": "Microsoft.DotNet.DesktopRuntime.8" }
}
}
],
// Custom actions: regsvr the shell extension + run a PowerShell init
"customActions": {
"registerDll": [
{ "filePath": "$.installDir\\My CompanyShellExt.dll" }
],
"powershell": [
{ "filePath": "ca\\InitializeDatabase.ps1",
"condition": "NOT Installed",
"sequence": "EndOfExecution" }
]
},
// Auto-updater service
"updater": {
"serviceName": "My ApplicationUpdaterSvc",
"serviceDisplayName": "My Application Updater Service",
"serviceDescription": "Checks for and silently installs updates.",
"latestVersionDescriptor": {
"url": "https://updates.MyCompany.example.com/notes/latest.json",
"versionMatcher": "\"version\"\\s*:\\s*\"([^\"]+)\"",
"versionUrlMatcher": "\"releaseNotes\"\\s*:\\s*\"([^\"]+)\"",
"installerUrlMatcher": "\"url\"\\s*:\\s*\"([^\"]+)\"",
"checkSumMatcher": "\"sha256\"\\s*:\\s*\"([^\"]+)\""
},
"scheduling": {
"enabled": true,
"initialDelay": 60000,
"interval": 86400000,
"retryInterval": 180000
},
"notifications": {
"enabled": true,
"triggers": ["MyApp.exe"]
},
"logging": {
"installerLogsRetentionDays": 14
}
}
},
// ──────────────────────────────────────────────────────────────
// MSIX-ONLY SECTION
// ──────────────────────────────────────────────────────────────
"msix": {
"outputDirectory": "build-output\\msix",
"packageDisplayName": "My Application",
"publisherDisplayName": "My Company Name Ltd.",
"packageDescription": "My Application – the modern way to take notes.",
"minVersion": "10.0.19041.0",
"maxVersionTested": "10.0.26100.0",
// Win32 app + outbound network access
"capabilities": ["runFullTrust", "internetClient"],
// Depend on VCLibs runtime
"packageDependencies": [
{ "name": "Microsoft.VCLibs.140.00",
"publisher": "CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US",
"minVersion": "14.0.30704.0" }
],
"installDialog": {
"primaryAccent": "#01787B"
}
}
}
Build it
set AZURE_TENANT_ID=<your-tenant>
set AZURE_CLIENT_ID=<your-client>
set AZURE_CLIENT_SECRET=<your-secret>
mpdev build package.json
Output:
build-output/
├── msi/
│ └── My Application_1.0.0_x64.msi
└── msix/
└── My Application_1.0.0_x64.msix
Both are signed and ready to ship.
What this installer does, step by step
When the user runs My Application_1.0.0_x64.msi:
- The MPDEV-branded install dialog opens with the My Application accent color, links to the publisher site, release notes, and EULA.
- MPDEV checks for
Microsoft .NET Windows Desktop Runtime 8.0≥ 8.0.0. If missing in Full or Reduced UI mode, WinGet is invoked to install it. In Silent or Basic mode the install fails with a clear message (override withMP_SKIPDEPCHECK=1). - MPDEV checks for running
MyApp.exe,My Application.Service.exe, andMy Application.Tray.exe, then prompts the user to close them. - Files in
source/, plus the EULA and licenses, are copied to%ProgramFiles%\My Application. - Registry keys are written under
HKLM\SOFTWARE\My Application. - A Start menu shortcut and a URL shortcut are created.
- The
.myappextension is associated withMyApp.exe, and a right-click context menu entry is added. - The
My CompanyShellExt.dllis registered withregsvr32. InitializeDatabase.ps1runs (only on fresh installs, thanks tocondition: "NOT Installed").- The
My ApplicationSyncservice is installed and started. - The
My ApplicationUpdaterSvcupdater service is installed. It pollshttps://updates.My Company.example.com/notes/latest.jsonevery 24 hours and silently upgrades the app when a new version is available. - A user logon hook starts
MyApp.exe --minimised. - The Windows Firewall gets an outbound TCP rule for
My Application.Service.exeon Domain and Private profiles. - The user sees a "Launch My Application" dialog at the end of install.
When the user runs My Application_1.0.0_x64.msix:
- Windows verifies the package signature against the trusted Azure Trusted Signing certificate.
- Windows checks that
Microsoft.VCLibs.140.00 ≥ 14.0.30704.0is installed. - The package is deployed into its container. Files and registry are virtualised.
- The app appears in Start menu and Apps & features as My Application by My Company Name Ltd..
- The
.myappassociation and the right-click "Open with My Application" are added to the context menu. - Updates are managed through standard MSIX (App Installer / Microsoft Store) – the MSI updater section is NOT used for MSIX.