Deploy-WwExecutionEngine.ps1 is the end-to-end orchestrator for deploying the Warewolf Lightweight Execution Engine to an Azure Function App. A single script call provisions infrastructure (resource group, storage account, Function App, Application Insights, Key Vault), configures Microsoft Entra ID authentication, stages and optionally encrypts the engine package and workflow resources, applies all required environment variables, and zip-deploys the package — in that order, with crash-safe summary logging and a matching rollback script.
Download the Warewolf Azure Execution Engine. Download the Warewolf Azure Execution Engine build from warewolf.io/release-notes, extract the
.zip, and supply the extracted folder (or the.zipitself) via-PublishPath.
Download the Deployment Scripts. Download the Warewolf Azure Execution Engine deployment scripts from warewolf.io/release-notes and extract the
.zipso that the scripts land inD:\ExecutionEngine\Scripts. All examples in this article assume that path.
Prerequisites
| Tool | Minimum version | Notes |
|---|---|---|
| PowerShell | 7.0+ (latest recommended) | The script requires PS 7+; it uses ternary operators. Windows PowerShell 5.1 will not run it. Install via winget install Microsoft.PowerShell. |
Azure CLI (az) |
2.55.0+ | All cloud provisioning runs through az. Must be logged in before running the script. Install via winget install Microsoft.AzureCLI. |
Azure Functions Core Tools (func) |
4.x | Only needed if you choose -PublishMethod Func (advanced, opt-in). The default Auto/Zip path uses az zip-deploy and does not require func. Install via winget install Microsoft.Azure.FunctionsCoreTools. |
Azure-side prerequisites: an Azure subscription with rights to create resource groups, storage accounts, Function Apps, Application Insights instances, and (when encrypting) Key Vaults and managed-identity role assignments.
Encryption prerequisite: when -EncryptResources is used, the script re-encrypts .bite sources from plain text or DPAPI to WFAES. DPAPI-encrypted sources can only be re-encrypted on the Windows machine that originally created them.
Verify your toolchain before starting:
$PSVersionTable.PSVersion # must be >= 7.0
az version # azure-cli >= 2.55
func --version # 4.x — only if using -PublishMethod Func
az account show # confirms you are logged in
Required roles & privileges
The deploy chain touches three independent planes (Azure RBAC, Key Vault data plane, and Microsoft Entra ID). Azure RBAC roles never grant Entra permissions and vice-versa. The script auto-assigns itself only the Key Vault data-plane role — every other role below must already be on the deploying user before you run.
| Plane | Role | When needed | Why |
|---|---|---|---|
| Azure RBAC (control) | Contributor at subscription scope (or RG scope if the RG already exists) | Always | Creates the resource group, storage, Function App, App Insights, managed identity, app settings, zip-deploy, and Easy Auth. Creating the RG itself requires subscription scope. |
| Azure RBAC (control) | User Access Administrator (or Owner / Role Based Access Control Administrator), scope covering the Key Vault (RG or subscription) | When a Key Vault is in play (-EncryptResources, or any -KeyVaultName) |
The script runs az role assignment create, which Contributor does not include. This is the most commonly missed grant. |
| Key Vault (data) | Key Vault Secrets Officer on the vault | When a Key Vault is in play | Reads/writes the AES-key secret. The deploy auto-assigns this to the signed-in user — but only if the user already has User Access Administrator or Owner above. Pre-grant it manually if not. |
| Microsoft Entra (directory) | Application Administrator (or Graph Application.ReadWrite.All) |
Unless -SkipAuthProvisioning |
Creates/updates the Entra app registration, service principal, OAuth scope, app roles, and client secret. |
Minimal path: with -SkipAuthProvisioning and no Key Vault (no encryption), Contributor alone is enough — no User Access Administrator, no Entra role.
Owner shortcut: granting Owner at subscription scope covers both Contributor and User Access Administrator in one role. It does not cover the Entra (directory) roles — those are always separate.
Grant commands (an Admin runs these for the deploying user):
# --- Resolve the target user's object id ---
$UserOid = az ad user show --id 'deployer@yourtenant.com' --query id -o tsv
$Sub = '<your-subscription-id>'
$Rg = '<your-resource-group>'
$Vault = '<your-key-vault-name>'
# === A. Azure RBAC (control plane) ===
# Simplest: Owner at subscription = Contributor + role-assignment rights in one grant
az role assignment create --assignee $UserOid --role 'Owner' --scope "/subscriptions/$Sub"
# --- OR least-privilege: the two roles separately ---
az role assignment create --assignee $UserOid --role 'Contributor' --scope "/subscriptions/$Sub"
az role assignment create --assignee $UserOid --role 'User Access Administrator' --scope "/subscriptions/$Sub"
# (If the RG already exists you may scope to "/subscriptions/$Sub/resourceGroups/$Rg"
# but RG creation needs subscription scope.)
# === B. Key Vault data plane (optional pre-grant; the deploy self-grants this if you have
# User Access Administrator / Owner, but the vault must already exist) ===
az role assignment create --assignee $UserOid --role 'Key Vault Secrets Officer' `
--scope "/subscriptions/$Sub/resourceGroups/$Rg/providers/Microsoft.KeyVault/vaults/$Vault"
# === C. Entra directory role: Application Administrator ===
az rest --method POST `
--url 'https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignments' `
--headers 'Content-Type=application/json' `
--body "{`"principalId`":`"$UserOid`",`"roleDefinitionId`":`"9b895d92-2cd3-44c7-9d02-a6ac2d5ea5c3`",`"directoryScopeId`":`"/`"}"
The admin running step C must themselves be Privileged Role Administrator or Global Administrator. Azure RBAC grants (steps A/B) require Owner or User Access Administrator at the target scope.
Step-by-step deployment
Step 0 — Log in and select the subscription
Run PowerShell 7+ as Administrator — some Azure CLI role-assignment operations require elevated privileges. Log in, then set all your deployment values once in the session — every example below reuses these variables.
az login
# ── Set your deployment values ONCE — every example in this article reuses these ──
$SubscriptionId = '<your-subscription-id>'
$ResourceGroup = '<your-resource-group>' # e.g. DEV2
$Location = 'southafricanorth'
$StorageAccount = '<your-storage-account>' # 3-24 lowercase chars
$AppName = '<your-function-app-name>' # globally unique
$PublishPath = 'D:\ExecutionEngine\AzureFunctionsPackage-3.0.1.200'
$AuthConfigPath = 'D:\ExecutionEngine\Deploy-WwExecutionEngine.authconfig.json'
$SecureConfigPath = 'C:\ProgramData\Warewolf\Server Settings\secure.config'
$WorkflowsSourcePath = 'C:\ProgramData\Warewolf\Resources'
$LicenseConfigPath = 'D:\ExecutionEngine\Warewolf License.secureconfig'
$KeyVaultName = '<your-key-vault-name>'
$KeyVaultSecretName = '<your-kv-secret-name>'
$ElasticsearchSourcePath = 'D:\ExecutionEngine\ElasticsearchLoggingSource.bite'
$LogDir = 'D:\ExecutionEngine\Scripts\logs'
az account set --subscription $SubscriptionId
cd D:\ExecutionEngine\Scripts
The script resolves SubscriptionId and TenantId from az account show when those parameters are omitted, so setting the active subscription here is what controls where resources land.
Step 1 — Deploy FOR REAL (creates billable resources)
$ts = Get-Date -Format 'yyyyMMdd-HHmmss'
Start-Transcript -Path ".\logs\deploy-$ts.log" | Out-Null
.\Deploy-WwExecutionEngine.ps1 `
-ResourceGroup $ResourceGroup -Location $Location `
-StorageAccount $StorageAccount -AppName $AppName `
-PublishPath $PublishPath `
-AuthConfigPath $AuthConfigPath `
-SecureConfigPath $SecureConfigPath `
-WorkflowsSourcePath $WorkflowsSourcePath `
-LicenseConfigPath $LicenseConfigPath `
-EncryptResources:$true -VerifyDecryption `
-KeyVaultName $KeyVaultName -KeyVaultSecretName $KeyVaultSecretName `
-EnableAppInsights:$true `
-EnableElasticsearch:$true -ElasticsearchSourcePath $ElasticsearchSourcePath `
-LogDir $LogDir `
-PublishMethod Zip
Stop-Transcript | Out-Null
Line-continuation gotcha: every line of a multi-line PowerShell call except the last must end with a backtick. A missing backtick causes the next parameter to be parsed as a separate statement and silently dropped. Use splatting (see worked examples below) to avoid this entirely.
The script runs six phases:
| Phase | Action |
|---|---|
| 0 / 0.5 | Pre-flight: verify az login, resolve subscription and tenant, print a masked summary of every planned action, and prompt once to proceed. |
| 1 | Create resource group, storage account, Function App, and Application Insights. |
| 2 | Provision Microsoft Entra ID app registration and Easy Auth from the -AuthConfigPath JSON. |
| 3 | Stage secure.config (validate and auto-encrypt if plaintext), workflow .bite resources (with optional WFAES encryption), Elasticsearch source, and generate Resources\workflow-index.json. Apply environment variables. |
| 4 | Zip-deploy the staged package to the Function App. |
| 5 | Verify: check the endpoint banner and run an optional HTTP probe. |
The script writes a timestamped transcript and a masked *.summary.json to -LogDir. The summary is updated after every phase and on failure — it is crash-safe and is consumed by the rollback script.
Step 2 — Rollback
The rollback script reads the summary from the real deploy run and previews what it would delete — by default the rollback is a dry run. Locate the summary, inspect the output, then re-run with the execute flag to perform the teardown.
# Find the real-run summary (exclude dry-run files)
$summary = (Get-ChildItem 'D:\ExecutionEngine\Scripts\logs\deploy-WwExecutionEngine-*.summary.json' |
Where-Object { $_.Name -notlike '*dryrun*' } |
Sort-Object LastWriteTime | Select-Object -Last 1).FullName
$summary # confirm this is the real run's summary
$ts = Get-Date -Format 'yyyyMMdd-HHmmss'
Start-Transcript -Path ".\logs\rollback-$ts.log" | Out-Null
.\Rollback-WwExecutionEngine.ps1 -SummaryPath $summary
Stop-Transcript | Out-Null
The rollback only deletes resources that this deployment created (created = true in the summary) and that still exist. Pre-existing resources (created = false) are never touched. It never deletes the resource group by default. A summary with status = failed or in-progress is treated as a partial run — the rollback cleans up exactly what that interrupted run managed to create. Run .\Rollback-WwExecutionEngine.ps1 -? for the exact confirm flag to execute the teardown.
Parameter reference
Omitted parameters are prompted interactively unless -NonInteractive is set, in which case a missing required value throws early.
Targeting
| Parameter | Required | Default | Description |
|---|---|---|---|
-SubscriptionId |
No | from az account show |
Azure subscription GUID. |
-TenantId |
No | from az account show |
Microsoft Entra tenant GUID. |
-ResourceGroup |
Yes | — | Resource group to create or use. |
-Location |
Yes | — | Azure region, e.g. southafricanorth. |
-StorageAccount |
Yes | — | Storage account name (3–24 lowercase alphanumeric characters). |
-AppName |
Yes | — | Function App name — must be globally unique. |
Publish source
| Parameter | Required | Default | Description |
|---|---|---|---|
-PublishPath |
Yes | — | The already-published engine package — a folder or a .zip. A zip is extracted to a sibling folder, which becomes the package directory. |
-PublishMethod |
No | Auto |
Auto/Zip use az zip-deploy — correct for the pre-built artifact. Func uses func azure functionapp publish --dotnet-isolated --no-build and is advanced/opt-in only (it expects a project source directory and fails on a pre-built package). |
Auth provisioning
| Parameter | Required | Default | Description |
|---|---|---|---|
-SkipAuthProvisioning |
No | off | Skip Entra ID and Easy Auth provisioning. |
-AuthConfigPath |
No | prompt | JSON describing GroupPermissions and UserAssignments for Entra ID / Easy Auth provisioning. Omit together with -SkipAuthProvisioning to skip auth setup entirely. |
Package inputs
| Parameter | Required | Default | Description |
|---|---|---|---|
-SecureConfigPath |
Yes | prompt | Path to a secure.config. An AES-encrypted file is validated and staged as-is; a plaintext JSON file is validated then auto-AES-encrypted before staging. See Security — Secure.config. |
-WorkflowsSourcePath |
Yes | prompt | Folder of workflow .bite resource files; staged into <PublishDir>/Resources. |
-LicenseConfigPath |
No | prompt (optional) | Path to a Warewolf License.secureconfig. Copied to the publish root. When omitted, the license check (default ON) may fail at startup. See Security — Warewolf License.secureconfig. |
Encryption / Key Vault
| Parameter | Required | Default | Description |
|---|---|---|---|
-EncryptResources |
No | false |
Encrypt all deployable sources (workflow .bite ConnectionStrings, Elasticsearch source) from plain text or DPAPI to WFAES using the Key Vault key. Encrypt once — leave this off on subsequent deploys; sources stay encrypted and are staged as-is. |
-VerifyDecryption |
No | off | After encryption, verify in memory that the Key Vault key can decrypt every value. No plaintext is written to disk. Only meaningful with -EncryptResources. |
-KeyVaultName |
Conditional | — | Key Vault the engine uses to decrypt WFAES sources at runtime. Required when -EncryptResources is set, and on all subsequent deploys where sources are already WFAES-encrypted (so app settings and the managed-identity role are wired correctly). |
-KeyVaultSecretName |
Yes (when -KeyVaultName used) |
— | Name of the Key Vault secret holding the AES key material. No default — name it explicitly. |
-GenerateNewKey |
No | off (implied for a new vault) | Generate a fresh AES-256 key. Use on first deploy or during key rotation. |
Application Insights
| Parameter | Required | Default | Description |
|---|---|---|---|
-EnableAppInsights |
No | prompt | Provision an Application Insights resource and wire WAREWOLF_APPINSIGHTS_CONNECTION_STRING. The engine uses a deliberately non-standard env-var name, so the Azure portal’s Function App monitoring blade will always show a “Turn On Application Insights” button — do not click it. Verify telemetry in the App Insights resource’s own Logs and Live Metrics blades instead. |
-AppInsightsName |
No | <AppName>-ai |
Application Insights resource name. |
Elasticsearch logging
| Parameter | Required | Default | Description |
|---|---|---|---|
-EnableElasticsearch |
No | prompt | Enable Elasticsearch logging. Requires -ElasticsearchSourcePath and Key Vault (the source ConnectionString is WFAES-encrypted before deploy). |
-ElasticsearchSourcePath |
Conditional | — | Path to the Elasticsearch source file. The file must be named exactly ElasticsearchLoggingSource.bite — the engine reads that exact filename. |
Logging / feature env vars
| Parameter | Required | Default | Description |
|---|---|---|---|
-ExecutionLogLevel |
No | INFO |
TRACE / DEBUG / INFO / WARN / ERROR / FATAL / OFF. Sets EXECUTIONLOGLEVEL — drives the engine’s console and App Insights logging. The isolated worker does not read host.json. |
-EnableConsoleLogging |
No | prompt | Set ENABLECONSOLELOGGING=true. |
-LicenseCheckEnabled |
No | true |
Set WAREWOLF_LICENSE_CHECK_ENABLED. |
-StructuredLogs |
No | true |
STRUCTURED_LOGS — JSON console output. |
-AlignHostJsonLogLevel |
No | off | Opt-in. Also rewrites the published host.json logLevel to the mapped level. Tunes only the Functions host process verbosity — not needed for the engine’s own logging. |
Logging output / control
| Parameter | Default | Description |
|---|---|---|
-DryRun |
off | Print every mutating action without executing it. Read-only probes still run; a .dryrun. transcript and summary are written. |
-NonInteractive |
off | Never prompt; a missing required value throws early with a clear message. Use in CI/unattended pipelines. |
-LogDir |
<PublishDir>\..\deploy-logs |
Directory for the transcript and summary JSON. |
-LoadFunctionsOnly |
off | Test hook. Dot-sources the script to define its helpers and returns before any cloud/filesystem action (used by the Pester suite). Not for normal runs. |
Fixed env vars (no parameters): ASPNETCORE_ENVIRONMENT is always Production; BYPASS_SECURE_CONFIG, WAREWOLF_SUPER_ADMIN_ENABLED, and SkipFailureToRetrieveSecret are always false.
Worked examples
Example A — Dry run: inspect the plan without touching Azure
.\Deploy-WwExecutionEngine.ps1 `
-ResourceGroup DEV2 -Location southafricanorth `
-StorageAccount stwwenginetestv1 -AppName wwenginetestv1 `
-PublishPath 'D:\ExecutionEngine\AzureFunctionsPackage-3.0.1.200' `
-DryRun
Example B — Minimal deploy: no encryption, no Elasticsearch, no App Insights
The smallest real deploy — infra, package, auth, and a plaintext secure.config that the script auto-encrypts on staging.
.\Deploy-WwExecutionEngine.ps1 `
-ResourceGroup DEV2 -Location southafricanorth `
-StorageAccount stwwenginetestv1 -AppName wwenginetestv1 `
-PublishPath 'D:\ExecutionEngine\AzureFunctionsPackage-3.0.1.200' `
-AuthConfigPath 'D:\ExecutionEngine\Deploy-WwExecutionEngine.authconfig.json' `
-SecureConfigPath 'C:\ProgramData\Warewolf\Server Settings\secure.config' `
-WorkflowsSourcePath 'C:\ProgramData\Warewolf\Resources' `
-EnableAppInsights:$false -EnableElasticsearch:$false `
-PublishMethod Zip
Example C — First-time encrypted deploy: generate a new AES key and verify decryption in memory
Use this on a brand-new deployment where no Key Vault or AES key exists yet. -GenerateNewKey creates the key; -VerifyDecryption confirms the key can decrypt everything before the deploy proceeds.
.\Deploy-WwExecutionEngine.ps1 `
-ResourceGroup DEV2 -Location southafricanorth `
-StorageAccount stwwenginetestv1 -AppName wwenginetestv1 `
-PublishPath 'D:\ExecutionEngine\AzureFunctionsPackage-3.0.1.200' `
-AuthConfigPath 'D:\ExecutionEngine\Deploy-WwExecutionEngine.authconfig.json' `
-SecureConfigPath 'C:\ProgramData\Warewolf\Server Settings\secure.config' `
-WorkflowsSourcePath 'C:\ProgramData\Warewolf\Resources' `
-LicenseConfigPath 'D:\ExecutionEngine\Warewolf License.secureconfig' `
-EncryptResources:$true -VerifyDecryption -GenerateNewKey `
-KeyVaultName WWExecutionEngine -KeyVaultSecretName WWExecutionEngineTestSecret `
-EnableAppInsights:$true `
-PublishMethod Zip
Example D — Re-deploy already-encrypted sources (do not re-encrypt)
Sources were encrypted on a previous run. Omit -EncryptResources so they are staged as-is, but still pass -KeyVaultName/-KeyVaultSecretName so the runtime app settings and managed-identity role are wired correctly.
.\Deploy-WwExecutionEngine.ps1 `
-ResourceGroup DEV2 -Location southafricanorth `
-StorageAccount stwwenginetestv1 -AppName wwenginetestv1 `
-PublishPath 'D:\ExecutionEngine\AzureFunctionsPackage-3.0.1.200' `
-AuthConfigPath 'D:\ExecutionEngine\Deploy-WwExecutionEngine.authconfig.json' `
-SecureConfigPath 'C:\ProgramData\Warewolf\Server Settings\secure.config' `
-WorkflowsSourcePath 'C:\ProgramData\Warewolf\Resources' `
-EncryptResources:$false `
-KeyVaultName WWExecutionEngine -KeyVaultSecretName WWExecutionEngineTestSecret `
-EnableAppInsights:$true `
-PublishMethod Zip
Example E — Full deploy using splatting (avoids the backtick gotcha)
A hashtable splat is identical to the Step 2 deploy but has no line-continuation backticks to get wrong, and is easy to diff and version-control.
$deploy = @{
ResourceGroup = 'DEV2'
Location = 'southafricanorth'
StorageAccount = 'stwwenginetestv1'
AppName = 'wwenginetestv1'
PublishPath = 'D:\ExecutionEngine\AzureFunctionsPackage-3.0.1.200'
AuthConfigPath = 'D:\ExecutionEngine\Deploy-WwExecutionEngine.authconfig.json'
SecureConfigPath = 'C:\ProgramData\Warewolf\Server Settings\secure.config'
WorkflowsSourcePath = 'C:\ProgramData\Warewolf\Resources'
LicenseConfigPath = 'D:\ExecutionEngine\Warewolf License.secureconfig'
EncryptResources = $true
VerifyDecryption = $true
KeyVaultName = 'WWExecutionEngine'
KeyVaultSecretName = 'WWExecutionEngineTestSecret'
EnableAppInsights = $true
EnableElasticsearch = $true
ElasticsearchSourcePath = 'D:\ExecutionEngine\ElasticsearchLoggingSource.bite'
LogDir = 'D:\ExecutionEngine\Scripts\logs'
PublishMethod = 'Zip'
}
$ts = Get-Date -Format 'yyyyMMdd-HHmmss'
Start-Transcript -Path ".\logs\deploy-$ts.log" | Out-Null
.\Deploy-WwExecutionEngine.ps1 @deploy
Stop-Transcript | Out-Null
Example F — Non-interactive / CI pipeline
Force an early, explicit error on any missing required value instead of prompting. Pass all required parameters via the splat and add -NonInteractive.
.\Deploy-WwExecutionEngine.ps1 @deploy -NonInteractive
Resources: created by the script vs. assumed pre-existing
The orchestrator is a thin deployer: it provisions cloud infrastructure and wires it up, but it does not build the package and does not create your input files or your identities. Every infrastructure resource is existence-checked first and recorded in the run summary’s created map (true = this run created it; false = found pre-existing) so the rollback only ever removes what this run actually created.
Created by the script (when absent)
| Resource | Condition | Notes |
|---|---|---|
| Resource group | Always | Created in -Location if it doesn’t exist. |
| Storage account | Always | Standard_LRS, StorageV2, TLS 1.2. |
| Function App | Always | Consumption (Y1), dotnet-isolated 8, Functions v4, HTTPS-only. |
| Application Insights | When -EnableAppInsights |
Default name <AppName>-ai; worker telemetry wired via WAREWOLF_APPINSIGHTS_CONNECTION_STRING. |
| System-assigned managed identity | When a Key Vault is in play | Enabled on the Function App so the engine can read the AES key at runtime. |
| Key Vault | Only with -EncryptResources |
RBAC-authorised vault. If a vault is needed but missing and -EncryptResources is off, the script throws rather than creating one. |
| AES key (stored as a Key Vault secret) | Only with -EncryptResources, real run |
AES-256 material written as a JSON secret (-KeyVaultSecretName). The script does not create a Key Vault cryptographic key object. |
| Key Vault role assignments | When a Key Vault is in play | Key Vault Secrets User → Function App identity (always); Key Vault Secrets Officer → current user (only when encrypting). |
| Entra app registration, service principal, OAuth scope, app roles, client secret, Easy Auth config | Unless -SkipAuthProvisioning |
Provisioned by Configure-WwExecutionAuth.ps1. Idempotent — re-runs upgrade in place. |
| App settings / environment variables | Always | The engine’s full env-var map (see Parameter reference above). |
Resources\workflow-index.json |
When workflows are staged | Generated over the staged Resources folder and bundled into the deploy zip. |
Assumed to already exist (the script validates and throws if missing)
| Item | Supplied via | Behaviour if missing |
|---|---|---|
Azure subscription + active az login |
az login (Step 0) |
Pre-flight throws: “Not logged in to Azure CLI.” |
| The signed-in user’s roles/privileges | Admin grants (see Required roles & privileges above) | Not self-granted (except the Key Vault data-plane role). Azure returns authorisation errors mid-run. |
| Published package | -PublishPath (folder or .zip) |
Throws — you must dotnet publish the engine yourself first; the script never builds. |
secure.config |
-SecureConfigPath |
Plaintext is auto-encrypted; encrypted is validated decryptable. Throws if unreadable or invalid. |
Workflow .bite resources |
-WorkflowsSourcePath |
Throws if the path doesn’t exist. |
Warewolf License.secureconfig |
-LicenseConfigPath |
Optional. If omitted, the license check (default ON) may fail at startup. |
ElasticsearchLoggingSource.bite |
-ElasticsearchSourcePath |
Required when -EnableElasticsearch; throws if missing or not named exactly ElasticsearchLoggingSource.bite. |
| Auth config JSON | -AuthConfigPath |
Throws if specified but not found. If omitted, auth is provisioned with empty group/user maps. |
| Existing Key Vault (when re-deploying encrypted sources) | -KeyVaultName without -EncryptResources |
The script throws rather than creating the vault — re-deploy of already-encrypted sources requires the vault to already exist. |
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Script fails immediately with “#Requires -Version 7.0” or syntax errors | Running under Windows PowerShell 5.1. | Open a PowerShell 7+ terminal and re-run. Verify with $PSVersionTable.PSVersion. |
az commands fail with “Please run ‘az login'” |
Not logged in to the Azure CLI. | Run az login and az account set --subscription <id> before running the script. |
| Deploy lands in the wrong subscription | Active subscription not set. | Run az account set --subscription <id> or pass -SubscriptionId explicitly. |
| Phase 4 zip-deploy fails or times out | Package too large, network issue, or Function App still starting. | Check -LogDir transcript for the az functionapp deploy error. Re-run the script — the deploy is idempotent and the summary records what was already created. |
| Engine returns HTTP 503 on every request after deploy | secure.config missing or invalid in the deployed package. |
Verify -SecureConfigPath pointed to a valid file. See Security — Secure.config. |
| Workflows fail — license check fails at startup | Warewolf License.secureconfig missing or Status not Active/InTrial. |
Supply a valid encrypted licence via -LicenseConfigPath. See Security — Warewolf License.secureconfig. |
WFAES decryption fails at runtime (SkipFailureToRetrieveSecret errors in logs) |
Key Vault app settings not wired, or managed identity lacks the Key Vault role. | Re-run the deploy passing -KeyVaultName and -KeyVaultSecretName (without -EncryptResources) to re-wire the app settings and role assignment. |
| App Insights portal blade shows “Turn On Application Insights” | By design — the engine uses WAREWOLF_APPINSIGHTS_CONNECTION_STRING, not the standard key. |
Do not click “Turn On”. Verify telemetry in the App Insights resource’s own Logs and Live Metrics blades. |
| Rollback deletes too much / too little | Wrong summary file selected (e.g. a dry-run summary). | Check that $summary points to the correct real-run summary and not a dry-run file. Preview the rollback output before re-running with the execute flag to perform the teardown. |




