| name | build-privatelink-demo |
| description | Provision, rename, re-region, verify or tear down the Azure environment for DATACON 2026 Demo 3 — "the control plane is the security perimeter" (Private Link + Entra-only Azure SQL Hyperscale + a client VM whose managed identity is the server admin). USE WHEN the presenter says any of: "build the private link demo", "provision demo 3", "set up the control plane demo", "deploy the privatelink demo on this machine", "rebuild demo 3", "move demo 3 to another region", "rename the demo 3 server", "the VM got deallocated, redeploy it", "run pre-flight for demo 3", "why is 05-verify failing", "tear down demo 3", or moves this talk to a new laptop and needs the VNet + VM + Entra-only server + demo kit in place. Scope is PROVISION + CONFIGURE + VERIFY + TEARDOWN ONLY. Do NOT use to present or rehearse the five beats (that's run-privatelink-demo), to build the Adventure Works / SQL MCP kit, or to deploy the Ward General hyperscale talk — those are separate. |
Build the Private Link (Demo 3) environment
Read presentations/dataconus2026/whyazurebest/demos/demo3_controlplane/README.md
first, every time. It is the source of truth and it is current. This skill covers
only what the README does not: the order to work in and the traps that have
already cost a rebuild.
All paths are workspace-relative to the bwsql root. Kit:
presentations/dataconus2026/whyazurebest/demos/demo3_controlplane/.
The shape of it
- Control plane runs on the laptop,
az only. The laptop never opens a SQL
connection — it cannot, by design.
- Data plane runs inside the VM,
sqlsim only. The VM never runs az.
az vm run-command invoke bridges the two through ARM. It keeps working even
after publicNetworkAccess=Disabled, so it is also the way back in if RDP breaks.
Running the scripts
- Always synchronous,
isBackground: false, timeout: 0. Provisioning steps
run minutes. Never background them, never poll.
- Check the exit code.
05-verify.ps1 exits 1 when the demo is not at Beat 1.
- Every step is idempotent. If step 4 fails, fix it and run
.\setup-all.ps1 -From 4.
- If the terminal starts mangling chained commands, switch to
execution_subagent.
First build on a new machine
cd presentations/dataconus2026/whyazurebest/demos/demo3_controlplane
.\setup-all.ps1
Steps 1–6: network → VM → RDP rule → Entra-only server + Hyperscale DB → ODBC
prerequisites → pre-flight.
Two things need a human:
- Step 2 prompts for the VM local administrator password. The presenter types
it straight into the terminal. Never collect it with a question tool, never
echo it, never put it in a script or a variable you print.
sqlsim.exe must be dragged over RDP into C:\demo — too big for
run-command. setup-all.ps1 pauses and prints the exact source path. Push the
other three files first with .\push-vmkit.ps1, then finish with
.\setup-all.ps1 -From 6.
Done when 05-verify.ps1 prints 17/17 PASS and "Demo is in its Beat 1 state".
Renaming or moving to another region
Both are edits to 00-config.ps1 — and to vmkit/config.ps1.
push-vmkit.ps1 copies vmkit/config.ps1 verbatim; it is not generated from
00-config.ps1. The FQDN and database name are therefore written down twice and
nothing enforces that they match.
This has already broken the demo once. After a re-region the VM-side file still
named the deleted server. Every laptop script and all 17 checks passed while
query.ps1 on the VM pointed at a server that no longer existed.
Order of work:
- Validate the target region has capacity for
Standard_E2s_v5 before touching
anything — az vm list-skus --location <region> --size Standard_E2s_v5 and check
restrictions is empty, plus vCPU quota for the ESv5 family.
- Edit
00-config.ps1 ($Location, $ServerName, $DatabaseName).
- Edit
vmkit/config.ps1 to match.
.\99-teardown.ps1 -Confirm, then .\setup-all.ps1.
.\push-vmkit.ps1, then verify by side effect:
. .\00-config.ps1
Invoke-VmScript "Get-Content 'C:\demo\config.ps1' | Select-String 'ServerFqdn|DatabaseName'"
Logical server names are globally unique DNS labels — a rename can collide.
Traps that are already settled — do not rediscover them
| Trap | The rule |
|---|
--external-admin-sid for a managed identity | Application (client) ID, never the object ID. The object ID creates cleanly and then every login fails. Never write an appId→objectId fallback |
| Entra admin assignment | Must happen at server create time. az sql server ad-admin create has no --principal-type, so it cannot declare Application |
| ODBC Driver 18 returns 1603 | Install VC++ redist first. The MSI log says Error 1723. Never diagnose an MSI from its exit code |
az ... dns-zone-group show on a missing group | Returns exit 0 and {}. Invoke-Az maps a property-less object to $null — keep that fix. Verify existence checks by side effect, not by the message |
az vm run-command --scripts with a multi-line string | Silently emits nothing. Use Invoke-VmScript, which writes a temp .ps1 and passes @file |
Read-Host in an agent-driven terminal | Returns empty. 99-teardown.ps1 asks for the database name, so it aborts with exit 1 and deletes nothing. The presenter must run teardown themselves |
Teardown
.\99-teardown.ps1 -Confirm
Scoped on purpose: VM, NIC, disk, public IP, private endpoint, DNS zone and link,
logical server, database, VNet, nsg-demo3-client, demo3.rdp. It never deletes
the resource group — bwsqlestaterg is shared and Demo 1 counts resources in it.
Tearing down drops Demo 1's estate by one logical server and one database, so
re-check that workbook if the recording matters.
Azure policy injects NRMS-* NSGs alongside the VNet. Teardown does not remove
them and they survive as orphans (subnets: null, networkInterfaces: null).
They are harmless. Confirm they are unassociated before proposing deletion, and
ask first — the resource group is shared.
Before you change shared state
Provisioning is fine to do. Do not, without asking:
- re-run a beat script that locks the server down, or leave
publicNetworkAccess=Disabled behind after an investigation
- delete anything in
bwsqlestaterg that this kit did not create
- re-measure by mutating the live environment when the presenter is rehearsing
Leave the environment at Beat 1, 17/17 PASS.