Workbooks and Dashboards¶
Azure Monitor workbooks provide parameterized operational analysis, while Azure dashboards provide at-a-glance status views for shared audiences. This runbook focuses on maintaining both assets as reusable, versioned operational artifacts.
flowchart TD
Data[Metrics and logs] --> Workbook[Azure Monitor workbook]
Workbook --> Query[KQL and metric visuals]
Workbook --> Dashboard[Azure dashboard pinning or summary]
Dashboard --> NOC[Operations viewers]
Workbook --> Ops[Investigators] Prerequisites¶
- Azure CLI authenticated with
az login. - A Log Analytics workspace with queryable data.
- Workbook JSON or serialized content stored in source control.
- If dashboards are used, a dashboard definition JSON file available for deployment.
- Permissions:
Workbook Contributorfor workbook changes.Contributoron the resource group for portal dashboard changes.
- Variables used below:
RG="rg-monitoring-prod" WORKBOOK_NAME="wb-ops-health-report" WORKBOOK_DISPLAY_NAME="Operations Health Report" WORKBOOK_FILE="./docs/examples/workbook-ops-health-report.json" DASHBOARD_NAME="dashboard-monitoring-overview" DASHBOARD_FILE="./docs/examples/dashboard-monitoring-overview.json" LOCATION="eastus"
When to Use¶
- You need a reusable operational view for incident triage.
- A workbook query or parameter set needs an update after schema changes.
- A NOC dashboard must be standardized across subscriptions.
- Visual content drifted from the version-controlled baseline.
- A workbook needs to be verified after alert or DCR changes.
- A central team needs the same monitoring view deployed across environments.
Procedure¶
Step 1: Inventory existing workbooks and dashboards¶
Check what already exists before you create a duplicate artifact.
az monitor workbook list \
--resource-group $RG \
--query "[].{name:name,displayName:displayName,location:location,kind:kind}" \
--output table
| Command | Purpose |
|---|---|
az monitor workbook list | List workbooks. |
--resource-group | Resource group that contains the resource. |
--query | JMESPath projection of the fields to return. |
--output | Output format for the result. |
Expected output:
Name DisplayName Location Kind
--------------------- ------------------------- ---------- ------------------
wb-ops-health-report Operations Health Report eastus shared
az portal dashboard list \
--resource-group $RG \
--query "[].{name:name,location:location,tags:tags}" \
--output table
| Command | Purpose |
|---|---|
az portal dashboard list | List portal dashboards. |
--resource-group | Resource group that contains the resource. |
--query | JMESPath projection of the fields to return. |
--output | Output format for the result. |
Expected output:
Name Location Tags
------------------------------ ---------- --------------------------------
dashboard-monitoring-overview eastus {'owner':'monitoring','tier':'ops'}
Step 2: Create or update the workbook from a checked-in file¶
Use a versioned source file rather than editing only in the portal.
az monitor workbook create \
--name $WORKBOOK_NAME \
--resource-group $RG \
--location $LOCATION \
--display-name "$WORKBOOK_DISPLAY_NAME" \
--kind shared \
--serialized-data @$WORKBOOK_FILE \
--output json
| Command | Purpose |
|---|---|
az monitor workbook create | Create a workbook. |
--name | Name of the resource. |
--resource-group | Resource group that contains the resource. |
--location | Azure region for the resource. |
--display-name | Display name shown in the portal. |
--kind | Resource kind. |
--serialized-data | Serialized JSON payload defining the resource. |
--output | Output format for the result. |
Expected output:
{
"displayName": "Operations Health Report",
"kind": "shared",
"location": "eastus",
"name": "wb-ops-health-report",
"provisioningState": "Succeeded"
}
az monitor workbook update \
--name $WORKBOOK_NAME \
--resource-group $RG \
--serialized-data @$WORKBOOK_FILE \
--output json
| Command | Purpose |
|---|---|
az monitor workbook update | Update a workbook. |
--name | Name of the resource. |
--resource-group | Resource group that contains the resource. |
--serialized-data | Serialized JSON payload defining the resource. |
--output | Output format for the result. |
Expected output:
{
"displayName": "Operations Health Report",
"name": "wb-ops-health-report",
"revision": "1d2f7d4c-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
Step 3: Read back workbook metadata and serialized content¶
Confirm that the workbook saved as a shared resource and still contains the expected definition.
az monitor workbook show \
--name $WORKBOOK_NAME \
--resource-group $RG \
--query "{name:name,displayName:displayName,kind:kind,location:location,version:version}" \
--output json
| Command | Purpose |
|---|---|
az monitor workbook show | Show a workbook. |
--name | Name of the resource. |
--resource-group | Resource group that contains the resource. |
--query | JMESPath projection of the fields to return. |
--output | Output format for the result. |
Expected output:
{
"displayName": "Operations Health Report",
"kind": "shared",
"location": "eastus",
"name": "wb-ops-health-report",
"version": "Notebook/1.0"
}
Step 4: Create or update the Azure dashboard definition¶
Dashboards are best treated like infrastructure definitions for team-wide operational views.
az portal dashboard create \
--resource-group $RG \
--name $DASHBOARD_NAME \
--location $LOCATION \
--input-path $DASHBOARD_FILE \
--tags owner=monitoring tier=ops \
--output json
| Command | Purpose |
|---|---|
az portal dashboard create | Create a portal dashboard. |
--resource-group | Resource group that contains the resource. |
--name | Name of the resource. |
--location | Azure region for the resource. |
--input-path | Path to the input payload file. |
--tags | Tags applied to the resource. |
--output | Output format for the result. |
Expected output:
{
"location": "eastus",
"name": "dashboard-monitoring-overview",
"provisioningState": "Succeeded",
"tags": {
"owner": "monitoring",
"tier": "ops"
}
}
Step 5: Validate workbook queries and dashboard presence¶
Operational views are only useful if the underlying queries still return data.
az monitor log-analytics query \
--workspace "/subscriptions/<subscription-id>/resourceGroups/rg-monitoring-prod/providers/Microsoft.OperationalInsights/workspaces/law-ops-central" \
--analytics-query "Heartbeat | where TimeGenerated > ago(1h) | summarize ActiveAgents=dcount(Computer)" \
--output table
| Command | Purpose |
|---|---|
az monitor log-analytics query | Run a KQL query against a Log Analytics workspace. |
--workspace | Log Analytics workspace ID for the query. |
--analytics-query | Kusto (KQL) query to execute. |
--output | Output format for the result. |
Expected output:
Then confirm the dashboard resource exists.az portal dashboard show \
--resource-group $RG \
--name $DASHBOARD_NAME \
--query "{name:name,location:location,tags:tags}" \
--output json
| Command | Purpose |
|---|---|
az portal dashboard show | Show a portal dashboard. |
--resource-group | Resource group that contains the resource. |
--name | Name of the resource. |
--query | JMESPath projection of the fields to return. |
--output | Output format for the result. |
Expected output:
{
"location": "eastus",
"name": "dashboard-monitoring-overview",
"tags": {
"owner": "monitoring",
"tier": "ops"
}
}
Verification¶
Verify workbook presence:
az monitor workbook list \
--resource-group $RG \
--query "[].{name:name,displayName:displayName}" \
--output table
| Command | Purpose |
|---|---|
az monitor workbook list | List workbooks. |
--resource-group | Resource group that contains the resource. |
--query | JMESPath projection of the fields to return. |
--output | Output format for the result. |
Expected output:
Name DisplayName
--------------------- -------------------------
wb-ops-health-report Operations Health Report
az portal dashboard list \
--resource-group $RG \
--query "[].{name:name,location:location}" \
--output table
| Command | Purpose |
|---|---|
az portal dashboard list | List portal dashboards. |
--resource-group | Resource group that contains the resource. |
--query | JMESPath projection of the fields to return. |
--output | Output format for the result. |
Expected output:
Verify that the workbook resource is still shared:az monitor workbook show \
--name $WORKBOOK_NAME \
--resource-group $RG \
--query "{name:name,kind:kind,displayName:displayName}" \
--output json
| Command | Purpose |
|---|---|
az monitor workbook show | Show a workbook. |
--name | Name of the resource. |
--resource-group | Resource group that contains the resource. |
--query | JMESPath projection of the fields to return. |
--output | Output format for the result. |
Expected output:
Verification succeeds when the workbook and dashboard exist in the resource group and the validation query used by the workbook still returns data.Rollback / Troubleshooting¶
Delete a broken workbook:
| Command | Purpose |
|---|---|
az monitor workbook delete | Delete a workbook. |
--name | Name of the resource. |
--resource-group | Resource group that contains the resource. |
--yes | Skips the confirmation prompt. |
Delete a broken dashboard:
| Command | Purpose |
|---|---|
az portal dashboard delete | Delete a portal dashboard. |
--resource-group | Resource group that contains the resource. |
--name | Name of the resource. |
Common problems: - Workbook loads but visual is empty - Run the underlying KQL manually and validate parameters. - Workbook update fails - Confirm the serialized JSON is valid and not truncated. - Dashboard tiles show authorization errors - Verify viewer access to the underlying resources, not only the dashboard object. - Duplicate assets appear - Standardize naming, tags, and source-controlled definitions. - Dashboard exists in the wrong subscription or resource group - Re-check deployment scope before assuming the JSON definition is broken. - Shared workbook was replaced by a private draft - Re-deploy the shared workbook from source control and confirm the kind value.
Automation¶
Treat workbook JSON and dashboard JSON as deployable artifacts.
az monitor workbook list \
--query "[].{name:name,resourceGroup:resourceGroup,displayName:displayName}" \
--output json
| Command | Purpose |
|---|---|
az monitor workbook list | List workbooks. |
--query | JMESPath projection of the fields to return. |
--output | Output format for the result. |
Useful automation patterns: - Store workbook JSON and dashboard JSON in the repository. - Deploy both through CI after pull-request review. - Add a smoke test query for each workbook's primary visual. - Report unmanaged workbooks or dashboards that lack standard tags. - Require owners and environment tags on every dashboard resource. - Run scheduled inventory exports so teams can review stale or duplicate visual assets. - Export workbook metadata regularly so private copies and shared copies are easy to compare. - Validate at least one parameterized workbook query after every monitoring schema change. - Review dashboard viewers and owners during quarterly operational access checks.
See Also¶
- Operations index
- Alert Rule Management
- Workspace Management
- Troubleshooting KQL query packs
- Export and Integration
- Reference KQL quick reference
Sources¶
- Microsoft Learn: Azure Monitor workbooks overview
- Microsoft Learn: Visualize data in Azure Monitor
- Microsoft Learn: Create Azure Monitor workbooks
- Microsoft Learn: Create and share dashboards in the Azure portal
- Microsoft Learn: Create Azure portal dashboards programmatically
- Microsoft Learn: Azure Monitor workbook samples and templates