Skip to content

ImpactIQ v3: headless, resumable rewrite with Azure DevOps automation (no service principal) - #1

Merged
bschram merged 12 commits into
mainfrom
claude/powerbi-workspace-automation-ubhqk5
Sep 10, 2026
Merged

ImpactIQ v3: headless, resumable rewrite with Azure DevOps automation (no service principal)#1
bschram merged 12 commits into
mainfrom
claude/powerbi-workspace-automation-ubhqk5

Conversation

@bschram

@bschram bschram commented Sep 4, 2026

Copy link
Copy Markdown
Owner

Summary

ImpactIQ v3: the 3,740-line interactive script is now a headless-capable, resumable, modular tool that produces the same four workbooks and backup folders, plus an Azure DevOps pipeline that runs it without a service principal or an Azure VM.

Written for the owner's situation: Power BI Premium (P SKU) on a GCC tenant, no Fabric, no service principal, Azure DevOps available.

What changed

  • ImpactIQ.ps1 + Config/Modules/ImpactIQ.*.ps1 replace the monolith. Final PS Script.txt is now a thin interactive launcher with the v2 experience (dialogs, browser sign-in, pickers). The original is kept untouched in Legacy/.
  • Headless: -NonInteractive plus parameters or IMPACTIQ_* environment variables for every former prompt. No scope given headless means the run stops instead of scanning the tenant by accident.
  • Resume: every workspace inventory, model backup, report export, model-detail CSV and dataflow export is checkpointed under State\runs\<RunId>\ the moment it finishes. Re-running skips finished items and retries failures. -Resume Auto also picks up an unfinished run from a previous day.
  • Time budget: -TimeBudgetMinutes stops cleanly before a hosted-agent job cap, assembles partial workbooks, exits 3 (Paused) and resumes on the next scheduled run.
  • Auth without a service principal: DeviceCode (pure OAuth device-code flow with an encrypted refresh-token cache, AES for hosted agents or DPAPI on a self-hosted box, optional Teams/Slack webhook for the code), Credential (ROPC for MFA-exempt accounts, with AADSTS error mapping), AzContext, AccessToken, and the original Interactive mode. GCC uses the commercial authority with the GCC resource; the GCC High and DoD resource hosts were wrong in v2 and are corrected.
  • Robustness: one HTTP wrapper with retry and back-off (429 Retry-After, 5xx, network errors, one token refresh on 401, paging), timeouts and captured output for every Tabular Editor and pbi-tools process, per-item failure records and a Failures sheet, exit codes 0/1/2/3, atomic manifest writes, secret redaction in logs.
  • Model detail without Tabular Editor: a pure-PowerShell TMSL (.bim) parser produces the same Semantic Models and Measure Dependencies CSVs, a Fabric getDefinition fallback fetches the model definition where Fabric exists, and a DAX INFO.VIEW.* path covers models where neither is available (-ModelDetailMethod Auto|TabularEditor|Bim|Dax|Both).
  • More data, additive sheets: dashboards and tiles, workspace users, dataset users, dataset parameters, direct-query refresh schedules, capacities, a run summary, failures; optional -IncludeAdminApis (admin groups, Scanner API, activity events) and -IncludeUsageMetrics (per-workspace usage-metrics model via DAX). Existing sheets and columns are unchanged, so the current .pbit keeps working.
  • Azure DevOps: pipelines/azure-pipelines.yml with a reusable template: scheduled runs, state restored from the previous run's artifact, outputs and backups published as artifacts, optional commit of the workbooks to a data branch so the Power BI template can read them over Web.Contents with a PAT.
  • Docs: docs/Automation.md (decision matrix), Auth-Options.md, Azure-DevOps.md, Headless-and-Resume.md, Data-Coverage.md, Validation-Report.md (audit findings and what was fixed).
  • Fixes to the existing code found by the audit: My Workspace page rows lost report ids, paginated reports were never detected, pseudo-workspace ids were spliced into API URLs, unguarded REST calls silently dropped whole sheets, Tabular Editor exit codes were ignored, CSV escaping in the model extractor, per-report error handling in the report extractors, a misspelled JSON path in the classic report extractor, and more (see docs/Validation-Report.md).

