Purpose: Eliminate the "Windows protected your PC" SmartScreen warning that appears when university students install the Examini desktop app.
Outcome: After completing this guide, the installer will show "Endolit LLC" as the verified publisher and Windows SmartScreen will allow installation without any warning.
Estimated time: 30 minutes of active work + 1–3 business days waiting for Microsoft to verify the organization.
Cost: $9.99 / month (billed by Microsoft via your Azure subscription).
Before starting, confirm the following:
| Requirement | Details |
|---|---|
| Azure account | A Microsoft account (personal or work). Create one free at portal.azure.com if you don't have one. |
| Credit card | Required to activate an Azure subscription. You will only be charged $9.99/month after setup. |
| Company documents | You will need to provide legal business name and registered address for org verification. |
| Build machine access | The developer who runs npm run build:prod needs the credentials from this guide. |
| Windows build machine | Azure Trusted Signing client runs on Windows. The Examini build already requires Windows. |
Skip this section if you already have an Azure account with an active subscription.
Open a browser and go to: https://portal.azure.com
Click "Start for free" or "Sign in" if you already have a Microsoft account.
Complete the sign-up form:
yourname@endolit.com)After sign-up, you will land on the Azure Portal dashboard.
In the top search bar, type "Subscriptions" and click it.
Important: If your subscription shows "Disabled" or "Expired", you must activate or upgrade it before proceeding. Click the subscription → "Reactivate".
This creates the Azure service that will sign your application files.
In the Azure Portal top search bar, type: Trusted Signing
Click "Trusted Signing Accounts" in the results.
Click the "+ Create" button (top left).
Fill in the form:
| Field | Value to enter |
|---|---|
| Subscription | Select your subscription |
| Resource group | Click "Create new" → enter examini-codesigning → click OK |
| Name | endolit-signing (or your preferred name, must be globally unique) |
| Region | East US (recommended — most features available here) |
| Pricing tier | Basic ($9.99/month) |
Click "Review + Create" at the bottom.
Review the details, then click "Create".
Wait for the deployment to complete (usually 30–60 seconds).
Click "Go to resource" to open your new Trusted Signing account.
Save for later: Copy the resource name (e.g.
endolit-signing) — you will need it in Step 9.
Microsoft must verify that Endolit LLC is a real legal entity before issuing a certificate.
Inside your Trusted Signing account, look at the left sidebar menu.
Click "Identity validation" (under the Settings section).
Click "+ Add".
Select validation type: "Organization" and click Next.
Fill in your company details exactly as they appear on your official business registration:
| Field | What to enter |
|---|---|
| Legal business name | Endolit LLC (must match business registration exactly) |
| Business registration number | Your EIN or company registration number |
| Address (line 1) | Registered street address |
| City | Registered city |
| State/Province | Registered state |
| Postal code | Registered ZIP code |
| Country | United States |
| Primary email | Company email address |
| Primary phone | Company phone number |
Click "Submit".
You will receive an email from Microsoft at the address you provided.
Wait time: Microsoft typically completes verification within 1–3 business days. You will receive an email confirmation when approved. You cannot proceed to Step 5 until this is complete.
Once Microsoft confirms your organization is verified, come back and complete this step.
In your Trusted Signing account (Azure Portal → Trusted Signing Accounts → your account).
In the left sidebar, click "Certificate profiles".
Click "+ Add".
Fill in:
| Field | Value |
|---|---|
| Name | examini-cert |
| Profile type | Public Trust |
| Common name | Endolit LLC |
| Include street address | Optional — leave unchecked unless required |
Click "Create".
The profile will appear in the list with status "Active".
Save for later: Copy the profile name (e.g.
examini-cert) — you will need it in Step 9.
This creates a "service account" identity that your build machine will use to sign files automatically without requiring manual login every time.
In the Azure Portal top search bar, type: App registrations and click it.
Click "+ New registration".
Fill in:
| Field | Value |
|---|---|
| Name | examini-build-signing |
| Supported account types | "Accounts in this organizational directory only" |
| Redirect URI | Leave blank |
Click "Register".
On the app registration overview page, copy and save these two values:
Application (client) ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Directory (tenant) ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
In the left sidebar, click "Certificates & secrets".
Click "+ New client secret".
Fill in:
examini-build-keyClick "Add".
Immediately copy the secret VALUE (the long string in the "Value" column).
Warning: This value is only shown once. If you navigate away without copying it, you must delete it and create a new one.
Client Secret Value: <paste the value here and keep it safe>
Keep these three values safe — they are the credentials your build machine will use:
- Client ID
- Tenant ID
- Client Secret
Now grant your app registration permission to use the certificate profile.
In the Azure Portal, go back to Trusted Signing Accounts → your account (endolit-signing).
In the left sidebar, click "Access control (IAM)".
Click "+ Add" → "Add role assignment".
In the Role tab, search for: Trusted Signing Certificate Profile Signer
In the Members tab:
examini-build-signing (the app registration you just created)Click "Review + assign" → "Review + assign" again to confirm.
The role assignment is now active. Your build service account can sign files.
These commands are run on the Windows machine where npm run build:prod is executed.
Open PowerShell as Administrator and run:
winget install Microsoft.TrustedSigningClient
If winget is not available, download the installer from:
https://aka.ms/trustedsigning/install
Verify installation:
trusted-signing-client --version
You should see a version number printed (e.g. 1.0.x).
winget install Microsoft.AzureCLI
These changes are made to the Examini project source code by the developer.
For the developer: All files referenced below are inside the
Examini/folder of the project.
Create a new file: Examini/sign.js
/**
* sign.js — Custom signing script for electron-builder.
* Called automatically by electron-builder for every EXE it produces.
* Uses Azure Trusted Signing via the trusted-signing-client CLI tool.
*
* Required environment variables (set in .env.build):
* AZURE_ENDPOINT — e.g. https://eus.codesigning.azure.net
* AZURE_ACCOUNT_NAME — your Trusted Signing account name
* AZURE_PROFILE_NAME — your certificate profile name
* AZURE_CLIENT_ID — App Registration client ID
* AZURE_CLIENT_SECRET — App Registration client secret
* AZURE_TENANT_ID — Azure Directory tenant ID
*/
const { execSync } = require('child_process');
exports.default = async function sign(config) {
const filePath = config.path;
const endpoint = process.env.AZURE_ENDPOINT;
const accountName = process.env.AZURE_ACCOUNT_NAME;
const profileName = process.env.AZURE_PROFILE_NAME;
const clientId = process.env.AZURE_CLIENT_ID;
const clientSecret = process.env.AZURE_CLIENT_SECRET;
const tenantId = process.env.AZURE_TENANT_ID;
if (!endpoint || !accountName || !profileName || !clientId || !clientSecret || !tenantId) {
console.warn('[sign] One or more Azure signing env vars are missing — skipping signing.');
console.warn('[sign] Set AZURE_ENDPOINT, AZURE_ACCOUNT_NAME, AZURE_PROFILE_NAME,');
console.warn('[sign] AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_TENANT_ID in .env.build');
return;
}
// Pass credentials to the Azure SDK used by trusted-signing-client
process.env.AZURE_CLIENT_ID = clientId;
process.env.AZURE_CLIENT_SECRET = clientSecret;
process.env.AZURE_TENANT_ID = tenantId;
console.log(`[sign] Signing: ${filePath}`);
execSync(
`trusted-signing-client sign` +
` --endpoint "${endpoint}"` +
` --account "${accountName}"` +
` --profile "${profileName}"` +
` --timestamp-rfc3161 "http://timestamp.acs.microsoft.com"` +
` --timestamp-digest sha256` +
` --file-digest sha256` +
` "${filePath}"`,
{ stdio: 'inherit' }
);
console.log('[sign] Successfully signed:', filePath);
};
package.jsonOpen Examini/package.json. Find the "win" section inside "build" and add the "sign" line:
Before:
"win": {
"target": [
{ "target": "nsis", "arch": ["x64", "ia32"] },
{ "target": "appx", "arch": ["x64", "ia32"] }
],
"icon": "icons/icon.ico"
}
After:
"win": {
"sign": "./sign.js",
"signingHashAlgorithms": ["sha256"],
"target": [
{ "target": "nsis", "arch": ["x64", "ia32"] },
{ "target": "appx", "arch": ["x64", "ia32"] }
],
"icon": "icons/icon.ico"
}
.env.build fileOpen or create Examini/.env.build and add these lines:
# Azure Trusted Signing credentials
# Get these values from Steps 3, 5, and 6 of the setup guide.
AZURE_ENDPOINT=https://eus.codesigning.azure.net
AZURE_ACCOUNT_NAME=endolit-signing
AZURE_PROFILE_NAME=examini-cert
AZURE_CLIENT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
AZURE_CLIENT_SECRET=your-client-secret-value-here
AZURE_TENANT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Replace each
xxxxplaceholder with the actual values collected in Steps 3, 5, and 6.
Security note:
.env.buildis already listed in.gitignore— it will never be committed to Git. Keep it only on the build machine.
.env.build before signingOpen Examini/sign.js and add the following two lines at the very top (before everything else):
const path = require('path');
require('dotenv').config({ path: path.join(__dirname, '.env.build') });
The final top of sign.js should look like:
const path = require('path');
require('dotenv').config({ path: path.join(__dirname, '.env.build') });
const { execSync } = require('child_process');
exports.default = async function sign(config) {
// ... rest of the file unchanged
Open PowerShell in the Examini/ folder and run:
npm run build:prod
Watch the output — you should see lines like:
[sign] Signing: dist\win-unpacked\Examini.exe
[sign] Successfully signed: dist\win-unpacked\Examini.exe
[sign] Signing: dist\Examini Setup 1.0.9.exe
[sign] Successfully signed: dist\Examini Setup 1.0.9.exe
In PowerShell:
Get-AuthenticodeSignature "dist\Examini Setup 1.0.9.exe" | Format-List
Expected output:
SignerCertificate : [Subject: CN=Endolit LLC, ...]
TimeStamperCertificate : [...]
Status : Valid
StatusMessage : Signature verified.
Path : dist\Examini Setup 1.0.9.exe
Alternatively: right-click Examini Setup 1.0.9.exe → Properties → Digital Signatures tab.
You should see "Endolit LLC" listed as the signer.
Double-click dist\Examini Setup 1.0.9.exe.
Before signing: Blue SmartScreen warning — "Windows protected your PC", Publisher: Unknown.
After signing: ✅ No SmartScreen warning at all, or a standard UAC prompt showing "Endolit LLC".
The CLI was not installed or is not in the system PATH.
winget install Microsoft.TrustedSigningClientThe AZURE_CLIENT_ID or AZURE_TENANT_ID value is incorrect.
examini-build-signingThe app registration does not have the signing role.
Organization verification is still pending.
This can happen for the very first few installs after getting a new certificate, while Microsoft's SmartScreen system builds reputation data. It typically clears within a few days and a few hundred installs. It is much less common with Azure Trusted Signing (since Microsoft trusts its own service) but can still occasionally occur on the first release.
The .env.build file is missing or the dotenv lines were not added to sign.js.
Examini/.env.build exists and contains all six AZURE_* variables.dotenv lines are at the very top of sign.js.Use this to track progress:
endolit-signing, East US, Basic tier)examini-cert, Public Trust)examini-build-signing)trusted-signing-client installed on build machinesign.js created in Examini/ folderpackage.json updated with "sign": "./sign.js".env.build updated with all six AZURE_* valuesdotenv lines added to top of sign.jsnpm run build:prod run successfully with signing output visibleGet-AuthenticodeSignatureDocument prepared for Endolit LLC — Examini Desktop App v1.0.9 Azure Trusted Signing — $9.99/month via Microsoft Azure portal