https://github.com/continuous-delphi/delphi-codesign-azure
Azure artifact signing orchestration for Delphi (or likely any) binaries
https://github.com/continuous-delphi/delphi-codesign-azure
azure azure-artifact-signing continuous-delphi delphi powershell pwsh tooling
Last synced: 12 days ago
JSON representation
Azure artifact signing orchestration for Delphi (or likely any) binaries
- Host: GitHub
- URL: https://github.com/continuous-delphi/delphi-codesign-azure
- Owner: continuous-delphi
- License: mit
- Created: 2026-06-10T01:51:36.000Z (25 days ago)
- Default Branch: main
- Last Pushed: 2026-06-10T03:50:37.000Z (25 days ago)
- Last Synced: 2026-06-10T04:21:01.372Z (25 days ago)
- Topics: azure, azure-artifact-signing, continuous-delphi, delphi, powershell, pwsh, tooling
- Language: PowerShell
- Homepage: https://github.com/continuous-delphi
- Size: 78.1 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# delphi-codesign-azure

[](https://www.embarcadero.com/products/delphi)
[](https://github.com/continuous-delphi/delphi-codesign-azure/actions/workflows/ci.yml)
[](https://github.com/continuous-delphi/delphi-codesign-azure/releases)
[](https://opensource.org/licenses/MIT)
[](https://deepwiki.com/continuous-delphi/delphi-codesign-azure)
[](https://github.com/continuous-delphi)
A PowerShell utility for Authenticode code signing and verification
using [Azure Artifact Signing](https://learn.microsoft.com/en-us/azure/artifact-signing/) and `signtool.exe`.
---
## Quick Start
```powershell
# Sign an executable
pwsh -File source/delphi-codesign-azure.ps1 -Sign -Files app.exe -EnvFile .env -Format text
# Sign multiple files
pwsh -File source/delphi-codesign-azure.ps1 -Sign -Files app.exe,lib.bpl -EnvFile .env -Format text
# Verify a signed executable
pwsh -File source/delphi-codesign-azure.ps1 -Verify -FilePath app.exe -Format text
# Version info
pwsh -File source/delphi-codesign-azure.ps1 -Version -Format text
```
---
## Commands
### `-Sign`
Signs one or more files using Azure Trusted Signing via
`signtool.exe sign` with SHA256 digest and RFC 3161 timestamping.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `-Sign` | switch | yes | Select the sign command |
| `-Files` | string[] | yes | One or more file paths to sign |
| `-SignToolPath` | string | no | Explicit path to `signtool.exe`. Auto-discovered from the Windows SDK if omitted |
| `-DlibPath` | string | no | Path to `Azure.CodeSigning.Dlib.dll`. Defaults to `%LOCALAPPDATA%\Microsoft\MicrosoftTrustedSigningClientTools\` |
| `-MetadataPath` | string | no | Path to `metadata.json`. Defaults to the `source/` directory |
| `-EnvFile` | string | no | `.env` file with Azure credentials (see Prerequisites) |
| `-Format` | string | no | Output format: `object` (default), `text`, `json` |
**Prerequisites:**
- `signtool.exe` from the Windows SDK
- `Azure.CodeSigning.Dlib.dll` -- install via `winget install -e --id
Microsoft.Azure.TrustedSigningClientTools`
- `metadata.json` with Azure Trusted Signing endpoint, account name, and certificate profile
- Azure credentials: `AZURE_TENANT_ID`, `AZURE_CLIENT_ID`, `AZURE_CLIENT_SECRET` (via environment or `-
EnvFile`)
See [docs/machine_setup.md](docs/machine_setup.md) for first-time setup instructions.
**Exit codes:**
| Code | Meaning |
|------|---------|
| 0 | All files signed successfully |
| 2 | Partial failure (some files failed) |
| 3 | Fatal error (prerequisites missing, no files signed) |
**Examples:**
```powershell
# Sign a single file
pwsh -File source/delphi-codesign-azure.ps1 -Sign -Files app.exe -EnvFile .env -Format text
# Sign multiple files
pwsh -File source/delphi-codesign-azure.ps1 -Sign -Files app.exe,lib.bpl -EnvFile .env -Format text
# JSON output for CI
pwsh -File source/delphi-codesign-azure.ps1 -Sign -Files app.exe -EnvFile .env -Format json
# Pipeline use
$result = & source/delphi-codesign-azure.ps1 -Sign -Files app.exe -EnvFile .env
$result.ok # $true if all signed
$result.result.signed # count of signed files
$result.result.failed # count of failed files
```
### `-Verify`
Verifies the Authenticode signature on a file using `signtool.exe verify /pa /v`.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `-Verify` | switch | yes | Select the verify command |
| `-FilePath` | string | yes | Path to the file to verify |
| `-SignToolPath` | string | no | Explicit path to `signtool.exe`. Auto-discovered from the Windows SDK if omitted |
| `-Format` | string | no | Output format: `object` (default), `text`, `json` |
**Exit codes:**
| Code | Meaning |
|------|---------|
| 0 | Signature is valid |
| 1 | Signature is invalid or file is not signed |
| 3 | Fatal error (file not found, signtool not found) |
**Examples:**
```powershell
# Verify a signed executable (text output)
pwsh -File source/delphi-codesign-azure.ps1 -Verify -FilePath app.exe -Format text
# JSON output for CI consumption
pwsh -File source/delphi-codesign-azure.ps1 -Verify -FilePath app.exe -Format json
# Pipeline use (object output, default)
$result = & source/delphi-codesign-azure.ps1 -Verify -FilePath app.exe
$result.ok # $true if signed
$result.result.signed # $true if signed
# Explicit signtool path
pwsh -File source/delphi-codesign-azure.ps1 -Verify -FilePath app.exe -SignToolPath "C:\path\to\signtool.exe"
```
**signtool.exe discovery:**
When `-SignToolPath` is not specified, the tool searches
`C:\Program Files (x86)\Windows Kits\10\bin` for the latest x64
version of `signtool.exe`. Install the Windows SDK if it is not found:
https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/
### `-Version`
Displays tool name and version.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `-Version` | switch | yes | Select the version command |
| `-Format` | string | no | Output format: `object` (default), `text`, `json` |
**Examples:**
```powershell
# Text format
pwsh -File source/delphi-codesign-azure.ps1 -Version -Format text
# => delphi-codesign-azure 0.1.0
# JSON format
pwsh -File source/delphi-codesign-azure.ps1 -Version -Format json
# => {"ok":true,"command":"version","tool":{"name":"delphi-codesign-azure","version":"0.1.0"}}
```
---
## metadata.json
The `-Sign` command requires a `metadata.json` file that tells Azure
Trusted Signing which endpoint, account, and certificate profile to use.
```json
{
"Endpoint": "https://eus.codesigning.azure.net/",
"CodeSigningAccountName": "yourAccountName",
"CertificateProfileName": "yourCertificateProfileName"
}
```
See [docs/metadata.json](docs/metadata.json) for an example.
### Fields
| Field | Description |
|-------|-------------|
| `Endpoint` | Azure Trusted Signing regional endpoint URL. Use `eus` (East US), `wus` (West US), `neu` (North Europe), or `weu` (West Europe) |
| `CodeSigningAccountName` | Name of the Trusted Signing account in the Azure portal |
| `CertificateProfileName` | Name of the certificate profile under the signing account |
### Location
By default the tool looks for `metadata.json` in the same directory as
the script (`source/`). Override with `-MetadataPath`:
```powershell
pwsh -File source/delphi-codesign-azure.ps1 -Sign -Files app.exe -MetadataPath path/to/metadata.json
```
### Obtaining the values
1. **Endpoint**: Azure portal > Trusted Signing account > Overview > Account URI
2. **CodeSigningAccountName**: Azure portal > Trusted Signing account > Overview > Name
3. **CertificateProfileName**: Azure portal > Trusted Signing account > Certificate profiles > Profile name
---
## Azure Credentials
The `-Sign` command requires three Azure environment variables for
authentication with Azure Trusted Signing:
| Variable | Description |
|----------|-------------|
| `AZURE_TENANT_ID` | Entra ID tenant ID |
| `AZURE_CLIENT_ID` | Application (client) ID of the app registration |
| `AZURE_CLIENT_SECRET` | Client secret value (not the secret ID) |
### Setting credentials in the shell
PowerShell:
```powershell
$env:AZURE_TENANT_ID = 'your-tenant-id'
$env:AZURE_CLIENT_ID = 'your-client-id'
$env:AZURE_CLIENT_SECRET = 'your-client-secret'
```
Batch:
```batch
set AZURE_TENANT_ID=your-tenant-id
set AZURE_CLIENT_ID=your-client-id
set AZURE_CLIENT_SECRET=your-client-secret
```
### Using a .env file
For local development, credentials can be stored in a `.env` file and
loaded via the `-EnvFile` parameter:
```powershell
pwsh -File source/delphi-codesign-azure.ps1 -Sign -Files app.exe -EnvFile .env -Format text
```
See [docs/.env.example](docs/.env.example) for the file format.
**Format rules:**
- One `KEY=VALUE` pair per line
- Lines starting with `#` are comments
- Blank lines are ignored
- Existing environment variables are **not** overwritten -- the `.env`
file only fills in values that are not already set
**Security:** The `.env` file contains secrets and should not be
committed. Add it to `.gitignore`.
### Obtaining credentials from Azure
1. **AZURE_TENANT_ID**: Azure portal > Entra ID > Overview > Tenant ID
2. **AZURE_CLIENT_ID**: Azure portal > Entra ID > App registrations > your app > Application (client) ID
3. **AZURE_CLIENT_SECRET**: Azure portal > Entra ID > App registrations > your app > Certificates & secrets
> New client secret > copy the **Value** (not the Secret ID)
If the client secret has expired, create a new one in the portal.
---
## Output Formats
The `-Format` parameter controls output across all commands:
| Format | Description |
|--------|-------------|
| `object` | Default. Returns a `PSCustomObject` for pipeline use |
| `text` | Human-readable text to the console |
| `json` | Single-line compressed JSON for CI/scripting |
### JSON Envelope
Success:
```json
{
"ok": true,
"command": "verify",
"tool": { "name": "delphi-codesign-azure", "version": "0.1.0" },
"result": {
"filePath": "C:/path/to/file.exe",
"signed": true,
"signtoolExitCode": 0,
"signtoolOutput": ["..."]
}
}
```
Error:
```json
{
"ok": false,
"command": "verify",
"tool": { "name": "delphi-codesign-azure", "version": "0.1.0" },
"error": { "code": 3, "message": "File not found: missing.exe" }
}
```
---
## Running Tests
Requires PowerShell 7+, Pester 5.7+, and PSScriptAnalyzer.
```powershell
./tests/run-tests.ps1
```
---
## Continuous-Delphi
This tool is part of the [Continuous-Delphi](https://github.com/continuous-delphi)
ecosystem, focused on strengthening Delphi's continued success.