Test plan

  • Parse and PSScriptAnalyzer (5.1 and 7 compatibility rules) clean on every .ps1
  • Pester suite green on PowerShell 7 (Linux) with mocked APIs and fake tool binaries: 565 passed, 0 failed, 3 skipped (Windows-only)
  • Manual run on Windows PowerShell 5.1 against the GCC tenant (owner): interactive launcher, then ImpactIQ.ps1 -NonInteractive -Environment USGov -AuthMode DeviceCode -AllWorkspaces
  • One ReportDetail and one ModelDetail run on Windows to confirm the edited C# extractor scripts compile under Tabular Editor 2
  • First pipeline run with IMPACTIQ_TOKEN_CACHE_KEY set, completing the device code from the log

Windows-only paths (Tabular Editor 2, pbi-tools, DPAPI, WinForms, real Power BI and Fabric APIs) could not be executed in the Linux build environment. docs/Validation-Report.md section 4 lists exactly what to check on Windows.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KVTWDExuXsqoqNTb5sFUJs

…tive script

Preparation for the headless/resumable refactor:
- Config/SheetContract.json: every sheet and expected column the Power BI
  Governance Model template reads, generated from the template's own
  ExpectedColumns lists, so the assembler can guarantee the contract.
- PSScriptAnalyzerSettings.psd1: PowerShell 5.1 + 7.0 compatibility rules.
- Legacy/: untouched copy of the current monolithic script as a fallback.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KVTWDExuXsqoqNTb5sFUJs
Work-in-progress snapshot of the new Config/Modules/*.ps1 files (context,
logging, state and checkpoints, HTTP wrapper, tool runner, inventory, model
and DAX stages). Not yet integrated or tested; later commits complete the
set, add the entry point, pipeline, docs, and tests.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KVTWDExuXsqoqNTb5sFUJs
Work-in-progress snapshot; modules are still being completed and have not
been integrated or tested together yet.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KVTWDExuXsqoqNTb5sFUJs
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KVTWDExuXsqoqNTb5sFUJs
… (snapshot)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KVTWDExuXsqoqNTb5sFUJs
…kup (snapshot)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KVTWDExuXsqoqNTb5sFUJs
…apshot)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KVTWDExuXsqoqNTb5sFUJs
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KVTWDExuXsqoqNTb5sFUJs
…tomation

- ImpactIQ.ps1 entry point + Config/Modules (Common, Auth, Http, State, Tools,
  Interactive, Inventory, Dax, Bim, Models, Reports, Dataflows, Extras, Assemble)
- Auth without a service principal: DeviceCode with encrypted refresh-token
  cache (AES or DPAPI), Credential (ROPC), AzContext, AccessToken, Interactive;
  corrected GCC High / DoD resource hosts; GCC uses the commercial authority
- Per-item checkpoints and manifest under State/runs/<RunId>; resume rules;
  -TimeBudgetMinutes with Paused status and exit code 3
- HTTP wrapper with retry/back-off/paging/LRO; process runner with timeouts
- Model detail via Tabular Editor, pure-PowerShell TMSL parser, Fabric
  getDefinition fallback, or DAX INFO.VIEW queries
- New collectors: dashboards, tiles, users, parameters, DQ schedules,
  capacities, run summary, failures; optional admin scanner/activity and
  usage metrics
- Azure DevOps pipeline + template (state restore, artifacts, exit-code mapping,
  unexpanded-macro guard), docs, validation report, Pester suite (565 tests)
- Audit fixes in the C# extractors (CSV escaping, per-report error handling,
  ExtractErrors.txt, JSON path typo, env-var driven folders)
- Original script kept unchanged under Legacy/

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KVTWDExuXsqoqNTb5sFUJs
@bschram bschram changed the title Headless, resumable ImpactIQ with Azure DevOps automation (no service principal) ImpactIQ v3: headless, resumable rewrite with Azure DevOps automation (no service principal) Sep 6, 2026
@bschram
bschram merged commit 7b0d3cf into main Sep 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants