Scripts
Every script runs in PowerShell 7 (pwsh) on Windows 11, and most also run on macOS. None installs system software. Get the same help in a terminal with Get-Help ./scripts/<name>.ps1 -Detailed.
Lab scripts
Section titled “Lab scripts”Restore-LabCheckpoint.ps1
Section titled “Restore-LabCheckpoint.ps1”Catches you up to the end of a lab by restoring the model from an upstream checkpoint tag.
Details
Use this when you want to skip a lab or start over from a known-good state.
- Stops if you have uncommitted changes. Commit or stash them first; the script won’t do it.
- Fetches the checkpoint tag from the upstream lab repo.
- Creates a new branch, lab/<checkpoint>-<timestamp>, from your current commit.
- Restores only fabric/ and lab/samples/ from the tag and stages the result.
- Creates the gitignored outputs the checkpoint implies (a local-baseline run, the sample assessment) when they don’t exist yet.
Your other files (instructions, agents, skills, prompts you wrote) are left alone. Close Power BI Desktop first, and reopen the project afterward.
| Parameter | Meaning |
|---|---|
-Checkpoint | lab02-start, lab05-complete, lab06-complete, lab07-complete, lab08-complete, or lab09-complete. |
-Remote | The remote that points at the upstream lab repo. Default: upstream. |
-List | List the checkpoints and exit. |
pwsh ./scripts/lab/Restore-LabCheckpoint.ps1 -Checkpoint lab07-completepwsh ./scripts/lab/Restore-LabCheckpoint.ps1 -ListStart-LabSite.ps1
Section titled “Start-LabSite.ps1”Runs the lab site locally at http://localhost:4321/ so you can read the labs offline or preview edits.
Details
Installs the site’s pinned Node packages with npm ci the first time, then starts the Astro dev server. Press Ctrl+C to stop it. Needs Node.js 20 or later.
| Parameter | Meaning |
|---|---|
-Build | Build the static site into site/dist and run the content checks instead of starting the server. |
pwsh ./scripts/lab/Start-LabSite.ps1Test-CheckpointTags.ps1
Section titled “Test-CheckpointTags.ps1”Maintainers and upstream CI: checks that every checkpoint tag exists and passes its lab checks.
Details
For each checkpoint in lab/checkpoints.json, checks out the tag into a temporary worktree,
creates the outputs a restore would create, runs the full validation, and runs the lab checks
listed under verify. Aliases (baseline-v1, ai-ready-v1) must point at the same commit.
| Parameter | Meaning |
|---|---|
-Fetch | Fetch tags from this remote first, for example origin. |
-AllowMissing | Report missing tags as warnings instead of failures (useful before the first release). |
pwsh ./scripts/lab/Test-CheckpointTags.ps1 -Fetch originTest-LabProgress.ps1
Section titled “Test-LabProgress.ps1”Checks whether you finished a lab, and tells you what to fix and where on the lab site.
Details
Runs the checks for one lab from lab/checks.yaml. Each result is PASS, FAIL, WARN (an optional check failed), or SKIP (Windows-only check on another OS). Failures include a hint and a link to the step on the lab site. Exits 0 when every required check passes.
Lab 00 runs before the Python environment exists, so it uses scripts/Test-Prerequisites.ps1.
| Parameter | Meaning |
|---|---|
-Lab | Lab number, for example 7 or 07. |
-Only | Run only these check IDs, comma-separated. |
-Json | Print results as JSON. |
pwsh ./scripts/lab/Test-LabProgress.ps1 -Lab 07Hook scripts
Section titled “Hook scripts”run-hook.ps1
Section titled “run-hook.ps1”Copilot hook entry point on Windows. Forwards the hook payload to python -m pharmacy_demo hook.
Details
Referenced by .github/hooks/guardrails.json. Reads the JSON payload from stdin and passes it to the Python handler, which prints a decision (deny or ask) or nothing. If the repo’s .venv doesn’t exist yet, the hook does nothing and lets the tool call through, so a fresh clone still works before scripts/Initialize-DevEnvironment.ps1 has run.
| Parameter | Meaning |
|---|---|
-HookEvent | session-start, pre-tool-use, post-tool-use, or session-end. |
Maintainer scripts
Section titled “Maintainer scripts”New-LabCheckpoints.ps1
Section titled “New-LabCheckpoints.ps1”Maintainers only: builds the reference/ai-ready branch and the checkpoint tags.
Details
Starting from a commit with the baseline model (normally the release commit on main):
- Tags it baseline-v1, checkpoint/lab02-start, and checkpoint/lab05-complete.
- In a temporary worktree on reference/ai-ready, commits one step per checkpoint: lab06 (sample assessment), lab07 (names), lab08 (relationships and measures), lab09 (AI metadata), generating each model stage with pharmacy_demo modelgen.
- Runs validation and the lab checks for every step before tagging it.
- Removes the worktree. Nothing is pushed unless you pass -Push.
The answers live only on reference/ai-ready and the tags, so learner copies made with Use this template don’t contain them.
| Parameter | Meaning |
|---|---|
-Source | Commit to build from. Default: HEAD. |
-Force | Move existing tags and reset reference/ai-ready. |
-Push | Push reference/ai-ready and all checkpoint tags to -Remote when done. |
-Remote | Remote to push to. Default: origin. |
pwsh ./scripts/maintainer/New-LabCheckpoints.ps1pwsh ./scripts/maintainer/New-LabCheckpoints.ps1 -Force -PushEveryday scripts
Section titled “Everyday scripts”Compare-QuestionRuns.ps1
Section titled “Compare-QuestionRuns.ps1”Compares two graded question runs and writes a Markdown before-and-after table.
| Parameter | Meaning |
|---|---|
-Before | Run label or path for the earlier run, for example local-baseline. |
-After | Run label or path for the later run, for example local-ai-ready. |
-OutFile | Where to write the table. Default: out/question-comparison.md. |
pwsh ./scripts/Compare-QuestionRuns.ps1 -Before local-baseline -After local-ai-readypwsh ./scripts/Compare-QuestionRuns.ps1 -Before sample-baseline -After sample-ai-readyGet-BusinessQuestions.ps1
Section titled “Get-BusinessQuestions.ps1”Prints the five business questions, their paraphrases, and the answer columns, without answers.
Details
This is the only way agents and learners should read the question set. The full file, evaluation/questions.yaml, also holds reference answers and is hidden from agents by the hooks.
| Parameter | Meaning |
|---|---|
-Json | Print the questions as JSON. |
pwsh ./scripts/Get-BusinessQuestions.ps1Grade-QuestionRun.ps1
Section titled “Grade-QuestionRun.ps1”Grades a question run against the expected answers and writes the grade into the run file.
Details
A run file (evaluation/runs/<label>.json) holds the answers an agent or person gave to the five business questions. Each question scores 0, 1, or 2 using the rubric in evaluation/rubric.md.
| Parameter | Meaning |
|---|---|
-Run | A run label such as local-baseline, or a path to a run file. |
-NoWrite | Print the grade without updating the run file. |
-Json | Print the grade as JSON. |
pwsh ./scripts/Grade-QuestionRun.ps1 -Run local-baselineInitialize-DevEnvironment.ps1
Section titled “Initialize-DevEnvironment.ps1”Creates the repo’s Python environment (.venv) and installs the pinned lab tools.
Details
- Finds Python 3.12+ (the py launcher on Windows, then python3 or python).
- Creates .venv in the repo root if it doesn’t exist.
- Installs tools/python/requirements-dev.txt with —require-hashes, then the pharmacy_demo package in editable mode.
- Optionally runs npm ci in site/ so you can preview the lab site locally.
- Runs the validation suite once.
It doesn’t install system software. Run scripts/Test-Prerequisites.ps1 first if you’re not sure what’s installed.
| Parameter | Meaning |
|---|---|
-Force | Delete and recreate .venv. |
-Site | Also install the lab site’s Node packages (needs Node.js 20+). |
pwsh ./scripts/Initialize-DevEnvironment.ps1Invoke-DaxQuestionTests.ps1
Section titled “Invoke-DaxQuestionTests.ps1”Runs the reference DAX for each business question against the model open in Power BI Desktop and checks the results against the expected answers (Windows only).
Details
- Finds the local Analysis Services instance that Power BI Desktop starts for an open model.
- Loads ADOMD.NET from .tools/adomd/. With -AllowDownload it downloads the pinned Microsoft.AnalysisServices.AdomdClient package from nuget.org first and checks its SHA-512.
- Runs each question’s reference DAX and grades the rows with the same grader the question runs use.
- Writes out/dax-tests.json with PASS or FAIL per question. The DAX itself isn’t printed.
The reference DAX uses the business names from Lab 08, so run this after Lab 08 with fabric/ContosoPharmacy.pbip open and refreshed.
| Parameter | Meaning |
|---|---|
-Port | The Desktop Analysis Services port. Default: found from msmdsrv.port.txt (newest instance). |
-AllowDownload | Download ADOMD.NET from nuget.org into .tools/adomd/ if it isn’t there yet. |
-OutFile | Where to write results. Default: out/dax-tests.json. |
pwsh ./scripts/Invoke-DaxQuestionTests.ps1 -AllowDownloadInvoke-Validation.ps1
Section titled “Invoke-Validation.ps1”Runs every validation step that doesn’t need a Fabric tenant or Power BI Desktop.
Details
Checks that the synthetic data matches the seed, the expected answers are current, the question and run files match their schemas, the TMDL lints clean, every report visual binds to a field that exists, and the repository hygiene rules pass (no PHI-like columns, identifiers, secrets, forbidden files, or dashes in prose). This is the same check CI runs on every pull request.
| Parameter | Meaning |
|---|---|
-Only | Run only these steps, comma-separated: data, expected, questions, runs, tmdl, bindings, customizations, hygiene. |
-Json | Print results as JSON. |
-Tests | Also run the Python unit tests (pytest) and the Pester tests. |
pwsh ./scripts/Invoke-Validation.ps1pwsh ./scripts/Invoke-Validation.ps1 -Only tmdl,bindingsNew-SyntheticData.ps1
Section titled “New-SyntheticData.ps1”Regenerates the synthetic CSV files in data/generated/, or checks that they match the seed.
Details
The data is deterministic: the same seed always produces the same bytes on Windows, macOS, and Linux. Only change the data by changing tools/python/pharmacy_demo/datagen.py; then run this script and scripts/Update-ExpectedResults.ps1.
| Parameter | Meaning |
|---|---|
-Check | Don’t write anything. Exit 1 if the committed files differ from the generator. |
pwsh ./scripts/New-SyntheticData.ps1 -CheckSet-LocalDataLink.ps1
Section titled “Set-LocalDataLink.ps1”Points C:\ContosoPharmacyDemo\data at this clone’s data\generated folder (Windows only).
Details
The semantic model reads the CSV files from the DataFolderPath parameter, which defaults to C:\ContosoPharmacyDemo\data. This script creates that path as a directory junction to data\generated in your clone, so the model works wherever you cloned the repo, including paths with spaces. Junctions don’t need administrator rights or Developer Mode.
If the path already exists as a junction it’s replaced. If it’s a real folder with files in it, the script stops and changes nothing.
| Parameter | Meaning |
|---|---|
-Path | Where to create the link. Default: C:\ContosoPharmacyDemo\data. If you change it, also change DataFolderPath in Power BI Desktop (Transform data > Edit parameters). |
-Remove | Remove the junction (and the parent folder if it’s empty). Your data isn’t touched. |
pwsh ./scripts/Set-LocalDataLink.ps1pwsh ./scripts/Set-LocalDataLink.ps1 -RemoveTest-ModelConventions.ps1
Section titled “Test-ModelConventions.ps1”Lists where the semantic model breaks the team conventions in rules/*.yaml.
Details
Rules C01 to C15 cover names, descriptions, hidden keys, summarization, relationships, the date table, measures, display folders, and AI metadata flags. The baseline model breaks most of them on purpose. This is the deterministic check behind the model-assessor agent and Labs 07 to 09. By default it reports findings and exits 0; use -Strict to exit 1 when there are findings.
| Parameter | Meaning |
|---|---|
-Rule | Only report these rule IDs, comma-separated, for example C01,C02. |
-Json | Print findings as JSON. |
-Markdown | Print findings as a Markdown table (Rule, Severity, Object, Finding, Fix). |
-OutFile | Also write the Markdown table to this file. |
-Strict | Exit 1 when there are findings. |
pwsh ./scripts/Test-ModelConventions.ps1 -Rule C01Test-Prerequisites.ps1
Section titled “Test-Prerequisites.ps1”Checks that the tools the labs need are installed. Installs nothing.
Details
Reports each tool as PASS, FAIL, WARN (optional or old), or SKIP (not applicable on this OS), with the install command to run yourself. Exits 1 when a required tool is missing.
Required everywhere: PowerShell 7.4+, Git 2.40+, Python 3.12+, VS Code. Required on Windows: Power BI Desktop, Git core.longpaths. Optional: Node.js 20+ (lab site and Power BI Modeling MCP via npx), GitHub CLI, Copilot CLI.
| Parameter | Meaning |
|---|---|
-Json | Print results as JSON. |
pwsh ./scripts/Test-Prerequisites.ps1Test-ReportBindings.ps1
Section titled “Test-ReportBindings.ps1”Checks that every field used by a report visual exists in the semantic model.
Details
Reads the PBIR visual.json files and the TMDL model, then lists visuals that point at a table, column, or measure that doesn’t exist (usually after a rename). Use the pbir-rebinding skill to fix what it finds.
| Parameter | Meaning |
|---|---|
-Json | Print problems as JSON. |
pwsh ./scripts/Test-ReportBindings.ps1Update-ExpectedResults.ps1
Section titled “Update-ExpectedResults.ps1”Recomputes evaluation/expected/*.json from the synthetic CSVs with DuckDB, or checks them.
Details
The expected answers come from reference SQL that runs directly over the CSV files, so they never depend on the semantic model being right. Run this after regenerating the data.
| Parameter | Meaning |
|---|---|
-Check | Don’t write anything. Exit 1 if the committed answers are out of date. |
pwsh ./scripts/Update-ExpectedResults.ps1 -Check