{
  "version": "Notebook/1.0",
  "items": [
    {
      "type": 9,
      "content": {
        "version": "KqlParameterItem/1.0",
        "parameters": [
          {
            "id": "7b05a598-5120-43f4-bf5d-576c2a7ff28d",
            "version": "KqlParameterItem/1.0",
            "name": "TimeRange",
            "type": 4,
            "isRequired": true,
            "value": {
              "durationMs": 86400000
            },
            "typeSettings": {
              "selectableValues": [
                {
                  "durationMs": 3600000
                },
                {
                  "durationMs": 14400000
                },
                {
                  "durationMs": 43200000
                },
                {
                  "durationMs": 86400000
                },
                {
                  "durationMs": 172800000
                },
                {
                  "durationMs": 604800000
                },
                {
                  "durationMs": 2592000000
                }
              ]
            }
          }
        ],
        "style": "pills",
        "queryType": 0,
        "resourceType": "microsoft.operationalinsights/workspaces"
      },
      "name": "parameters"
    },
    {
      "type": 1,
      "content": {
        "json": "<div style=\"display:flex;align-items:center;padding:8px 0 16px 0;border-bottom:1px solid #1e293b\"><svg width=\"40\" height=\"40\" style=\"margin-right:14px;flex-shrink:0;fill:#3b82f6\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\"><path d=\"M65.6 127.7c35.3 0 63.9-28.6 63.9-63.9S100.9 0 65.6 0 1.8 28.6 1.8 63.9s28.6 63.8 63.8 63.8\" opacity=\".2\"/><path d=\"M65.6 318.1c35.3 0 63.9-28.6 63.9-63.9s-28.6-63.9-63.9-63.9S1.8 219 1.8 254.2s28.6 63.9 63.8 63.9\"/><path d=\"M65.6 512c35.3 0 63.9-28.6 63.9-63.9s-28.6-63.9-63.9-63.9-63.8 28.7-63.8 63.9S30.4 512 65.6 512\" opacity=\".2\"/><path d=\"M257.2 318.1c35.3 0 63.9-28.6 63.9-63.9s-28.6-63.9-63.9-63.9-63.9 28.6-63.9 63.9 28.6 63.9 63.9 63.9m0 193.9c35.3 0 63.9-28.6 63.9-63.9s-28.6-63.9-63.9-63.9-63.9 28.6-63.9 63.9 28.6 63.9 63.9 63.9\"/><path d=\"M257.2 127.7c35.3 0 63.9-28.6 63.9-63.9S292.5 0 257.2 0s-63.9 28.6-63.9 63.9 28.6 63.8 63.9 63.8m189.2 0c35.3 0 63.9-28.6 63.9-63.9S481.6 0 446.4 0c-35.3 0-63.9 28.6-63.9 63.9s28.6 63.8 63.9 63.8\" opacity=\".2\"/><path d=\"M446.4 318.1c35.3 0 63.9-28.6 63.9-63.9s-28.6-63.9-63.9-63.9-63.9 28.6-63.9 63.9 28.6 63.9 63.9 63.9\"/><path d=\"M446.4 512c35.3 0 63.9-28.6 63.9-63.9s-28.6-63.9-63.9-63.9-63.9 28.6-63.9 63.9 28.6 63.9 63.9 63.9\" opacity=\".2\"/></svg><div><div style=\"font-size:22px;font-weight:600;letter-spacing:-0.5px\">Tailscale Operations (Premium)</div><div style=\"font-size:13px;color:#94a3b8;margin-top:2px\">Single-pane visibility into your Tailscale tailnet on Personal (Free), Starter and Premium tiers: who, what, when, where, and what changed. Scope every panel with the time range below; the Investigate tab adds Actor and Device pickers for drilldown. Premium-tier panels (network flow logs, posture integrations) live in the separate <strong>Tailscale Operations (Premium)</strong> workbook.</div></div></div>"
      },
      "name": "header"
    },
    {
      "type": 11,
      "content": {
        "version": "LinkItem/1.0",
        "style": "tabs",
        "links": [
          {
            "id": "9794e9fd-916b-494d-8e72-af63d2f4c6c7",
            "cellValue": "selectedTab",
            "linkTarget": "parameter",
            "linkLabel": "Overview",
            "subTarget": "overview",
            "style": "link"
          },
          {
            "id": "71cf49db-33c5-4d4b-920a-2ec0c6a258dc",
            "cellValue": "selectedTab",
            "linkTarget": "parameter",
            "linkLabel": "Investigate",
            "subTarget": "investigate",
            "style": "link"
          },
          {
            "id": "5c56bb37-2053-47a0-b6fd-9539768c144d",
            "cellValue": "selectedTab",
            "linkTarget": "parameter",
            "linkLabel": "Hunts",
            "subTarget": "hunts",
            "style": "link"
          },
          {
            "id": "d2004ded-07f8-446a-a720-f0a63d1d9dda",
            "cellValue": "selectedTab",
            "linkTarget": "parameter",
            "linkLabel": "Identity",
            "subTarget": "identity",
            "style": "link"
          },
          {
            "id": "f23b3e14-1511-4a29-bf5e-bd65e55dbb40",
            "cellValue": "selectedTab",
            "linkTarget": "parameter",
            "linkLabel": "Devices",
            "subTarget": "devices",
            "style": "link"
          },
          {
            "id": "724f8352-e21b-45a6-9029-39dc92693c05",
            "cellValue": "selectedTab",
            "linkTarget": "parameter",
            "linkLabel": "Credentials",
            "subTarget": "credentials",
            "style": "link"
          },
          {
            "id": "8400ec64-e118-44e0-ae29-84afe94b8e0e",
            "cellValue": "selectedTab",
            "linkTarget": "parameter",
            "linkLabel": "Admin Audit",
            "subTarget": "audit",
            "style": "link"
          },
          {
            "id": "b7e04861-edfa-4426-b6be-f1481ca569b6",
            "cellValue": "selectedTab",
            "linkTarget": "parameter",
            "linkLabel": "Network & DNS",
            "subTarget": "network",
            "style": "link"
          },
          {
            "id": "b8506d3d-e615-4775-8c6f-14d9cc7db943",
            "cellValue": "selectedTab",
            "linkTarget": "parameter",
            "linkLabel": "Network Flows",
            "subTarget": "network-flows",
            "style": "link"
          },
          {
            "id": "c98574ec-7a60-4c1a-b4c6-4d24c5bd02ce",
            "cellValue": "selectedTab",
            "linkTarget": "parameter",
            "linkLabel": "Posture",
            "subTarget": "posture",
            "style": "link"
          },
          {
            "id": "cfbc96e4-8585-4d89-8f65-8344c8cc6eb2",
            "cellValue": "selectedTab",
            "linkTarget": "parameter",
            "linkLabel": "Pipeline Health",
            "subTarget": "pipeline",
            "style": "link"
          }
        ]
      },
      "name": "tabs"
    },
    {
      "type": 12,
      "content": {
        "version": "NotebookGroup/1.0",
        "groupType": "editable",
        "items": [
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Tailnet at a glance</div>"
            },
            "name": "div-tailnet-at-a-glance-04e62b"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "let DEV = Tailscale_Devices_CL | summarize arg_max(TimeGenerated, *) by DeviceId;\nlet USR = Tailscale_Users_CL   | summarize arg_max(TimeGenerated, *) by UserId;\nlet KEY = Tailscale_Keys_CL    | summarize arg_max(TimeGenerated, *) by KeyId;\nunion\n  (DEV | summarize V=toreal(count())                                            | extend Metric=\"Devices\",         Order=1),\n  (DEV | where Authorized == true                                               | summarize V=toreal(count()) | extend Metric=\"Authorized\",      Order=2),\n  (DEV | where UpdateAvailable == true                                          | summarize V=toreal(count()) | extend Metric=\"Updates Available\", Order=3),\n  (DEV | where SshEnabled == true                                               | summarize V=toreal(count()) | extend Metric=\"SSH-Enabled\",     Order=4),\n  (USR | summarize V=toreal(count())                                            | extend Metric=\"Users\",           Order=5),\n  (USR | where Role =~ \"admin\" or Role =~ \"owner\" or Role =~ \"network-admin\"    | summarize V=toreal(count()) | extend Metric=\"Admins\",          Order=6),\n  (KEY | where isnull(Revoked) and (isnull(Expires) or Expires > now())         | summarize V=toreal(count()) | extend Metric=\"Active Keys\",     Order=7),\n  (Tailscale_Audit_CL | where TimeGenerated {TimeRange} | summarize V=toreal(count()) | extend Metric=\"Audit Events ({TimeRange:label})\", Order=8)\n,\n  (Tailscale_Network_CL | where TimeGenerated {TimeRange} | summarize V=toreal(count())                                  | extend Metric=\"Flows ({TimeRange:label})\", Order=9),\n  (Tailscale_Network_CL | where TimeGenerated {TimeRange} | summarize V=toreal(dcount(SrcNodeName))                      | extend Metric=\"Active Talkers\",           Order=10),\n  (Tailscale_Network_CL | where TimeGenerated {TimeRange} | summarize V=toreal(iff(count()==0, 0.0, 100.0 * countif(IsRelayed) / count())) | extend Metric=\"DERP Relayed %\",  Order=11),\n  (Tailscale_PostureIntegrations_CL | where TimeGenerated {TimeRange} | summarize arg_max(TimeGenerated, *) by IntegrationId | summarize V=toreal(count()) | extend Metric=\"Posture Integrations\", Order=12)\n| order by Order asc | project Metric, Value=V",
              "size": 3,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "tiles",
              "tileSettings": {
                "titleContent": {
                  "columnMatch": "Metric",
                  "formatter": 1
                },
                "leftContent": {
                  "columnMatch": "Value",
                  "formatter": 12,
                  "formatOptions": {
                    "palette": "auto"
                  }
                },
                "showBorder": false
              }
            },
            "name": "q-4e9d7cff"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Audit activity over time</div>"
            },
            "name": "div-audit-activity-over--546688"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Audit_CL\n| where TimeGenerated {TimeRange}\n| summarize EventCount = count() by bin(TimeGenerated, 1h), Action\n| order by TimeGenerated asc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "timechart",
              "title": "Audit events by action",
              "noDataMessage": "No audit events in the selected window. Widen the time range; remember the Tailscale audit poll runs every ~30 min.",
              "noDataMessageStyle": 5
            },
            "name": "q-effcd498"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Who's doing what</div>"
            },
            "name": "div-who's-doing-what-52144e"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Audit_CL\n| where TimeGenerated {TimeRange}\n| extend Actor=tostring(coalesce(Actor.loginName, Actor.displayName, Actor.type))\n| where isnotempty(Actor)\n| summarize Events=count(), DistinctActions=dcount(Action), LastSeen=max(TimeGenerated) by Actor\n| order by Events desc | take 15",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "Top actors (by event count)",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "Events",
                    "formatter": 8,
                    "formatOptions": {
                      "palette": "blue"
                    }
                  },
                  {
                    "columnMatch": "LastSeen",
                    "formatter": 6
                  }
                ]
              }
            },
            "name": "q-34c77fa9",
            "customWidth": "50"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Audit_CL\n| where TimeGenerated {TimeRange}\n| extend TargetType=tostring(Target.type)\n| where isnotempty(TargetType)\n| summarize Events=count() by TargetType\n| order by Events desc | take 15",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "piechart",
              "title": "Activity by target type"
            },
            "name": "q-4b3b709d",
            "customWidth": "50"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Recent admin events</div>"
            },
            "name": "div-recent-admin-events-87c9e0"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Audit_CL\n| where TimeGenerated {TimeRange}\n| extend Actor=tostring(coalesce(Actor.loginName, Actor.displayName, Actor.type))\n| extend TargetType=tostring(Target.type), TargetName=tostring(coalesce(Target.name, Target.id))\n| project TimeGenerated, Action, Actor, TargetType, TargetName, Origin\n| order by TimeGenerated desc | take 30",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "Most recent 30 audit events",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "TimeGenerated",
                    "formatter": 6
                  }
                ]
              }
            },
            "name": "q-5e7d6306"
          }
        ]
      },
      "conditionalVisibility": {
        "parameterName": "selectedTab",
        "comparison": "isEqualTo",
        "value": "overview"
      },
      "name": "group-overview"
    },
    {
      "type": 12,
      "content": {
        "version": "NotebookGroup/1.0",
        "groupType": "editable",
        "items": [
          {
            "type": 9,
            "content": {
              "version": "KqlParameterItem/1.0",
              "parameters": [
                {
                  "id": "b83a25c1-da18-49a2-a444-6517f13d891c",
                  "version": "KqlParameterItem/1.0",
                  "name": "SelectedActor",
                  "label": "Actor",
                  "type": 2,
                  "isRequired": false,
                  "query": "let opts = Tailscale_Audit_CL\n| where TimeGenerated {TimeRange}\n| extend ActorLogin=tostring(coalesce(Actor.loginName, Actor.displayName))\n| where isnotempty(ActorLogin)\n| summarize Events=count() by ActorLogin\n| project value=ActorLogin, label=strcat(ActorLogin, \" (\", tostring(Events), \" events)\");\n(print value=\"__ALL__\", label=\"(All actors)\")\n| union opts",
                  "typeSettings": {
                    "showDefault": false
                  },
                  "queryType": 0,
                  "resourceType": "microsoft.operationalinsights/workspaces",
                  "value": "__ALL__"
                }
              ],
              "style": "pills",
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces"
            },
            "name": "investigate-picker-actor"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Actor activity timeline</div>"
            },
            "name": "div-actor-activity-timel-5ec305"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Audit_CL\n| where TimeGenerated {TimeRange}\n| extend ActorLogin=tostring(coalesce(Actor.loginName, Actor.displayName))\n| where \"{SelectedActor}\" == \"__ALL__\" or ActorLogin == \"{SelectedActor}\"\n| summarize Events=count() by bin(TimeGenerated, 1h), Action\n| order by TimeGenerated asc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "timechart",
              "title": "Actions over time -- actor: {SelectedActor:label}",
              "noDataMessage": "Select an actor from the Actor dropdown above, or leave on 'All' to see total activity.",
              "noDataMessageStyle": 5
            },
            "name": "q-32d40848"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Audit_CL\n| where TimeGenerated {TimeRange}\n| extend ActorLogin=tostring(coalesce(Actor.loginName, Actor.displayName))\n| where \"{SelectedActor}\" == \"__ALL__\" or ActorLogin == \"{SelectedActor}\"\n| extend TargetType=tostring(Target.type), TargetName=tostring(coalesce(Target.name, Target.id))\n| project TimeGenerated, ActorLogin, Action, TargetType, TargetName, Origin\n| order by TimeGenerated desc | take 100",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "Recent events for actor: {SelectedActor:label}",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "TimeGenerated",
                    "formatter": 6
                  }
                ]
              },
              "noDataMessage": "No events for this actor in the selected window.",
              "noDataMessageStyle": 5
            },
            "name": "q-a742f6fd"
          },
          {
            "type": 9,
            "content": {
              "version": "KqlParameterItem/1.0",
              "parameters": [
                {
                  "id": "a9cf7907-f201-4725-a072-a8bd34bef74e",
                  "version": "KqlParameterItem/1.0",
                  "name": "SelectedDevice",
                  "label": "Device",
                  "type": 2,
                  "isRequired": false,
                  "query": "let opts = Tailscale_Devices_CL\n| summarize arg_max(TimeGenerated, *) by DeviceId\n| order by LastSeen desc | take 100\n| project value=DeviceName, label=strcat(coalesce(DeviceName, Hostname), \" (\", User, \")\");\n(print value=\"__ALL__\", label=\"(All devices)\")\n| union opts",
                  "typeSettings": {
                    "showDefault": false
                  },
                  "queryType": 0,
                  "resourceType": "microsoft.operationalinsights/workspaces",
                  "value": "__ALL__"
                }
              ],
              "style": "pills",
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces"
            },
            "name": "investigate-picker-device"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Selected device timeline</div>"
            },
            "name": "div-selected-device-time-00bead"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Devices_CL\n| where \"{SelectedDevice}\" == \"__ALL__\" or DeviceName == \"{SelectedDevice}\"\n| summarize arg_max(TimeGenerated, *) by DeviceId\n| extend OnlineNow = ClientConnectivity.endpoints != \"\" or ConnectedToControl == true\n| project DeviceName, Hostname, User, Os, ClientVersion, UpdateAvailable, Authorized, IsExternal, SshEnabled, LastSeen, Expires, KeyExpiryDisabled, OnlineNow, Addresses, Tags, AdvertisedRoutes",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "Summary for device: {SelectedDevice:label}",
              "noDataMessage": "Select a device from the Device dropdown above. Defaults to 'All'.",
              "noDataMessageStyle": 5
            },
            "name": "q-11094dc8"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Audit_CL\n| where TimeGenerated {TimeRange}\n| extend TargetType=tostring(Target.type), TargetName=tostring(Target.name), TargetId=tostring(Target.id)\n| where (\"{SelectedDevice}\" == \"__ALL__\" and TargetType == \"NODE\") or TargetName == \"{SelectedDevice}\"\n| extend ActorLogin=tostring(coalesce(Actor.loginName, Actor.displayName))\n| project TimeGenerated, Action, ActorLogin, TargetName, TargetId, Origin\n| order by TimeGenerated desc | take 100",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "Audit events touching device: {SelectedDevice:label}",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "TimeGenerated",
                    "formatter": 6
                  }
                ]
              },
              "noDataMessage": "No audit events recorded against the selected device in this window. Tailscale tags device events with Target.type=NODE; the audit feed only emits NODE events on create/update/delete, so quiet devices stay quiet here.",
              "noDataMessageStyle": 5
            },
            "name": "q-ead106ce"
          }
        ]
      },
      "conditionalVisibility": {
        "parameterName": "selectedTab",
        "comparison": "isEqualTo",
        "value": "investigate"
      },
      "name": "group-investigate"
    },
    {
      "type": 12,
      "content": {
        "version": "NotebookGroup/1.0",
        "groupType": "editable",
        "items": [
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">First-seen actors in the last 24h</div>"
            },
            "name": "div-first-seen-actors-in-ce38d9"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "let recent = Tailscale_Audit_CL | where TimeGenerated > ago(24h) | extend A=tostring(coalesce(Actor.loginName, Actor.displayName)) | summarize FirstSeen24h=min(TimeGenerated), Events=count() by A;\nlet historical = Tailscale_Audit_CL | where TimeGenerated between(ago(30d) .. ago(24h)) | extend A=tostring(coalesce(Actor.loginName, Actor.displayName)) | distinct A;\nrecent | join kind=leftanti historical on A | where isnotempty(A) | project FirstSeen24h, Actor=A, Events | order by Events desc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "Actors who have NEVER appeared before (30d baseline)",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "FirstSeen24h",
                    "formatter": 6
                  },
                  {
                    "columnMatch": "Events",
                    "formatter": 8,
                    "formatOptions": {
                      "palette": "orange"
                    }
                  }
                ]
              },
              "noDataMessage": "Every actor seen in the last 24h has appeared at least once in the prior 30d. Healthy state.",
              "noDataMessageStyle": 1
            },
            "name": "q-9ba7b85e"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Off-hours configuration changes</div>"
            },
            "name": "div-off-hours-configurat-3c3787"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Audit_CL\n| where TimeGenerated {TimeRange}\n| extend Hour=hourofday(TimeGenerated), DayOfWeek=dayofweek(TimeGenerated)/1d\n| where Hour < 7 or Hour > 19 or DayOfWeek in (0, 6)\n| extend ActorLogin=tostring(coalesce(Actor.loginName, Actor.displayName))\n| extend TargetType=tostring(Target.type)\n| where Action !in (\"LOGIN\", \"LOGOUT\")\n| project TimeGenerated, ActorLogin, Action, TargetType, Origin\n| order by TimeGenerated desc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "Admin actions outside 07:00-19:00 weekdays",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "TimeGenerated",
                    "formatter": 6
                  }
                ]
              },
              "noDataMessage": "No off-hours admin changes recorded - healthy state for an organisation working business hours.",
              "noDataMessageStyle": 1
            },
            "name": "q-721ee490"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Devices with key expiry disabled</div>"
            },
            "name": "div-devices-with-key-exp-dfe9c1"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Devices_CL\n| summarize arg_max(TimeGenerated, *) by DeviceId\n| where KeyExpiryDisabled == true\n| project DeviceName, Hostname, User, Os, ClientVersion, LastSeen, Authorized, Tags\n| order by LastSeen desc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "Devices that will never re-authenticate (high-risk drift)",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "LastSeen",
                    "formatter": 6
                  }
                ]
              },
              "noDataMessage": "No devices have key expiry disabled - good. Disabling key expiry creates devices that never re-auth, drifting from policy.",
              "noDataMessageStyle": 1
            },
            "name": "q-8a8e2fb5"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Auth keys with no expiry</div>"
            },
            "name": "div-auth-keys-with-no-ex-b11207"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Keys_CL\n| summarize arg_max(TimeGenerated, *) by KeyId\n| where isnull(Revoked) and (isnull(Expires) or ExpirySeconds == 0)\n| project KeyId, Description, UserId, KeyType, Created, Capabilities\n| order by Created desc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "Active keys that never expire",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "Created",
                    "formatter": 6
                  }
                ]
              },
              "noDataMessage": "No never-expiring auth keys - rotation hygiene is good.",
              "noDataMessageStyle": 1
            },
            "name": "q-1372740c"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Devices running outdated clients</div>"
            },
            "name": "div-devices-running-outd-bcd077"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Devices_CL\n| summarize arg_max(TimeGenerated, *) by DeviceId\n| where UpdateAvailable == true\n| project DeviceName, Hostname, User, Os, ClientVersion, LastSeen, Tags\n| order by LastSeen desc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "Devices flagged update-available by Tailscale",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "LastSeen",
                    "formatter": 6
                  }
                ]
              },
              "noDataMessage": "All devices on current client - nothing to patch.",
              "noDataMessageStyle": 1
            },
            "name": "q-ecebf1f7"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Dormant devices (LastSeen > 30 days)</div>"
            },
            "name": "div-dormant-devices-(las-761156"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Devices_CL\n| summarize arg_max(TimeGenerated, *) by DeviceId\n| where LastSeen < ago(30d)\n| extend DaysIdle = toint((now() - LastSeen) / 1d)\n| project DeviceName, Hostname, User, Os, ClientVersion, LastSeen, DaysIdle, Authorized, Tags\n| order by DaysIdle desc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "Devices idle 30+ days - candidates for retirement",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "LastSeen",
                    "formatter": 6
                  },
                  {
                    "columnMatch": "DaysIdle",
                    "formatter": 8,
                    "formatOptions": {
                      "palette": "redBright"
                    }
                  }
                ]
              },
              "noDataMessage": "No devices idle 30+ days - inventory is fresh.",
              "noDataMessageStyle": 1
            },
            "name": "q-fb6c1fcc"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Subnet route exposure</div>"
            },
            "name": "div-subnet-route-exposur-289c42"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Devices_CL\n| summarize arg_max(TimeGenerated, *) by DeviceId\n| where array_length(AdvertisedRoutes) > 0 or array_length(EnabledRoutes) > 0\n| extend Routes = tostring(EnabledRoutes), Advertised = tostring(AdvertisedRoutes)\n| project DeviceName, Hostname, User, Os, Advertised, Routes, LastSeen, SshEnabled, Authorized\n| order by LastSeen desc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "Devices advertising or running subnet routes / exit-node duty",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "LastSeen",
                    "formatter": 6
                  }
                ]
              },
              "noDataMessage": "No devices advertising subnet routes. Pure mesh topology.",
              "noDataMessageStyle": 1
            },
            "name": "q-9533b081"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Devices with SSH enabled</div>"
            },
            "name": "div-devices-with-ssh-ena-285238"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Devices_CL\n| summarize arg_max(TimeGenerated, *) by DeviceId\n| where SshEnabled == true\n| project DeviceName, Hostname, User, Os, ClientVersion, LastSeen, Authorized, Tags\n| order by LastSeen desc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "Devices with Tailscale SSH enabled (Tailscale-managed remote-shell access)",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "LastSeen",
                    "formatter": 6
                  }
                ]
              },
              "noDataMessage": "No devices have Tailscale SSH enabled - no SSH-via-Tailscale risk surface.",
              "noDataMessageStyle": 1
            },
            "name": "q-735368fb"
          }
        ]
      },
      "conditionalVisibility": {
        "parameterName": "selectedTab",
        "comparison": "isEqualTo",
        "value": "hunts"
      },
      "name": "group-hunts"
    },
    {
      "type": 12,
      "content": {
        "version": "NotebookGroup/1.0",
        "groupType": "editable",
        "items": [
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">User inventory snapshot</div>"
            },
            "name": "div-user-inventory-snaps-9dc96c"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "let U = Tailscale_Users_CL | summarize arg_max(TimeGenerated, *) by UserId;\nunion\n  (U | summarize V=toreal(count())                                                | extend Metric=\"Total users\",        Order=1),\n  (U | where Role in~ (\"admin\",\"owner\",\"network-admin\",\"it-admin\",\"billing-admin\") | summarize V=toreal(count()) | extend Metric=\"Admin-tier users\",  Order=2),\n  (U | where Status =~ \"active\"                                                   | summarize V=toreal(count()) | extend Metric=\"Active\",            Order=3),\n  (U | where CurrentlyConnected == true                                           | summarize V=toreal(count()) | extend Metric=\"Connected now\",     Order=4),\n  (U | where Status =~ \"idle\" or LastSeen < ago(30d)                              | summarize V=toreal(count()) | extend Metric=\"Idle / dormant\",    Order=5),\n  (U | where UserType =~ \"shared\"                                                 | summarize V=toreal(count()) | extend Metric=\"Shared (external)\", Order=6)\n| order by Order asc | project Metric, Value=V",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "tiles",
              "tileSettings": {
                "titleContent": {
                  "columnMatch": "Metric",
                  "formatter": 1
                },
                "leftContent": {
                  "columnMatch": "Value",
                  "formatter": 12,
                  "formatOptions": {
                    "palette": "auto"
                  }
                },
                "showBorder": false
              }
            },
            "name": "q-5689d9e8"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Distribution</div>"
            },
            "name": "div-distribution-de67ec"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Users_CL\n| summarize arg_max(TimeGenerated, *) by UserId\n| summarize Count=count() by Role\n| order by Count desc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "piechart",
              "title": "Users by role"
            },
            "name": "q-0c47912a",
            "customWidth": "33"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Users_CL\n| summarize arg_max(TimeGenerated, *) by UserId\n| summarize Count=count() by Status\n| order by Count desc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "piechart",
              "title": "Users by status"
            },
            "name": "q-e8c20a69",
            "customWidth": "33"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Users_CL\n| summarize arg_max(TimeGenerated, *) by UserId\n| summarize Count=count() by UserType\n| order by Count desc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "piechart",
              "title": "Users by type (member / shared)"
            },
            "name": "q-2c51776d",
            "customWidth": "33"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Activity heatmap</div>"
            },
            "name": "div-activity-heatmap-ca6a21"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Users_CL\n| summarize arg_max(TimeGenerated, *) by UserId\n| extend DaysSinceLogin = toint((now() - LastSeen) / 1d)\n| extend Bucket = case(\n    DaysSinceLogin < 1, \"Today\",\n    DaysSinceLogin < 7, \"This week\",\n    DaysSinceLogin < 30, \"This month\",\n    DaysSinceLogin < 90, \"Past quarter\",\n    \"90+ days\")\n| summarize Users=count() by Bucket\n| order by case(Bucket==\"Today\",1, Bucket==\"This week\",2, Bucket==\"This month\",3, Bucket==\"Past quarter\",4, 5) asc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "barchart",
              "title": "Users by recency of last login"
            },
            "name": "q-350e118d"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Full user list</div>"
            },
            "name": "div-full-user-list-136aac"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Users_CL\n| summarize arg_max(TimeGenerated, *) by UserId\n| project DisplayName, LoginName, Role, Status, UserType, DeviceCount, CurrentlyConnected, Created, LastSeen\n| order by LastSeen desc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "All users (latest snapshot per user ID)",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "Created",
                    "formatter": 6
                  },
                  {
                    "columnMatch": "LastSeen",
                    "formatter": 6
                  },
                  {
                    "columnMatch": "Role",
                    "formatter": 1
                  },
                  {
                    "columnMatch": "Status",
                    "formatter": 1
                  },
                  {
                    "columnMatch": "DeviceCount",
                    "formatter": 8,
                    "formatOptions": {
                      "palette": "blue"
                    }
                  }
                ]
              }
            },
            "name": "q-cee23d3c"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Orphaned users (active but no devices)</div>"
            },
            "name": "div-orphaned-users-(acti-56d6f8"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Users_CL\n| summarize arg_max(TimeGenerated, *) by UserId\n| where Status =~ \"active\" and DeviceCount == 0\n| project DisplayName, LoginName, Role, UserType, Created, LastSeen\n| order by Created desc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "Active accounts with zero devices - candidates for offboarding review",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "Created",
                    "formatter": 6
                  },
                  {
                    "columnMatch": "LastSeen",
                    "formatter": 6
                  }
                ]
              },
              "noDataMessage": "Every active account has at least one device - good hygiene.",
              "noDataMessageStyle": 1
            },
            "name": "q-83fcd942"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Role escalation history</div>"
            },
            "name": "div-role-escalation-hist-bd8df4"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Audit_CL\n| where TimeGenerated {TimeRange}\n| where Action == \"USER_ROLE_UPDATE\" or Action == \"USER_ROLES_ASSIGNED\" or Action contains \"ROLE\"\n| extend ActorLogin=tostring(coalesce(Actor.loginName, Actor.displayName))\n| extend TargetName=tostring(coalesce(Target.name, Target.id))\n| extend FromRole=tostring(Old.role), ToRole=tostring(New.role)\n| project TimeGenerated, ActorLogin, Action, TargetName, FromRole, ToRole, Origin\n| order by TimeGenerated desc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "Recent role changes",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "TimeGenerated",
                    "formatter": 6
                  },
                  {
                    "columnMatch": "ToRole",
                    "formatter": 1
                  }
                ]
              },
              "noDataMessage": "No role changes in this window.",
              "noDataMessageStyle": 1
            },
            "name": "q-f6c8358a"
          }
        ]
      },
      "conditionalVisibility": {
        "parameterName": "selectedTab",
        "comparison": "isEqualTo",
        "value": "identity"
      },
      "name": "group-identity"
    },
    {
      "type": 12,
      "content": {
        "version": "NotebookGroup/1.0",
        "groupType": "editable",
        "items": [
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Device fleet snapshot</div>"
            },
            "name": "div-device-fleet-snapsho-939675"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "let D = Tailscale_Devices_CL | summarize arg_max(TimeGenerated, *) by DeviceId;\nunion\n  (D | summarize V=toreal(count())                              | extend Metric=\"Total devices\",       Order=1),\n  (D | where Authorized == true                                 | summarize V=toreal(count()) | extend Metric=\"Authorized\",          Order=2),\n  (D | where IsExternal == true                                 | summarize V=toreal(count()) | extend Metric=\"External (shared)\",   Order=3),\n  (D | where UpdateAvailable == true                            | summarize V=toreal(count()) | extend Metric=\"Updates available\",   Order=4),\n  (D | where SshEnabled == true                                 | summarize V=toreal(count()) | extend Metric=\"SSH-enabled\",         Order=5),\n  (D | where KeyExpiryDisabled == true                          | summarize V=toreal(count()) | extend Metric=\"No key expiry\",       Order=6),\n  (D | where array_length(AdvertisedRoutes) > 0                 | summarize V=toreal(count()) | extend Metric=\"Subnet/exit-node\",    Order=7),\n  (D | where LastSeen < ago(30d)                                | summarize V=toreal(count()) | extend Metric=\"Stale (30+ days)\",    Order=8)\n| order by Order asc | project Metric, Value=V",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "tiles",
              "tileSettings": {
                "titleContent": {
                  "columnMatch": "Metric",
                  "formatter": 1
                },
                "leftContent": {
                  "columnMatch": "Value",
                  "formatter": 12,
                  "formatOptions": {
                    "palette": "auto"
                  }
                },
                "showBorder": false
              }
            },
            "name": "q-366964fc"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Distribution</div>"
            },
            "name": "div-distribution-396d03"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Devices_CL\n| summarize arg_max(TimeGenerated, *) by DeviceId\n| summarize Count=count() by Os\n| order by Count desc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "piechart",
              "title": "Devices by OS"
            },
            "name": "q-0c8f5988",
            "customWidth": "33"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Devices_CL\n| summarize arg_max(TimeGenerated, *) by DeviceId\n| summarize Count=count() by ClientVersion\n| order by Count desc | take 10",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "barchart",
              "title": "Top 10 client versions"
            },
            "name": "q-af1c45cd",
            "customWidth": "33"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Devices_CL\n| summarize arg_max(TimeGenerated, *) by DeviceId\n| mv-expand Tag = Tags to typeof(string)\n| summarize Devices=dcount(DeviceId) by Tag=iff(isempty(Tag), \"(untagged)\", Tag)\n| order by Devices desc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "piechart",
              "title": "Devices by tag"
            },
            "name": "q-c3a0ef5b",
            "customWidth": "33"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Devices needing attention</div>"
            },
            "name": "div-devices-needing-atte-f04a47"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Devices_CL\n| summarize arg_max(TimeGenerated, *) by DeviceId\n| where UpdateAvailable == true or KeyExpiryDisabled == true or LastSeen < ago(30d) or Authorized == false\n| extend Issues = strcat_array(pack_array(\n    iff(UpdateAvailable == true, \"needs-update\", \"\"),\n    iff(KeyExpiryDisabled == true, \"key-never-expires\", \"\"),\n    iff(LastSeen < ago(30d), \"stale\", \"\"),\n    iff(Authorized == false, \"unauthorized\", \"\")), \",\")\n| extend Issues = trim(\",\", trim_start(\",\", trim_end(\",\", replace_string(Issues, \",,\", \",\"))))\n| project DeviceName, Hostname, User, Os, ClientVersion, LastSeen, Issues\n| order by LastSeen desc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "Devices flagged with one or more issues",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "LastSeen",
                    "formatter": 6
                  },
                  {
                    "columnMatch": "Issues",
                    "formatter": 1
                  }
                ]
              },
              "noDataMessage": "No devices need attention - all updated, fresh, authorized, and key-rotating.",
              "noDataMessageStyle": 1
            },
            "name": "q-dc5db84c"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Full device inventory</div>"
            },
            "name": "div-full-device-inventor-b70642"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Devices_CL\n| summarize arg_max(TimeGenerated, *) by DeviceId\n| project DeviceName, Hostname, User, Os, ClientVersion, UpdateAvailable, Authorized, IsExternal, SshEnabled, LastSeen, KeyExpiryDisabled, Tags, AdvertisedRoutes\n| order by LastSeen desc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "All devices (latest snapshot per device ID)",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "LastSeen",
                    "formatter": 6
                  },
                  {
                    "columnMatch": "Os",
                    "formatter": 1
                  },
                  {
                    "columnMatch": "ClientVersion",
                    "formatter": 1
                  }
                ]
              }
            },
            "name": "q-7f7e7a9a"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Subnet routers / exit nodes</div>"
            },
            "name": "div-subnet-routers-/-exi-b082d6"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Devices_CL\n| summarize arg_max(TimeGenerated, *) by DeviceId\n| where array_length(AdvertisedRoutes) > 0\n| extend AdvertisedSummary = tostring(AdvertisedRoutes), EnabledSummary = tostring(EnabledRoutes)\n| project DeviceName, Hostname, User, Os, AdvertisedSummary, EnabledSummary, LastSeen, Authorized\n| order by LastSeen desc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "Devices advertising subnet routes or exit-node capability",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "LastSeen",
                    "formatter": 6
                  }
                ]
              },
              "noDataMessage": "No subnet routers in this tailnet - pure mesh topology.",
              "noDataMessageStyle": 1
            },
            "name": "q-5004df25"
          }
        ]
      },
      "conditionalVisibility": {
        "parameterName": "selectedTab",
        "comparison": "isEqualTo",
        "value": "devices"
      },
      "name": "group-devices"
    },
    {
      "type": 12,
      "content": {
        "version": "NotebookGroup/1.0",
        "groupType": "editable",
        "items": [
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Credentials snapshot</div>"
            },
            "name": "div-credentials-snapshot-fd464a"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "let K = Tailscale_Keys_CL | summarize arg_max(TimeGenerated, *) by KeyId;\nunion\n  (K | summarize V=toreal(count())                                     | extend Metric=\"Total keys\",          Order=1),\n  (K | where isnull(Revoked) and (isnull(Expires) or Expires > now())  | summarize V=toreal(count()) | extend Metric=\"Active\",              Order=2),\n  (K | where isnotnull(Revoked)                                        | summarize V=toreal(count()) | extend Metric=\"Revoked\",             Order=3),\n  (K | where Expires < now() and isnull(Revoked)                       | summarize V=toreal(count()) | extend Metric=\"Expired\",             Order=4),\n  (K | where isnull(Revoked) and Expires between(now() .. ago(-7d))    | summarize V=toreal(count()) | extend Metric=\"Expiring in 7d\",      Order=5),\n  (K | where isnull(Revoked) and (isnull(Expires) or ExpirySeconds==0) | summarize V=toreal(count()) | extend Metric=\"Never expire\",        Order=6),\n  (K | where KeyType =~ \"auth\"                                         | summarize V=toreal(count()) | extend Metric=\"Auth keys\",           Order=7),\n  (K | where KeyType =~ \"api\" or KeyType contains \"oauth\"              | summarize V=toreal(count()) | extend Metric=\"API / OAuth\",         Order=8)\n| order by Order asc | project Metric, Value=V",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "tiles",
              "tileSettings": {
                "titleContent": {
                  "columnMatch": "Metric",
                  "formatter": 1
                },
                "leftContent": {
                  "columnMatch": "Value",
                  "formatter": 12,
                  "formatOptions": {
                    "palette": "auto"
                  }
                },
                "showBorder": false
              }
            },
            "name": "q-79398bc0"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Distribution</div>"
            },
            "name": "div-distribution-15f665"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Keys_CL\n| summarize arg_max(TimeGenerated, *) by KeyId\n| summarize Count=count() by KeyType\n| order by Count desc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "piechart",
              "title": "Keys by type"
            },
            "name": "q-23e6618b",
            "customWidth": "50"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Keys_CL\n| summarize arg_max(TimeGenerated, *) by KeyId\n| where isnull(Revoked)\n| extend Bucket = case(\n    isnull(Expires) or ExpirySeconds == 0, \"Never\",\n    Expires < now(), \"Already expired\",\n    Expires < ago(-1d), \"<24h\",\n    Expires < ago(-7d), \"1-7d\",\n    Expires < ago(-30d), \"8-30d\",\n    Expires < ago(-90d), \"31-90d\",\n    \"90+d\")\n| summarize Keys=count() by Bucket\n| order by case(Bucket==\"Already expired\",1, Bucket==\"<24h\",2, Bucket==\"1-7d\",3, Bucket==\"8-30d\",4, Bucket==\"31-90d\",5, Bucket==\"90+d\",6, Bucket==\"Never\",7, 8) asc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "barchart",
              "title": "Active key expiry distribution"
            },
            "name": "q-7484d1a0",
            "customWidth": "50"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Active credential register</div>"
            },
            "name": "div-active-credential-re-c27539"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Keys_CL\n| summarize arg_max(TimeGenerated, *) by KeyId\n| where isnull(Revoked)\n| extend ExpiryStatus = case(\n    isnull(Expires) or ExpirySeconds == 0, \"Never expires\",\n    Expires < now(), \"Expired\",\n    Expires < ago(-7d), \"Expires in 7d\",\n    Expires < ago(-30d), \"Expires in 30d\",\n    \"OK\")\n| project KeyId, KeyType, Description, UserId, Created, Expires, ExpiryStatus, Capabilities\n| order by Created desc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "All active credentials with computed expiry status",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "Created",
                    "formatter": 6
                  },
                  {
                    "columnMatch": "Expires",
                    "formatter": 6
                  },
                  {
                    "columnMatch": "ExpiryStatus",
                    "formatter": 1
                  },
                  {
                    "columnMatch": "KeyType",
                    "formatter": 1
                  }
                ]
              }
            },
            "name": "q-4b27a750"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Credential CRUD events</div>"
            },
            "name": "div-credential-crud-even-e455b0"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Audit_CL\n| where TimeGenerated {TimeRange}\n| where Action contains \"API_KEY\" or Action contains \"AUTH_KEY\" or Action contains \"OAUTH\" or Action contains \"KEY_CREATE\" or Action contains \"KEY_REVOKE\"\n| extend ActorLogin=tostring(coalesce(Actor.loginName, Actor.displayName))\n| extend TargetId=tostring(Target.id), TargetType=tostring(Target.type)\n| project TimeGenerated, Action, ActorLogin, TargetType, TargetId, Origin\n| order by TimeGenerated desc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "Recent credential create / revoke / rotate events",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "TimeGenerated",
                    "formatter": 6
                  }
                ]
              },
              "noDataMessage": "No credential CRUD activity in this window.",
              "noDataMessageStyle": 1
            },
            "name": "q-777693bd"
          }
        ]
      },
      "conditionalVisibility": {
        "parameterName": "selectedTab",
        "comparison": "isEqualTo",
        "value": "credentials"
      },
      "name": "group-credentials"
    },
    {
      "type": 12,
      "content": {
        "version": "NotebookGroup/1.0",
        "groupType": "editable",
        "items": [
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Audit volume</div>"
            },
            "name": "div-audit-volume-de29a2"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Audit_CL\n| where TimeGenerated {TimeRange}\n| summarize Events=count() by bin(TimeGenerated, 1h)\n| order by TimeGenerated asc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "timechart",
              "title": "Audit events per hour",
              "noDataMessage": "No audit events in this window.",
              "noDataMessageStyle": 5
            },
            "name": "q-f5eee265"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Action heatmap by hour of day</div>"
            },
            "name": "div-action-heatmap-by-ho-c8bd5e"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Audit_CL\n| where TimeGenerated {TimeRange}\n| extend Hour=hourofday(TimeGenerated)\n| summarize Events=count() by Hour, Action\n| order by Hour asc, Events desc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "categoricalbar",
              "title": "When are admin actions happening?"
            },
            "name": "q-c6f45d95"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Actor / Action heatmap</div>"
            },
            "name": "div-actor-/-action-heatm-d820ba"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Audit_CL\n| where TimeGenerated {TimeRange}\n| extend ActorLogin=tostring(coalesce(Actor.loginName, Actor.displayName))\n| where isnotempty(ActorLogin)\n| summarize Events=count() by ActorLogin, Action\n| order by Events desc | take 100",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "Who is firing which action",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "Events",
                    "formatter": 4,
                    "formatOptions": {
                      "palette": "blue"
                    }
                  }
                ]
              },
              "noDataMessage": "No audit events in this window.",
              "noDataMessageStyle": 5
            },
            "name": "q-06c13b3b"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Recent activity</div>"
            },
            "name": "div-recent-activity-63b210"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Audit_CL\n| where TimeGenerated {TimeRange}\n| extend ActorLogin=tostring(coalesce(Actor.loginName, Actor.displayName))\n| extend TargetType=tostring(Target.type), TargetName=tostring(coalesce(Target.name, Target.id))\n| project TimeGenerated, Action, ActorLogin, TargetType, TargetName, Origin, EventGroupID\n| order by TimeGenerated desc | take 100",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "Last 100 audit events",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "TimeGenerated",
                    "formatter": 6
                  },
                  {
                    "columnMatch": "Action",
                    "formatter": 1
                  }
                ]
              },
              "noDataMessage": "No audit events in this window.",
              "noDataMessageStyle": 5
            },
            "name": "q-07a25a40"
          }
        ]
      },
      "conditionalVisibility": {
        "parameterName": "selectedTab",
        "comparison": "isEqualTo",
        "value": "audit"
      },
      "name": "group-audit"
    },
    {
      "type": 12,
      "content": {
        "version": "NotebookGroup/1.0",
        "groupType": "editable",
        "items": [
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">DNS configuration (current state)</div>"
            },
            "name": "div-dns-configuration-(c-5f2e1e"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Dns_CL\n| summarize arg_max(TimeGenerated, *) by ConfigType\n| project ConfigType, Nameservers, MagicDNS, SearchPaths, LastSnapshot=TimeGenerated\n| order by ConfigType asc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "MagicDNS, nameservers, search paths",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "LastSnapshot",
                    "formatter": 6
                  },
                  {
                    "columnMatch": "ConfigType",
                    "formatter": 1
                  }
                ]
              },
              "noDataMessage": "No DNS snapshots in the workspace yet. DNS polls runs at ~30 min cadence.",
              "noDataMessageStyle": 5
            },
            "name": "q-d6a6a358"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Tailnet settings (current)</div>"
            },
            "name": "div-tailnet-settings-(cu-e03b16"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Settings_CL\n| summarize arg_max(TimeGenerated, *) by TenantId\n| project DevicesApprovalOn, DevicesAutoUpdatesOn, DevicesKeyDurationDays, UsersApprovalOn, NetworkFlowLoggingOn, RegionalRoutingOn, PostureIdentityCollectionOn, UsersRoleAllowedToJoinExternalTailnets, LastSnapshot=TimeGenerated",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "Tailnet policy gates",
              "noDataMessage": "No settings snapshot yet.",
              "noDataMessageStyle": 5
            },
            "name": "q-0622cfc3"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">DNS change history</div>"
            },
            "name": "div-dns-change-history-9dd376"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Audit_CL\n| where TimeGenerated {TimeRange}\n| extend TargetProperty=tostring(Target.property)\n| where Action contains \"DNS\" or TargetProperty has_any (\"DNS_NAMESERVERS\", \"DNS_SPLIT_DNS\", \"MAGICDNS\", \"DNS_SEARCH_PATHS\")\n| extend ActorLogin=tostring(coalesce(Actor.loginName, Actor.displayName))\n| project TimeGenerated, ActorLogin, Action, TargetProperty, Origin\n| order by TimeGenerated desc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "Recent DNS-related admin changes",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "TimeGenerated",
                    "formatter": 6
                  }
                ]
              },
              "noDataMessage": "No DNS changes in this window.",
              "noDataMessageStyle": 1
            },
            "name": "q-a132ff6a"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">ACL policy changes</div>"
            },
            "name": "div-acl-policy-changes-ff0e68"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Audit_CL\n| where TimeGenerated {TimeRange}\n| where Action == \"ACL_UPDATE\" or Action contains \"ACL\"\n| extend ActorLogin=tostring(coalesce(Actor.loginName, Actor.displayName))\n| project TimeGenerated, ActorLogin, Action, Origin, EventGroupID\n| order by TimeGenerated desc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "Recent ACL / policy file modifications",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "TimeGenerated",
                    "formatter": 6
                  }
                ]
              },
              "noDataMessage": "No ACL changes in this window.",
              "noDataMessageStyle": 1
            },
            "name": "q-94818c53"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Subnet routes & exit nodes</div>"
            },
            "name": "div-subnet-routes-and-ex-eef47f"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Devices_CL\n| summarize arg_max(TimeGenerated, *) by DeviceId\n| where array_length(EnabledRoutes) > 0\n| project DeviceName, User, Os, EnabledRoutes=tostring(EnabledRoutes), AdvertisedRoutes=tostring(AdvertisedRoutes), LastSeen\n| order by LastSeen desc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "Routes currently being served from devices",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "LastSeen",
                    "formatter": 6
                  }
                ]
              },
              "noDataMessage": "No subnet routers active in this tailnet.",
              "noDataMessageStyle": 1
            },
            "name": "q-61a792cd"
          }
        ]
      },
      "conditionalVisibility": {
        "parameterName": "selectedTab",
        "comparison": "isEqualTo",
        "value": "network"
      },
      "name": "group-network"
    },
    {
      "type": 12,
      "conditionalVisibility": {
        "parameterName": "selectedTab",
        "comparison": "isEqualTo",
        "value": "network-flows"
      },
      "name": "group-network-flows",
      "content": {
        "version": "NotebookGroup/1.0",
        "groupType": "editable",
        "items": [
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Activity snapshot</div>"
            },
            "name": "div-flow-snapshot"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "let NET = Tailscale_Network_CL | where TimeGenerated {TimeRange};\nunion\n  (NET | summarize V=toreal(count())                          | extend Metric=\"Total flows\",     Order=1),\n  (NET | summarize V=toreal(dcount(SrcNodeName))              | extend Metric=\"Src nodes\",       Order=2),\n  (NET | summarize V=toreal(dcount(DstNodeName))              | extend Metric=\"Dst nodes\",       Order=3),\n  (NET | where HasVirtualTraffic | summarize V=toreal(count())| extend Metric=\"Virtual\",         Order=4),\n  (NET | where HasSubnetTraffic  | summarize V=toreal(count())| extend Metric=\"Subnet\",          Order=5),\n  (NET | where HasExitTraffic    | summarize V=toreal(count())| extend Metric=\"Exit\",            Order=6),\n  (NET | where IsRelayed         | summarize V=toreal(count())| extend Metric=\"Relayed (DERP)\",  Order=7)\n| order by Order asc | project Metric, Value=V",
              "size": 3,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "tiles",
              "title": "Activity (selected time range)",
              "noDataMessage": "No data in this window.",
              "noDataMessageStyle": 5,
              "tileSettings": {
                "titleContent": {
                  "columnMatch": "Metric",
                  "formatter": 1
                },
                "leftContent": {
                  "columnMatch": "Value",
                  "formatter": 12,
                  "formatOptions": {
                    "palette": "auto"
                  },
                  "numberFormat": {
                    "unit": 17,
                    "options": {
                      "style": "decimal",
                      "maximumFractionDigits": 0
                    }
                  }
                },
                "showBorder": false
              }
            },
            "name": "q-flow-tiles"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Top talkers</div>"
            },
            "name": "div-flow-top-talkers"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Network_CL\n| where TimeGenerated {TimeRange}\n| extend SrcLabel = case(\n    isnotempty(SrcUser), strcat(SrcNodeName, \" - \", SrcUser),\n    isnotempty(SrcTags), strcat(SrcNodeName, \" \", tostring(SrcTags)),\n    SrcNodeName)\n| summarize Flows=count() by SrcLabel\n| top 10 by Flows",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "barchart",
              "title": "Top source nodes by flow count",
              "noDataMessage": "No flow records in this window.",
              "noDataMessageStyle": 5
            },
            "name": "q-flow-top-src",
            "customWidth": "50"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Network_CL\n| where TimeGenerated {TimeRange}\n| extend DstLabel = case(\n    isnotempty(DstUser), strcat(DstNodeName, \" - \", DstUser),\n    isnotempty(DstTags), strcat(DstNodeName, \" \", tostring(DstTags)),\n    DstNodeName)\n| extend DstKind = case(\n    isnotempty(DstUser), \"User device\",\n    isnotempty(DstTags), \"Tagged service\",\n    \"Other\")\n| summarize Flows=count() by DstLabel, DstKind\n| top 10 by Flows",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "categoricalbar",
              "title": "Top destination nodes (split by user vs tagged service)",
              "noDataMessage": "No flow records in this window.",
              "noDataMessageStyle": 5
            },
            "name": "q-flow-top-dst",
            "customWidth": "50"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Traffic mix over time (stacked area: Virtual / Subnet / Exit / Physical)</div>"
            },
            "name": "div-flow-time-mix"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "let NET = Tailscale_Network_CL | where TimeGenerated {TimeRange};\nunion\n  (NET | where HasVirtualTraffic  | summarize Flows=count() by bin(TimeGenerated, 10m) | extend Kind=\"Virtual\"),\n  (NET | where HasSubnetTraffic   | summarize Flows=count() by bin(TimeGenerated, 10m) | extend Kind=\"Subnet\"),\n  (NET | where HasExitTraffic     | summarize Flows=count() by bin(TimeGenerated, 10m) | extend Kind=\"Exit\"),\n  (NET | where HasPhysicalTraffic | summarize Flows=count() by bin(TimeGenerated, 10m) | extend Kind=\"Physical\")\n| project TimeGenerated, Kind, Flows\n| order by TimeGenerated asc",
              "size": 4,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "timechart",
              "title": "Flow count by traffic kind over time",
              "noDataMessage": "No flow records.",
              "noDataMessageStyle": 5,
              "chartSettings": {
                "group": "Kind",
                "createOtherGroup": 10,
                "showLegend": true,
                "ySettings": {
                  "min": 0
                },
                "chartType": "Area"
              }
            },
            "name": "q-flow-traffic-mix"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">DERP relay health</div>"
            },
            "name": "div-flow-derp-watch"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Network_CL\n| where TimeGenerated {TimeRange}\n| summarize Count=count() by Path = iff(IsRelayed, \"Relayed (DERP)\", \"Direct (P2P)\")\n| project Path, Count",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "piechart",
              "title": "Direct vs relayed",
              "noDataMessage": "No flow records.",
              "noDataMessageStyle": 5
            },
            "name": "q-flow-derp-pie",
            "customWidth": "40"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Network_CL\n| where TimeGenerated {TimeRange}\n| where IsRelayed\n| extend SrcLabel = strcat(SrcNodeName, iff(isempty(SrcUser),\"\",strcat(\" (\",SrcUser,\")\")))\n| summarize RelayedFlows=count(), LastRelay=max(TimeGenerated) by SrcLabel, SrcOs\n| top 10 by RelayedFlows",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "Devices stuck on DERP (potential NAT/firewall issue)",
              "noDataMessage": "No data in this window.",
              "noDataMessageStyle": 5,
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "RelayedFlows",
                    "formatter": 4,
                    "formatOptions": {
                      "palette": "orange"
                    }
                  },
                  {
                    "columnMatch": "LastRelay",
                    "formatter": 6
                  }
                ]
              }
            },
            "name": "q-flow-derp-devices",
            "customWidth": "60"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Tagged-service flows + anomaly hunt</div>"
            },
            "name": "div-flow-tag-anomaly"
          },
          {
            "type": 12,
            "name": "row-tag-anomaly-row",
            "content": {
              "version": "NotebookGroup/1.0",
              "groupType": "editable",
              "items": [
                {
                  "type": 3,
                  "content": {
                    "version": "KqlItem/1.0",
                    "query": "Tailscale_Network_CL\n| where TimeGenerated {TimeRange}\n| extend SrcKind = case(\n    isnotempty(SrcTags), tostring(SrcTags),\n    isnotempty(SrcUser), \"<user>\",\n    \"<unknown>\")\n| extend DstKind = case(\n    isnotempty(DstTags), tostring(DstTags),\n    isnotempty(DstUser), \"<user>\",\n    \"<unknown>\")\n| summarize Flows=count() by SrcKind, DstKind\n| order by Flows desc",
                    "size": 1,
                    "queryType": 0,
                    "resourceType": "microsoft.operationalinsights/workspaces",
                    "visualization": "table",
                    "title": "Tagged-service flow matrix",
                    "noDataMessage": "No data in this window.",
                    "noDataMessageStyle": 5,
                    "gridSettings": {
                      "formatters": [
                        {
                          "columnMatch": "Flows",
                          "formatter": 4,
                          "formatOptions": {
                            "palette": "blue"
                          }
                        }
                      ]
                    }
                  },
                  "name": "q-flow-tag-matrix",
                  "customWidth": "50"
                },
                {
                  "type": 3,
                  "content": {
                    "version": "KqlItem/1.0",
                    "query": "let baseline = Tailscale_Network_CL\n    | where TimeGenerated between (ago(7d) .. ago(1h))\n    | distinct SrcNodeName, DstNodeName;\nTailscale_Network_CL\n| where TimeGenerated {TimeRange}\n| where HasVirtualTraffic or HasSubnetTraffic or HasExitTraffic\n| extend ShortSrc = tostring(split(SrcNodeName, \".\")[0])\n| extend ShortDst = tostring(split(DstNodeName, \".\")[0])\n| extend ShortSrcUser = tostring(split(SrcUser, \"@\")[0])\n| extend ShortDstUser = tostring(split(DstUser, \"@\")[0])\n| extend Src = strcat(ShortSrc, iff(isempty(ShortSrcUser),\"\",strcat(\" - \",ShortSrcUser)))\n| extend Dst = strcat(ShortDst, iff(isempty(ShortDstUser),\"\",strcat(\" - \",ShortDstUser)))\n| summarize FirstSeen=min(TimeGenerated), Flows=count() by Src, Dst, SrcNodeName, DstNodeName\n| join kind=leftanti baseline on SrcNodeName, DstNodeName\n| project FirstSeen, Src, Dst, Flows\n| order by FirstSeen desc",
                    "size": 1,
                    "queryType": 0,
                    "resourceType": "microsoft.operationalinsights/workspaces",
                    "visualization": "table",
                    "title": "Anomaly: pairs NOT seen in past 7 days",
                    "noDataMessage": "No new src/dst pairs - all flows match the 7-day baseline.",
                    "noDataMessageStyle": 5,
                    "gridSettings": {
                      "formatters": [
                        {
                          "columnMatch": "FirstSeen",
                          "formatter": 6
                        },
                        {
                          "columnMatch": "Flows",
                          "formatter": 4,
                          "formatOptions": {
                            "palette": "red"
                          }
                        }
                      ]
                    }
                  },
                  "name": "q-flow-new-pairs",
                  "customWidth": "50"
                }
              ]
            }
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Egress destinations - exit nodes + subnet routes</div>"
            },
            "name": "div-flow-egress"
          },
          {
            "type": 12,
            "name": "row-egress-row",
            "content": {
              "version": "NotebookGroup/1.0",
              "groupType": "editable",
              "items": [
                {
                  "type": 3,
                  "content": {
                    "version": "KqlItem/1.0",
                    "query": "Tailscale_Network_CL\n| where TimeGenerated {TimeRange}\n| where HasExitTraffic\n| extend ExitTag = iff(isempty(DstTags), DstNodeName, tostring(DstTags))\n| summarize Flows=count() by ExitTag",
                    "size": 1,
                    "queryType": 0,
                    "resourceType": "microsoft.operationalinsights/workspaces",
                    "visualization": "piechart",
                    "title": "Exit-node tag distribution",
                    "noDataMessage": "No exit-node traffic in this window.",
                    "noDataMessageStyle": 5
                  },
                  "name": "q-flow-exit-providers",
                  "customWidth": "40"
                },
                {
                  "type": 3,
                  "content": {
                    "version": "KqlItem/1.0",
                    "query": "Tailscale_Network_CL\n| where TimeGenerated {TimeRange}\n| where HasSubnetTraffic\n| mv-expand s=SubnetTraffic\n| extend DstHost = tostring(split(tostring(s.dst), \":\")[0])\n| extend Bytes = toint(coalesce(s.txBytes,0)) + toint(coalesce(s.rxBytes,0))\n| extend Pkts = toint(coalesce(s.txPkts,0)) + toint(coalesce(s.rxPkts,0))\n| summarize TotalBytes=sum(Bytes), TotalPkts=sum(Pkts), Talkers=dcount(SrcNodeName) by DstHost\n| top 10 by TotalBytes\n| project DstHost, TotalBytes, TotalPkts, Talkers",
                    "size": 1,
                    "queryType": 0,
                    "resourceType": "microsoft.operationalinsights/workspaces",
                    "visualization": "table",
                    "title": "Top subnet route destinations",
                    "noDataMessage": "No subnet-route traffic in this window.",
                    "noDataMessageStyle": 5,
                    "gridSettings": {
                      "formatters": [
                        {
                          "columnMatch": "TotalBytes",
                          "formatter": 4,
                          "formatOptions": {
                            "palette": "green"
                          }
                        },
                        {
                          "columnMatch": "TotalPkts",
                          "formatter": 4,
                          "formatOptions": {
                            "palette": "blue"
                          }
                        },
                        {
                          "columnMatch": "Talkers",
                          "formatter": 4,
                          "formatOptions": {
                            "palette": "purple"
                          }
                        }
                      ]
                    }
                  },
                  "name": "q-flow-subnet-dests",
                  "customWidth": "60"
                }
              ]
            }
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Recent flow detail (last 100)</div>"
            },
            "name": "div-flow-recent-detail"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Network_CL\n| where TimeGenerated {TimeRange}\n| order by TimeGenerated desc\n| take 100\n| project TimeGenerated,\n    Src=SrcNodeName, SrcUser, SrcTags=tostring(SrcTags),\n    Dst=DstNodeName, DstUser, DstTags=tostring(DstTags),\n    Vir=HasVirtualTraffic, Sub=HasSubnetTraffic, Exi=HasExitTraffic, Phy=HasPhysicalTraffic, IsRelayed",
              "size": 4,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "Last 100 flow records in time range",
              "noDataMessage": "No data in this window.",
              "noDataMessageStyle": 5,
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "TimeGenerated",
                    "formatter": 6
                  },
                  {
                    "columnMatch": "IsRelayed",
                    "formatter": 11
                  }
                ]
              }
            },
            "name": "q-flow-recent"
          }
        ]
      }
    },
    {
      "type": 12,
      "conditionalVisibility": {
        "parameterName": "selectedTab",
        "comparison": "isEqualTo",
        "value": "posture"
      },
      "name": "group-posture",
      "content": {
        "version": "NotebookGroup/1.0",
        "groupType": "editable",
        "items": [
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Posture integrations - MDM/EDR providers configured for device posture</div>"
            },
            "name": "div-posture-overview"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "let CUR = Tailscale_PostureIntegrations_CL\n    | where TimeGenerated {TimeRange}\n    | summarize arg_max(TimeGenerated, *) by IntegrationId;\nunion\n  (CUR | summarize V=toreal(count())            | extend Metric=\"Integrations\",       Order=1),\n  (CUR | summarize V=toreal(dcount(Provider))   | extend Metric=\"Distinct providers\", Order=2),\n  (CUR | where tostring(Status) has \"healthy\" or tostring(Status) has \"ok\"\n       | summarize V=toreal(count())            | extend Metric=\"Healthy\",            Order=3),\n  (CUR | where not(tostring(Status) has \"healthy\" or tostring(Status) has \"ok\")\n       | summarize V=toreal(count())            | extend Metric=\"Unhealthy / unknown\", Order=4)\n| order by Order asc | project Metric, Value=V",
              "size": 3,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "tiles",
              "title": "Integration inventory (selected time range)",
              "noDataMessage": "No posture integrations configured. Set them up at https://login.tailscale.com/admin/settings/posture-integrations.",
              "noDataMessageStyle": 5,
              "tileSettings": {
                "titleContent": {
                  "columnMatch": "Metric",
                  "formatter": 1
                },
                "leftContent": {
                  "columnMatch": "Value",
                  "formatter": 12,
                  "formatOptions": {
                    "palette": "auto"
                  },
                  "numberFormat": {
                    "unit": 17,
                    "options": {
                      "style": "decimal",
                      "maximumFractionDigits": 0
                    }
                  }
                },
                "showBorder": false
              }
            },
            "name": "q-posture-tile"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Distribution</div>"
            },
            "name": "div-posture-distribution"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_PostureIntegrations_CL\n| where TimeGenerated {TimeRange}\n| summarize arg_max(TimeGenerated, *) by IntegrationId\n| summarize Count=count() by Provider",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "piechart",
              "title": "Integrations by provider",
              "noDataMessage": "No posture integrations configured.",
              "noDataMessageStyle": 5
            },
            "name": "q-posture-by-provider",
            "customWidth": "50"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_PostureIntegrations_CL\n| where TimeGenerated {TimeRange}\n| summarize arg_max(TimeGenerated, *) by IntegrationId\n| extend Health = case(\n    tostring(Status) has \"healthy\" or tostring(Status) has \"ok\", \"Healthy\",\n    tostring(Status) has \"error\" or tostring(Status) has \"failed\", \"Error\",\n    isnotempty(tostring(Status)), \"Other\",\n    \"Unknown\")\n| summarize Count=count() by Health",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "piechart",
              "title": "Health status across integrations",
              "noDataMessage": "No posture integrations configured.",
              "noDataMessageStyle": 5
            },
            "name": "q-posture-by-status",
            "customWidth": "50"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Inventory detail</div>"
            },
            "name": "div-posture-inventory"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_PostureIntegrations_CL\n| where TimeGenerated {TimeRange}\n| summarize arg_max(TimeGenerated, *) by IntegrationId\n| project IntegrationId, Provider, CloudId, ClientId, TenantId_Provider, Status, LastSnapshot=TimeGenerated",
              "size": 4,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "Configured integrations (latest snapshot per IntegrationId)",
              "noDataMessage": "No posture integrations configured.",
              "noDataMessageStyle": 5,
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "Provider",
                    "formatter": 11
                  },
                  {
                    "columnMatch": "LastSnapshot",
                    "formatter": 6
                  }
                ]
              }
            },
            "name": "q-posture-inventory"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Lifecycle (from audit log)</div>"
            },
            "name": "div-posture-lifecycle"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "Tailscale_Audit_CL\n| where TimeGenerated {TimeRange}\n| where EventType == \"CONFIG\"\n| where tostring(Target.type) contains \"POSTURE\" or tostring(Target.type) contains \"INTEGRATION\"\n| project TimeGenerated, Actor=tostring(Actor.loginName), Action,\n          Target=tostring(Target.name), TargetType=tostring(Target.type), ActionDetails\n| order by TimeGenerated desc",
              "size": 4,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "Recent posture integration create/update/delete events",
              "noDataMessage": "No posture-integration audit events in this window.",
              "noDataMessageStyle": 5,
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "TimeGenerated",
                    "formatter": 6
                  },
                  {
                    "columnMatch": "Action",
                    "formatter": 11
                  }
                ]
              }
            },
            "name": "q-posture-audit"
          }
        ]
      }
    },
    {
      "type": 12,
      "content": {
        "version": "NotebookGroup/1.0",
        "groupType": "editable",
        "items": [
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Ingest rate per table</div>"
            },
            "name": "div-ingest-rate-per-tabl-24e5f6"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "union withsource=Table Tailscale_Audit_CL, Tailscale_Devices_CL, Tailscale_Users_CL, Tailscale_Keys_CL, Tailscale_Dns_CL, Tailscale_Settings_CL\n| where TimeGenerated > ago(24h)\n| summarize Rows=count() by Table, bin(TimeGenerated, 1h)\n| order by TimeGenerated asc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "timechart",
              "title": "Rows ingested per Tailscale table per hour (last 24h)",
              "noDataMessage": "No Tailscale data ingested in the last 24h - check the connector card under Sentinel Data Connectors.",
              "noDataMessageStyle": 5
            },
            "name": "q-c6fd0143"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Last poll time per table</div>"
            },
            "name": "div-last-poll-time-per-t-49b051"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "union withsource=Table Tailscale_Audit_CL, Tailscale_Devices_CL, Tailscale_Users_CL, Tailscale_Keys_CL, Tailscale_Dns_CL, Tailscale_Settings_CL\n| summarize LastRow=max(TimeGenerated), TotalRows=count() by Table\n| extend MinutesAgo=toint((now() - LastRow) / 1m)\n| extend Status=case(MinutesAgo < 60, \"Fresh\", MinutesAgo < 360, \"Recent\", MinutesAgo < 1440, \"Stale\", \"Very Stale\")\n| project Table, LastRow, MinutesAgo, TotalRows, Status\n| order by MinutesAgo asc",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "Per-table freshness",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "LastRow",
                    "formatter": 6
                  },
                  {
                    "columnMatch": "MinutesAgo",
                    "formatter": 8,
                    "formatOptions": {
                      "palette": "redBright"
                    }
                  },
                  {
                    "columnMatch": "TotalRows",
                    "formatter": 8,
                    "formatOptions": {
                      "palette": "blue"
                    }
                  },
                  {
                    "columnMatch": "Status",
                    "formatter": 1
                  }
                ]
              }
            },
            "name": "q-a02e37a8"
          },
          {
            "type": 1,
            "content": {
              "json": "<div style=\"border-left:4px solid #3b82f6;padding:8px 12px;margin:16px 0 8px 0;background:rgba(59,130,246,0.05);font-size:14px;font-weight:600;letter-spacing:0.3px;text-transform:uppercase;color:#94a3b8\">Log Analytics operational events</div>"
            },
            "name": "div-log-analytics-operat-630749"
          },
          {
            "type": 3,
            "content": {
              "version": "KqlItem/1.0",
              "query": "_LogOperation\n| where TimeGenerated > ago(24h)\n| where _ResourceId contains \"tailscale\" or Detail contains \"Tailscale_\"\n| project TimeGenerated, Operation, Level, Detail\n| order by TimeGenerated desc | take 100",
              "size": 0,
              "queryType": 0,
              "resourceType": "microsoft.operationalinsights/workspaces",
              "visualization": "table",
              "title": "Log Analytics operational events touching Tailscale tables",
              "gridSettings": {
                "formatters": [
                  {
                    "columnMatch": "TimeGenerated",
                    "formatter": 6
                  },
                  {
                    "columnMatch": "Level",
                    "formatter": 1
                  }
                ]
              },
              "noDataMessage": "No operational issues recorded in the last 24h.",
              "noDataMessageStyle": 1
            },
            "name": "q-b492f150"
          }
        ]
      },
      "conditionalVisibility": {
        "parameterName": "selectedTab",
        "comparison": "isEqualTo",
        "value": "pipeline"
      },
      "name": "group-pipeline"
    },
    {
      "type": 1,
      "content": {
        "json": "<div style=\"margin-top:32px;padding-top:16px;border-top:1px solid #1e293b;color:#64748b;font-size:12px\"><strong>Tailscale Operations (Premium) (CCF)</strong> - Microsoft Sentinel content from the Tailscale (CCF) solution, Premium-tier surface. Tables polled from the Tailscale REST API: audit, devices, users, keys, dns, settings, <strong>network flows</strong> (/logging/network), <strong>posture integrations</strong>. Filter every panel via the time range above; the Investigate tab adds Actor and Device pickers for drilldown. The Network Flows and Posture tabs use the 15 promoted columns added in 3.1.0 (SrcUser, SrcTags, DstUser, DstTags, HasVirtualTraffic, HasSubnetTraffic, HasExitTraffic, HasPhysicalTraffic, IsRelayed, etc.). Companion workbook: <strong>Tailscale Operations (Standard)</strong> for Personal / Starter tailnets.</div>"
      },
      "name": "footer"
    }
  ],
  "fallbackResourceIds": [
    "Azure Monitor"
  ],
  "fromTemplateId": "sentinel-TailscalePremiumWorkbook",
  "$schema": "https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json"
}