<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>Notebook Gallery topics</title>
    <link>https://community.fabric.microsoft.com/t5/Notebook-Gallery/bd-p/pbi_notebookgallery</link>
    <description>Notebook Gallery topics</description>
    <pubDate>Sun, 08 Nov 2026 06:04:01 GMT</pubDate>
    <dc:creator>pbi_notebookgallery</dc:creator>
    <dc:date>2026-11-08T06:04:01Z</dc:date>
    <item>
      <title>Fabric Metadata &amp; Data Quality Assessment Framework</title>
      <link>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Fabric-Metadata-Data-Quality-Assessment-Framework/m-p/5367651#M213</link>
      <description>&lt;P&gt;&lt;STRONG&gt;Overview&lt;/STRONG&gt;&lt;/P&gt;&lt;P&gt;A reusable Microsoft Fabric notebook for metadata discovery, single-pass PySpark data profiling, rule-based data quality assessment, and Data Quality Index (DQI) scoring.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Key Capabilities&lt;/STRONG&gt;&lt;/P&gt;&lt;P&gt;Dual Execution Modes: Run on synthetic e-commerce data or target existing Delta tables in OneLake.&lt;/P&gt;&lt;P&gt;High-Performance Profiling: Single-pass PySpark aggregations compute distinct counts, null ratios, and boundaries in a single Spark action call.&lt;/P&gt;&lt;P&gt;Multi-Dimension Quality Auditing: Evaluates Completeness, Uniqueness, and Validity using custom weighted thresholds.&lt;/P&gt;&lt;P&gt;Executive Reporting: Generates an aggregate Data Quality Index (DQI) score and automated remediation guidance.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Use Cases&lt;/STRONG&gt;&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;Lakehouse data quality monitoring and health checks&lt;/LI&gt;&lt;LI&gt;Data product readiness for Gold layer consumption&lt;/LI&gt;&lt;LI&gt;Pre- and post-migration validation&lt;/LI&gt;&lt;LI&gt;Enterprise data platform modernization&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;Full Notebook &amp;amp; Code: Download the complete .ipynb notebook file from the Github Repository&lt;/P&gt;</description>
      <pubDate>Fri, 18 Sep 2026 02:31:34 GMT</pubDate>
      <guid>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Fabric-Metadata-Data-Quality-Assessment-Framework/m-p/5367651#M213</guid>
      <dc:creator>thisismukund</dc:creator>
      <dc:date>2026-09-18T02:31:34Z</dc:date>
    </item>
    <item>
      <title>Fabric Data Agent Analyzer</title>
      <link>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Fabric-Data-Agent-Analyzer/m-p/5363095#M212</link>
      <description>&lt;P&gt;Fabric Data Agents are only as effective as the data foundation behind them. Following best practices is critical to achieving accurate, reliable, and consistent responses. This notebook automates the review process, helping you quickly identify optimization opportunities and improve AI readiness.&lt;/P&gt;</description>
      <pubDate>Fri, 28 Aug 2026 17:26:55 GMT</pubDate>
      <guid>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Fabric-Data-Agent-Analyzer/m-p/5363095#M212</guid>
      <dc:creator>farhansoomro</dc:creator>
      <dc:date>2026-08-28T17:26:55Z</dc:date>
    </item>
    <item>
      <title>Direct Query Semantic Model BPA</title>
      <link>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Direct-Query-Semantic-Model-BPA/m-p/5363093#M211</link>
      <description>&lt;P&gt;DirectQuery is often blamed for poor performance, but a well-designed DirectQuery semantic model can perform efficiently when best practices are followed. This notebook automates the review process, quickly identifying potential performance bottlenecks and optimization opportunities.&lt;/P&gt;</description>
      <pubDate>Fri, 28 Aug 2026 12:53:42 GMT</pubDate>
      <guid>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Direct-Query-Semantic-Model-BPA/m-p/5363093#M211</guid>
      <dc:creator>farhansoomro</dc:creator>
      <dc:date>2026-08-28T12:53:42Z</dc:date>
    </item>
    <item>
      <title>OneLake security data access role replication</title>
      <link>https://community.fabric.microsoft.com/t5/Notebook-Gallery/OneLake-security-data-access-role-replication/m-p/5361117#M210</link>
      <description>&lt;P&gt;This Python notebook provides a basic example for OneLake security data access roles replication between different environments.&lt;/P&gt;&lt;H5&gt;At the moment:&lt;/H5&gt;&lt;UL&gt;&lt;LI&gt;OneLake security roles are only deployed through Fabric deployment pipelines, which only covers the roles defined, not the actual Entra ID user/group member assignments (just permission group assignments).&lt;/LI&gt;&lt;LI&gt;&lt;A href="https://microsoft.github.io/fabric-cicd/1.3.0/" target="_blank" rel="noopener"&gt;On its latest version&lt;/A&gt;, fabric-cicd does not deploy OneLake security roles.&lt;/LI&gt;&lt;/UL&gt;&lt;H5&gt;How it works:&lt;/H5&gt;&lt;P&gt;Through the &lt;A href="https://learn.microsoft.com/en-us/rest/api/fabric/core/onelake-data-access-security" target="_blank" rel="noopener"&gt;OneLake security REST APIs&lt;/A&gt;, we can take the existing role definition and assignments from a specific environment and replicate them to another entirely.&amp;nbsp;&lt;/P&gt;&lt;P&gt;The example relies on two specific methods:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;List Data Access Roles&lt;/LI&gt;&lt;LI&gt;Create Or Update Data Access Roles&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;This way, we can:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;Persist/modify the already assigned Entra ID users and/or groups to the existing roles from one lakehouse to another.&lt;/LI&gt;&lt;LI&gt;Point the existing permission group assignments to the target (workspace + lakehouse).&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;Credentials for the whole process are provided through&amp;nbsp;&lt;A href="https://learn.microsoft.com/en-us/fabric/data-engineering/notebookutils/notebookutils-credentials?tabs=python#get-token" target="_blank" rel="noopener"&gt;NotebookUtils&lt;/A&gt;.&lt;/P&gt;&lt;H4&gt;⚠️IMPORTANT&lt;/H4&gt;&lt;UL&gt;&lt;LI&gt;The process, as it is, overwrites the existing roles and assignments at the target with the source's configuration. Any roles and/or assignments non declared at the source will be deleted.&lt;/LI&gt;&lt;LI&gt;The identity running the process must have at least the Member role in the referenced workspaces.&lt;/LI&gt;&lt;LI&gt;When running under a service principal, token management could require some adjustments, specially if the code does not run inside Fabric.&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;&lt;A href="https://github.com/l2aFa/pbi-notebook-gallery/blob/main/onelake_security_role_replicator.ipynb" target="_blank" rel="noopener"&gt;You can find the notebook here&lt;/A&gt;, feel free to adapt the code as needed. For example, once tweaked, it could be used as an step inside an ADO/GitHub pipeline and deploy the existing OneLake roles defined over each lakehouse while replicating the roles established and updating the user/group assignments depending on the deployment environment, complementing fabric-cicd deployments.&lt;/P&gt;&lt;P&gt;Another possible implementation can be done with Terraform. If interested in managing Fabric with Terraform, you can take a look at &lt;A href="https://github.com/l2aFa/fabric_terraform" target="_blank" rel="noopener"&gt;my GitHub repo&lt;/A&gt;.&lt;/P&gt;&lt;P&gt;Hope you find it useful!&lt;/P&gt;</description>
      <pubDate>Thu, 03 Sep 2026 06:14:45 GMT</pubDate>
      <guid>https://community.fabric.microsoft.com/t5/Notebook-Gallery/OneLake-security-data-access-role-replication/m-p/5361117#M210</guid>
      <dc:creator>baguena_raf</dc:creator>
      <dc:date>2026-09-03T06:14:45Z</dc:date>
    </item>
    <item>
      <title>Find Which Semantic Models Use a Specific Database Table — Across All Workspaces</title>
      <link>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Find-Which-Semantic-Models-Use-a-Specific-Database-Table-Across/m-p/5331597#M209</link>
      <description>&lt;P&gt;Ever needed to know which Power BI semantic models reference a specific source table before making a change or deprecating it?&lt;/P&gt;&lt;P&gt;This reusable Fabric Notebook scans all accessible workspaces in one run and identifies every semantic model that references your target table — no manual clicking required.&lt;/P&gt;&lt;P&gt;Key Features:&lt;BR /&gt;&lt;span class="lia-unicode-emoji" title=":white_heavy_check_mark:"&gt;✅&lt;/span&gt; Scans all workspaces in a single run&lt;BR /&gt;&lt;span class="lia-unicode-emoji" title=":white_heavy_check_mark:"&gt;✅&lt;/span&gt; Filter by workspace name keyword (e.g. [DEV] only)&lt;BR /&gt;&lt;span class="lia-unicode-emoji" title=":white_heavy_check_mark:"&gt;✅&lt;/span&gt; Three scan methods per model — datasources, model objects, and BIM/M query expressions&lt;BR /&gt;&lt;span class="lia-unicode-emoji" title=":white_heavy_check_mark:"&gt;✅&lt;/span&gt; Deduplicates results across scan methods&lt;BR /&gt;&lt;span class="lia-unicode-emoji" title=":white_heavy_check_mark:"&gt;✅&lt;/span&gt; Logs skipped models separately (permission errors)&lt;BR /&gt;&lt;span class="lia-unicode-emoji" title=":white_heavy_check_mark:"&gt;✅&lt;/span&gt; Export results to CSV in Lakehouse&lt;/P&gt;&lt;P&gt;Libraries used: semantic-link-labs, sempy.fabric&lt;/P&gt;&lt;P&gt;&lt;SPAN class="msgUrl hidden"&gt;https%3A%2F%2Fgithub.com%2FBIWithSadia%2Fbi-toolkit%2Fblob%2Fmain%2FDB_table_across_all_workspaces.ipynb&lt;/SPAN&gt;&lt;/P&gt;</description>
      <pubDate>Fri, 31 Jul 2026 03:28:13 GMT</pubDate>
      <guid>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Find-Which-Semantic-Models-Use-a-Specific-Database-Table-Across/m-p/5331597#M209</guid>
      <dc:creator>SBegum</dc:creator>
      <dc:date>2026-07-31T03:28:13Z</dc:date>
    </item>
    <item>
      <title>Fabric Shortcut Inventory</title>
      <link>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Fabric-Shortcut-Inventory/m-p/5317759#M205</link>
      <description>&lt;P&gt;&lt;SPAN&gt;A Microsoft Fabric notebook that scans workspaces and builds a&amp;nbsp;&lt;/SPAN&gt;&lt;STRONG&gt;complete inventory of OneLake shortcuts&lt;/STRONG&gt;&lt;SPAN&gt;, detecting&amp;nbsp;&lt;/SPAN&gt;&lt;STRONG&gt;orphaned&lt;/STRONG&gt;&lt;SPAN&gt;,&amp;nbsp;&lt;/SPAN&gt;&lt;STRONG&gt;circular&lt;/STRONG&gt;&lt;SPAN&gt;&amp;nbsp;and&amp;nbsp;&lt;/SPAN&gt;&lt;STRONG&gt;ungoverned external&lt;/STRONG&gt;&lt;SPAN&gt;&amp;nbsp;shortcuts, with an interactive HTML report and optional persistence to a Delta table.&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;SPAN&gt;&lt;img /&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;DIV class=""&gt;&lt;H2&gt;&lt;STRONG&gt;Why?&lt;/STRONG&gt;&lt;/H2&gt;&lt;/DIV&gt;&lt;P&gt;OneLake shortcuts are easy to create and hard to govern: over time you accumulate shortcuts pointing to deleted items, circular chains between lakehouses, and connections to external storage (S3, ADLS, GCS…) with no sensitivity label or endorsement whatsoever. Fabric offers no centralized view of any of this. This notebook builds one in a single run.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;DIV class=""&gt;&lt;H2&gt;&lt;STRONG&gt;What it does&lt;/STRONG&gt;&lt;/H2&gt;&lt;/DIV&gt;&lt;OL&gt;&lt;LI&gt;&lt;STRONG&gt;Discovers workspaces&lt;/STRONG&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;— the entire tenant (with admin permissions) or a specific list, by name or ID.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Discovers items&lt;/STRONG&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;— lists the items in each workspace via the&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;A href="https://learn.microsoft.com/rest/api/fabric/" target="_blank" rel="nofollow noopener"&gt;Fabric REST API&lt;/A&gt;.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Extracts shortcuts&lt;/STRONG&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;— in parallel, from the item types that support them (Lakehouse, KQL Database, Mirrored Database).&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Parses targets&lt;/STRONG&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;— normalizes OneLake targets (workspace/item/path) and external ones (Amazon S3, ADLS Gen2, Google Cloud Storage, S3 compatible, Dataverse, Azure Blob Storage, OneDrive/SharePoint).&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Validates&lt;/STRONG&gt;:&lt;UL&gt;&lt;LI&gt;&lt;STRONG&gt;Orphaned&lt;/STRONG&gt;: the target item no longer exists within the scanned scope.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Circular&lt;/STRONG&gt;: shortcut chains that form a cycle (DFS detection over the dependency graph).&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Governance&lt;/STRONG&gt;: external shortcuts on items with no sensitivity label and no endorsement (Certified/Promoted).&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Resolves names&lt;/STRONG&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;— turns target GUIDs into human-readable names, even for targets outside the scanned scope.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Presents&lt;/STRONG&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;— an interactive HTML report with 4 views (Overview, Circular, Orphan, Governance) and per-row color coding.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Persists (optional)&lt;/STRONG&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;— writes the inventory to a Delta table so you can query it with SQL or build Power BI reports on top&lt;/LI&gt;&lt;/OL&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;SPAN&gt;All the code and documentation can be found in the &lt;A href="https://github.com/kilianbs/fabric-shortcut-inventory" target="_blank" rel="noopener"&gt;Github Repository&lt;/A&gt;&lt;/SPAN&gt;&lt;SPAN&gt;.&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;SPAN class="msgUrl hidden"&gt;https%3A%2F%2Fgithub.com%2Fkilianbs%2Ffabric-shortcut-inventory%2Fblob%2Fmain%2Fshortcut_inventory_en.ipynb&lt;/SPAN&gt;&lt;/P&gt;</description>
      <pubDate>Thu, 30 Jul 2026 13:59:31 GMT</pubDate>
      <guid>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Fabric-Shortcut-Inventory/m-p/5317759#M205</guid>
      <dc:creator>kilianbs</dc:creator>
      <dc:date>2026-07-30T13:59:31Z</dc:date>
    </item>
    <item>
      <title>DP-600 Study Companion Notebook for Microsoft Fabric</title>
      <link>https://community.fabric.microsoft.com/t5/Notebook-Gallery/DP-600-Study-Companion-Notebook-for-Microsoft-Fabric/m-p/5234675#M199</link>
      <description>&lt;P&gt;I created this study companion notebook while preparing for the DP-600: Implementing Analytics Solutions Using Microsoft Fabric certification.&lt;/P&gt;&lt;P&gt;The repository brings together key Microsoft Fabric concepts including OneLake, Lakehouse, Data Warehouse, Direct Lake, Semantic Models, DAX, Security, Governance, and Monitoring in a single reference guide.&lt;/P&gt;&lt;P&gt;The goal is to help analytics engineers, Power BI developers, and certification candidates understand Fabric architecture through practical notes, diagrams, and notebook-based examples.&lt;/P&gt;&lt;P&gt;Repository:&lt;BR /&gt;&lt;A href="https://github.com/sabledattatray/dp600-study-companion-notebook" target="_blank"&gt;https://github.com/sabledattatray/dp600-study-companion-notebook&lt;/A&gt;&lt;/P&gt;&lt;P&gt;Feedback and suggestions are welcome. I hope this resource helps others on their Microsoft Fabric learning journey.&lt;/P&gt;&lt;P&gt;&lt;SPAN class="msgUrl hidden"&gt;https%3A%2F%2Fgithub.com%2Fsabledattatray%2Fdp600-study-companion-notebook&lt;/SPAN&gt;&lt;/P&gt;</description>
      <pubDate>Thu, 25 Jun 2026 03:36:41 GMT</pubDate>
      <guid>https://community.fabric.microsoft.com/t5/Notebook-Gallery/DP-600-Study-Companion-Notebook-for-Microsoft-Fabric/m-p/5234675#M199</guid>
      <dc:creator>sabledattatray</dc:creator>
      <dc:date>2026-06-25T03:36:41Z</dc:date>
    </item>
    <item>
      <title>Fabric Spark Pool Optimiser</title>
      <link>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Fabric-Spark-Pool-Optimiser/m-p/5191017#M198</link>
      <description>&lt;P class=""&gt;&lt;STRONG&gt;Fabric Spark Pool Optimiser — right-size your Spark pools in 3 minutes&lt;/STRONG&gt;&lt;/P&gt;&lt;P class=""&gt;Every workspace in Microsoft Fabric gets the same default Spark pool. Medium node, up to 10 nodes. Nobody changes it — even in production, even when the actual workload is a 5,000-row dimension table or a monitoring notebook reading 0.002 GB.&lt;/P&gt;&lt;P class=""&gt;This notebook analyses 7 days of real Spark session history across all your workspaces and tells you exactly which pools are oversized, undersized, or correctly sized — with a step-by-step configuration guide for each one.&lt;/P&gt;&lt;P class=""&gt;&lt;STRONG&gt;What it does:&lt;/STRONG&gt;&lt;/P&gt;&lt;P&gt;- Auto-discovers all workspaces you have access to&lt;/P&gt;&lt;P&gt;- Detects orchestrator workspaces automatically (runMultiple / Data Factory)&lt;/P&gt;&lt;P&gt;- Separates automated pipeline sessions from interactive dev sessions — dev sessions skew duration data and are excluded from the CU calculation&lt;/P&gt;&lt;P&gt;- Analyses GB read/written/shuffled via the Spark History stages API&lt;/P&gt;&lt;P&gt;- Estimates monthly CU savings based on real usage&lt;/P&gt;&lt;P&gt;- Renders an interactive dashboard directly in the notebook output&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P class=""&gt;&lt;STRONG&gt;No lakehouse needed. No configuration. Just import and Run All.&lt;/STRONG&gt;&lt;/P&gt;&lt;P class=""&gt;Tested across two organisations. In one run: 50 workspaces analysed, 8 pools to change, 1,441 CU estimated monthly saving.&lt;/P&gt;&lt;P class=""&gt;Feedback welcome — especially if you find API behaviour that differs in your environment.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;SPAN class="msgUrl hidden"&gt;https%3A%2F%2Fgithub.com%2Fenekoegiguren%2Ffabricsparkpooloptimiser&lt;/SPAN&gt;&lt;/P&gt;</description>
      <pubDate>Sun, 31 May 2026 16:39:03 GMT</pubDate>
      <guid>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Fabric-Spark-Pool-Optimiser/m-p/5191017#M198</guid>
      <dc:creator>eguigurene</dc:creator>
      <dc:date>2026-05-31T16:39:03Z</dc:date>
    </item>
    <item>
      <title>Fix Slicers with Custom Visual SLICERBAR</title>
      <link>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Fix-Slicers-with-Custom-Visual-SLICERBAR/m-p/5190504#M197</link>
      <description>&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;H1&gt;&lt;A href="https://github.com/KornAlexander/Fabric-Notebooks/blob/main/Migrate%20Slicers%20to%20SLICERBAR.ipynb" target="_blank"&gt;Fabric-Notebooks/Migrate Slicers to SLICERBAR.ipynb at main · KornAlexander/Fabric-Notebooks&lt;/A&gt;&lt;/H1&gt;&lt;H1&gt;Migrate Native Slicers → SLICERBAR&lt;/H1&gt;&lt;P&gt;This notebook consolidates the&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;STRONG&gt;native Power BI slicer visuals&lt;/STRONG&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;on a report page into a single&lt;SPAN&gt;&amp;nbsp;&lt;STRONG&gt;SLICERBAR&amp;nbsp;&lt;/STRONG&gt;&lt;/SPAN&gt;custom visual using the&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;fix_migrate_slicer_to_slicerbar&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;fixer from the PBI Fixer build of&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;A href="https://github.com/KornAlexander/semantic-link-labs/tree/feature/pbi-fixer-ui" target="_blank" rel="noopener"&gt;semantic-link-labs&lt;/A&gt;.&amp;nbsp;&lt;/P&gt;&lt;H2&gt;Purpose&lt;/H2&gt;&lt;P&gt;Reports often accumulate many individual slicer visuals that clutter the canvas and consume real estate. The&lt;SPAN&gt; &lt;STRONG&gt;SLICERBAR&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;custom visual collapses all of those filters into one compact, modern control. This fixer automates that migration directly against the report definition (PBIR) — no manual rebuilding required.&lt;/P&gt;&lt;H2&gt;What it does&lt;/H2&gt;&lt;P&gt;For the page you specify, the fixer:&lt;/P&gt;&lt;OL&gt;&lt;LI&gt;&lt;STRONG&gt;Finds the &lt;SPAN&gt;SLICERBAR&amp;nbsp;&lt;/SPAN&gt;visual&lt;/STRONG&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;on the page. If none exists, it&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;STRONG&gt;creates a narrow one in the top-right corner&lt;/STRONG&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;and registers the custom visual in the report.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Finds every native&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;slicer&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;visual&lt;/STRONG&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;on the page.&lt;/LI&gt;&lt;LI&gt;For each slicer, extracts its field (Entity&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;+&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;Property) and adds it to the Slicer Bar's query + configuration.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Skips duplicates&lt;/STRONG&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;(a field already present in the Slicer Bar) but still removes the redundant native slicer.&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Deletes&lt;/STRONG&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;the original native slicers once migrated.&lt;/LI&gt;&lt;/OL&gt;&lt;H2&gt;Requirements&lt;/H2&gt;&lt;UL&gt;&lt;LI&gt;The report must be in&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;STRONG&gt;PBIR&lt;/STRONG&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;format. If it is in the legacy format, run&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;EM&gt;Upgrade to PBIR&lt;/EM&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;first.&lt;/LI&gt;&lt;LI&gt;Use&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;scan_only=True&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;for a safe dry run before committing changes.&lt;/LI&gt;&lt;/UL&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;H2&gt;1. Install&lt;/H2&gt;&lt;P&gt;Install the PBI Fixer build of&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;semantic-link-labs. The PySpark kernel restarts automatically after install — that is expected. Run this once per session.&lt;/P&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;%pip install git+&lt;A href="https://github.com/KornAlexander/semantic-link-labs.git@feature/pbi-fixer-ui" target="_blank" rel="noopener"&gt;https://github.com/KornAlexander/semantic-link-labs.git@feature/pbi-fixer-ui&lt;/A&gt; -q&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;H2&gt;2. Import the fixer&lt;/H2&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;SPAN class=""&gt;from&lt;/SPAN&gt; sempy_labs.report._Fix_MigrateSlicerToSlicerbar &lt;SPAN class=""&gt;import&lt;/SPAN&gt; fix_migrate_slicer_to_slicerbar&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;H2&gt;3. Dry run (recommended first)&lt;/H2&gt;&lt;P&gt;scan_only=True&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;reports exactly which slicers&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;STRONG&gt;would&lt;/STRONG&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;be migrated — nothing is written to the report. Review the output before running the real migration.&lt;/P&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;fix_migrate_slicer_to_slicerbar(report=&lt;SPAN class=""&gt;"report name"&lt;/SPAN&gt;, page_name=&lt;SPAN class=""&gt;"page name"&lt;/SPAN&gt;, scan_only=&lt;SPAN class=""&gt;True&lt;/SPAN&gt;)&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;H2&gt;4. Run the migration&lt;/H2&gt;&lt;P&gt;This applies the changes: it creates the Slicer Bar if missing, migrates the native slicers into it, and deletes the originals.&lt;/P&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;fix_migrate_slicer_to_slicerbar(report=&lt;SPAN class=""&gt;"report name"&lt;/SPAN&gt;, page_name=&lt;SPAN class=""&gt;"page name"&lt;/SPAN&gt;)&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&amp;nbsp;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;HR /&gt;&lt;H3&gt;Parameters&lt;/H3&gt;Parameter Description &lt;TABLE&gt;&lt;TBODY&gt;&lt;TR&gt;&lt;TD&gt;report&lt;/TD&gt;&lt;TD&gt;Name or ID of the report.&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;page_name&lt;/TD&gt;&lt;TD&gt;Display name of the page to migrate.&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;workspace&lt;/TD&gt;&lt;TD&gt;Workspace name or ID. Defaults to the attached lakehouse / notebook workspace.&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;scan_only&lt;/TD&gt;&lt;TD&gt;If&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;True, only reports what would change without writing.&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;H3&gt;Notes&lt;/H3&gt;&lt;UL&gt;&lt;LI&gt;When no Slicer Bar exists on the page, a new one is placed&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;STRONG&gt;top-right, 200&amp;nbsp;px wide, full page height&lt;/STRONG&gt;, titled&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;EM&gt;Slicers&lt;/EM&gt;.&lt;/LI&gt;&lt;LI&gt;The SLICERBAR custom visual is registered in&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;report.json&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;automatically (idempotent).&lt;/LI&gt;&lt;LI&gt;Re-running on a page that already has all fields migrated simply removes any leftover duplicate native slicers.&lt;/LI&gt;&lt;/UL&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;SPAN class="msgUrl hidden"&gt;https%3A%2F%2Fgithub.com%2FKornAlexander%2FFabric-Notebooks%2Fblob%2Fmain%2FMigrate%2520Slicers%2520to%2520SLICERBAR.ipynb&lt;/SPAN&gt;&lt;/P&gt;</description>
      <pubDate>Fri, 29 May 2026 13:52:09 GMT</pubDate>
      <guid>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Fix-Slicers-with-Custom-Visual-SLICERBAR/m-p/5190504#M197</guid>
      <dc:creator>AlexanderKornMS</dc:creator>
      <dc:date>2026-05-29T13:52:09Z</dc:date>
    </item>
    <item>
      <title>Get a list of Custom Visuals</title>
      <link>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Get-a-list-of-Custom-Visuals/m-p/5183373#M191</link>
      <description>&lt;P&gt;The following two scripts check for custom visuals in use for the whole tenant and lists them.&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Lightweight alternative for individual reports&lt;/P&gt;&lt;LI-CODE lang="markup"&gt;%pip install semantic-link-labs --quiet

