{"id":183,"date":"2025-09-16T00:00:00","date_gmt":"2025-09-16T00:00:00","guid":{"rendered":"https:\/\/blog.ivos.place\/?p=183"},"modified":"2025-09-16T06:18:47","modified_gmt":"2025-09-16T06:18:47","slug":"tmdl-case-1-3-rls-generator","status":"publish","type":"post","link":"https:\/\/blog.ivos.place\/?p=183","title":{"rendered":"TMDL demo 1\/3: RLS Generator"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Disclaimer<\/h2>\n\n\n\n<p>This blog post is part of a three-part series based on my speaker session at the European Microsoft Fabric Community Conference 2025 (FabCon) in Vienna, which I had the pleasure of delivering together with my colleague <strong><a href=\"https:\/\/www.linkedin.com\/in\/rogerunholz\/\">Roger Unholz<\/a><\/strong>.<br><br>Our session, titled <em>\u201cTMDL Playoffs\u201d<\/em>, was a fast-paced showdown where we shared our favorite tips and tricks for working with TMDL. In this series, I\u2019ll take a deeper dive into each topic we presented on stage and explore them in more detail.All source files referenced throughout the posts are available in my public GitHub repository. <br><br><strong>Please note, <\/strong>that the scripts are not tested for every scenario, that they are only created for demonstration purposes and should <strong>never be applied on any running, productive enviroments. <\/strong><br>Link: <a href=\"https:\/\/github.com\/ivsch\/TMDLPlayoffs?utm_source=chatgpt.com\">ivsch\/TMDLPlayoffs<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Idea<\/h2>\n\n\n\n<p>The configuration of Role Level Security (RLS) within Power BI semantic models can sometimes be straightforward, but at other times it can feel like opening Pandora\u2019s box. In most customer scenarios I encounter, the RLS setup is fairly basic. Nevertheless, managing RLS across a large number of semantic models can be a real challenge, especially when ensuring that the correct settings are applied consistently.<\/p>\n\n\n\n<p>To address this, I often maintain role definitions outside of the semantic model to provide a clear overview of all enabled RLS settings. That could be a Excel file as well as a small &#8220;security application&#8221;. This should then be the basic information for a simple script generator to quickly and reliably apply the defined roles to a Power BI semantic model file.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">TMDL RLS definition<\/h2>\n\n\n\n<p>To check existing RLS definitions in your Power BI semantic model, first enable the TMDL view in Power BI Desktop settings (currently available under <em>Preview features<\/em>).<br><br>On the right side of your semantic model, you\u2019ll find all the objects available in the TMDL scripting language. If you drag and drop the Roles object into the script window, you\u2019ll see the definition of the roles.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"540\" src=\"https:\/\/blog.ivos.place\/wp-content\/uploads\/2025\/09\/image-1-1024x540.png\" alt=\"\" class=\"wp-image-188\" srcset=\"https:\/\/blog.ivos.place\/wp-content\/uploads\/2025\/09\/image-1-1024x540.png 1024w, https:\/\/blog.ivos.place\/wp-content\/uploads\/2025\/09\/image-1-300x158.png 300w, https:\/\/blog.ivos.place\/wp-content\/uploads\/2025\/09\/image-1-768x405.png 768w, https:\/\/blog.ivos.place\/wp-content\/uploads\/2025\/09\/image-1.png 1366w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Outcome<\/h2>\n\n\n\n<p>Even if it\u2019s not a complete solution for handling complex RLS definitions, the most common\/basic scenarios can be covered with the Jupyter Notebook <strong><code>apply_rls<\/code><\/strong> in the GitHub source folder.<br><br>In the very first cell, you can provide all settings for the roles you want to apply. At the moment, the script only works with <strong>string<\/strong> values; it can be extended\/adjusted to support other data types.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#d8dee9ff;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>\nRLS_DEFINITION = [\n    {\n        \"role_name\":\"CustomerSegmentManagersEnterprise\",\n        \"table_name\":\"DimCustomer\",\n        \"rls_field_name\":\"Segment\",\n        \"allowed_values\":&#91;\"Consumer\", \"Enterprise\"&#93;\n    },\n    {\n        \"role_name\":\"CustomerSegmentManagersSMB\",\n        \"table_name\":\"DimCustomer\",\n        \"rls_field_name\":\"Segment\",\n        \"allowed_values\":&#91;\"SMB\"&#93;\n    }\n]<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki nord\" style=\"background-color: #2e3440ff\" tabindex=\"0\"><code><span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">RLS_DEFINITION <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">[<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #ECEFF4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">        <\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">role_name<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">CustomerSegmentManagersEnterprise<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">        <\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">table_name<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">DimCustomer<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">        <\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">rls_field_name<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">Segment<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">        <\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">allowed_values<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">:&#91;<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">Consumer<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">,<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">Enterprise<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #ECEFF4\">},<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #ECEFF4\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">        <\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">role_name<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">CustomerSegmentManagersSMB<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">        <\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">table_name<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">DimCustomer<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">        <\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">rls_field_name<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">Segment<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">        <\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">allowed_values<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">:&#91;<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">SMB<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #ECEFF4\">&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #ECEFF4\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ECEFF4\">]<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>This configuration generates a script for two roles\u2014<strong>CustomerSegmentManagersEnterprise<\/strong> and <strong>CustomerSegmentManagersSMB<\/strong>\u2014that filters the <strong><code>DimCustomer[Segment]<\/code><\/strong> column to the specified values.<br><br>With those settings, the following output is provided and can be taken over to existing semantic model files.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#d8dee9ff;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>Generated createOrReplace TMDL script:\n\ncreateOrReplace\n\n\trole CustomerSegmentManagersEnterprise\n\t\tmodelPermission: read\n\n\t\ttablePermission DimCustomer = &#91;Segment&#93; == \"Consumer\" || &#91;Segment&#93; == \"Enterprise\"\n\n\n\trole CustomerSegmentManagersSMB\n\t\tmodelPermission: read\n\n\t\ttablePermission DimCustomer = &#91;Segment&#93; == \"SMB\"<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki nord\" style=\"background-color: #2e3440ff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D8DEE9FF\">Generated createOrReplace TMDL script:<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">createOrReplace<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">\trole CustomerSegmentManagersEnterprise<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">\t\tmodelPermission: read<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">\t\ttablePermission DimCustomer <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">&#91;<\/span><span style=\"color: #D8DEE9FF\">Segment<\/span><span style=\"color: #ECEFF4\">&#93;<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">==<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">Consumer<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #D8DEE9FF\"> || <\/span><span style=\"color: #ECEFF4\">&#91;<\/span><span style=\"color: #D8DEE9FF\">Segment<\/span><span style=\"color: #ECEFF4\">&#93;<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">==<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">Enterprise<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">\trole CustomerSegmentManagersSMB<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">\t\tmodelPermission: read<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">\t\ttablePermission DimCustomer <\/span><span style=\"color: #81A1C1\">=<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">&#91;<\/span><span style=\"color: #D8DEE9FF\">Segment<\/span><span style=\"color: #ECEFF4\">&#93;<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">==<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">SMB<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Extendability<\/h2>\n\n\n\n<p>With further extensions, this functionality could be applied to an application that centrally defines roles and their respective security settings. This would simplify the management of RLS settings across multiple semantic models. In a pro version, you could even imagine downloading the Power BI semantic model, editing the TMDL role definitions, and re-uploading it via the Fabric REST API.<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Disclaimer This blog post is part of a three-part series based on my speaker session at the European Microsoft Fabric Community Conference 2025 (FabCon) in Vienna, which I had the pleasure of delivering together with my colleague Roger Unholz. Our session, titled \u201cTMDL Playoffs\u201d, was a fast-paced showdown where we shared our favorite tips and [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[13,9],"tags":[22,20],"class_list":["post-183","post","type-post","status-publish","format-standard","hentry","category-fabric","category-powerbi","tag-fabconeurope","tag-tmdl"],"_links":{"self":[{"href":"https:\/\/blog.ivos.place\/index.php?rest_route=\/wp\/v2\/posts\/183","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.ivos.place\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.ivos.place\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.ivos.place\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.ivos.place\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=183"}],"version-history":[{"count":7,"href":"https:\/\/blog.ivos.place\/index.php?rest_route=\/wp\/v2\/posts\/183\/revisions"}],"predecessor-version":[{"id":206,"href":"https:\/\/blog.ivos.place\/index.php?rest_route=\/wp\/v2\/posts\/183\/revisions\/206"}],"wp:attachment":[{"href":"https:\/\/blog.ivos.place\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=183"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.ivos.place\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=183"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.ivos.place\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=183"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}