bi-superpowers 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +31 -0
- package/.claude-plugin/plugin.json +34 -0
- package/.claude-plugin/skill-manifest.json +79 -0
- package/.mcp.json +13 -0
- package/.plugin/plugin.json +14 -0
- package/LICENSE +21 -0
- package/README.md +849 -0
- package/bin/build-plugin.js +97 -0
- package/bin/cli.js +891 -0
- package/bin/commands/autoupdate.js +128 -0
- package/bin/commands/build-desktop.js +368 -0
- package/bin/commands/create-from-template.js +165 -0
- package/bin/commands/diff.js +435 -0
- package/bin/commands/install.js +542 -0
- package/bin/commands/lint.js +441 -0
- package/bin/commands/mcp-setup.js +255 -0
- package/bin/commands/session-update.js +204 -0
- package/bin/commands/smoke-test.js +20 -0
- package/bin/commands/uninstall.js +611 -0
- package/bin/commands/update-check.js +427 -0
- package/bin/commands/validate-cases.js +264 -0
- package/bin/commands/validate-projects.js +426 -0
- package/bin/commands/watch.js +251 -0
- package/bin/lib/agents.js +62 -0
- package/bin/lib/base-template-smoke.js +299 -0
- package/bin/lib/claude-hooks.js +160 -0
- package/bin/lib/generators/claude-plugin.js +529 -0
- package/bin/lib/generators/index.js +116 -0
- package/bin/lib/generators/shared.js +257 -0
- package/bin/lib/mcp-config.js +835 -0
- package/bin/lib/microsoft-mcp.js +206 -0
- package/bin/lib/powerbi-mcp-session.js +140 -0
- package/bin/lib/skills.js +164 -0
- package/bin/lib/template-scaffold.js +366 -0
- package/bin/mcp/powerbi-modeling-launcher.js +42 -0
- package/bin/postinstall.js +50 -0
- package/bin/utils/mcp-detect.js +346 -0
- package/bin/utils/tui.js +314 -0
- package/commands/bi-connect.md +520 -0
- package/commands/bi-dax.md +464 -0
- package/commands/bi-kickoff.md +550 -0
- package/commands/bi-modeling.md +485 -0
- package/commands/bi-performance.md +521 -0
- package/commands/bi-powerquery.md +229 -0
- package/commands/bi-refactor.md +249 -0
- package/commands/bi-scorecard.md +268 -0
- package/commands/bi-start.md +272 -0
- package/config.example.json +23 -0
- package/config.json +23 -0
- package/desktop-extension/manifest.json +30 -0
- package/desktop-extension/package.json +10 -0
- package/desktop-extension/server.js +137 -0
- package/package.json +94 -0
- package/skills/bi-connect/SKILL.md +522 -0
- package/skills/bi-connect/scripts/update-check.js +427 -0
- package/skills/bi-dax/SKILL.md +466 -0
- package/skills/bi-dax/scripts/update-check.js +427 -0
- package/skills/bi-kickoff/SKILL.md +552 -0
- package/skills/bi-kickoff/references/flow.html +78 -0
- package/skills/bi-kickoff/references/flow.md +62 -0
- package/skills/bi-kickoff/scripts/update-check.js +427 -0
- package/skills/bi-modeling/SKILL.md +487 -0
- package/skills/bi-modeling/scripts/update-check.js +427 -0
- package/skills/bi-performance/SKILL.md +523 -0
- package/skills/bi-performance/scripts/install-tabular-editor.ps1 +159 -0
- package/skills/bi-performance/scripts/run-bpa.ps1 +265 -0
- package/skills/bi-performance/scripts/update-check.js +427 -0
- package/skills/bi-powerquery/SKILL.md +231 -0
- package/skills/bi-powerquery/references/base-template-data-contract.md +323 -0
- package/skills/bi-powerquery/references/power-query-standards.md +74 -0
- package/skills/bi-powerquery/scripts/new-powerquery-staging.ps1 +371 -0
- package/skills/bi-powerquery/scripts/test-powerquery-contract.ps1 +225 -0
- package/skills/bi-powerquery/scripts/update-check.js +427 -0
- package/skills/bi-refactor/SKILL.md +251 -0
- package/skills/bi-refactor/references/flow.md +27 -0
- package/skills/bi-refactor/scripts/update-check.js +427 -0
- package/skills/bi-scorecard/SKILL.md +270 -0
- package/skills/bi-scorecard/examples/base-template-scorecard-overlay.json +82 -0
- package/skills/bi-scorecard/scripts/new-scorecard-blueprint-from-base-template.ps1 +124 -0
- package/skills/bi-scorecard/scripts/powerbi-goal-status-rules-api.ps1 +39 -0
- package/skills/bi-scorecard/scripts/powerbi-goal-values-api.ps1 +48 -0
- package/skills/bi-scorecard/scripts/powerbi-goals-api.ps1 +68 -0
- package/skills/bi-scorecard/scripts/powerbi-rest-common.ps1 +197 -0
- package/skills/bi-scorecard/scripts/powerbi-scorecards-api.ps1 +53 -0
- package/skills/bi-scorecard/scripts/update-check.js +427 -0
- package/skills/bi-start/SKILL.md +274 -0
- package/skills/bi-start/scripts/update-check.js +427 -0
- package/src/content/base.md +197 -0
- package/src/content/mcp-requirements.json +57 -0
- package/src/content/routing.md +201 -0
- package/src/content/skills/bi-connect.md +493 -0
- package/src/content/skills/bi-dax.md +437 -0
- package/src/content/skills/bi-kickoff/SKILL.md +523 -0
- package/src/content/skills/bi-kickoff/references/flow.html +78 -0
- package/src/content/skills/bi-kickoff/references/flow.md +62 -0
- package/src/content/skills/bi-modeling.md +458 -0
- package/src/content/skills/bi-performance/SKILL.md +494 -0
- package/src/content/skills/bi-performance/scripts/install-tabular-editor.ps1 +159 -0
- package/src/content/skills/bi-performance/scripts/run-bpa.ps1 +265 -0
- package/src/content/skills/bi-powerquery/SKILL.md +202 -0
- package/src/content/skills/bi-powerquery/references/base-template-data-contract.md +323 -0
- package/src/content/skills/bi-powerquery/references/power-query-standards.md +74 -0
- package/src/content/skills/bi-powerquery/scripts/new-powerquery-staging.ps1 +371 -0
- package/src/content/skills/bi-powerquery/scripts/test-powerquery-contract.ps1 +225 -0
- package/src/content/skills/bi-refactor/SKILL.md +222 -0
- package/src/content/skills/bi-refactor/references/flow.md +27 -0
- package/src/content/skills/bi-scorecard/SKILL.md +241 -0
- package/src/content/skills/bi-scorecard/examples/base-template-scorecard-blueprint.expected.json +105 -0
- package/src/content/skills/bi-scorecard/examples/base-template-scorecard-overlay.json +82 -0
- package/src/content/skills/bi-scorecard/scripts/new-scorecard-blueprint-from-base-template.ps1 +124 -0
- package/src/content/skills/bi-scorecard/scripts/powerbi-goal-status-rules-api.ps1 +39 -0
- package/src/content/skills/bi-scorecard/scripts/powerbi-goal-values-api.ps1 +48 -0
- package/src/content/skills/bi-scorecard/scripts/powerbi-goals-api.ps1 +68 -0
- package/src/content/skills/bi-scorecard/scripts/powerbi-rest-common.ps1 +197 -0
- package/src/content/skills/bi-scorecard/scripts/powerbi-scorecards-api.ps1 +53 -0
- package/src/content/skills/bi-start.md +266 -0
- package/templates/base-template/AGENTS.md +33 -0
- package/templates/base-template/base-template.Report/.platform +11 -0
- package/templates/base-template/base-template.Report/StaticResources/RegisteredResources/BISuperpowers.json +3888 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BaseThemes/CY18SU07.json +177 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BaseThemes/Fluent2-CY26SU03.json +4104 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/AccessibleCityPark.json +26 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/AccessibleDefault.json +26 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/AccessibleNeutral.json +26 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/AccessibleOrchid.json +26 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/AccessibleTidal.json +26 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Bloom.json +139 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/CityPark.json +40 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Classroom.json +40 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/ColorblindSafe.json +48 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/CopilotDefault.json +1861 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Divergent.json +127 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Electric.json +48 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Frontier.json +136 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/HighContrast.json +40 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Highrise.json +41 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Innovate.json +227 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/NewExecutive.json +41 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Solar.json +33 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Storm.json +25 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Sunset.json +48 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Temperature.json +33 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Tidal.json +100 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Twilight.json +40 -0
- package/templates/base-template/base-template.Report/definition/bookmarks/1d40d43c7ade66e8603c.bookmark.json +2297 -0
- package/templates/base-template/base-template.Report/definition/bookmarks/af068ff51c0ca3089ea7.bookmark.json +2300 -0
- package/templates/base-template/base-template.Report/definition/bookmarks/bookmarks.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/page.json +130 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/0352fd80d074693a65db/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/0352fd80d074693a65db/visual.json +669 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/1c5a14bf493697344b68/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/1c5a14bf493697344b68/visual.json +723 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/3486cf7624c5b109b4e5/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/3486cf7624c5b109b4e5/visual.json +333 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/4d8b989008edc0db28d1/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/4d8b989008edc0db28d1/visual.json +109 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/55e10ac7d76a1954f94f/mobile.json +31 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/55e10ac7d76a1954f94f/visual.json +378 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/57f52ecf4490f70e4da1/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/57f52ecf4490f70e4da1/visual.json +175 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/5f4d76bbc870118e9840/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/5f4d76bbc870118e9840/visual.json +468 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/73629e1abebb7a444b59/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/73629e1abebb7a444b59/visual.json +359 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/749cb1388c7e0a88161c/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/749cb1388c7e0a88161c/visual.json +690 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/90677f13cea5d1275990/visual.json +17 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/92cf92e3da10493adb78/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/92cf92e3da10493adb78/visual.json +468 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/9fe17b1971f68443fc15/mobile.json +10 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/9fe17b1971f68443fc15/visual.json +328 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a30bd0950630ed94e8a3/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a30bd0950630ed94e8a3/visual.json +578 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a56e91d9400a835e4814/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a56e91d9400a835e4814/visual.json +432 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/aded24cd205c0b528642/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/aded24cd205c0b528642/visual.json +801 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/af34b26f14a8a724c9a9/mobile.json +37 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/af34b26f14a8a724c9a9/visual.json +1318 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/b529688fe5a226643322/visual.json +209 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/c4c6f332d05e72e2eb06/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/c4c6f332d05e72e2eb06/visual.json +174 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/fa81f184e2cb0e8b087c/mobile.json +29 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/fa81f184e2cb0e8b087c/visual.json +241 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/page.json +130 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/07e9c4302e29029c5462/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/07e9c4302e29029c5462/visual.json +690 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/109ceede4bc015b0c006/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/109ceede4bc015b0c006/visual.json +468 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/118257e006d472277e10/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/118257e006d472277e10/visual.json +359 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/2caf02e0137c4a1280cc/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/2caf02e0137c4a1280cc/visual.json +669 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/311e76fe3c9edad68204/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/311e76fe3c9edad68204/visual.json +109 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/31c21f8cbeb3b208940a/visual.json +209 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/3ab72c25062437149b03/visual.json +17 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/5959867442abcb0ce2b3/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/5959867442abcb0ce2b3/visual.json +788 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/5b96e0f88d192b044a13/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/5b96e0f88d192b044a13/visual.json +592 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/64e749a63d0786000e22/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/64e749a63d0786000e22/visual.json +468 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/7ae1ca604edac6586ad0/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/7ae1ca604edac6586ad0/visual.json +1310 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/840300733885141a6603/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/840300733885141a6603/visual.json +175 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/a38448cdb203279273d2/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/a38448cdb203279273d2/visual.json +516 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/d1e86f213a3841d12e20/visual.json +328 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/d4a484c1bcc8ee3075e2/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/d4a484c1bcc8ee3075e2/visual.json +432 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/d87cb5cf06acca19bbb5/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/d87cb5cf06acca19bbb5/visual.json +241 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/e243da2677209ed69408/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/e243da2677209ed69408/visual.json +174 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/f3aaf24f5b22b67573b0/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/f3aaf24f5b22b67573b0/visual.json +333 -0
- package/templates/base-template/base-template.Report/definition/pages/pages.json +8 -0
- package/templates/base-template/base-template.Report/definition/report.json +89 -0
- package/templates/base-template/base-template.Report/definition/version.json +4 -0
- package/templates/base-template/base-template.Report/definition.pbir +9 -0
- package/templates/base-template/base-template.SemanticModel/.platform +11 -0
- package/templates/base-template/base-template.SemanticModel/definition/cultures/es-AR.tmdl +11185 -0
- package/templates/base-template/base-template.SemanticModel/definition/database.tmdl +3 -0
- package/templates/base-template/base-template.SemanticModel/definition/expressions.tmdl +234 -0
- package/templates/base-template/base-template.SemanticModel/definition/functions.tmdl +637 -0
- package/templates/base-template/base-template.SemanticModel/definition/model.tmdl +82 -0
- package/templates/base-template/base-template.SemanticModel/definition/relationships.tmdl +271 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Calendario.tmdl +200 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Campa/303/261as.tmdl +75 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Canales.tmdl +84 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Clientes.tmdl +143 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Devoluciones.tmdl +95 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Ejecuci/303/263n proyectos.tmdl" +130 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Entregas.tmdl +122 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Equipos m/303/251tricas.tmdl" +40 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Equipos.tmdl +73 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Horas.tmdl +122 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Interacciones clientes.tmdl +146 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Leads.tmdl +119 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Monedas.tmdl +44 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Movimientos financieros.tmdl +145 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/M/303/251tricas.tmdl +1294 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/N/303/263mina.tmdl +110 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Oportunidades.tmdl +135 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Presupuesto.tmdl +125 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Productos.tmdl +98 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Proyectos.tmdl +77 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Servicios.tmdl +75 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Tareas proyecto.tmdl +102 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Tipo de cambio.tmdl +67 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Ventas.tmdl +180 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux An/303/241lisis dimensiones.tmdl" +38 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Comparaciones.tmdl +227 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Compatibilidad m/303/251trica-dimensi/303/263n.tmdl" +68 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Modelo configuraci/303/263n.tmdl" +44 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Modo fechas.tmdl +36 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux M/303/251trica-Equipo.tmdl" +102 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Overrides m/303/251trica-dimensi/303/263n.tmdl" +54 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Per/303/255odos.tmdl" +182 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Rango fechas modo.tmdl +36 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Rango fechas.tmdl +27 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Vista de calendario.tmdl +30 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_GC C/303/241lculo.tmdl" +70 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_GC Eje X.tmdl +63 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_GC M/303/251trica.tmdl" +374 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_GC Tipo c/303/241lculo.tmdl" +223 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_PC Dimensi/303/263n.tmdl" +98 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_PC Eje X.tmdl +68 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables//303/223rdenes servicio.tmdl" +151 -0
- package/templates/base-template/base-template.SemanticModel/definition.pbism +5 -0
- package/templates/base-template/base-template.SemanticModel/diagramLayout.json +568 -0
- package/templates/base-template/base-template.pbip +14 -0
- package/templates/base-template/template.manifest.json +41 -0
- package/theme/BISuperpowers.json +3888 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# install-tabular-editor.ps1
|
|
2
|
+
# Detects Tabular Editor 2 (free, MIT) at the expected install path.
|
|
3
|
+
# With -Install, downloads the latest stable release ZIP from GitHub and
|
|
4
|
+
# extracts it to %LOCALAPPDATA%\TabularEditor\.
|
|
5
|
+
#
|
|
6
|
+
# Outputs the absolute path to TabularEditor.exe on stdout.
|
|
7
|
+
# Exit code: 0 = installed/found; non-zero = missing or infrastructure failure.
|
|
8
|
+
#
|
|
9
|
+
# Used by /bi-performance and /bi-modeling for Best Practice Analyzer
|
|
10
|
+
# and VertiPaq Analyzer integration.
|
|
11
|
+
|
|
12
|
+
#requires -Version 7.0
|
|
13
|
+
|
|
14
|
+
[CmdletBinding()]
|
|
15
|
+
param(
|
|
16
|
+
[switch]$Force,
|
|
17
|
+
[switch]$Install
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
$ErrorActionPreference = 'Stop'
|
|
21
|
+
|
|
22
|
+
function Get-LocalAppDataPath {
|
|
23
|
+
$localAppData = $env:LOCALAPPDATA
|
|
24
|
+
if ([string]::IsNullOrWhiteSpace($localAppData)) {
|
|
25
|
+
$localAppData = [Environment]::GetFolderPath('LocalApplicationData')
|
|
26
|
+
}
|
|
27
|
+
if ([string]::IsNullOrWhiteSpace($localAppData)) {
|
|
28
|
+
throw 'LOCALAPPDATA is not set and LocalApplicationData could not be resolved.'
|
|
29
|
+
}
|
|
30
|
+
return $localAppData
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function Assert-ValidAuthenticodeSignature {
|
|
34
|
+
param(
|
|
35
|
+
[Parameter(Mandatory = $true)]
|
|
36
|
+
[string]$FilePath
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
# Get-AuthenticodeSignature is a Windows-only cmdlet. If it is unavailable we
|
|
40
|
+
# cannot verify; warn and proceed rather than blocking an otherwise-working
|
|
41
|
+
# Tabular Editor install.
|
|
42
|
+
if (-not (Get-Command Get-AuthenticodeSignature -ErrorAction SilentlyContinue)) {
|
|
43
|
+
Write-Warning "Cannot check the Authenticode signature on this platform; skipping verification for ${FilePath}."
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
$signature = Get-AuthenticodeSignature -FilePath $FilePath
|
|
48
|
+
|
|
49
|
+
# Explicit tampering / trust failures are fatal — never run a binary that
|
|
50
|
+
# fails these.
|
|
51
|
+
$fatalStatuses = @('HashMismatch', 'NotTrusted', 'NotSigned')
|
|
52
|
+
if ($fatalStatuses -contains $signature.Status) {
|
|
53
|
+
throw "Authenticode signature validation failed for ${FilePath}: $($signature.Status)"
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
# 'Valid' is the happy path. Anything else (most often 'UnknownError' when the
|
|
57
|
+
# certificate revocation servers are unreachable on offline / locked-down
|
|
58
|
+
# corporate machines) is NOT evidence of tampering, so warn and continue
|
|
59
|
+
# instead of aborting the Best Practice Analyzer run on a setup that worked
|
|
60
|
+
# before.
|
|
61
|
+
if ($signature.Status -ne 'Valid') {
|
|
62
|
+
Write-Warning "Could not fully verify the Authenticode signature for ${FilePath} (status: $($signature.Status)). This is common on offline or locked-down machines; proceeding with the existing install."
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function Invoke-TabularEditorInstall {
|
|
67
|
+
param(
|
|
68
|
+
[switch]$Force,
|
|
69
|
+
[switch]$Install
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
$installDir = Join-Path (Get-LocalAppDataPath) 'TabularEditor'
|
|
73
|
+
$exePath = Join-Path $installDir 'TabularEditor.exe'
|
|
74
|
+
|
|
75
|
+
if ((Test-Path $exePath) -and -not $Force) {
|
|
76
|
+
Assert-ValidAuthenticodeSignature -FilePath $exePath
|
|
77
|
+
Write-Output $exePath
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (-not $Install) {
|
|
82
|
+
throw "Tabular Editor 2 was not found at $exePath. Ask the user for permission, then rerun this script with -Install."
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
Write-Host "Tabular Editor 2 was not found at $installDir." -ForegroundColor Yellow
|
|
86
|
+
Write-Host "Downloading the latest stable release from GitHub..." -ForegroundColor Yellow
|
|
87
|
+
|
|
88
|
+
# GitHub API: latest release for the official Tabular Editor 2 repo
|
|
89
|
+
$apiUrl = 'https://api.github.com/repos/TabularEditor/TabularEditor/releases/latest'
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
$headers = @{ 'User-Agent' = 'bi-superpowers-installer' }
|
|
93
|
+
if ($env:GITHUB_TOKEN) {
|
|
94
|
+
$headers['Authorization'] = "Bearer $env:GITHUB_TOKEN"
|
|
95
|
+
}
|
|
96
|
+
$release = Invoke-RestMethod -Uri $apiUrl -Headers $headers -UseBasicParsing
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
throw "Could not query the GitHub releases API: $($_.Exception.Message). If this is a rate-limit error, set GITHUB_TOKEN and rerun."
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
# Pick the standard Windows ZIP. Prefer the non-portable ZIP when both assets
|
|
103
|
+
# exist because it matches the expected TabularEditor.exe layout.
|
|
104
|
+
$asset = $release.assets |
|
|
105
|
+
Where-Object { $_.name -match '\.zip$' -and $_.name -notmatch 'portable' } |
|
|
106
|
+
Select-Object -First 1
|
|
107
|
+
|
|
108
|
+
if (-not $asset) {
|
|
109
|
+
throw "No Windows ZIP asset was found in release $($release.tag_name)."
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
$assetUri = [System.Uri]$asset.browser_download_url
|
|
113
|
+
if (-not $assetUri.IsAbsoluteUri -or $assetUri.Scheme -ne 'https' -or $assetUri.Host -notmatch '(^|\.)github\.com$') {
|
|
114
|
+
throw "Unexpected Tabular Editor asset host: $($assetUri.Host)"
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
$tempZip = Join-Path $env:TEMP "TabularEditor_$([guid]::NewGuid().ToString('N')).zip"
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
Invoke-WebRequest -Uri $asset.browser_download_url -OutFile $tempZip -UseBasicParsing -Headers $headers
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
throw "Download failed for $($asset.browser_download_url): $($_.Exception.Message)"
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (-not (Test-Path $installDir)) {
|
|
127
|
+
New-Item -ItemType Directory -Path $installDir -Force | Out-Null
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
Expand-Archive -Path $tempZip -DestinationPath $installDir -Force
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
Remove-Item $tempZip -Force -ErrorAction SilentlyContinue
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (-not (Test-Path $exePath)) {
|
|
138
|
+
throw "Installation completed, but $exePath was not found. Check the contents of $installDir."
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
Assert-ValidAuthenticodeSignature -FilePath $exePath
|
|
142
|
+
|
|
143
|
+
Write-Host "Tabular Editor 2 installed: $exePath (version $($release.tag_name))" -ForegroundColor Green
|
|
144
|
+
Write-Output $exePath
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if ($MyInvocation.InvocationName -ne '.') {
|
|
148
|
+
try {
|
|
149
|
+
Invoke-TabularEditorInstall -Force:$Force -Install:$Install
|
|
150
|
+
exit 0
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
[Console]::Error.WriteLine($_.Exception.Message)
|
|
154
|
+
if (-not $Install -and $_.Exception.Message -match 'was not found') {
|
|
155
|
+
exit 2
|
|
156
|
+
}
|
|
157
|
+
exit 1
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
# run-bpa.ps1
|
|
2
|
+
# Runs the Microsoft Best Practice Rules (BPA) against the open
|
|
3
|
+
# Power BI Desktop semantic model using Tabular Editor 2 CLI.
|
|
4
|
+
#
|
|
5
|
+
# Auto-detects the AS port from the local PBI Desktop workspace and
|
|
6
|
+
# downloads the latest BPA rules JSON from microsoft/Analysis-Services.
|
|
7
|
+
#
|
|
8
|
+
# Usage:
|
|
9
|
+
# pwsh run-bpa.ps1 # default rules, autodetect port
|
|
10
|
+
# pwsh run-bpa.ps1 -RulesUrl <url> # override rules source
|
|
11
|
+
# pwsh run-bpa.ps1 -Port 51234 # override port autodetect
|
|
12
|
+
# pwsh run-bpa.ps1 -InstallTabularEditor # install TE2 after user consent
|
|
13
|
+
#
|
|
14
|
+
# Output: BPA findings to stdout. Exit 0 on success (regardless of finding count),
|
|
15
|
+
# non-zero on infrastructure failure.
|
|
16
|
+
|
|
17
|
+
#requires -Version 7.0
|
|
18
|
+
|
|
19
|
+
[CmdletBinding()]
|
|
20
|
+
param(
|
|
21
|
+
[string]$RulesUrl = 'https://raw.githubusercontent.com/microsoft/Analysis-Services/master/BestPracticeRules/BPARules.json',
|
|
22
|
+
[switch]$AllowCustomRulesUrl,
|
|
23
|
+
[int]$Port = 0,
|
|
24
|
+
[string]$Database = '',
|
|
25
|
+
[switch]$InstallTabularEditor
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
$ErrorActionPreference = 'Stop'
|
|
29
|
+
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
30
|
+
|
|
31
|
+
function Assert-SafeRulesUri {
|
|
32
|
+
param(
|
|
33
|
+
[Parameter(Mandatory = $true)]
|
|
34
|
+
[string]$Uri,
|
|
35
|
+
|
|
36
|
+
[switch]$AllowCustomRulesUrl
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
$parsed = [System.Uri]$Uri
|
|
40
|
+
if (-not $parsed.IsAbsoluteUri -or $parsed.Scheme -ne 'https') {
|
|
41
|
+
throw 'RulesUrl must use HTTPS.'
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (-not $AllowCustomRulesUrl) {
|
|
45
|
+
$expectedHost = 'raw.githubusercontent.com'
|
|
46
|
+
$expectedPrefix = '/microsoft/Analysis-Services/'
|
|
47
|
+
if ($parsed.Host -ne $expectedHost -or -not $parsed.AbsolutePath.StartsWith($expectedPrefix, [System.StringComparison]::OrdinalIgnoreCase)) {
|
|
48
|
+
throw 'RulesUrl must point to Microsoft Analysis-Services on raw.githubusercontent.com unless -AllowCustomRulesUrl is provided.'
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function Get-LocalAppDataPath {
|
|
54
|
+
$localAppData = $env:LOCALAPPDATA
|
|
55
|
+
if ([string]::IsNullOrWhiteSpace($localAppData)) {
|
|
56
|
+
$localAppData = [Environment]::GetFolderPath('LocalApplicationData')
|
|
57
|
+
}
|
|
58
|
+
if ([string]::IsNullOrWhiteSpace($localAppData)) {
|
|
59
|
+
throw 'LOCALAPPDATA is not set and LocalApplicationData could not be resolved.'
|
|
60
|
+
}
|
|
61
|
+
return $localAppData
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function Get-BpaRulesCachePath {
|
|
65
|
+
param(
|
|
66
|
+
[Parameter(Mandatory = $true)]
|
|
67
|
+
[string]$RulesUrl,
|
|
68
|
+
|
|
69
|
+
[Parameter(Mandatory = $true)]
|
|
70
|
+
[string]$CacheRoot
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
$sha256 = [System.Security.Cryptography.SHA256]::Create()
|
|
74
|
+
try {
|
|
75
|
+
$bytes = [System.Text.Encoding]::UTF8.GetBytes($RulesUrl.Trim())
|
|
76
|
+
$hashBytes = $sha256.ComputeHash($bytes)
|
|
77
|
+
$hash = [System.BitConverter]::ToString($hashBytes).Replace('-', '').ToLowerInvariant()
|
|
78
|
+
return Join-Path $CacheRoot "BPARules-$($hash.Substring(0, 16)).json"
|
|
79
|
+
}
|
|
80
|
+
finally {
|
|
81
|
+
$sha256.Dispose()
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
# Step 2 — Detect the live Power BI Desktop AS port (if not provided)
|
|
86
|
+
function Read-PowerBIPortFile {
|
|
87
|
+
param([string]$Path)
|
|
88
|
+
|
|
89
|
+
foreach ($encoding in @('Unicode', 'Default')) {
|
|
90
|
+
$text = Get-Content $Path -Raw -Encoding $encoding -ErrorAction SilentlyContinue
|
|
91
|
+
$digits = ($text -replace '[^\d]', '')
|
|
92
|
+
$port = 0
|
|
93
|
+
# TryParse + range guard: a corrupt/oversized port file must skip this
|
|
94
|
+
# workspace gracefully, not overflow [int] and abort autodetection.
|
|
95
|
+
if ($digits -and [int]::TryParse($digits, [ref]$port) -and $port -ge 1 -and $port -le 65535) {
|
|
96
|
+
return $port
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return $null
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function Test-LocalPort {
|
|
104
|
+
param([int]$CandidatePort)
|
|
105
|
+
|
|
106
|
+
$client = [System.Net.Sockets.TcpClient]::new()
|
|
107
|
+
try {
|
|
108
|
+
$async = $client.BeginConnect('127.0.0.1', $CandidatePort, $null, $null)
|
|
109
|
+
if (-not $async.AsyncWaitHandle.WaitOne(500)) { return $false }
|
|
110
|
+
$client.EndConnect($async)
|
|
111
|
+
return $true
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return $false
|
|
115
|
+
}
|
|
116
|
+
finally {
|
|
117
|
+
$client.Close()
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function Get-PowerBIPort {
|
|
122
|
+
$localAppData = Get-LocalAppDataPath
|
|
123
|
+
$candidates = @(
|
|
124
|
+
(Join-Path $localAppData 'Microsoft\Power BI Desktop\AnalysisServicesWorkspaces\*\Data\msmdsrv.port.txt'),
|
|
125
|
+
(Join-Path $localAppData 'Microsoft\Power BI Desktop Store App\AnalysisServicesWorkspaces\*\Data\msmdsrv.port.txt')
|
|
126
|
+
)
|
|
127
|
+
$portFiles = @()
|
|
128
|
+
foreach ($pattern in $candidates) {
|
|
129
|
+
$portFiles += Get-ChildItem -Path $pattern -ErrorAction SilentlyContinue
|
|
130
|
+
}
|
|
131
|
+
if (-not $portFiles) { return $null }
|
|
132
|
+
|
|
133
|
+
$reachable = @()
|
|
134
|
+
foreach ($file in $portFiles) {
|
|
135
|
+
$candidatePort = Read-PowerBIPortFile -Path $file.FullName
|
|
136
|
+
if ($candidatePort -and (Test-LocalPort -CandidatePort $candidatePort)) {
|
|
137
|
+
$reachable += [PSCustomObject]@{
|
|
138
|
+
Port = $candidatePort
|
|
139
|
+
Path = $file.FullName
|
|
140
|
+
LastWriteTime = $file.LastWriteTime
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (-not $reachable) { return $null }
|
|
146
|
+
|
|
147
|
+
if ($reachable.Count -gt 1) {
|
|
148
|
+
$details = ($reachable | Sort-Object LastWriteTime -Descending | ForEach-Object {
|
|
149
|
+
"localhost:$($_.Port) from $($_.Path)"
|
|
150
|
+
}) -join "`n "
|
|
151
|
+
[Console]::Error.WriteLine("Multiple active Power BI Desktop workspaces were detected. Rerun with -Port for the target instance:`n $details")
|
|
152
|
+
exit 5
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return $reachable[0].Port
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function Invoke-BpaRun {
|
|
159
|
+
param(
|
|
160
|
+
[string]$RulesUrl,
|
|
161
|
+
[switch]$AllowCustomRulesUrl,
|
|
162
|
+
[int]$Port,
|
|
163
|
+
[string]$Database,
|
|
164
|
+
[switch]$InstallTabularEditor
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
# Step 1 — Resolve Tabular Editor 2 (install if missing)
|
|
168
|
+
$installScript = Join-Path $here 'install-tabular-editor.ps1'
|
|
169
|
+
$installArgs = @()
|
|
170
|
+
if ($InstallTabularEditor) {
|
|
171
|
+
$installArgs += '-Install'
|
|
172
|
+
}
|
|
173
|
+
$exePath = & $installScript @installArgs
|
|
174
|
+
if (-not $exePath -or -not (Test-Path $exePath)) {
|
|
175
|
+
[Console]::Error.WriteLine("Could not resolve TabularEditor.exe. If the user approved installation, rerun with -InstallTabularEditor.")
|
|
176
|
+
exit 1
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
# Step 2 — Detect the live Power BI Desktop AS port (if not provided)
|
|
180
|
+
if ($Port -eq 0) {
|
|
181
|
+
$detected = Get-PowerBIPort
|
|
182
|
+
if (-not $detected) {
|
|
183
|
+
[Console]::Error.WriteLine("No active Power BI Desktop workspace was detected. Is the .pbip open?")
|
|
184
|
+
exit 2
|
|
185
|
+
}
|
|
186
|
+
$Port = [int]$detected
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
Write-Host "Connecting to Power BI Desktop at localhost:$Port" -ForegroundColor Cyan
|
|
190
|
+
|
|
191
|
+
# Step 3 — Download (or cache) the BPA rules JSON
|
|
192
|
+
Assert-SafeRulesUri -Uri $RulesUrl -AllowCustomRulesUrl:$AllowCustomRulesUrl
|
|
193
|
+
|
|
194
|
+
$cacheRoot = Join-Path (Join-Path (Get-LocalAppDataPath) 'BI Superpowers') 'Cache'
|
|
195
|
+
New-Item -ItemType Directory -Force -Path $cacheRoot | Out-Null
|
|
196
|
+
$rulesPath = Get-BpaRulesCachePath -RulesUrl $RulesUrl -CacheRoot $cacheRoot
|
|
197
|
+
$cacheStale = -not (Test-Path $rulesPath) -or `
|
|
198
|
+
((Get-Item $rulesPath).LastWriteTime -lt (Get-Date).AddDays(-7))
|
|
199
|
+
|
|
200
|
+
if ($cacheStale) {
|
|
201
|
+
Write-Host "Downloading BPA rules from $RulesUrl..." -ForegroundColor Cyan
|
|
202
|
+
try {
|
|
203
|
+
$headers = @{ 'User-Agent' = 'bi-superpowers-bpa' }
|
|
204
|
+
if ($env:GITHUB_TOKEN) {
|
|
205
|
+
$headers['Authorization'] = "Bearer $env:GITHUB_TOKEN"
|
|
206
|
+
}
|
|
207
|
+
Invoke-WebRequest -Uri $RulesUrl -OutFile $rulesPath -UseBasicParsing -Headers $headers
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
[Console]::Error.WriteLine("Failed to download BPA rules: $($_.Exception.Message). If this is a rate-limit error, set GITHUB_TOKEN and rerun.")
|
|
211
|
+
exit 3
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
# Step 4 — Run TE2 with -A (Analyze). TE2 connects to localhost:port and
|
|
216
|
+
# auto-discovers the database when only one is present (always the case for
|
|
217
|
+
# a Power BI Desktop instance).
|
|
218
|
+
$server = "localhost:$Port"
|
|
219
|
+
$argsList = @($server)
|
|
220
|
+
if ($Database) { $argsList += $Database }
|
|
221
|
+
$argsList += @('-A', $rulesPath)
|
|
222
|
+
|
|
223
|
+
Write-Host "Running: $exePath $($argsList -join ' ')" -ForegroundColor DarkGray
|
|
224
|
+
# Capture stdout and stderr separately. TE2 writes BPA findings (and a
|
|
225
|
+
# non-zero exit) to stdout for rule violations — the *normal* audit case —
|
|
226
|
+
# while connection/CLI failures go to stderr. Merging them with 2>&1 would
|
|
227
|
+
# let a failure's stderr text masquerade as findings and exit 0.
|
|
228
|
+
$stderrFile = [System.IO.Path]::GetTempFileName()
|
|
229
|
+
try {
|
|
230
|
+
$output = & $exePath @argsList 2>$stderrFile
|
|
231
|
+
$exitCode = $LASTEXITCODE
|
|
232
|
+
$stderr = Get-Content -LiteralPath $stderrFile -Raw -ErrorAction SilentlyContinue
|
|
233
|
+
}
|
|
234
|
+
finally {
|
|
235
|
+
Remove-Item -LiteralPath $stderrFile -Force -ErrorAction SilentlyContinue
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
# No findings on stdout AND a non-zero exit = infrastructure failure (bad
|
|
239
|
+
# port, unsupported -A, failed AS connection). Now that stderr is captured
|
|
240
|
+
# separately, an empty stdout reliably means "no findings", so a clean
|
|
241
|
+
# zero-finding audit (exit 0) is never treated as a failure even if TE2
|
|
242
|
+
# emitted an incidental warning to stderr (surfaced as a diagnostic below).
|
|
243
|
+
if ([string]::IsNullOrWhiteSpace($output) -and $exitCode -ne 0) {
|
|
244
|
+
$detail = if ([string]::IsNullOrWhiteSpace($stderr)) { 'no output' } else { $stderr.Trim() }
|
|
245
|
+
[Console]::Error.WriteLine("TE2 failed (exit code $exitCode) connecting to localhost:$Port. $detail")
|
|
246
|
+
exit 4
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
# Surface any stderr as a diagnostic without letting it pollute the findings.
|
|
250
|
+
if (-not [string]::IsNullOrWhiteSpace($stderr)) {
|
|
251
|
+
[Console]::Error.WriteLine($stderr.Trim())
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
Write-Output $output
|
|
255
|
+
exit 0
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if ($MyInvocation.InvocationName -ne '.') {
|
|
259
|
+
Invoke-BpaRun `
|
|
260
|
+
-RulesUrl $RulesUrl `
|
|
261
|
+
-AllowCustomRulesUrl:$AllowCustomRulesUrl `
|
|
262
|
+
-Port $Port `
|
|
263
|
+
-Database $Database `
|
|
264
|
+
-InstallTabularEditor:$InstallTabularEditor
|
|
265
|
+
}
|