import sempy_labs as labs
from sempy_labs.report import ReportWrapper

cv = ReportWrapper(report="Report Name", workspace="Workspace Name").list_custom_visuals()
display(cv)&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;This script checks for custom visuals in use for the whole tenant and lists them.&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="python"&gt;%pip install semantic-link-labs --quiet

import sempy_labs as labs
from sempy_labs.report import ReportWrapper

cv = ReportWrapper(report="Report Name", workspace="Workspace Name").list_custom_visuals()
display(cv)&amp;lt;p&amp;gt; &amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;For all reports in current or all workspaces the following notebook works:&amp;lt;li-code lang="markup"&amp;gt;# Custom Visuals Inventory across a Power BI / Fabric Workspace

**Author:** Alexander Korn — Solution Engineer Data Platform, Microsoft  
**Last updated:** 2026-05-15  
**Runtime:** Microsoft Fabric Notebook (Python)  
**Dependencies:** [`semantic-link-labs`](https://github.com/microsoft/semantic-link-labs)

---

## Purpose

Governance teams frequently need to answer a deceptively simple question:

&amp;gt; **Which custom (third-party / AppSource / organizational) visuals are actually used in our Power BI reports — and where?**

This information is essential for:

- **Tenant governance** — admins disabling or restricting custom visuals need an impact assessment first.
- **Security &amp;amp; compliance** — custom visuals are arbitrary code; you should know what is in production.
- **Lifecycle management** — identifying unused or deprecated visuals before cleanup.
- **Migration planning** — moving reports between tenants or to Fabric requires knowing every visual dependency.

## What this notebook does

It scans **every Power BI report in a given workspace** (or list of workspaces) and produces a tidy table:

| Workspace | Report | Custom Visual Name | Custom Visual Display Name |
|-----------|--------|--------------------|----------------------------|

Under the hood it uses `sempy_labs.report.ReportWrapper.list_custom_visuals()` from semantic-link-labs, which parses the report definition (PBIR) and returns the visuals registered in the report.

&amp;gt; ℹ️ Reports stored in the legacy single-file PBIX layout are skipped — see **Notes &amp;amp; limitations** at the bottom for how to convert them.

## How to use

1. Attach this notebook to any Lakehouse in your target workspace (no tables are written — the lakehouse attachment is only required by the Fabric Python runtime).
2. Run the install cell once per session (or bake `semantic-link-labs` into a custom Fabric environment).
3. Set `MODE` (and optionally `WORKSPACES`) in the configuration cell.
4. Run all cells. The final cell renders the inventory table and a few aggregations.

---
## 1. Install dependencies

Run this once per Fabric session. To avoid the install on every run, add `semantic-link-labs` to a [custom Fabric environment](https://learn.microsoft.com/fabric/data-engineering/create-and-use-environment) and attach it to the notebook.
%pip install semantic-link-labs --quiet
## 2. Configuration

Pick the **scan mode**:

- `"current"` — scan only the workspace this notebook is attached to.
- `"list"` — scan the workspaces named in `WORKSPACES`.
- `"all"` — scan every workspace the executing identity can see (slow on large tenants).
# Scan mode: "current" | "list" | "all"
MODE = "current"

# Used only when MODE == "list" — workspace names or IDs.
WORKSPACES: list[str] = ["Demo"]
## 3. The function

`list_custom_visuals_in_workspace(workspace)` returns a tidy DataFrame with one row per (report, custom visual) pair. It silently skips paginated reports and any report it can't parse, logging the reason.
import traceback
import pandas as pd
import sempy.fabric as fabric
from sempy_labs.report import ReportWrapper


def _resolve_workspace(workspace: str | None) -&amp;gt; str:
    """Resolve workspace name — fall back to the notebook's current workspace."""
    if workspace:
        return workspace
    ws_id = fabric.get_notebook_workspace_id()
    return fabric.resolve_workspace_name(ws_id)


def list_custom_visuals_in_workspace(workspace: str | None = None) -&amp;gt; pd.DataFrame:
    """Return all custom visuals used by Power BI reports in a workspace.

    Columns: Workspace, Report, Custom Visual Name, Custom Visual Display Name.
    """
    ws = _resolve_workspace(workspace)

    try:
        reports = fabric.list_reports(workspace=ws)
    except Exception:
        print(f"  · could not list reports in '{ws}':")
        traceback.print_exc()
        return pd.DataFrame(columns=["Workspace", "Report", "Custom Visual Name", "Custom Visual Display Name"])

    type_col = "Report Type" if "Report Type" in reports.columns else None
    if type_col:
        reports = reports[reports[type_col].isin(["PowerBIReport", "Power BI Report"])]

    name_col = "Name" if "Name" in reports.columns else "Report Name"

    rows = []
    for _, r in reports.iterrows():
        report_name = r[name_col]
        try:
            rw = ReportWrapper(report=report_name, workspace=ws)
            cv = rw.list_custom_visuals()
        except Exception as e:
            print(f"  · skipping '{report_name}': {type(e).__name__}: {e}")
            continue

        if cv is None or cv.empty:
            continue

        used_col = next((c for c in cv.columns if c.lower().startswith("used")), None)
        used = cv[cv[used_col] == True] if used_col else cv  # noqa: E712

        for _, v in used.iterrows():
            rows.append({
                "Workspace": ws,
                "Report": report_name,
                "Custom Visual Name": v.get("Custom Visual Name"),
                "Custom Visual Display Name": v.get("Custom Visual Display Name"),
            })

    return pd.DataFrame(
        rows,
        columns=["Workspace", "Report", "Custom Visual Name", "Custom Visual Display Name"],
    )


def list_custom_visuals_multi(workspaces: list[str | None]) -&amp;gt; pd.DataFrame:
    """Run the inventory across multiple workspaces and concatenate the results."""
    frames = []
    for ws in workspaces:
        print(f"Scanning workspace: {ws or '&amp;lt;current&amp;gt;'}")
        frames.append(list_custom_visuals_in_workspace(ws))
    return pd.concat(frames, ignore_index=True) if frames else pd.DataFrame()
## 4. Report format inventory (PBIR vs. PBIRLegacy)

Lists every Power BI report in the configured workspace(s) along with its **storage format** (`PBIR` or `PBIRLegacy`). Reports flagged as `PBIRLegacy` will be skipped by the custom-visuals scan in section 5.

This uses the Power BI REST API `format` field directly — the same signal that [`sempy_labs.report.upgrade_to_pbir`](https://semantic-link-labs.readthedocs.io/en/stable/sempy_labs.report.html) reads. To actually upgrade, see the tip at the bottom of the cell.

The same `MODE` / `WORKSPACES` configuration applies.
from sempy.fabric import FabricRestClient

_client = FabricRestClient()


def list_report_formats(workspace: str | None = None) -&amp;gt; pd.DataFrame:
    """List Workspace, Report, Format ('PBIR' / 'PBIRLegacy') for every PBI report.

    Uses the Power BI REST API `format` field — same signal that
    ``sempy_labs.report.upgrade_to_pbir`` relies on, but read-only.
    """
    ws_name = _resolve_workspace(workspace)
    ws_id = fabric.resolve_workspace_id(ws_name)

    resp = _client.get(f"/v1.0/myorg/groups/{ws_id}/reports").json()
    rows = [
        {"Workspace": ws_name, "Report": r["name"], "Format": r.get("format", "Unknown")}
        for r in resp.get("value", [])
        if r.get("reportType") in (None, "PowerBIReport")
    ]
    return pd.DataFrame(rows, columns=["Workspace", "Report", "Format"])


# Reuse the same MODE / WORKSPACES configuration as the rest of the notebook.
def _targets_from_config() -&amp;gt; list[str | None]:
    if MODE == "current":
        return [None]
    if MODE == "list":
        return list(WORKSPACES)
    if MODE == "all":
        all_ws = fabric.list_workspaces()
        if "Type" in all_ws.columns:
            all_ws = all_ws[all_ws["Type"] == "Workspace"]
        name_col = "Name" if "Name" in all_ws.columns else "Workspace Name"
        return all_ws[name_col].tolist()
    raise ValueError(f"Unknown MODE '{MODE}'.")


formats = pd.concat(
    [list_report_formats(ws) for ws in _targets_from_config()],
    ignore_index=True,
)

if formats.empty:
    print("No Power BI reports found.")
else:
    counts = formats["Format"].value_counts().to_dict()
    print("Report format summary — " + ", ".join(f"{k}: {v}" for k, v in counts.items()))
    display(formats)

# Tip: to convert all PBIRLegacy reports automatically, run:
#   import sempy_labs as labs
#   labs.report.upgrade_to_pbir(workspace="Demo")
## 5. Run the inventory

Resolves the workspace list from `MODE` and runs the scan. The result is always stored in `df`.
def _resolve_workspace_list(mode: str, workspaces: list[str]) -&amp;gt; list[str | None]:
    """Translate MODE + WORKSPACES into the actual list of workspaces to scan."""
    if mode == "current":
        return [None]
    if mode == "list":
        if not workspaces:
            raise ValueError("MODE='list' requires at least one entry in WORKSPACES.")
        return list(workspaces)
    if mode == "all":
        all_ws = fabric.list_workspaces()
        if "Type" in all_ws.columns:
            all_ws = all_ws[all_ws["Type"] == "Workspace"]
        name_col = "Name" if "Name" in all_ws.columns else "Workspace Name"
        return all_ws[name_col].tolist()
    raise ValueError(f"Unknown MODE '{mode}'. Use 'current', 'list', or 'all'.")


targets = _resolve_workspace_list(MODE, WORKSPACES)
print(f"MODE='{MODE}' → scanning {len(targets)} workspace(s).\n")

df = list_custom_visuals_multi(targets)

if df.empty:
    print("\nNo custom visuals found.")
else:
    print(f"\nFound {len(df)} (report, custom visual) pairs across {df['Workspace'].nunique()} workspace(s) and {df['Report'].nunique()} report(s).")
    display(df)
## 6. Quick aggregations

A few common slices the governance team typically wants right after the raw list.
if not df.empty:
    # Most-used custom visuals
    top_visuals = (
        df.groupby("Custom Visual Display Name")
          .agg(Reports=("Report", "nunique"), Workspaces=("Workspace", "nunique"))
          .sort_values("Reports", ascending=False)
          .reset_index()
    )
    display(top_visuals)

    # Reports with the most custom visuals
    heavy_reports = (
        df.groupby(["Workspace", "Report"])
          .agg(CustomVisuals=("Custom Visual Display Name", "nunique"))
          .sort_values("CustomVisuals", ascending=False)
          .reset_index()
    )
    display(heavy_reports)
else:
    print("No data to aggregate — result set is empty.")
---

## Notes &amp;amp; limitations

### Reports must be stored in PBIR format

This notebook reads each report's enhanced report definition (PBIR / `definition.pbir`) via the Fabric REST API. Reports still stored in the legacy single-file PBIX layout cannot be parsed by `ReportWrapper` — they are flagged as `Legacy (PBIX)` in section 4 and **skipped with a `NotImplementedError`** in section 5.

**Two ways to convert a report to PBIR:**

- **Power BI Service (Edit in browser)** — open the report in the service, click **Edit**, make any tiny change (or none), and **Save**. The service automatically rewrites the report to PBIR on save. Often the fastest option for bulk conversion.
- **Power BI Desktop** — open the report, enable **File → Options → Preview features → "Power BI Project (.pbip) save format"** and **"Store reports using enhanced report format (PBIR)"**, then republish.

PBIR is the default for any report authored natively in Fabric.

### Other notes

- Only **Power BI reports** are inspected — paginated reports are skipped automatically.
- Detection relies on visuals registered in the report's `definition.pbir`. A visual that is registered but not placed on a page can still appear; the `Used in Report` flag from semantic-link-labs is honoured when present.
- Requires the executing identity to have at least **Viewer** role on every workspace it scans.
- semantic-link-labs is an open-source community project maintained by Microsoft engineers — column names may evolve between releases. Pin a version in your custom Fabric environment for production use.

## License

MIT — feel free to adapt and reuse.&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;SPAN class="msgUrl hidden"&gt;https%3A%2F%2Fgithub.com%2FKornAlexander%2FPBI-Tools%2Fblob%2Fmain%2FNotebook%2520Gallery%2FCustom%2520Visuals%2520Inventory.ipynb&lt;/SPAN&gt;&lt;/P&gt;</description>
      <pubDate>Fri, 15 May 2026 08:16:29 GMT</pubDate>
      <guid>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Get-a-list-of-Custom-Visuals/m-p/5183373#M191</guid>
      <dc:creator>AlexanderKornMS</dc:creator>
      <dc:date>2026-05-15T08:16:29Z</dc:date>
    </item>
    <item>
      <title>Usage Metrics Snapshot — Unlimited Power BI Usage History</title>
      <link>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Usage-Metrics-Snapshot-Unlimited-Power-BI-Usage-History/m-p/5181590#M190</link>
      <description>&lt;P&gt;Snapshot the hidden&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;Report Usage Metrics Model&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;semantic model into Lakehouse Delta tables via XMLA /&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;sempy.evaluate_dax. Six append-only tables (Views,&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;Reports,&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;Users,&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;Dates,&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;DistributionMethods,&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;Platforms), one&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;SnapshotUtc&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;column for deduplication, optional retention. Schedule daily after 04:00 UTC and you've broken Power BI's 30-day usage history wall — forever.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Requires:&lt;/STRONG&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;Premium / PPU / Fabric capacity, attached Lakehouse, tenant setting "Usage metrics for content creators" enabled.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="markup"&gt;# Usage Metrics Snapshot

Snapshot the hidden **Report Usage Metrics Model** semantic model into Lakehouse Delta tables for **unlimited history**.

## Why
Power BI's built-in usage metrics dataset only retains **30 days** of activity (rolling window). By querying it daily over XMLA via `sempy` and appending the rows to Lakehouse tables, we accumulate full history we control.

## Prerequisites
- Workspace on Premium / PPU / Fabric capacity (XMLA endpoint enabled).
- The `Report Usage Metrics Model` dataset exists in the workspace. It is auto-created the first time anyone clicks *More options → View usage metrics report* on a report.
- A Lakehouse attached to this notebook (any Lakehouse in the workspace).
- Tenant setting *“Usage metrics for content creators”* enabled.

## How to operate
1. Set `WORKSPACE_ID` below.
2. Run all cells once to verify.
3. Schedule the notebook **daily after 04:00 UTC** (the source refreshes around 03:00 UTC).

## What lands in the Lakehouse
One Delta table per source table, prefixed `usage_metrics_*`, with an extra `SnapshotUtc` column. Append-only.

| Source table         | Lakehouse table                       | Role          |
|----------------------|---------------------------------------|---------------|
| `Views`              | `usage_metrics_views`                 | Fact          |
| `Reports`            | `usage_metrics_reports`               | Dimension     |
| `Users`              | `usage_metrics_users`                 | Dimension     |
| `Dates`              | `usage_metrics_dates`                 | Dimension     |
| `DistributionMethods`| `usage_metrics_distributionmethods`   | Dimension     |
| `Platforms`          | `usage_metrics_platforms`             | Dimension     |
## 1. Configuration
import sempy.fabric as fabric
from datetime import datetime, timezone, timedelta

# ---- EDIT ME --------------------------------------------------------------
WORKSPACE_ID = "&amp;lt;your-workspace-guid&amp;gt;"   # e.g., da2e15a8-c06d-4da0-ad10-c68aba63e564
DATASET_NAME = "Report Usage Metrics Model"

TABLES = [
    "Views",                # fact
    "Reports",              # dimensions
    "Users",
    "Dates",
    "DistributionMethods",
    "Platforms",
]

# How many days of snapshots to keep (set to None to keep forever)
RETENTION_DAYS = 400
# ---------------------------------------------------------------------------

snap_ts = datetime.now(timezone.utc)
print(f"Snapshot timestamp: {snap_ts.isoformat()}")
## 2. Snapshot all tables

Each table is pulled with `EVALUATE 'TableName'` (full table scan). Column names are cleaned up (DAX returns them as `'Table'[Column]`). The result is appended to the corresponding Lakehouse Delta table with `mergeSchema=true` so new columns added by Microsoft over time are tolerated.
results = []

for t in TABLES:
    df = fabric.evaluate_dax(
        dataset=DATASET_NAME,
        workspace=WORKSPACE_ID,
        dax_string=f"EVALUATE '{t}'",
    )

    # Strip table name prefix from column names (DAX returns "TableName[Column]")
    df.columns = [c.split("[")[-1].rstrip("]") if "[" in c else c for c in df.columns]
    df["SnapshotUtc"] = snap_ts.isoformat()

    table_name = f"usage_metrics_{t.lower()}"
    sdf = spark.createDataFrame(df)
    (sdf.write
        .mode("append")
        .option("mergeSchema", "true")
        .saveAsTable(table_name))

    results.append((t, table_name, len(df)))
    print(f"  {t:25s} -&amp;gt; {table_name:40s} {len(df):&amp;gt;8} rows")

print("\nDone.")
## 3. Retention (optional)

Trim snapshots older than `RETENTION_DAYS` so the tables don't grow forever. Default 400 days ≈ 13 months — enough for YoY comparisons.
if RETENTION_DAYS:
    cutoff = (snap_ts - timedelta(days=RETENTION_DAYS)).isoformat()
    for _, table_name, _ in results:
        spark.sql(f"DELETE FROM {table_name} WHERE SnapshotUtc &amp;lt; '{cutoff}'")
        print(f"  Trimmed {table_name} (&amp;lt; {cutoff})")
else:
    print("Retention disabled — keeping all snapshots.")
---
# Verification &amp;amp; query examples

The cells below are **not part of the daily job** — use them to verify the snapshot worked and to demo how to query the historical data.
## 4. Snapshot health check
for _, table_name, _ in results:
    df = spark.sql(f"""
        SELECT '{table_name}'                  AS table_name,
               COUNT(*)                        AS total_rows,
               COUNT(DISTINCT SnapshotUtc)     AS snapshot_count,
               MIN(SnapshotUtc)                AS first_snapshot,
               MAX(SnapshotUtc)                AS latest_snapshot
        FROM {table_name}
    """)
    df.show(truncate=False)
## 5. Peek at the latest snapshot of `Views`
display(spark.sql("""
    WITH latest AS (
        SELECT MAX(SnapshotUtc) AS ts FROM usage_metrics_views
    )
    SELECT v.*
    FROM usage_metrics_views v
    JOIN latest ON v.SnapshotUtc = latest.ts
    LIMIT 20
"""))
## 6. Daily views per report (full history)

De-duplication pattern: take the **latest snapshot per natural key** so overlapping 30-day windows don't double-count. Adjust the `PARTITION BY` columns to whatever the real key columns are in your `Views` table (inspect with the previous cell).
display(spark.sql("""
    WITH ranked AS (
        SELECT v.*,
               ROW_NUMBER() OVER (
                   PARTITION BY Date, ReportGuid, UserGuid
                   ORDER BY SnapshotUtc DESC
               ) AS rn
        FROM usage_metrics_views v
    )
    SELECT Date,
           ReportGuid,
           COUNT(*)                  AS views,
           COUNT(DISTINCT UserGuid)  AS distinct_users
    FROM ranked
    WHERE rn = 1
    GROUP BY Date, ReportGuid
    ORDER BY Date DESC, views DESC
"""))
## 7. Top reports last 30 days (joined to `Reports` dim)
display(spark.sql("""
    WITH ranked_views AS (
        SELECT v.*,
               ROW_NUMBER() OVER (
                   PARTITION BY Date, ReportGuid, UserGuid
                   ORDER BY SnapshotUtc DESC
               ) AS rn
        FROM usage_metrics_views v
    ),
    latest_reports AS (
        SELECT r.*,
               ROW_NUMBER() OVER (
                   PARTITION BY ReportGuid
                   ORDER BY SnapshotUtc DESC
               ) AS rn
        FROM usage_metrics_reports r
    )
    SELECT r.DisplayName,
           COUNT(*)                  AS views,
           COUNT(DISTINCT v.UserGuid) AS distinct_users
    FROM ranked_views v
    LEFT JOIN latest_reports r
      ON r.ReportGuid = v.ReportGuid AND r.rn = 1
    WHERE v.rn = 1
      AND v.Date &amp;gt;= date_sub(current_date(), 30)
    GROUP BY r.DisplayName
    ORDER BY views DESC
"""))&lt;/LI-CODE&gt;&lt;P&gt;&lt;SPAN class="msgUrl hidden"&gt;https%3A%2F%2Fgithub.com%2FKornAlexander%2FPBI-Tools%2Fblob%2Fmain%2FNotebook%2520Gallery%2FUsage%2520Metrics%2520Snapshot.ipynb&lt;/SPAN&gt;&lt;/P&gt;</description>
      <pubDate>Tue, 12 May 2026 14:50:25 GMT</pubDate>
      <guid>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Usage-Metrics-Snapshot-Unlimited-Power-BI-Usage-History/m-p/5181590#M190</guid>
      <dc:creator>AlexanderKornMS</dc:creator>
      <dc:date>2026-05-12T14:50:25Z</dc:date>
    </item>
    <item>
      <title>Semantic Link - Semantic Model Chaos Lab</title>
      <link>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Semantic-Link-Semantic-Model-Chaos-Lab/m-p/5159032#M189</link>
      <description>&lt;P&gt;# Semantic Link - Semantic Model Chaos Lab&lt;/P&gt;&lt;P&gt;Semantic Model Chaos Lab brings chaos engineering to Fabric semantic models. It uses Semantic Link to create a lightweight digital twin of a selected semantic model: metadata, measures, relationships, roles, Copilot readiness signals, and baseline DAX checks.&lt;/P&gt;&lt;P&gt;The notebook then simulates realistic schema, relationship, DAX, metadata, and security changes against that model twin to measure blast radius before deployment. The generated release gate report shows broken measures, value drift, impacted model objects, security role risk, Copilot readiness degradation, and suggested remediation.&lt;/P&gt;&lt;P&gt;The result is a reusable developer tool that helps BI teams prevent semantic model incidents before they reach production.&lt;/P&gt;&lt;P&gt;Note: I realize the official submission deadline has passed, but I wanted to share this as a late community showcase because the idea explores a different angle for Semantic Link: model twins, chaos engineering, and release gates for semantic models.&lt;/P&gt;&lt;P&gt;&lt;SPAN class="msgUrl hidden"&gt;https%3A%2F%2Fgithub.com%2Fflthibau%2Fsemantic-model-chaos-lab%2Fblob%2Fmain%2F2026_SemanticLink_flthibau_SemanticModelChaosLab.ipynb&lt;/SPAN&gt;&lt;/P&gt;</description>
      <pubDate>Mon, 27 Apr 2026 08:02:52 GMT</pubDate>
      <guid>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Semantic-Link-Semantic-Model-Chaos-Lab/m-p/5159032#M189</guid>
      <dc:creator>FLTHIBAU</dc:creator>
      <dc:date>2026-04-27T08:02:52Z</dc:date>
    </item>
    <item>
      <title>Semantic Model Version Control &amp; Change Diff</title>
      <link>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Semantic-Model-Version-Control-amp-Change-Diff/m-p/5154890#M187</link>
      <description>&lt;P&gt;Power BI's built-in version history is UI-only — capped at 5 snapshots,14-day retention, and zero API access. Enterprise teams have no programmatic&amp;nbsp;way to list, compare, or audit model changes.This notebook bridges that gap using Semantic Link (SemPy) and Microsoft&amp;nbsp;Fabric. It captures point-in-time snapshots of all five semantic model&amp;nbsp;artifact types — Measures, Columns, Relationships, Tables, and RLS Roles — and persists them as Delta tables in OneLake via Apache Spark. A field-level &lt;BR /&gt;diff engine then compares any two run IDs and classifies every change as&amp;nbsp;ADDED, REMOVED, or MODIFIED with before/after values.&lt;/P&gt;
&lt;P&gt;Key capabilities:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Dual-path extraction: fabric.list_*() API with automatic DMV fallback.&lt;/LI&gt;
&lt;LI&gt;Unlimited history beyond the built-in 5-version / 14-day limit.&lt;/LI&gt;
&lt;LI&gt;Field-level diff across all artifact types including DAX expressions.&lt;/LI&gt;
&lt;LI&gt;RLS role and membership change detection for security auditing.&lt;/LI&gt;
&lt;LI&gt;Interactive ipywidgets UI with Fabric-branded HTML output.&lt;/LI&gt;
&lt;LI&gt;Delta append mode — queryable directly from Power BI reports.&lt;/LI&gt;
&lt;LI&gt;Schedulable via Fabric Data Pipeline for automated daily governance&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;Built entirely within Microsoft Fabric using sempy.fabric, sempy_labs, &lt;BR /&gt;PySpark, Delta Lake, and ipywidgets. No external tools or services required.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Github-&lt;A href="https://github.com/praful-potphode/Fabric-Semantic-Link-Competition-2026" target="_self"&gt;https://github.com/praful-potphode/Fabric-Semantic-Link-Competition-2026&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;LinkedIn-&lt;A href="https://www.linkedin.com/in/praful-p-912349241/" target="_self"&gt;https://www.linkedin.com/in/praful-p-912349241/&lt;/A&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Community Profile-&lt;A href="https://community.fabric.microsoft.com/t5/user/viewprofilepage/user-id/1261729" target="_self"&gt;https://community.fabric.microsoft.com/t5/user/viewprofilepage/user-id/1261729&lt;/A&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN class="msgUrl hidden"&gt;https%3A%2F%2Fgithub.com%2Fpraful-potphode%2FFabric-Semantic-Link-Competition-2026&lt;/SPAN&gt;&lt;/P&gt;</description>
      <pubDate>Mon, 20 Apr 2026 17:44:35 GMT</pubDate>
      <guid>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Semantic-Model-Version-Control-amp-Change-Diff/m-p/5154890#M187</guid>
      <dc:creator>Praful_Potphode</dc:creator>
      <dc:date>2026-04-20T17:44:35Z</dc:date>
    </item>
    <item>
      <title>Semantic Link – MetaData Extractor</title>
      <link>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Semantic-Link-MetaData-Extractor/m-p/5154861#M186</link>
      <description>&lt;P&gt;&lt;span class="lia-unicode-emoji" title=":blue_book:"&gt;📘&lt;/span&gt; Notebook Description&lt;/P&gt;
&lt;P&gt;The notebook is designed to extract, enrich, and visualize semantic model metadata and measure-level dependencies within Microsoft Fabric. It connects to a specified semantic model, retrieves tables, columns, measures, and relationships, and enhances measures with AI-generated business descriptions. The notebook then derives measure-to-measure dependencies from DAX expressions, builds a Directed Acyclic Graph (DAG), and presents both tabular lineage outputs and graph-based visualizations. This enables a deep understanding of how calculations are structured and interrelated within the semantic model.&lt;/P&gt;
&lt;P&gt;&lt;span class="lia-unicode-emoji" title=":glowing_star:"&gt;🌟&lt;/span&gt; Benefits&lt;/P&gt;
&lt;P&gt;Measure Lineage Transparency: Provides clear visibility into how measures are built on top of one another, improving model understanding and governance.&lt;/P&gt;
&lt;P&gt;AI-Powered Documentation: Automatically generates business-friendly descriptions for DAX measures, reducing manual documentation effort.&lt;/P&gt;
&lt;P&gt;Impact Analysis: Identifies upstream and downstream dependencies between measures, helping assess the impact of logic changes&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;GitHub URL :&amp;nbsp;&lt;A href="https://github.com/NandanHegde15/MSFTFabric-Notebook/blob/main/SemanticModel/Metadata%20Extraction/2026_SemanticLink_NandanHegde_MetadataExtractor.ipynb" target="_blank"&gt;https://github.com/NandanHegde15/MSFTFabric-Notebook/blob/main/SemanticModel/Metadata%20Extraction/2026_SemanticLink_NandanHegde_MetadataExtractor.ipynb&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN class="msgUrl hidden"&gt;https%3A%2F%2Fgithub.com%2FNandanHegde15%2FMSFTFabric-Notebook%2Fblob%2Fmain%2FSemanticModel%2FMetadata%2520Extraction%2F2026_SemanticLink_NandanHegde_MetadataExtractor.ipynb&lt;/SPAN&gt;&lt;/P&gt;</description>
      <pubDate>Mon, 20 Apr 2026 17:13:05 GMT</pubDate>
      <guid>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Semantic-Link-MetaData-Extractor/m-p/5154861#M186</guid>
      <dc:creator>NandanHegde</dc:creator>
      <dc:date>2026-04-20T17:13:05Z</dc:date>
    </item>
    <item>
      <title>Semantic Link – DAXLoadTest</title>
      <link>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Semantic-Link-DAXLoadTest/m-p/5154488#M185</link>
      <description>&lt;DIV&gt;
&lt;DIV&gt;&lt;SPAN&gt;Every semantic-model developer asks the same question before a deploy: "will this regress under real user load?" Today there's no answer, &amp;nbsp;Power BI teams either hand-write synthetic DAX or skip load-testing entirely.&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV&gt;&lt;SPAN&gt;DAXLoadTest replays the real DAX queries your users have been running against your semantic model, under configurable concurrency, and pinpoints which queries slow down — then tells you the exact Report → Page → Visualresponsible for each regression.&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV&gt;&lt;SPAN&gt;The tool combines three Fabric capabilities that have never been stitched together before:&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;SPAN&gt;Workspace Monitoring Eventhouse as the query corpus, the only source of historical DAX text in Fabric&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;SPAN&gt;sempy.fabric.evaluate_dax for parallel replay, with a novel DAX-VAR-literal tagging trick that survives XMLA normalization and gives a bulletproof join key between sent queries and trace logs&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;SPAN&gt;sempy_labs.report.ReportWrapper to auto-map VisualId GUIDs to human-readable report/page/visual names&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;SPAN&gt;Results land in an interactive Plotly dashboard (KPI tiles, regression bar chart, baseline-vs-load scatter, drill-down table) rendered inline. No Lakehouse, no Delta tables, no setup, set 4 parameters, run the notebook, read the dashboard. Drop it into a Data Factory pipeline to catch performance regressions before they reach users.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;BR /&gt;&lt;BR /&gt;
&lt;DIV&gt;&lt;SPAN&gt;External libraries used:&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;SPAN&gt;semantic-link-labs (sempy_labs) — Microsoft's extension library. Used for sempy_labs.report.ReportWrapper.list_visuals() to enrich queries with Report → Page → Visual metadata. Repo: github.com/microsoft/semantic-link-labs&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;SPAN&gt;plotly — interactive dashboard rendering (KPI indicators, bar chart, log-log scatter, drill-down table).&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;SPAN&gt;pandas / numpy — in-memory analytics and join orchestration (pre-installed).&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;SPAN&gt;PySpark + Azure Data Explorer Spark connector (com.microsoft.kusto.spark.synapse.datasource) — pre-installed on Fabric; used to query the Workspace Monitoring Eventhouse via KQL.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;BR /&gt;&lt;BR /&gt;Github Repo Link: &lt;A href="https://github.com/tharunkumarr98/semanticLinkChallenge2026" target="_self"&gt;Semantic Link - DAXLoadTest&lt;/A&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;/DIV&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN class="msgUrl hidden"&gt;https%3A%2F%2Fgithub.com%2Ftharunkumarr98%2FsemanticLinkChallenge2026%2Fblob%2Fmain%2F2026_SemanticLink_tharunkumarr98_DAXLoadTest.ipynb&lt;/SPAN&gt;&lt;/P&gt;</description>
      <pubDate>Mon, 20 Apr 2026 12:21:47 GMT</pubDate>
      <guid>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Semantic-Link-DAXLoadTest/m-p/5154488#M185</guid>
      <dc:creator>tharunkumarRTK</dc:creator>
      <dc:date>2026-04-20T12:21:47Z</dc:date>
    </item>
    <item>
      <title>Semantic Link – Moodle LMS Analytics &amp; Model Governance Toolkit</title>
      <link>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Semantic-Link-Moodle-LMS-Analytics-amp-Model-Governance-Toolkit/m-p/5153722#M184</link>
      <description>&lt;P&gt;This notebook delivers a reusable Moodle LMS analytics and governance toolkit built entirely in Microsoft Fabric using Semantic Link Labs. It connects a real Moodle MySQL database through a Bronze-Silver Medallion Architecture, creates a Direct Lake semantic model with 31 measures across 8 folders, and uses sempy_labs for BPA, Vertipaq analysis,&amp;nbsp; Hindi translation, and automated model refresh. Unique developer tools include DAX unit testing, DAX vs Silver data validation, model snapshot &amp;amp; diff, and custom Moodle-specific BPA rules.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Link to GitHub URL- &lt;A href="https://github.com/cseprs/MoodleLMSToolkit/tree/main" target="_blank" rel="noopener"&gt;MoodleLMSToolkit&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN class="msgUrl hidden"&gt;https%3A%2F%2Fgithub.com%2Fcseprs%2FMoodleLMSToolkit&lt;/SPAN&gt;&lt;/P&gt;</description>
      <pubDate>Sun, 19 Apr 2026 17:27:47 GMT</pubDate>
      <guid>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Semantic-Link-Moodle-LMS-Analytics-amp-Model-Governance-Toolkit/m-p/5153722#M184</guid>
      <dc:creator>techies</dc:creator>
      <dc:date>2026-04-19T17:27:47Z</dc:date>
    </item>
    <item>
      <title>Semantic Link - Model Health &amp; Security Suite</title>
      <link>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Semantic-Link-Model-Health-amp-Security-Suite/m-p/5153426#M183</link>
      <description>&lt;P&gt;One notebook. 13 tools. Zero guesswork.&lt;/P&gt;&lt;P&gt;A comprehensive &lt;STRONG&gt;diagnostic, remediation, and security auditing toolkit&lt;/STRONG&gt; for Microsoft Fabric semantic models — delivered as a single self-contained Fabric notebook with an interactive ipywidgets console. Scans any Import / Direct Lake / DirectQuery model, produces a full HTML dashboard with scores and findings, and auto-applies fixes via TOM writes.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Three features in this notebook solve problems that no existing Fabric or Power BI tool addresses end-to-end:&lt;/STRONG&gt;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;&lt;span class="lia-unicode-emoji" title=":locked:"&gt;🔒&lt;/span&gt; Security X-Ray — Effective Access Map&lt;/STRONG&gt;&lt;/P&gt;&lt;P&gt;Enterprise Power BI security is managed through &lt;EM&gt;Azure AD groups&lt;/EM&gt;, not individual users. An AD group assigned to an RLS role might contain 200 users, nested sub-groups, and service principals. Until now there was &lt;STRONG&gt;no tool, no REST API, no sempy function&lt;/STRONG&gt; that answered:&lt;/P&gt;&lt;BLOCKQUOTE&gt;&lt;EM&gt;"Given all the RLS filters, OLS restrictions, AD group memberships, and workspace roles — what does each real human actually see?"&lt;/EM&gt;&lt;/BLOCKQUOTE&gt;&lt;P&gt;Security X-Ray combines &lt;STRONG&gt;TOM + DAX INFO.ROLES() + Microsoft Graph /transitiveMembers + Fabric REST roleAssignments&lt;/STRONG&gt; into a single Effective Access Map that flags the critical blind spot: users who &lt;STRONG&gt;bypass RLS via workspace Admin/Member/Contributor privileges&lt;/STRONG&gt; — a silent risk the standard Power BI UI never surfaces.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;&lt;span class="lia-unicode-emoji" title=":robot_face:"&gt;🤖&lt;/span&gt; AI Generation — Schema-Aware Descriptions at Scale&lt;/STRONG&gt;&lt;/P&gt;&lt;P&gt;Writing meaningful descriptions, synonyms, and AI instructions across hundreds of tables, columns, and measures is impractical by hand. Generic AI prompts miss business context and produce bland, interchangeable text that weakens Copilot quality. Bringing rich schema context into AI generation from inside a Fabric notebook hasn't been possible — until now.&lt;/P&gt;&lt;BLOCKQUOTE&gt;&lt;EM&gt;"How do I make every measure, column, and table in my model Copilot-ready with descriptions, synonyms, and AI instructions that actually reflect my business — without writing them all by hand?"&lt;/EM&gt;&lt;/BLOCKQUOTE&gt;&lt;P&gt;AI Generation combines &lt;STRONG&gt;Azure OpenAI via Fabric Copilot auth&lt;/STRONG&gt; (no API key, no endpoint config — just synapse.ml.fabric.credentials.get_openai_httpx_sync_client()) with &lt;STRONG&gt;full schema context injection&lt;/STRONG&gt;: relationships, data types, DAX expressions, and user-supplied business domain. Every generated description is grounded in the actual model, not hallucinated. Reviewable plan before any TOM write, with graceful fallback to rule-based templates when AI is unavailable.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;&lt;span class="lia-unicode-emoji" title=":counterclockwise_arrows_button:"&gt;🔄&lt;/span&gt; Model Diff — Cross-Workspace Drift Detection&lt;/STRONG&gt;&lt;/P&gt;&lt;P&gt;Semantic models live across multiple workspaces — dev, test, UAT, prod, client A, client B. There is no built-in Fabric tool that compares two models to answer "what changed?" Drift happens silently: someone adds a measure in dev, tweaks a DAX formula in prod, removes a column during a refactor — and these changes go unnoticed until a report breaks.&lt;/P&gt;&lt;BLOCKQUOTE&gt;&lt;EM&gt;"What changed between my dev model and my prod model? Which tables, columns, or measures were added, removed, or modified — and are any DAX expressions different?"&lt;/EM&gt;&lt;/BLOCKQUOTE&gt;&lt;P&gt;Model Diff uses &lt;STRONG&gt;sempy TOM reads across two workspaces&lt;/STRONG&gt; + &lt;STRONG&gt;tabular schema comparison&lt;/STRONG&gt; + &lt;STRONG&gt;DAX expression normalization&lt;/STRONG&gt; to produce a structured drift report covering tables, columns, measures, relationships, and DAX changes. Essential for DataOps / release workflows and multi-tenant engagements where models live in many places.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;&lt;span class="lia-unicode-emoji" title=":direct_hit:"&gt;🎯&lt;/span&gt; 13 Tools In One Scan&lt;/STRONG&gt;&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;&lt;STRONG&gt;Copilot Readiness&lt;/STRONG&gt; — descriptions, synonyms, hidden keys, format strings, AI Prep&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Lineage&lt;/STRONG&gt; — measure → source, blast radius, unused columns, dead code&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Test Framework&lt;/STRONG&gt; — every DAX measure evaluated, relationships validated&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Model Diff&lt;/STRONG&gt; — compare across workspaces (dev vs prod drift)&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Report Visuals&lt;/STRONG&gt; — broken refs, unused measures (model-filtered)&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Security Audit&lt;/STRONG&gt; — role compliance, RLS/OLS coverage&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Security X-Ray&lt;/STRONG&gt; — effective access + workspace bypass detection&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Data Quality&lt;/STRONG&gt; — referential integrity, null-rate (batched DAX UNION, 10× faster)&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;DAX Dependencies&lt;/STRONG&gt; — fan-in/fan-out, circular references&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;sempy_labs integrations&lt;/STRONG&gt; — BPA, Vertipaq, Direct Lake, Capacity (opt-in)&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;&lt;span class="lia-unicode-emoji" title=":gear:"&gt;⚙️&lt;/span&gt; Auto-Fix 9 Categories Via TOM&lt;/STRONG&gt;&lt;/P&gt;&lt;P&gt;Preview all generated fixes in a reviewable plan, then apply selected ones: AI/template descriptions, synonyms (Culture ObjectTranslation), hidden keys, format strings, summarize-by, model CustomInstructions, AI instructions, schema reduction (isAvailableInMDX + LinguisticMetadata Entity Visibility), role descriptions.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;&lt;span class="lia-unicode-emoji" title=":building_construction:"&gt;🏗&lt;/span&gt;️ Technical Highlights&lt;/STRONG&gt;&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;&lt;STRONG&gt;Chunked HTML rendering&lt;/STRONG&gt; — overcomes Fabric's ~100 KB displayHTML limit&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;SPN Graph token via MSAL&lt;/STRONG&gt; — 0.3s vs 60s+ notebookutils.credentials hang&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Azure OpenAI via Fabric auth&lt;/STRONG&gt; — no API key needed&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;AAD group expansion&lt;/STRONG&gt; — recursive /transitiveMembers with pagination&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Scan log capture&lt;/STRONG&gt; — contextlib.redirect_stdout keeps the config form visible&lt;/LI&gt;&lt;LI&gt;&lt;STRONG&gt;Demo Mode&lt;/STRONG&gt; — sequential pseudonyms for safe public screenshots&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;&lt;span class="lia-unicode-emoji" title=":rocket:"&gt;🚀&lt;/span&gt; Quick Start&lt;/STRONG&gt;&lt;/P&gt;&lt;P&gt;Cell 1 (install) → Cell 2 (engine) → Cell 3 (console + Run Scan) → Cell 4 (scan log) → Cell 5 (dashboard) → Cell 6 (apply fixes).&lt;/P&gt;&lt;P&gt;Graceful degradation: works without SPN (skips Graph expansion), without Copilot (falls back to template descriptions), without Directory.Read.All (shows object GUIDs), and read-only mode if no write access.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;&lt;span class="lia-unicode-emoji" title=":package:"&gt;📦&lt;/span&gt; Complete Repo&lt;/STRONG&gt;&lt;/P&gt;&lt;P&gt;&lt;A href="https://github.com/NatarajanManivasagan/Fabric-Semantic-Link-Developer-Experience-Challenge-2026-Apr" target="_blank" rel="noopener"&gt;&lt;STRONG&gt;GitHub — full repo, 37 screenshots, sample HTML dashboard, MIT license&lt;/STRONG&gt;&lt;/A&gt;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Author:&lt;/STRONG&gt; Natarajan Manivasagan&lt;BR /&gt;&lt;A href="https://www.linkedin.com/in/natarajan-manivasagan" target="_blank" rel="noopener"&gt;LinkedIn&lt;/A&gt; · &lt;A href="https://community.fabric.microsoft.com/t5/user/viewprofilepage/user-id/1345926" target="_blank" rel="noopener"&gt;Fabric Community Profile&lt;/A&gt;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;SPAN class="msgUrl hidden"&gt;https%3A%2F%2Fgithub.com%2FNatarajanManivasagan%2FFabric-Semantic-Link-Developer-Experience-Challenge-2026-Apr%2Fblob%2Fmain%2F2026_SemanticLink_NatarajanManivasagan_ModelHealthAndSecuritySuite.ipynb&lt;/SPAN&gt;&lt;/P&gt;</description>
      <pubDate>Sun, 19 Apr 2026 17:51:14 GMT</pubDate>
      <guid>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Semantic-Link-Model-Health-amp-Security-Suite/m-p/5153426#M183</guid>
      <dc:creator>Natarajan_M</dc:creator>
      <dc:date>2026-04-19T17:51:14Z</dc:date>
    </item>
    <item>
      <title>Semantic Link: Playground</title>
      <link>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Semantic-Link-Playground/m-p/5152909#M181</link>
      <description>&lt;P&gt;&lt;STRONG&gt;The problem&lt;/STRONG&gt;&lt;/P&gt;&lt;P&gt;&lt;BR /&gt;Semantic model developers constantly face "what if?" questions: What if I change this measure's formula? How much would the number move? Which downstream KPIs would be affected? Is it safe to make this change?&lt;/P&gt;&lt;P&gt;Today the only option is to edit the live model, evaluate, and revert. That's risky in production, slow in development, and impossible to do side-by-side. There's no "preview" button for DAX.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;The solution&lt;/STRONG&gt;&lt;/P&gt;&lt;P&gt;&lt;BR /&gt;Playground gives you a safe sandbox for measure experimentation. It introduces four operations:&lt;/P&gt;&lt;P&gt;Explore&amp;nbsp;reads every measure from the TMSL , evaluates each one at total level, and presents a searchable catalog with DAX expressions and current values.&lt;/P&gt;&lt;P&gt;What-If.&amp;nbsp;evaluates both the original and your modified DAX side-by-side using&amp;nbsp;overrides in&amp;nbsp;. The live model definition is never touched. Supports optional dimensional breakdowns via&amp;nbsp;.&lt;/P&gt;&lt;P&gt;Impact&amp;nbsp;finds every downstream measure that references the one you changed (via regex-based DAX dependency parsing), re-evaluates each with your override injected, and reports the full cascade of value changes.&lt;/P&gt;&lt;P&gt;Compare evaluates multiple alternative formulas for the same measure in a single call, rendering a comparison table and chart.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Why this advances developer experience&lt;/STRONG&gt;&lt;/P&gt;&lt;P&gt;&lt;BR /&gt;Every other tool in the Semantic Link ecosystem is read-only — it inspects, validates, diffs, or documents the model as it is. Playground is the only tool that lets you safely change a measure and see what happens, without committing to the live model. It fills the gap between "I have an idea for a formula change" and "I'm confident enough to deploy it."&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;A href="https://github.com/ssritharsajitha/Semantic-Link-Playground" target="_blank"&gt;https://github.com/ssritharsajitha/Semantic-Link-Playground&lt;/A&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN class="msgUrl hidden"&gt;https%3A%2F%2Fgithub.com%2Fssritharsajitha%2FSemantic-Link-Playground&lt;/SPAN&gt;&lt;/P&gt;</description>
      <pubDate>Sat, 18 Apr 2026 03:46:04 GMT</pubDate>
      <guid>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Semantic-Link-Playground/m-p/5152909#M181</guid>
      <dc:creator>ssrithar</dc:creator>
      <dc:date>2026-04-18T03:46:04Z</dc:date>
    </item>
    <item>
      <title>Semantic Link – Semantic Radar</title>
      <link>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Semantic-Link-Semantic-Radar/m-p/5152831#M180</link>
      <description>&lt;P class=""&gt;This solution presents an automated governance framework for Microsoft Fabric semantic models that helps organizations detect duplication, reduce semantic model sprawl, and improve reuse across workspaces and capacities.&lt;/P&gt;&lt;P class=""&gt;&amp;nbsp;&lt;/P&gt;&lt;P class=""&gt;The notebook scans semantic models using either service principal or current-user access, analyzes datasource and metadata patterns, identifies duplicate or overlapping models, and turns the findings into actionable governance outputs for administrators and data owners.&lt;/P&gt;&lt;P class=""&gt;&amp;nbsp;&lt;/P&gt;&lt;P class=""&gt;&lt;STRONG&gt;Capabilities:&lt;/STRONG&gt;&lt;/P&gt;&lt;P class=""&gt;Semantic Model Discovery: Scans semantic models across Microsoft Fabric workspaces and capacities, with support for admin APIs, workspace-level access, and optional workspace targeting.&lt;/P&gt;&lt;P class=""&gt;Duplicate Source Detection: Identifies semantic models that connect to the same normalized datasource and highlights consolidation opportunities to promote shared semantic layers and reduce redundant logic.&lt;/P&gt;&lt;P class=""&gt;Probable Overlap Detection: Detects likely duplicate or overlapping semantic models by comparing entities, columns, and metadata, even when datasource metadata is incomplete.&lt;/P&gt;&lt;P class=""&gt;&lt;STRONG&gt;Actionable Governance Outputs:&lt;/STRONG&gt; Produces prioritized action plans, executive summaries, responsibility views, diagnostics, and compact visual tables that help teams focus on the most important governance decisions.&lt;/P&gt;&lt;P class=""&gt;Ownership and Collaboration Support: Maps impacted semantic models to dataset owners and workspace admins, and generates email drafts to accelerate review, coordination, and remediation.&lt;/P&gt;&lt;P class=""&gt;&lt;STRONG&gt;Noise Reduction and Flexibility:&lt;/STRONG&gt; Supports exclusions for intentional duplicates, sandbox models, and workspace-specific exceptions, while suppressing likely deployment clones to reduce false positives.&lt;/P&gt;&lt;P class=""&gt;Microsoft Fabric-Native Experience: Designed as a Fabric notebook solution with visual-first output, configurable execution modes, and optional SemPy enrichment for deeper semantic model metadata.&lt;/P&gt;&lt;P class=""&gt;&lt;STRONG&gt;Business value:&lt;/STRONG&gt;&lt;BR /&gt;This solution helps data teams improve governance, reduce duplication, strengthen semantic model reuse, and create a clearer path toward centralized, maintainable, and trusted analytics assets in Microsoft Fabric.&lt;/P&gt;&lt;P class=""&gt;&lt;STRONG&gt;All code and documentation can be found in the GitHub repository&lt;/STRONG&gt;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;SPAN class="msgUrl hidden"&gt;https%3A%2F%2Fgithub.com%2Fchristiantodte%2FSemanticRadar&lt;/SPAN&gt;&lt;/P&gt;</description>
      <pubDate>Fri, 17 Apr 2026 20:22:08 GMT</pubDate>
      <guid>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Semantic-Link-Semantic-Radar/m-p/5152831#M180</guid>
      <dc:creator>Christian_To</dc:creator>
      <dc:date>2026-04-17T20:22:08Z</dc:date>
    </item>
    <item>
      <title>Semantic Link - Semantic Radar</title>
      <link>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Semantic-Link-Semantic-Radar/m-p/5152829#M179</link>
      <description>&lt;P class=""&gt;This solution presents an automated governance framework for Microsoft Fabric semantic models that helps organizations detect duplication, reduce semantic model sprawl, and improve reuse across workspaces and capacities. The notebook scans semantic models using either service principal or current-user access, analyzes datasource and metadata patterns, identifies duplicate or overlapping models, and turns the findings into actionable governance outputs for administrators and data owners.&lt;/P&gt;&lt;P class=""&gt;Capabilities:&lt;/P&gt;&lt;P class=""&gt;Semantic Model Discovery: Scans semantic models across Microsoft Fabric workspaces and capacities, with support for admin APIs, workspace-level access, and optional workspace targeting.&lt;/P&gt;&lt;P class=""&gt;Duplicate Source Detection: Identifies semantic models that connect to the same normalized datasource and highlights consolidation opportunities to promote shared semantic layers and reduce redundant logic.&lt;/P&gt;&lt;P class=""&gt;Probable Overlap Detection: Detects likely duplicate or overlapping semantic models by comparing entities, columns, and metadata, even when datasource metadata is incomplete.&lt;/P&gt;&lt;P class=""&gt;Actionable Governance Outputs: Produces prioritized action plans, executive summaries, responsibility views, diagnostics, and compact visual tables that help teams focus on the most important governance decisions.&lt;/P&gt;&lt;P class=""&gt;Ownership and Collaboration Support: Maps impacted semantic models to dataset owners and workspace admins, and generates email drafts to accelerate review, coordination, and remediation.&lt;/P&gt;&lt;P class=""&gt;Noise Reduction and Flexibility: Supports exclusions for intentional duplicates, sandbox models, and workspace-specific exceptions, while suppressing likely deployment clones to reduce false positives.&lt;/P&gt;&lt;P class=""&gt;Microsoft Fabric-Native Experience: Designed as a Fabric notebook solution with visual-first output, configurable execution modes, and optional SemPy enrichment for deeper semantic model metadata.&lt;/P&gt;&lt;P class=""&gt;Business value:&lt;BR /&gt;This solution helps data teams improve governance, reduce duplication, strengthen semantic model reuse, and create a clearer path toward centralized, maintainable, and trusted analytics assets in Microsoft Fabric.&lt;/P&gt;&lt;P class=""&gt;All code and documentation can be found in the GitHub repository.&lt;/P&gt;&lt;P&gt;&lt;SPAN class="msgUrl hidden"&gt;https%3A%2F%2Fgithub.com%2Fchristiantodte%2FSemanticRadar&lt;/SPAN&gt;&lt;/P&gt;</description>
      <pubDate>Fri, 17 Apr 2026 20:15:02 GMT</pubDate>
      <guid>https://community.fabric.microsoft.com/t5/Notebook-Gallery/Semantic-Link-Semantic-Radar/m-p/5152829#M179</guid>
      <dc:creator>Christian_To</dc:creator>
      <dc:date>2026-04-17T20:15:02Z</dc:date>
    </item>
  </channel>
</rss>

