├── Analysis Services ├── README.md ├── SSAS_ModelSize.ps1 └── SSAS_ModelSize_CSV.ps1 ├── Fabric ├── BPA Report.pbit ├── BPA_Monitoring.ipynb ├── Copilot Adoption.pbit ├── Data Chouette - P to F.ipynb ├── DateDimensionTable.ipynb ├── ExportFabricTenantSetting.py ├── TenantSettingsReport.pbit └── TenantSettingsReport.pbix ├── LICENSE.txt ├── PBIRS-SSRS └── ScheduleReport_History.sql ├── PBI_BPA_Workspace ├── PBI_BPA_Workspace.pbit └── PBI_BPA_Workspace.ps1 ├── Power BI ├── Export-PbiLicenses.ps1 ├── Export-PbiRefreshHistory.ps1 ├── PBIRS_ModelSize.sql ├── Query PBI Dataset in Scale-Out.ps1 ├── README.md └── Update-AdminUserWorkspaces.ps1 ├── README.md └── SQL └── README.md /Analysis Services/README.md: -------------------------------------------------------------------------------- 1 | SSAS & Azure Analysis Services Scripts -------------------------------------------------------------------------------- /Analysis Services/SSAS_ModelSize.ps1: -------------------------------------------------------------------------------- 1 | # Romain Casteres - Analyzing PBIRS Tabular Model Size 2 | # AMO Required (SSAS Feature Pack) 3 | # SSAS Instance for PBIRS : "localhost:5132" 4 | 5 | Param($ServerName="localhost:5132") 6 | 7 | $loadInfo = [Reflection.Assembly]::LoadWithPartialName("Microsoft.AnalysisServices") 8 | 9 | $server = New-Object Microsoft.AnalysisServices.Server 10 | $server.connect($ServerName) 11 | 12 | if ($server.name -eq $null) { 13 | Write-Output (“Server ‘{0}’ not found” -f $ServerName) 14 | break 15 | } 16 | 17 | $sum=0 18 | foreach ($d in $server.Databases ){ 19 | Write-Output ( "Database: {0}; Status: {1}; Size: {2}MB" -f $d.Name, $d.State, ($d.EstimatedSize/1024/1024).ToString("#,##0") ) 20 | $sum=$sum+$d.EstimatedSize/1024/1024 21 | } 22 | 23 | $SizeGB=$Sum/1024 24 | 25 | write-host 'Sum of Database = '$sum ' MB' 26 | Write-host 'Total Size of Cube Databases =' $SizeGB ' GB' -------------------------------------------------------------------------------- /Analysis Services/SSAS_ModelSize_CSV.ps1: -------------------------------------------------------------------------------- 1 | # Romain Casteres - Analyzing PBIRS Tabular Model Size 2 | # AMO Required (SSAS Feature Pack) 3 | # SSAS Instance for PBIRS : "localhost:5132" 4 | # Export to CSV 5 | 6 | Param($ServerName="localhost:5132") 7 | $loadInfo = [Reflection.Assembly]::LoadWithPartialName("Microsoft.AnalysisServices") 8 | 9 | $outputfile = "C:\temp\PBIRS_ModelSize.csv" 10 | if (Test-Path $outputfile) { 11 | Remove-Item $outputfile 12 | } 13 | 14 | $server = New-Object Microsoft.AnalysisServices.Server 15 | $server.connect($ServerName) 16 | if ($server.name -eq $null) { 17 | Write-Output (“Server ‘{0}’ not found” -f $ServerName) 18 | break 19 | } 20 | 21 | $sum=0 22 | foreach ($d in $server.Databases ){ 23 | New-Object PSObject -Property @{ 24 | Name = $d.Name; 25 | ItemID = $d.Name.SubString(0,36); # Mapping to the ItemID column from Catalog table 26 | SizeMB = [math]::Round($d.EstimatedSize/1024/1024,2); 27 | } | export-csv -Path $outputfile -NoTypeInformation -Append 28 | } 29 | -------------------------------------------------------------------------------- /Fabric/BPA Report.pbit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pulsweb/MyScripts/925ba1a04b367f6c52190868a6eb068a7775a572/Fabric/BPA Report.pbit -------------------------------------------------------------------------------- /Fabric/BPA_Monitoring.ipynb: -------------------------------------------------------------------------------- 1 | {"cells":[{"cell_type":"markdown","source":["### Monitoring Best Practice Analyzer\n","By Romain Casteres\n"," \n","Blog Article : \n","- EN : https://www.linkedin.com/pulse/monitoring-power-bi-semantics-models-over-time-romain-casteres-ypzae/?trackingId=ebwAVRzuRQuVL3QPOR8Xow%3D%3D\n","- FR : https://pulsweb.fr/qualite-modeles-semantiques-powerbi/"],"metadata":{"nteract":{"transient":{"deleting":false}}},"id":"5c27dfd1-4fe0-4a97-92e6-ddf78889aa93"},{"cell_type":"code","source":["#%pip install semantic-link-labs"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":9,"statement_ids":[5,6,7,8,9],"livy_statement_state":"available","session_id":"34ef5cfa-682e-46d6-8c31-e2e385f7d953","state":"finished","normalized_state":"finished","queued_time":"2024-07-31T07:01:23.9989802Z","session_start_time":"2024-07-31T07:01:24.2209984Z","execution_start_time":"2024-07-31T07:04:47.9293871Z","execution_finish_time":"2024-07-31T07:05:10.849169Z","parent_msg_id":"ce966fac-25bf-4566-abdc-eb38a96697db"},"text/plain":"StatementMeta(, 34ef5cfa-682e-46d6-8c31-e2e385f7d953, 9, Finished, Available, Finished)"},"metadata":{}},{"output_type":"stream","name":"stdout","text":["Requirement already satisfied: semantic-link-labs in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (0.6.0)\nCollecting semantic-link-sempy>=0.7.6 (from semantic-link-labs)\n Downloading semantic_link_sempy-0.7.7-py3-none-any.whl (3.0 MB)\n\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m3.0/3.0 MB\u001b[0m \u001b[31m25.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0ma \u001b[36m0:00:01\u001b[0m\n\u001b[?25hRequirement already satisfied: anytree in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from semantic-link-labs) (2.12.1)\nRequirement already satisfied: powerbiclient in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from semantic-link-labs) (3.1.1)\nRequirement already satisfied: clr-loader>=0.2.5 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from semantic-link-sempy>=0.7.6->semantic-link-labs) (0.2.6)\nRequirement already satisfied: graphviz>=0.20.1 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from semantic-link-sempy>=0.7.6->semantic-link-labs) (0.20.1)\nRequirement already satisfied: pyarrow>=12.0.1 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from semantic-link-sempy>=0.7.6->semantic-link-labs) (12.0.1)\nRequirement already satisfied: pythonnet>=3.0.1 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from semantic-link-sempy>=0.7.6->semantic-link-labs) (3.0.1)\nRequirement already satisfied: scikit-learn>=1.2.2 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from semantic-link-sempy>=0.7.6->semantic-link-labs) (1.3.0)\nRequirement already satisfied: setuptools>=68.2.2 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from semantic-link-sempy>=0.7.6->semantic-link-labs) (68.2.2)\nRequirement already satisfied: tqdm>=4.65.0 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from semantic-link-sempy>=0.7.6->semantic-link-labs) (4.66.1)\nRequirement already satisfied: six in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from anytree->semantic-link-labs) (1.16.0)\nRequirement already satisfied: ipywidgets>=7.0.0 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from powerbiclient->semantic-link-labs) (8.0.7)\nRequirement already satisfied: jupyter-ui-poll>=0.1.2 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from powerbiclient->semantic-link-labs) (0.2.2)\nRequirement already satisfied: msal>=1.8.0 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from powerbiclient->semantic-link-labs) (1.24.1)\nRequirement already satisfied: requests>=2.25.1 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from powerbiclient->semantic-link-labs) (2.31.0)\nRequirement already satisfied: pandas in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from powerbiclient->semantic-link-labs) (2.0.3)\nRequirement already satisfied: pyspark in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from powerbiclient->semantic-link-labs) (3.4.1.5.3.20230713)\nRequirement already satisfied: cffi>=1.13 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from clr-loader>=0.2.5->semantic-link-sempy>=0.7.6->semantic-link-labs) (1.16.0)\nRequirement already satisfied: ipykernel>=4.5.1 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from ipywidgets>=7.0.0->powerbiclient->semantic-link-labs) (6.26.0)\nRequirement already satisfied: ipython>=6.1.0 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from ipywidgets>=7.0.0->powerbiclient->semantic-link-labs) (8.14.0)\nRequirement already satisfied: traitlets>=4.3.1 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from ipywidgets>=7.0.0->powerbiclient->semantic-link-labs) (5.12.0)\nRequirement already satisfied: widgetsnbextension~=4.0.7 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from ipywidgets>=7.0.0->powerbiclient->semantic-link-labs) (4.0.9)\nRequirement already satisfied: jupyterlab-widgets~=3.0.7 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from ipywidgets>=7.0.0->powerbiclient->semantic-link-labs) (3.0.9)\nRequirement already satisfied: PyJWT[crypto]<3,>=1.0.0 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from msal>=1.8.0->powerbiclient->semantic-link-labs) (2.8.0)\nRequirement already satisfied: cryptography<44,>=0.6 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from msal>=1.8.0->powerbiclient->semantic-link-labs) (41.0.5)\nRequirement already satisfied: numpy>=1.16.6 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from pyarrow>=12.0.1->semantic-link-sempy>=0.7.6->semantic-link-labs) (1.24.3)\nRequirement already satisfied: charset-normalizer<4,>=2 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from requests>=2.25.1->powerbiclient->semantic-link-labs) (3.3.1)\nRequirement already satisfied: idna<4,>=2.5 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from requests>=2.25.1->powerbiclient->semantic-link-labs) (3.4)\nRequirement already satisfied: urllib3<3,>=1.21.1 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from requests>=2.25.1->powerbiclient->semantic-link-labs) (1.26.17)\nRequirement already satisfied: certifi>=2017.4.17 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from requests>=2.25.1->powerbiclient->semantic-link-labs) (2023.7.22)\nRequirement already satisfied: scipy>=1.5.0 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from scikit-learn>=1.2.2->semantic-link-sempy>=0.7.6->semantic-link-labs) (1.10.1)\nRequirement already satisfied: joblib>=1.1.1 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from scikit-learn>=1.2.2->semantic-link-sempy>=0.7.6->semantic-link-labs) (1.3.2)\nRequirement already satisfied: threadpoolctl>=2.0.0 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from scikit-learn>=1.2.2->semantic-link-sempy>=0.7.6->semantic-link-labs) (3.2.0)\nRequirement already satisfied: python-dateutil>=2.8.2 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from pandas->powerbiclient->semantic-link-labs) (2.8.2)\nRequirement already satisfied: pytz>=2020.1 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from pandas->powerbiclient->semantic-link-labs) (2023.3.post1)\nRequirement already satisfied: tzdata>=2022.1 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from pandas->powerbiclient->semantic-link-labs) (2023.3)\nRequirement already satisfied: py4j==0.10.9.7 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from pyspark->powerbiclient->semantic-link-labs) (0.10.9.7)\nRequirement already satisfied: pycparser in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from cffi>=1.13->clr-loader>=0.2.5->semantic-link-sempy>=0.7.6->semantic-link-labs) (2.21)\nRequirement already satisfied: comm>=0.1.1 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from ipykernel>=4.5.1->ipywidgets>=7.0.0->powerbiclient->semantic-link-labs) (0.1.4)\nRequirement already satisfied: debugpy>=1.6.5 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from ipykernel>=4.5.1->ipywidgets>=7.0.0->powerbiclient->semantic-link-labs) (1.8.0)\nRequirement already satisfied: jupyter-client>=6.1.12 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from ipykernel>=4.5.1->ipywidgets>=7.0.0->powerbiclient->semantic-link-labs) (8.5.0)\nRequirement already satisfied: jupyter-core!=5.0.*,>=4.12 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from ipykernel>=4.5.1->ipywidgets>=7.0.0->powerbiclient->semantic-link-labs) (5.4.0)\nRequirement already satisfied: matplotlib-inline>=0.1 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from ipykernel>=4.5.1->ipywidgets>=7.0.0->powerbiclient->semantic-link-labs) (0.1.6)\nRequirement already satisfied: nest-asyncio in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from ipykernel>=4.5.1->ipywidgets>=7.0.0->powerbiclient->semantic-link-labs) (1.5.8)\nRequirement already satisfied: packaging in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from ipykernel>=4.5.1->ipywidgets>=7.0.0->powerbiclient->semantic-link-labs) (23.2)\nRequirement already satisfied: psutil in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from ipykernel>=4.5.1->ipywidgets>=7.0.0->powerbiclient->semantic-link-labs) (5.9.5)\nRequirement already satisfied: pyzmq>=20 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from ipykernel>=4.5.1->ipywidgets>=7.0.0->powerbiclient->semantic-link-labs) (25.1.1)\nRequirement already satisfied: tornado>=6.1 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from ipykernel>=4.5.1->ipywidgets>=7.0.0->powerbiclient->semantic-link-labs) (6.3.3)\nRequirement already satisfied: backcall in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from ipython>=6.1.0->ipywidgets>=7.0.0->powerbiclient->semantic-link-labs) (0.2.0)\nRequirement already satisfied: decorator in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from ipython>=6.1.0->ipywidgets>=7.0.0->powerbiclient->semantic-link-labs) (5.1.1)\nRequirement already satisfied: jedi>=0.16 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from ipython>=6.1.0->ipywidgets>=7.0.0->powerbiclient->semantic-link-labs) (0.19.1)\nRequirement already satisfied: pickleshare in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from ipython>=6.1.0->ipywidgets>=7.0.0->powerbiclient->semantic-link-labs) (0.7.5)\nRequirement already satisfied: prompt-toolkit!=3.0.37,<3.1.0,>=3.0.30 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from ipython>=6.1.0->ipywidgets>=7.0.0->powerbiclient->semantic-link-labs) (3.0.39)\nRequirement already satisfied: pygments>=2.4.0 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from ipython>=6.1.0->ipywidgets>=7.0.0->powerbiclient->semantic-link-labs) (2.16.1)\nRequirement already satisfied: stack-data in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from ipython>=6.1.0->ipywidgets>=7.0.0->powerbiclient->semantic-link-labs) (0.6.2)\nRequirement already satisfied: pexpect>4.3 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from ipython>=6.1.0->ipywidgets>=7.0.0->powerbiclient->semantic-link-labs) (4.8.0)\nRequirement already satisfied: parso<0.9.0,>=0.8.3 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from jedi>=0.16->ipython>=6.1.0->ipywidgets>=7.0.0->powerbiclient->semantic-link-labs) (0.8.3)\nRequirement already satisfied: platformdirs>=2.5 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from jupyter-core!=5.0.*,>=4.12->ipykernel>=4.5.1->ipywidgets>=7.0.0->powerbiclient->semantic-link-labs) (3.5.1)\nRequirement already satisfied: ptyprocess>=0.5 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from pexpect>4.3->ipython>=6.1.0->ipywidgets>=7.0.0->powerbiclient->semantic-link-labs) (0.7.0)\nRequirement already satisfied: wcwidth in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from prompt-toolkit!=3.0.37,<3.1.0,>=3.0.30->ipython>=6.1.0->ipywidgets>=7.0.0->powerbiclient->semantic-link-labs) (0.2.8)\nRequirement already satisfied: executing>=1.2.0 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from stack-data->ipython>=6.1.0->ipywidgets>=7.0.0->powerbiclient->semantic-link-labs) (1.2.0)\nRequirement already satisfied: asttokens>=2.1.0 in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from stack-data->ipython>=6.1.0->ipywidgets>=7.0.0->powerbiclient->semantic-link-labs) (2.4.0)\nRequirement already satisfied: pure-eval in /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages (from stack-data->ipython>=6.1.0->ipywidgets>=7.0.0->powerbiclient->semantic-link-labs) (0.2.2)\nInstalling collected packages: semantic-link-sempy\n Attempting uninstall: semantic-link-sempy\n Found existing installation: semantic-link-sempy 0.7.2\n Not uninstalling semantic-link-sempy at /home/trusted-service-user/cluster-env/trident_env/lib/python3.10/site-packages, outside environment /nfs4/pyenv-7a1fb602-cfa3-40a7-bc18-06d014411203\n Can't uninstall 'semantic-link-sempy'. No files were found to uninstall.\nSuccessfully installed semantic-link-sempy-0.7.7\n\n\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.1.2\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.2\u001b[0m\n\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpython -m pip install --upgrade pip\u001b[0m\nNote: you may need to restart the kernel to use updated packages.\nWarning: PySpark kernel has been restarted to use updated packages.\n\n"]}],"execution_count":1,"metadata":{"jupyter":{"outputs_hidden":true,"source_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"d5cae9db-cef9-48a8-a351-9c5fcc99645c"},{"cell_type":"code","source":["import sempy.fabric as fabric\n","import sempy_labs as labs\n","from sempy_labs import lakehouse as lake\n","from sempy_labs import directlake\n","from sempy_labs.tom import connect_semantic_model"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":11,"statement_ids":[11],"livy_statement_state":"available","session_id":"34ef5cfa-682e-46d6-8c31-e2e385f7d953","state":"finished","normalized_state":"finished","queued_time":"2024-07-31T07:01:23.5961713Z","session_start_time":null,"execution_start_time":"2024-07-31T07:05:16.0168005Z","execution_finish_time":"2024-07-31T07:05:28.1736593Z","parent_msg_id":"5a5b80a2-93d1-409a-8908-79f8992d783f"},"text/plain":"StatementMeta(, 34ef5cfa-682e-46d6-8c31-e2e385f7d953, 11, Finished, Available, Finished)"},"metadata":{}}],"execution_count":2,"metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"},"jupyter":{"outputs_hidden":false}},"id":"5cc6eedf"},{"cell_type":"code","source":["WorkspaceSemanticModelName = 'SalesAnalysis'\n","df_datasets = fabric.list_datasets(WorkspaceSemanticModelName)\n","for index, row in df_datasets.iterrows():\n"," mydataset = row['Dataset Name']\n"," try:\n"," if (mydataset !='BPA Report'):\n"," labs.run_model_bpa(dataset=mydataset, workspace=WorkspaceSemanticModelName, export=True)\n"," except:\n"," print('Semantic Model not supported')"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":17,"statement_ids":[17],"livy_statement_state":"available","session_id":"34ef5cfa-682e-46d6-8c31-e2e385f7d953","state":"finished","normalized_state":"finished","queued_time":"2024-07-31T07:17:22.7625262Z","session_start_time":null,"execution_start_time":"2024-07-31T07:17:23.2548749Z","execution_finish_time":"2024-07-31T07:17:37.8508455Z","parent_msg_id":"ad801a47-c345-4173-a1ad-4e20742abf12"},"text/plain":"StatementMeta(, 34ef5cfa-682e-46d6-8c31-e2e385f7d953, 17, Finished, Available, Finished)"},"metadata":{}},{"output_type":"stream","name":"stdout","text":["🟢 Model Best Practice Analyzer results for the 'Regional Sales Sample' semantic model have been appended to the 'modelbparesults' delta table.\n"]},{"output_type":"display_data","data":{"text/plain":"","text/html":"\n \n
Rule NameObject TypeObject NameSeverity
Column references should be fully qualifiedUsing fully qualified column references makes it easier to distinguish between column and measure references, and also helps avoid certain errors. When referencing a column in DAX, first specify the table name, then specify the column name in square brackets.MeasureRevenue In Pipeline
Column references should be fully qualifiedUsing fully qualified column references makes it easier to distinguish between column and measure references, and also helps avoid certain errors. When referencing a column in DAX, first specify the table name, then specify the column name in square brackets.MeasureRevenue Open
Filter column values with proper syntaxInstead of using this pattern FILTER('Table','Table'[Column]=\"Value\") for the filter parameters of a CALCULATE or CALCULATETABLE function, use one of the options below. As far as whether to use the KEEPFILTERS function, see the second reference link below.\nOption 1: KEEPFILTERS('Table'[Column]=\"Value\")\nOption 2: 'Table'[Column]=\"Value\"MeasureOpportunity Count In Pipeline⚠️
Measure references should be unqualifiedUsing unqualified measure references makes it easier to distinguish between column and measure references, and also helps avoid certain errors. When referencing a measure using DAX, do not specify the table name. Use only the measure name in square brackets.MeasureFcst adj slicer alt text
Measure references should be unqualifiedUsing unqualified measure references makes it easier to distinguish between column and measure references, and also helps avoid certain errors. When referencing a measure using DAX, do not specify the table name. Use only the measure name in square brackets.MeasureRevenue In Pipeline
Measure references should be unqualifiedUsing unqualified measure references makes it easier to distinguish between column and measure references, and also helps avoid certain errors. When referencing a measure using DAX, do not specify the table name. Use only the measure name in square brackets.MeasureRevenue Open
Rule NameObject TypeObject NameSeverity
Relationship columns should be of the same data typeColumns used in a relationship should be of the same data type. Ideally, they will be of integer data type (see the related rule '[Formatting] Relationship columns should be of integer data type'). Having columns within a relationship which are of different data types may lead to various issues.Relationship'Accounts'[TerritorySeq] -> 'Territories'[TerritorySeq]⚠️
Rule NameObject TypeObject NameSeverity
Add data category for columnsAdd Data Category property for appropriate columns.Column'Territories'[Country]ℹ️
Do not summarize numeric columnsNumeric columns (integer, decimal, double) should have their SummarizeBy property set to \"None\" to avoid accidental summation in Power BI (create measures instead).Column'Opportunities'[Blank]⚠️
Do not summarize numeric columnsNumeric columns (integer, decimal, double) should have their SummarizeBy property set to \"None\" to avoid accidental summation in Power BI (create measures instead).Column'Opportunities'[Days Remaining In Pipeline]⚠️
Do not summarize numeric columnsNumeric columns (integer, decimal, double) should have their SummarizeBy property set to \"None\" to avoid accidental summation in Power BI (create measures instead).Column'Opportunities'[DaysToClose]⚠️
Do not summarize numeric columnsNumeric columns (integer, decimal, double) should have their SummarizeBy property set to \"None\" to avoid accidental summation in Power BI (create measures instead).Column'Opportunities'[Discount]⚠️
Do not summarize numeric columnsNumeric columns (integer, decimal, double) should have their SummarizeBy property set to \"None\" to avoid accidental summation in Power BI (create measures instead).Column'Opportunities'[Probability]⚠️
Do not summarize numeric columnsNumeric columns (integer, decimal, double) should have their SummarizeBy property set to \"None\" to avoid accidental summation in Power BI (create measures instead).Column'Opportunities'[Weeks Open]⚠️
First letter of objects must be capitalizedThe first letter of object names should be capitalized to maintain professional quality.Column'Owners'[systemuserid]ℹ️
Hide foreign keysForeign keys should always be hidden.Column'Opportunities'[CloseDate]ℹ️
Mark primary keysSet the 'Key' property to 'True' for primary key columns within the column properties.Column'Accounts'[AccountSeq]ℹ️
Mark primary keysSet the 'Key' property to 'True' for primary key columns within the column properties.Column'Campaigns'[CampaignSeq]ℹ️
Mark primary keysSet the 'Key' property to 'True' for primary key columns within the column properties.Column'Industries'[IndustrySeq]ℹ️
Mark primary keysSet the 'Key' property to 'True' for primary key columns within the column properties.Column'Opportunity Calendar'[Date]ℹ️
Mark primary keysSet the 'Key' property to 'True' for primary key columns within the column properties.Column'Owners'[SystemUserSeq]ℹ️
Mark primary keysSet the 'Key' property to 'True' for primary key columns within the column properties.Column'Products'[ProductSeq]ℹ️
Mark primary keysSet the 'Key' property to 'True' for primary key columns within the column properties.Column'Territories'[TerritorySeq]ℹ️
Percentages should be formatted with thousands separators and 1 decimalMeasureClose %⚠️
Percentages should be formatted with thousands separators and 1 decimalMeasureForecast %⚠️
Provide format string for 'Date' columnsColumns of type \"DateTime\" that have \"Month\" in their names should be formatted as \"mm/dd/yyyy\".Column'Opportunities'[CloseDate]⚠️
Provide format string for 'Date' columnsColumns of type \"DateTime\" that have \"Month\" in their names should be formatted as \"mm/dd/yyyy\".Column'Opportunity Calendar'[Date]⚠️
Provide format string for measuresVisible measures should have their format string property assigned.MeasureFcst adj slicer alt textℹ️
Relationship columns should be of integer data typeIt is a best practice for relationship columns to be of integer data type. This applies not only to data warehousing but data modeling as well.Relationship'Accounts'[TerritorySeq] -> 'Territories'[TerritorySeq]⚠️
Relationship columns should be of integer data typeIt is a best practice for relationship columns to be of integer data type. This applies not only to data warehousing but data modeling as well.Relationship'Opportunities'[CloseDate] -> 'Opportunity Calendar'[Date]⚠️
Whole numbers should be formatted with thousands separators and no decimalsMeasureFcst adj slicer alt text⚠️
Whole numbers should be formatted with thousands separators and no decimalsMeasureForecast Adjustment Value⚠️
Rule NameObject TypeObject NameSeverity
Ensure tables have relationshipsThis rule highlights tables which are not connected to any other table in the model with a relationship.TableOpportunity Forecast Adjustment⚠️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Accounts'[Account Name]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Accounts'[Account Number]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Accounts'[Country]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Accounts'[State or Province]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Campaigns'[Campaign Type]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Campaigns'[Campaign]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Contacts'[Contact]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Contacts'[Job Title]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Industries'[Industry]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Opportunities'[Blank]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Opportunities'[CloseDate]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Opportunities'[Days Remaining In Pipeline (bins)]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Opportunities'[Days Remaining In Pipeline]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Opportunities'[DaysToClose]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Opportunities'[Decision Maker Identified]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Opportunities'[Discount]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Opportunities'[Opportunity Created On]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Opportunities'[Probability]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Opportunities'[Purchase Process]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Opportunities'[Rating]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Opportunities'[Sales Stage]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Opportunities'[Status]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Opportunities'[Weeks Open]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Opportunity Calendar'[Date]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Opportunity Calendar'[MONTH]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Opportunity Calendar'[RELATIVE 07 DAY PERIOD]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Opportunity Calendar'[RELATIVE 30 DAY PERIOD]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Opportunity Calendar'[RELATIVE DAY]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Opportunity Calendar'[RELATIVE MONTH]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Opportunity Calendar'[RELATIVE WEEK]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Opportunity Calendar'[WEEK]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Opportunity Calendar'[YEAR MONTH]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Opportunity Calendar'[YEAR WEEK]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Opportunity Calendar'[YEAR]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Owners'[Manager]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Owners'[Owner]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Products'[Product Category]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Products'[Product]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Territories'[Region]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Territories'[State Or Province]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Territories'[Territory]ℹ️
Rule NameObject TypeObject NameSeverity
Avoid using calculated columnsCalculated columns do not compress as well as data columns so they take up more memory. They also slow down processing times for both the table as well as process recalc. Offload calculated column logic to your data warehouse and turn these calculated columns into data columns.Column'Opportunities'[Blank]⚠️
Avoid using calculated columnsCalculated columns do not compress as well as data columns so they take up more memory. They also slow down processing times for both the table as well as process recalc. Offload calculated column logic to your data warehouse and turn these calculated columns into data columns.Column'Opportunities'[Days Remaining In Pipeline (bins)]⚠️
Avoid using calculated columnsCalculated columns do not compress as well as data columns so they take up more memory. They also slow down processing times for both the table as well as process recalc. Offload calculated column logic to your data warehouse and turn these calculated columns into data columns.Column'Opportunities'[Days Remaining In Pipeline]⚠️
Avoid using calculated columnsCalculated columns do not compress as well as data columns so they take up more memory. They also slow down processing times for both the table as well as process recalc. Offload calculated column logic to your data warehouse and turn these calculated columns into data columns.Column'Opportunities'[Weeks Open]⚠️
Avoid using calculated columnsCalculated columns do not compress as well as data columns so they take up more memory. They also slow down processing times for both the table as well as process recalc. Offload calculated column logic to your data warehouse and turn these calculated columns into data columns.Column'Opportunity Forecast Adjustment'[Blank]⚠️
Consider a star-schema instead of a snowflake architectureGenerally speaking, a star-schema is the optimal architecture for tabular models. That being the case, there are valid cases to use a snowflake approach. Please check your model and consider moving to a star-schema architecture.TableAccounts⚠️
Date/calendar tables should be marked as a date tableThis rule looks for tables that contain the words 'date' or 'calendar' as they should likely be marked as a date table.TableOpportunity Calendar⚠️
Do not use floating point data typesThe \"Double\" floating point data type should be avoided, as it can result in unpredictable roundoff errors and decreased performance in certain scenarios. Use \"Int64\" or \"Decimal\" where appropriate (but note that \"Decimal\" is limited to 4 digits after the decimal sign).Column'Opportunities'[Discount]⚠️
Do not use floating point data typesThe \"Double\" floating point data type should be avoided, as it can result in unpredictable roundoff errors and decreased performance in certain scenarios. Use \"Int64\" or \"Decimal\" where appropriate (but note that \"Decimal\" is limited to 4 digits after the decimal sign).Column'Opportunities'[Probability (raw)]⚠️
Do not use floating point data typesThe \"Double\" floating point data type should be avoided, as it can result in unpredictable roundoff errors and decreased performance in certain scenarios. Use \"Int64\" or \"Decimal\" where appropriate (but note that \"Decimal\" is limited to 4 digits after the decimal sign).Column'Opportunities'[Probability]⚠️
Do not use floating point data typesThe \"Double\" floating point data type should be avoided, as it can result in unpredictable roundoff errors and decreased performance in certain scenarios. Use \"Int64\" or \"Decimal\" where appropriate (but note that \"Decimal\" is limited to 4 digits after the decimal sign).Column'Opportunity Calendar'[RELATIVE 07 DAY PERIOD]⚠️
Do not use floating point data typesThe \"Double\" floating point data type should be avoided, as it can result in unpredictable roundoff errors and decreased performance in certain scenarios. Use \"Int64\" or \"Decimal\" where appropriate (but note that \"Decimal\" is limited to 4 digits after the decimal sign).Column'Opportunity Calendar'[RELATIVE 30 DAY PERIOD]⚠️
Do not use floating point data typesThe \"Double\" floating point data type should be avoided, as it can result in unpredictable roundoff errors and decreased performance in certain scenarios. Use \"Int64\" or \"Decimal\" where appropriate (but note that \"Decimal\" is limited to 4 digits after the decimal sign).Column'Opportunity Calendar'[RELATIVE WEEK]⚠️
Model should have a date tableGenerally speaking, models should generally have a date table. Models that do not have a date table generally are not taking advantage of features such as time intelligence or may not have a properly structured architecture.ModelModel⚠️
Reduce usage of calculated tablesMigrate calculated table logic to your data warehouse. Reliance on calculated tables will lead to technical debt and potential misalignments if you have multiple models on your platform.TableOpportunity Calendar⚠️
Reduce usage of calculated tablesMigrate calculated table logic to your data warehouse. Reliance on calculated tables will lead to technical debt and potential misalignments if you have multiple models on your platform.TableOpportunity Forecast Adjustment⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Accounts'[AccountID]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Accounts'[AccountOwnerSeq]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Accounts'[AccountSeq]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Accounts'[IndustrySeq]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Accounts'[TerritorySeq]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Campaigns'[CampaignSeq]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Contacts'[AccountSeq]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Contacts'[ContactSeq]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Industries'[IndustrySeq]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Opportunities'[AccountSeq]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Opportunities'[CampaignSeq]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Opportunities'[DateDiff-Days]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Opportunities'[OpportunitySeq]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Opportunities'[Probability (raw)]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Opportunities'[ProductSeq]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Opportunities'[SystemUserSeq]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Opportunities'[Value]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Opportunity Calendar'[DAY]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Opportunity Calendar'[DaySeq]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Opportunity Calendar'[MONTH NUMBER]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Opportunity Calendar'[YEAR MONTH NUMBER]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Opportunity Forecast Adjustment'[Blank]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Opportunity Forecast Adjustment'[Forecast Adjustment]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Owners'[SystemUserSeq]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Owners'[systemuserid]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Products'[ProductSeq]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Territories'[Country]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Territories'[TerritorySeq]⚠️
\n \n "},"metadata":{}},{"output_type":"stream","name":"stdout","text":["🟢 Model Best Practice Analyzer results for the 'Sample Revenue Opportunities' semantic model have been appended to the 'modelbparesults' delta table.\n"]},{"output_type":"display_data","data":{"text/plain":"","text/html":"\n \n
Rule NameObject TypeObject NameSeverity
Column references should be fully qualifiedUsing fully qualified column references makes it easier to distinguish between column and measure references, and also helps avoid certain errors. When referencing a column in DAX, first specify the table name, then specify the column name in square brackets.MeasureSommes des Ventes
Column references should be fully qualifiedUsing fully qualified column references makes it easier to distinguish between column and measure references, and also helps avoid certain errors. When referencing a column in DAX, first specify the table name, then specify the column name in square brackets.MeasureVentes YTD
Rule NameObject TypeObject NameSeverity
Do not summarize numeric columnsNumeric columns (integer, decimal, double) should have their SummarizeBy property set to \"None\" to avoid accidental summation in Power BI (create measures instead).Column'Groupe de calcul'[Ordinal]⚠️
Mark primary keysSet the 'Key' property to 'True' for primary key columns within the column properties.Column'Date'[Date]ℹ️
Mark primary keysSet the 'Key' property to 'True' for primary key columns within the column properties.Column'LocalDateTable_9d7ebeab-b996-4711-9605-371d7c858706'[Date]ℹ️
Mark primary keysSet the 'Key' property to 'True' for primary key columns within the column properties.Column'Magasin'[Magasin]ℹ️
Mark primary keysSet the 'Key' property to 'True' for primary key columns within the column properties.Column'Produit'[Produit]ℹ️
Provide format string for 'Date' columnsColumns of type \"DateTime\" that have \"Month\" in their names should be formatted as \"mm/dd/yyyy\".Column'Date'[Date]⚠️
Provide format string for 'Date' columnsColumns of type \"DateTime\" that have \"Month\" in their names should be formatted as \"mm/dd/yyyy\".Column'DateTableTemplate_7502f2a9-ee3b-411d-b731-ee0821894ecf'[Date]⚠️
Provide format string for 'Date' columnsColumns of type \"DateTime\" that have \"Month\" in their names should be formatted as \"mm/dd/yyyy\".Column'LocalDateTable_9d7ebeab-b996-4711-9605-371d7c858706'[Date]⚠️
Provide format string for 'Date' columnsColumns of type \"DateTime\" that have \"Month\" in their names should be formatted as \"mm/dd/yyyy\".Column'Vente'[Date]⚠️
Relationship columns should be of integer data typeIt is a best practice for relationship columns to be of integer data type. This applies not only to data warehousing but data modeling as well.Relationship'Date'[Date] -> 'LocalDateTable_9d7ebeab-b996-4711-9605-371d7c858706'[Date]⚠️
Relationship columns should be of integer data typeIt is a best practice for relationship columns to be of integer data type. This applies not only to data warehousing but data modeling as well.Relationship'Vente'[Date] -> 'Date'[Date]⚠️
Whole numbers should be formatted with thousands separators and no decimalsMeasureSommes des Ventes⚠️
Whole numbers should be formatted with thousands separators and no decimalsMeasureVentes YTD⚠️
Rule NameObject TypeObject NameSeverity
Ensure tables have relationshipsThis rule highlights tables which are not connected to any other table in the model with a relationship.TableDateTableTemplate_7502f2a9-ee3b-411d-b731-ee0821894ecf⚠️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Date'[Annee]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Date'[Jour de la semaine]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Date'[Jour du mois]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Date'[Jour]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Date'[Mois de l'annee]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Date'[Mois]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Groupe de calcul'[Colonne du groupe de calcul]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Groupe de calcul'[Ordinal]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Magasin'[Nom Magasin]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Magasin'[Pays]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Magasin'[Ville]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Produit'[Categorie Produit]ℹ️
Visible objects with no descriptionCalculation groups have no function unless they have calculation items.Column'Produit'[Nom Produit]ℹ️
Rule NameObject TypeObject NameSeverity
Avoid using calculated columnsCalculated columns do not compress as well as data columns so they take up more memory. They also slow down processing times for both the table as well as process recalc. Offload calculated column logic to your data warehouse and turn these calculated columns into data columns.Column'DateTableTemplate_7502f2a9-ee3b-411d-b731-ee0821894ecf'[Année]⚠️
Avoid using calculated columnsCalculated columns do not compress as well as data columns so they take up more memory. They also slow down processing times for both the table as well as process recalc. Offload calculated column logic to your data warehouse and turn these calculated columns into data columns.Column'DateTableTemplate_7502f2a9-ee3b-411d-b731-ee0821894ecf'[Jour]⚠️
Avoid using calculated columnsCalculated columns do not compress as well as data columns so they take up more memory. They also slow down processing times for both the table as well as process recalc. Offload calculated column logic to your data warehouse and turn these calculated columns into data columns.Column'DateTableTemplate_7502f2a9-ee3b-411d-b731-ee0821894ecf'[Mois]⚠️
Avoid using calculated columnsCalculated columns do not compress as well as data columns so they take up more memory. They also slow down processing times for both the table as well as process recalc. Offload calculated column logic to your data warehouse and turn these calculated columns into data columns.Column'DateTableTemplate_7502f2a9-ee3b-411d-b731-ee0821894ecf'[NoMois]⚠️
Avoid using calculated columnsCalculated columns do not compress as well as data columns so they take up more memory. They also slow down processing times for both the table as well as process recalc. Offload calculated column logic to your data warehouse and turn these calculated columns into data columns.Column'DateTableTemplate_7502f2a9-ee3b-411d-b731-ee0821894ecf'[NoTrimestre]⚠️
Avoid using calculated columnsCalculated columns do not compress as well as data columns so they take up more memory. They also slow down processing times for both the table as well as process recalc. Offload calculated column logic to your data warehouse and turn these calculated columns into data columns.Column'DateTableTemplate_7502f2a9-ee3b-411d-b731-ee0821894ecf'[Trimestre]⚠️
Avoid using calculated columnsCalculated columns do not compress as well as data columns so they take up more memory. They also slow down processing times for both the table as well as process recalc. Offload calculated column logic to your data warehouse and turn these calculated columns into data columns.Column'LocalDateTable_9d7ebeab-b996-4711-9605-371d7c858706'[Année]⚠️
Avoid using calculated columnsCalculated columns do not compress as well as data columns so they take up more memory. They also slow down processing times for both the table as well as process recalc. Offload calculated column logic to your data warehouse and turn these calculated columns into data columns.Column'LocalDateTable_9d7ebeab-b996-4711-9605-371d7c858706'[Jour]⚠️
Avoid using calculated columnsCalculated columns do not compress as well as data columns so they take up more memory. They also slow down processing times for both the table as well as process recalc. Offload calculated column logic to your data warehouse and turn these calculated columns into data columns.Column'LocalDateTable_9d7ebeab-b996-4711-9605-371d7c858706'[Mois]⚠️
Avoid using calculated columnsCalculated columns do not compress as well as data columns so they take up more memory. They also slow down processing times for both the table as well as process recalc. Offload calculated column logic to your data warehouse and turn these calculated columns into data columns.Column'LocalDateTable_9d7ebeab-b996-4711-9605-371d7c858706'[NoMois]⚠️
Avoid using calculated columnsCalculated columns do not compress as well as data columns so they take up more memory. They also slow down processing times for both the table as well as process recalc. Offload calculated column logic to your data warehouse and turn these calculated columns into data columns.Column'LocalDateTable_9d7ebeab-b996-4711-9605-371d7c858706'[NoTrimestre]⚠️
Avoid using calculated columnsCalculated columns do not compress as well as data columns so they take up more memory. They also slow down processing times for both the table as well as process recalc. Offload calculated column logic to your data warehouse and turn these calculated columns into data columns.Column'LocalDateTable_9d7ebeab-b996-4711-9605-371d7c858706'[Trimestre]⚠️
Consider a star-schema instead of a snowflake architectureGenerally speaking, a star-schema is the optimal architecture for tabular models. That being the case, there are valid cases to use a snowflake approach. Please check your model and consider moving to a star-schema architecture.TableDate⚠️
Date/calendar tables should be marked as a date tableThis rule looks for tables that contain the words 'date' or 'calendar' as they should likely be marked as a date table.TableDate⚠️
Date/calendar tables should be marked as a date tableThis rule looks for tables that contain the words 'date' or 'calendar' as they should likely be marked as a date table.TableDateTableTemplate_7502f2a9-ee3b-411d-b731-ee0821894ecf⚠️
Date/calendar tables should be marked as a date tableThis rule looks for tables that contain the words 'date' or 'calendar' as they should likely be marked as a date table.TableLocalDateTable_9d7ebeab-b996-4711-9605-371d7c858706⚠️
Model should have a date tableGenerally speaking, models should generally have a date table. Models that do not have a date table generally are not taking advantage of features such as time intelligence or may not have a properly structured architecture.ModelModel⚠️
Reduce usage of calculated tablesMigrate calculated table logic to your data warehouse. Reliance on calculated tables will lead to technical debt and potential misalignments if you have multiple models on your platform.TableDateTableTemplate_7502f2a9-ee3b-411d-b731-ee0821894ecf⚠️
Reduce usage of calculated tablesMigrate calculated table logic to your data warehouse. Reliance on calculated tables will lead to technical debt and potential misalignments if you have multiple models on your platform.TableLocalDateTable_9d7ebeab-b996-4711-9605-371d7c858706⚠️
Remove auto-date tableAvoid using auto-date tables. Make sure to turn off auto-date table in the settings in Power BI Desktop. This will save memory resources.TableDateTableTemplate_7502f2a9-ee3b-411d-b731-ee0821894ecf⚠️
Remove auto-date tableAvoid using auto-date tables. Make sure to turn off auto-date table in the settings in Power BI Desktop. This will save memory resources.TableLocalDateTable_9d7ebeab-b996-4711-9605-371d7c858706⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Date'[Date]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'DateTableTemplate_7502f2a9-ee3b-411d-b731-ee0821894ecf'[Date]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'DateTableTemplate_7502f2a9-ee3b-411d-b731-ee0821894ecf'[NoMois]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'DateTableTemplate_7502f2a9-ee3b-411d-b731-ee0821894ecf'[NoTrimestre]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'LocalDateTable_9d7ebeab-b996-4711-9605-371d7c858706'[Date]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'LocalDateTable_9d7ebeab-b996-4711-9605-371d7c858706'[NoMois]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'LocalDateTable_9d7ebeab-b996-4711-9605-371d7c858706'[NoTrimestre]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Magasin'[Magasin]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Produit'[Produit]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Vente'[Date]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Vente'[Magasin]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Vente'[Produit]⚠️
Set IsAvailableInMdx to false on non-attribute columnsTo speed up processing time and conserve memory after processing, attribute hierarchies should not be built for columns that are never used for slicing by MDX clients. In other words, all hidden columns that are not used as a Sort By Column or referenced in user hierarchies should have their IsAvailableInMdx property set to false. The IsAvailableInMdx property is not relevant for Direct Lake models.Column'Vente'[Vente]⚠️
\n \n "},"metadata":{}},{"output_type":"stream","name":"stdout","text":["Semantic Model not supported\n"]}],"execution_count":8,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"ff3242c5-2d30-4a1c-825d-34022118d1d1"},{"cell_type":"code","source":["#labs.refresh_semantic_model(dataset='BPA Report', workspace='SalesAnalysis')"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":null,"statement_ids":null,"livy_statement_state":null,"session_id":null,"state":"cancelled","normalized_state":"cancelled","queued_time":"2024-07-31T07:01:23.5975556Z","session_start_time":null,"execution_start_time":null,"execution_finish_time":"2024-07-31T07:06:25.6849673Z","parent_msg_id":"d4150a56-2d38-4d30-a112-b4b43ec6b83e"},"text/plain":"StatementMeta(, , , Cancelled, , Cancelled)"},"metadata":{}}],"execution_count":null,"metadata":{"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"e09fdabe-4b49-4a79-a2de-9f7fbd55243a"}],"metadata":{"kernel_info":{"name":"synapse_pyspark"},"kernelspec":{"name":"synapse_pyspark","language":"Python","display_name":"Synapse PySpark"},"language_info":{"name":"python"},"microsoft":{"language":"python","language_group":"synapse_pyspark","ms_spell_check":{"ms_spell_check_language":"en"}},"nteract":{"version":"nteract-front-end@1.0.0"},"widgets":{},"synapse_widget":{"state":{},"version":"0.1"},"spark_compute":{"compute_id":"/trident/default"},"dependencies":{"lakehouse":{"default_lakehouse":"587ff68f-bd64-4c3d-97e8-ec345ba966c9","default_lakehouse_name":"BPA_Lakehouse","default_lakehouse_workspace_id":"12bf1bca-ee95-4e8f-928b-d378aba54a7d"},"environment":{"environmentId":"d1be124a-478c-4883-9ccc-f07286b94a0f","workspaceId":"12bf1bca-ee95-4e8f-928b-d378aba54a7d"}}},"nbformat":4,"nbformat_minor":5} -------------------------------------------------------------------------------- /Fabric/Copilot Adoption.pbit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pulsweb/MyScripts/925ba1a04b367f6c52190868a6eb068a7775a572/Fabric/Copilot Adoption.pbit -------------------------------------------------------------------------------- /Fabric/Data Chouette - P to F.ipynb: -------------------------------------------------------------------------------- 1 | {"cells":[{"cell_type":"markdown","source":["# 🦉 Data Chouette - P to F"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"552bad68-c2ba-4197-a551-5ce17b482f6f"},{"cell_type":"code","source":["%pip install semantic-link-labs"],"outputs":[],"execution_count":null,"metadata":{"jupyter":{"outputs_hidden":true,"source_hidden":false},"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"d5cae9db-cef9-48a8-a351-9c5fcc99645c"},{"cell_type":"markdown","source":["## 1 - Assess"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"1b3cc93c-94dd-41ff-a30e-fe41060c5d1c"},{"cell_type":"code","source":["import sempy_labs.admin as labs_admin\n","df_models = labs_admin.list_datasets()\n","df_models_filtered = df_models[df_models['Dataset Id']=='5f303257-b786-4bf6-8be0-ac34d36a6fa8']\n","df_models_filtered"],"outputs":[],"execution_count":null,"metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"2b04a8df-6802-4b60-ad17-febb9daf7f9e"},{"cell_type":"code","source":["import sempy_labs as labs\n","labs.vertipaq_analyzer(dataset='Sales', workspace='DataChouette1-Large')"],"outputs":[],"execution_count":null,"metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"},"collapsed":false,"jupyter":{"outputs_hidden":false}},"id":"9928b513-e0c7-42f9-9e12-0dccdc46e4e6"},{"cell_type":"markdown","source":["## 2 - Migrate"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"5e3d5702-c614-4635-be24-1099eaca3c68"},{"cell_type":"code","source":["import sempy_labs.admin as admin\n","admin.assign_workspaces_to_capacity(\n"," source_capacity='datachouette1',\n"," target_capacity='datachouette2',\n"," workspace='DataChouette1-Large'\n",")"],"outputs":[],"execution_count":null,"metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"8377764a-abfe-41ad-b3bd-db1b936fc2cc"},{"cell_type":"markdown","source":["## 3 - Verify"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"67af0f9d-544e-4801-b10f-87bc6d4bd27e"},{"cell_type":"markdown","source":["## 4 - Changes"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"5850282f-6810-4a6c-a8da-121deca081b1"},{"cell_type":"code","source":["import sempy_labs as labs\n","labs.set_semantic_model_storage_format(dataset='Sales', workspace='DataChouette1-Large',storage_format='Small')"],"outputs":[],"execution_count":null,"metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"52d34b72-05b9-4687-ae63-22e2025b7cb5"},{"cell_type":"markdown","source":["## 5 - Migrate"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"5ee7b11e-1997-49e9-8a3d-b81ae3cc65b8"},{"cell_type":"code","source":["admin.assign_workspaces_to_capacity(\n"," source_capacity='datachouette1',\n"," target_capacity='datachouette2',\n"," workspace='DataChouette1-Large'\n",")"],"outputs":[],"execution_count":null,"metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"d924e648-a97b-47c4-a604-5487997ba820"},{"cell_type":"markdown","source":["## 6 - Verify"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"f8e315d4-61a3-47b0-9bde-d91c553a02b5"},{"cell_type":"code","source":["df_models = labs_admin.list_datasets()\n","df_models_filtered = df_models[df_models['Dataset Id']=='5f303257-b786-4bf6-8be0-ac34d36a6fa8']\n","df_models_filtered"],"outputs":[],"execution_count":null,"metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"0bae7866-b754-40fd-b776-a9a662b2222b"},{"cell_type":"code","source":["labs.refresh_semantic_model(dataset='Sales', workspace='DataChouette1-Large')"],"outputs":[],"execution_count":null,"metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"15d81647-eadc-4cd7-b7a2-a0314a1d5594"},{"cell_type":"code","source":["labs.vertipaq_analyzer(dataset='Sales', workspace='DataChouette1-Large')"],"outputs":[],"execution_count":null,"metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"6eaed8ff-0db7-4fd7-bf03-eb600a487fcd"},{"cell_type":"code","source":["labs.set_semantic_model_storage_format(dataset='Sales', workspace='DataChouette1-Large',storage_format='Large')"],"outputs":[],"execution_count":null,"metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"7ef0e051-78d4-41a4-929e-6b7d0f7b5683"},{"cell_type":"code","source":["labs.refresh_semantic_model(dataset='Sales', workspace='DataChouette1-Large')"],"outputs":[],"execution_count":null,"metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"b7886920-5be5-431f-97f7-5541777aba7c"},{"cell_type":"code","source":["df_models = labs_admin.list_datasets()\n","df_models_filtered = df_models[df_models['Dataset Id']=='5f303257-b786-4bf6-8be0-ac34d36a6fa8']\n","df_models_filtered"],"outputs":[],"execution_count":null,"metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"e8fe9de3-1397-449a-845b-07009f06d237"},{"cell_type":"markdown","source":["# Large Semantic Model > 10 GB"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"b81a6cd0-df22-4727-ba9f-b781af4964f6"},{"cell_type":"code","source":["df_models = labs_admin.list_datasets()\n","df_models_filtered = df_models[df_models['Dataset Id']=='107fd8fc-4ae1-4daa-a913-1229e535e758']\n","df_models_filtered"],"outputs":[],"execution_count":null,"metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"f4e28cb3-f6d2-4661-ad50-35ab0d35d462"},{"cell_type":"markdown","source":["## 1 - Assign Workspaces to Storage Account"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"b1e4e6fa-ca5e-4221-abf3-dc1239dcf358"},{"cell_type":"code","source":["import sempy_labs as labs\n","labs.assign_workspace_to_dataflow_storage(dataflow_storage_account='bckstore', workspace='DataChouette1-Large10')"],"outputs":[],"execution_count":null,"metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"b6fa2ed0-35e6-4854-bfa0-4621736f0942"},{"cell_type":"markdown","source":["## 2 - Backup Semantic Model"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"54a90de4-9cdb-4c2a-b27a-2d0faf8e49ca"},{"cell_type":"code","source":["labs.backup_semantic_model(\n"," dataset='107fd8fc-4ae1-4daa-a913-1229e535e758',\n"," file_path=f'Sales.abf',\n"," allow_overwrite=True, \n"," apply_compression=True,\n"," workspace='DataChouette1-Large10'\n",")"],"outputs":[],"execution_count":null,"metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"fbe162d0-5664-4a1d-be45-07152ab739bc"},{"cell_type":"markdown","source":["## 3 - Process Clear to empty Semantic Model"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"7d0c1bc8-c413-4514-a063-988d87a3adee"},{"cell_type":"code","source":["labs.refresh_semantic_model(dataset='107fd8fc-4ae1-4daa-a913-1229e535e758', refresh_type='clearValues', workspace='DataChouette1-Large10')"],"outputs":[],"execution_count":null,"metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"65c085c2-26b7-43b7-b136-4d588b3af5dc"},{"cell_type":"code","source":["labs.vertipaq_analyzer(dataset='Sales', workspace='DataChouette1-Large10')"],"outputs":[],"execution_count":null,"metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"ce4e6a19-289f-4787-b385-df7c55a67b8e"},{"cell_type":"markdown","source":["## 4 - Set Storage Format to Small"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"1f6a29af-1300-4ebf-a80f-4be81fa4287c"},{"cell_type":"code","source":["labs.set_semantic_model_storage_format(dataset='Sales', workspace='DataChouette1-Large10',storage_format='Small')"],"outputs":[],"execution_count":null,"metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"9da71e1e-d927-432b-808d-07f47d0b39f3"},{"cell_type":"markdown","source":["## 5 - Migrate to F Capacity"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"61b49b59-30d1-40c7-b1bb-7c821ee923cf"},{"cell_type":"code","source":["admin.assign_workspaces_to_capacity(\n"," source_capacity='datachouette1',\n"," target_capacity='datachouette2',\n"," workspace='DataChouette1-Large10'\n",")"],"outputs":[],"execution_count":null,"metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"596d0831-4f08-4f8a-af94-0ea723119f50"},{"cell_type":"markdown","source":["## 6 - Set Storage Format to Large"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"e039b36d-849e-4c75-bbc5-3f63ff266bd7"},{"cell_type":"code","source":["labs.set_semantic_model_storage_format(dataset='Sales', workspace='DataChouette1-Large10',storage_format='Large')"],"outputs":[],"execution_count":null,"metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"d87ea655-63ab-488d-8965-317f3ee9a08d"},{"cell_type":"markdown","source":["## 7 - Restore Semantic Model"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"3789f8f5-162d-40c8-8ebf-c82e4b1af553"},{"cell_type":"code","source":["labs.restore_semantic_model(\n"," dataset='Sales',\n"," file_path=f'Sales.abf',\n"," allow_overwrite=True,\n"," ignore_incompatibilities=True,\n"," workspace='DataChouette1-Large10',\n"," force_restore=True\n",")"],"outputs":[],"execution_count":null,"metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"eb7e2e34-72d1-4df8-b02c-f5d6214bc920"},{"cell_type":"markdown","source":["## 8 - Verify"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"db802b27-9db7-4f33-838e-28de6bd95dcb"},{"cell_type":"code","source":["labs.vertipaq_analyzer(dataset='Sales', workspace='DataChouette1-Large10')"],"outputs":[],"execution_count":null,"metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"76c6f7ad-b85a-4464-8039-c1076e5e089e"}],"metadata":{"kernel_info":{"name":"synapse_pyspark"},"kernelspec":{"name":"synapse_pyspark","language":"Python","display_name":"Synapse PySpark"},"language_info":{"name":"python"},"microsoft":{"language":"python","language_group":"synapse_pyspark","ms_spell_check":{"ms_spell_check_language":"en"}},"nteract":{"version":"nteract-front-end@1.0.0"},"widgets":{},"synapse_widget":{"state":{},"version":"0.1"},"spark_compute":{"compute_id":"/trident/default","session_options":{"conf":{"spark.synapse.nbs.session.timeout":"1200000"}}}},"nbformat":4,"nbformat_minor":5} -------------------------------------------------------------------------------- /Fabric/DateDimensionTable.ipynb: -------------------------------------------------------------------------------- 1 | {"cells":[{"cell_type":"markdown","source":["### Creating a Date Dimension Table in Microsoft Fabric Lakehouse\n","By Romain Casteres\n"," \n","Blog Article : \n","- EN : https://www.linkedin.com/pulse/generating-date-dimension-table-direct-lake-model-fabric-casteres-fmjue\n","- FR : https://pulsweb.fr/dimension-date-direct-lake/"],"metadata":{"nteract":{"transient":{"deleting":false}},"microsoft":{"language":"python","language_group":"synapse_pyspark"}},"id":"9a527033-01e9-496e-bc8f-b89f1671533e"},{"cell_type":"code","source":["import pandas as pd\n","import holidays #https://pypi.org/project/holidays/\n","\n","def DimDate(start_date, end_date):\n"," from pandas.tseries.offsets import MonthEnd, QuarterEnd\n"," dfdate = pd.DataFrame({\"Date\": pd.date_range(start=f'{start_date}', end=f'{end_date}', freq='D')})\n"," def get_end_of_month(date):\n"," if date.is_month_end == True:\n"," return date\n"," else:\n"," return date + MonthEnd(1)\n"," def get_end_of_quarter(date):\n"," if date.is_quarter_end == True:\n"," return date\n"," else:\n"," return date + QuarterEnd(1)\n"," dfdate[\"Day\"] = dfdate.Date.dt.day\n"," dfdate[\"Week\"] = dfdate.Date.dt.weekday\n"," dfdate[\"Month\"] = dfdate.Date.dt.month\n"," dfdate[\"MonthName\"] = dfdate.Date.dt.month_name()\n"," dfdate[\"Quarter\"] = dfdate.Date.dt.quarter\n"," dfdate[\"Year\"] = dfdate.Date.dt.year\n"," dfdate[\"FiscalYear\"] = dfdate['Date'].dt.to_period('A-JUN')\n"," dfdate['EndOfMonth'] = dfdate['Date'].apply(get_end_of_month)\n"," dfdate['EOM'] = dfdate['Date'].dt.is_month_end\n"," dfdate['EndOfQuarter'] = dfdate['Date'].apply(get_end_of_quarter)\n"," dfdate['EOQ'] = dfdate['Date'].dt.is_quarter_end\n"," return dfdate\n","\n","def DimDateWorkday(start_date, end_date):\n"," dfdate = DimDate(start_date, end_date)\n"," dfdate['Workday'] = True\n"," for index, row in dfdate.iterrows():\n"," if row['Day'] in ['Saturday', 'Sunday']:\n"," dfdate.loc[index, 'Workday'] = False\n"," date = row['Date'].strftime(\"%Y-%m-%d\")\n"," if date in holidays.France():\n"," dfdate.loc[index, 'Workday'] = False\n"," return dfdate\n","\n","#DimDate('2024-01-01', '2025-12-31')\n","#DimDateWorkday('2024-01-01', '2025-12-31')\n","df_DimDate = spark.createDataFrame(DimDateWorkday('2024-01-01', '2025-12-31'))\n","df_DimDate.write.mode(\"overwrite\").format(\"delta\").saveAsTable('calandar')"],"outputs":[{"output_type":"display_data","data":{"application/vnd.livy.statement-meta+json":{"spark_pool":null,"statement_id":5,"statement_ids":[5],"livy_statement_state":"available","session_id":"b540e040-6a41-4869-b26e-86b14b64c6d9","state":"finished","normalized_state":"finished","queued_time":"2024-08-01T15:19:41.4597319Z","session_start_time":"2024-08-01T15:19:41.8020996Z","execution_start_time":"2024-08-01T15:22:52.2112205Z","execution_finish_time":"2024-08-01T15:23:27.2880723Z","parent_msg_id":"b5141831-9352-4c86-89ab-85e2dc32b7da"},"text/plain":"StatementMeta(, b540e040-6a41-4869-b26e-86b14b64c6d9, 5, Finished, Available, Finished)"},"metadata":{}},{"output_type":"stream","name":"stderr","text":["/opt/spark/python/lib/pyspark.zip/pyspark/sql/pandas/conversion.py:428: UserWarning: createDataFrame attempted Arrow optimization because 'spark.sql.execution.arrow.pyspark.enabled' is set to true; however, failed by the reason below:\n Unsupported type in conversion from Arrow: extension>\nAttempting non-optimization as 'spark.sql.execution.arrow.pyspark.fallback.enabled' is set to true.\n"]}],"execution_count":1,"metadata":{"microsoft":{"language":"python","language_group":"synapse_pyspark"},"jupyter":{"outputs_hidden":true}},"id":"5cb2ec76-ec9c-4525-b915-6fbdcbda7fc4"}],"metadata":{"kernel_info":{"name":"synapse_pyspark"},"kernelspec":{"name":"synapse_pyspark","language":"Python","display_name":"Synapse PySpark"},"language_info":{"name":"python"},"microsoft":{"language":"python","language_group":"synapse_pyspark","ms_spell_check":{"ms_spell_check_language":"en"}},"widgets":{},"nteract":{"version":"nteract-front-end@1.0.0"},"spark_compute":{"compute_id":"/trident/default"},"dependencies":{"lakehouse":{"default_lakehouse":"587ff68f-bd64-4c3d-97e8-ec345ba966c9","default_lakehouse_name":"BPA_Lakehouse","default_lakehouse_workspace_id":"12bf1bca-ee95-4e8f-928b-d378aba54a7d"},"environment":{"environmentId":"d1be124a-478c-4883-9ccc-f07286b94a0f","workspaceId":"12bf1bca-ee95-4e8f-928b-d378aba54a7d"}}},"nbformat":4,"nbformat_minor":5} -------------------------------------------------------------------------------- /Fabric/ExportFabricTenantSetting.py: -------------------------------------------------------------------------------- 1 | spark.conf.set("spark.sql.parquet.vorder.enabled", "true") 2 | import json, requests, pandas as pd 3 | from datetime import date 4 | 5 | auth_with_username = True 6 | if auth_with_username_password: 7 | # use when running outside of Fabric 8 | from azure.identity import UsernamePasswordCredential 9 | tenant = '###' 10 | api = 'https://analysis.windows.net/powerbi/api/.default' 11 | client_id = '###' 12 | username = '###' 13 | password = '###' 14 | username_password_credential_class = UsernamePasswordCredential(client_id=client_id, username=username, password=password, tenant_id=tenant) 15 | access_token_class = username_password_credential_class.get_token(api) 16 | access_token = access_token_class.token 17 | else: 18 | # use when running in fabric 19 | access_token = mssparkutils.credentials.getToken('pbi') 20 | 21 | path = '/lakehouse/default/Files/TenantSettings/' 22 | activityDate = date.today().strftime("%Y-%m-%d") 23 | 24 | TenantSettingsURL = 'https://api.fabric.microsoft.com/v1/admin/tenantsettings' 25 | header = {'Authorization': f'Bearer {access_token}'} 26 | TenantSettingsJSON = requests.get(TenantSettingsURL, headers=header) 27 | 28 | TenantSettingsJSONContent = json.loads(TenantSettingsJSON.content) 29 | TenantSettingsJSONContentExplode = TenantSettingsJSONContent['tenantSettings'] 30 | 31 | df = pd.DataFrame(TenantSettingsJSONContentExplode) 32 | df['ExportedDate'] = activityDate 33 | df.to_csv(path + activityDate + '_TenantSettings.csv', index=False) 34 | 35 | df = spark.read.format("csv").option("header","true").load("Files/TenantSettings/*.csv") 36 | df.write.mode("overwrite").format("delta").saveAsTable("TenantSettings") 37 | -------------------------------------------------------------------------------- /Fabric/TenantSettingsReport.pbit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pulsweb/MyScripts/925ba1a04b367f6c52190868a6eb068a7775a572/Fabric/TenantSettingsReport.pbit -------------------------------------------------------------------------------- /Fabric/TenantSettingsReport.pbix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pulsweb/MyScripts/925ba1a04b367f6c52190868a6eb068a7775a572/Fabric/TenantSettingsReport.pbix -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Romain Casteres 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PBIRS-SSRS/ScheduleReport_History.sql: -------------------------------------------------------------------------------- 1 | SELECT 2 | SUB.SubscriptionID, 3 | SUB.Report_OID, 4 | CAT.Path, 5 | CAT.Name, 6 | USR.username, 7 | SUB.Description AS SchedulName, 8 | SUB.EventType, 9 | HIST.SubscriptionHistoryID, 10 | HIST.StartTime, 11 | Hist.EndTime, 12 | DATEDIFF(SECOND,HIST.StartTime,Hist.EndTime) AS Dure, 13 | HIST.Status, 14 | HIST.Message, 15 | CASE 16 | WHEN HIST.Status = 0 THEN 'Data refresh finished sucessfully' 17 | WHEN HIST.Status = 1 THEN 'Data refresh is in progress' 18 | ELSE 'Error during refresh' 19 | END AS RESULT 20 | FROM 21 | dbo.Subscriptions SUB 22 | INNER JOIN dbo.Users USR ON USR.UserID = SUB.OwnerID 23 | INNER JOIN SubscriptionHistory HIST ON HIST.SubscriptionID = SUB.SubscriptionID 24 | INNER JOIN dbo.Catalog CAT ON CAT.ItemID = SUB.Report_OID -------------------------------------------------------------------------------- /PBI_BPA_Workspace/PBI_BPA_Workspace.pbit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pulsweb/MyScripts/925ba1a04b367f6c52190868a6eb068a7775a572/PBI_BPA_Workspace/PBI_BPA_Workspace.pbit -------------------------------------------------------------------------------- /PBI_BPA_Workspace/PBI_BPA_Workspace.ps1: -------------------------------------------------------------------------------- 1 | # ================================================================================================================================================= 2 | # Best Practice Analyzer for Workspace with XMLA Endpoint 3 | # Romain Casteres - Microsoft Customer Engineer Data & AI - http://pulsweb.fr/ 4 | # Inspirations & Thanks : 5 | # - Tabular Editor : https://docs.tabulareditor.com/Best-Practice-Analyzer.html 6 | # - Michael Kovalsky : https://powerbi.microsoft.com/en-us/blog/best-practice-rules-to-improve-your-models-performance/ 7 | # - Dave Ruijter : https://www.moderndata.ai/2020/09/check-the-quality-of-all-power-bi-data-models-at-once-with-best-practice-analyzer-automation-bpaa/ 8 | # ================================================================================================================================================= 9 | 10 | # Parameters 11 | $ConnectionMode = 2 # 1 for SSPI | 2 for Login and Password | 3 for Service Principal 12 | $PowerBIServicePrincipalTenantId = "###" 13 | $PowerBIServicePrincipalClientId = "###" 14 | $PowerBIServicePrincipalSecret = "###" 15 | $PowerBIUserId = "###" 16 | $PowerBIPassword = "###" 17 | $OutputDirectory = "C:\temp\" 18 | $TabularEditorPortableExePath = "C:\Program Files (x86)\Tabular Editor\TabularEditor.exe" 19 | $PremiumWokspaceNameToBeAnalyzed = "###" #PREMIUM REQUIRED 20 | $TabularEditorBPARulesPath = "https://raw.githubusercontent.com/microsoft/Analysis-Services/master/BestPracticeRules/BPARules.json" 21 | $biglistofdatasets = [System.Collections.ArrayList]::new() 22 | $CurrentDateTime = (Get-Date).tostring("yyyyMMdd-HHmmss") 23 | $OutputDir = Join-Path -Path $OutputDirectory -ChildPath "\$CurrentDateTime" 24 | new-item $OutputDir -itemtype directory -Force | Out-Null 25 | 26 | # Download BPA Rules 27 | [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 28 | wget $TabularEditorBPARulesPath -outfile $OutputDir"\Rules.json" 29 | 30 | # Runctions to call the .exe - Author: https://mnaoumov.wordpress.com/ 31 | function Test-CalledFromPrompt { 32 | (Get-PSCallStack)[-2].Command -eq "prompt" 33 | } 34 | function Invoke-NativeApplication { 35 | param ( 36 | [ScriptBlock] $ScriptBlock, 37 | [int[]] $AllowedExitCodes = @(0), 38 | [switch] $IgnoreExitCode 39 | ) 40 | $backupErrorActionPreference = $ErrorActionPreference 41 | $ErrorActionPreference = "Continue" 42 | try { 43 | if (Test-CalledFromPrompt) { 44 | $lines = & $ScriptBlock 45 | } else { 46 | $lines = & $ScriptBlock 2>&1 47 | } 48 | $lines | ForEach-Object -Process { 49 | $isError = $_ -is [System.Management.Automation.ErrorRecord] 50 | "$_" | Add-Member -Name IsError -MemberType NoteProperty -Value $isError -PassThru 51 | } 52 | if ((-not $IgnoreExitCode) -and ($AllowedExitCodes -notcontains $LASTEXITCODE)){ 53 | throw "Execution failed with exit code $LASTEXITCODE" 54 | } 55 | } 56 | finally{ 57 | $ErrorActionPreference = $backupErrorActionPreference 58 | } 59 | } 60 | 61 | # Connection 62 | IF ($WithServicePrincipal -eq "True") { 63 | Write-Host "Connecting with Service Principal..." 64 | $secureServicePrincipalSecretBis = $PowerBIServicePrincipalSecret | ConvertTo-SecureString -AsPlainText -Force 65 | $credential = New-Object PSCredential -ArgumentList $PowerBIServicePrincipalClientId, $secureServicePrincipalSecretBis 66 | Connect-PowerBIServiceAccount -ServicePrincipal -Credential $credential -Tenant $PowerBIServicePrincipalTenantId 67 | } ELSE { 68 | Write-Host "Connecting to the service..." 69 | Connect-PowerBIServiceAccount 70 | } 71 | 72 | # BPA for every Datasets within the Workspace 73 | $workspaces = Get-PowerBIWorkspace -Name $PremiumWokspaceNameToBeAnalyzed 74 | if ($workspaces) { 75 | $workspacesOutputPath = Join-Path -Path $OutputDirectory -ChildPath "\$CurrentDateTime\Workspaces.json" 76 | $workspaces | ConvertTo-Json -Compress | Out-File -FilePath $workspacesOutputPath 77 | $workspaces | Where-Object {$_.IsOnDedicatedCapacity -eq $True} | ForEach-Object { 78 | $workspaceName = $_.Name 79 | $worskpaceId = $_.Id 80 | Write-Host "Premium workspace: $workspaceName" 81 | $datasets = Get-PowerBIDataset -WorkspaceId $_.Id | Where-Object {$_.Name -ne "Report Usage Metrics Model"} 82 | $datasets | Add-Member -MemberType NoteProperty -Name "WorkspaceId" -Value $worskpaceId 83 | $biglistofdatasets += $datasets 84 | if ($datasets) { 85 | $datasets | ForEach-Object { 86 | $datasetName = $_.Name 87 | Write-Host "- Dataset: $datasetName" 88 | $DatasetTRXOutputDir = Join-Path -Path $OutputDirectory -ChildPath "\$CurrentDateTime\" 89 | new-item $DatasetTRXOutputDir -itemtype directory -Force | Out-Null 90 | $DatasetTRXOutputPath = Join-Path -Path $DatasetTRXOutputDir -ChildPath "\$workspaceName - $datasetName.trx" 91 | Write-Host "--- Performing Best Practice Analyzer on dataset: $datasetName." 92 | Write-Host "--- Output saved: $DatasetTRXOutputPath." 93 | Switch ($ConnectionMode){ 94 | 1 { 95 | Write-Host "----- Connecting with SSPI" 96 | Invoke-NativeApplication { cmd /c """$TabularEditorPortableExePath"" ""Provider=MSOLAP;Data Source=powerbi://api.powerbi.com/v1.0/myorg/$workspaceName;Integrated Security=SSPI;"" ""$datasetName"" -A ""$TabularEditorBPARulesPath"" -TRX ""$DatasetTRXOutputPath""" } @(0, 1) $True | Out-Null 97 | } 98 | 2 { 99 | Write-Host "----- Connecting with Login and Password" 100 | Invoke-NativeApplication { cmd /c """$TabularEditorPortableExePath"" ""Provider=MSOLAP;Data Source=powerbi://api.powerbi.com/v1.0/myorg/$workspaceName;User ID=$PowerBIUserId;Password=$PowerBIPassword;"" ""$datasetName"" -A ""$TabularEditorBPARulesPath"" -TRX ""$DatasetTRXOutputPath""" } @(0, 1) $True | Out-Null 101 | } 102 | 3 { 103 | Write-Host "----- Connecting with Service Principal" 104 | Invoke-NativeApplication { cmd /c """$TabularEditorPortableExePath"" ""Provider=MSOLAP;Data Source=powerbi://api.powerbi.com/v1.0/myorg/$workspaceName;User ID=app:$PowerBIServicePrincipalClientId@$PowerBIServicePrincipalTenantId;Password=$($credential.getNetworkCredential().password)"" ""$datasetName"" -A ""$TabularEditorBPARulesPath"" -TRX ""$DatasetTRXOutputPath""" } @(0, 1) $True | Out-Null 105 | } 106 | } 107 | } 108 | } 109 | } 110 | Write-Host "Finished on workspace: $workspaceName." 111 | } 112 | $datasetsOutputPath = Join-Path -Path $OutputDirectory -ChildPath "\$CurrentDateTime\Datasets.json" 113 | $biglistofdatasets | ConvertTo-Json -Compress | Out-File -FilePath $datasetsOutputPath -------------------------------------------------------------------------------- /Power BI/Export-PbiLicenses.ps1: -------------------------------------------------------------------------------- 1 | # Romain Casteres - https://www.pulsweb.fr 2 | 3 | $PBIAdminUPN = "" 4 | $PBIAdminPW = "" 5 | $TenantID = "" 6 | 7 | $SecPasswd = ConvertTo-SecureString $PBIAdminPW -AsPlainText -Force 8 | $myCred = New-Object System.Management.Automation.PSCredential($PBIAdminUPN,$SecPasswd) 9 | Connect-AzureAD -TenantId $TenantID -Credential $myCred 10 | 11 | $RetrieveDate = Get-Date 12 | $BasePath = "C:\Users\romainca\Desktop\PBI Licences\" 13 | $AzureADUsersCSV = $BasePath + "LicencesUsers.csv" 14 | $OrgO365LicensesCSV = $BasePath + "LicensesOrgO365.csv" 15 | $UserPBIProLicensesCSV = $BasePath + "LicensesUserPBIPro.csv" 16 | 17 | $PBIProServicePlanID = "70d33638-9c74-4d01-bfd3-562de28bd4ba" 18 | 19 | Write-Host "Retrieve and export users" 20 | $ADUsers = Get-AzureADUser -All $true | Select-Object ObjectId, ObjectType, CompanyName, Department, DisplayName, Mail, UserPrincipalName, UserType, @{Name="Date Retrieved";Expression={$RetrieveDate}} 21 | 0..($ADUsers.count-1) | foreach { 22 | $percent = ($_/$ADUsers.count)*100 23 | Write-Progress -Activity 'Retrieve and export users to CSV' -Status "$percent % Complete" -CurrentOperation "Exporting item # $($_+1)" -PercentComplete $percent 24 | $ADUsers[$_] 25 | } | Export-Csv $AzureADUsersCSV -NoTypeInformation -Force 26 | 27 | Write-Host "Retrieve and export organizational licenses" 28 | $OrgO365Licenses = Get-AzureADSubscribedSku | Select-Object SkuID, SkuPartNumber,CapabilityStatus, ConsumedUnits -ExpandProperty PrepaidUnits | ` 29 | Select-Object SkuID,SkuPartNumber,CapabilityStatus,ConsumedUnits,Enabled,Suspended,Warning, @{Name="Retrieve Date";Expression={$RetrieveDate}} 30 | 0..($OrgO365Licenses.count-1) | foreach { 31 | $percent = ($_/$OrgO365Licenses.count)*100 32 | Write-Progress -Activity 'Retrieve and export organizational licenses to CSV' -Status "$percent % Complete" -CurrentOperation "Exporting item # $($_+1)" -PercentComplete $percent 33 | $OrgO365Licenses[$_] 34 | } | Export-Csv $OrgO365LicensesCSV -NoTypeInformation -Force 35 | 36 | Write-Host "Retrieve and export users with pro licenses based on Power BI Pro service plan ID" 37 | $ProUsersCounter = 0 38 | $ProUsersCount = $ADUsers.Count 39 | $UserLicenseDetail = ForEach ($ADUser in $ADUsers){ 40 | $UserObjectID = $ADUser.ObjectId 41 | $UPN = $ADUser.UserPrincipalName 42 | Get-AzureADUserLicenseDetail -ObjectId $UserObjectID -ErrorAction SilentlyContinue | ` 43 | Select-Object ObjectID, @{Name="UserPrincipalName";Expression={$UPN}} -ExpandProperty ServicePlans 44 | Write-Progress -Activity "Retreiving users licences, set `$Licences to `$False and rerun the script" -PercentComplete ($ProUsersCounter * 100.0/$ProUsersCount) 45 | $ProUsersCounter += 1 46 | } 47 | $ProUsers = $UserLicenseDetail | Where-Object {$_.ServicePlanId -eq $PBIProServicePlanID} 48 | $ProUsers | Export-Csv $UserPBIProLicensesCSV -NoTypeInformation -Force -------------------------------------------------------------------------------- /Power BI/Export-PbiRefreshHistory.ps1: -------------------------------------------------------------------------------- 1 | # Romain Casteres - https://www.pulsweb.fr 2 | 3 | # The output folder to put all the extracts 4 | $folder = "out" 5 | $folderFullPath = "$PSScriptRoot\$folder" 6 | 7 | If(!(test-path $folderFullPath)){ 8 | New-Item -ItemType Directory -Force -Path $folderFullPath 9 | } 10 | 11 | # Installing PbiAdminModules if not present 12 | if (Get-Module -ListAvailable -Name "MicrosoftPowerBIMgmt") { 13 | Write-Host "MicrosoftPowerBIMgmt Module exists" 14 | } else { 15 | Write-Host "MicrosoftPowerBIMgmt Module does not exist - Installing it..." 16 | Install-PbiAdminModules 17 | } 18 | 19 | # Prompt the user for credentials 20 | $credential = (Get-Credential -Message "Credentials") 21 | 22 | # Log in to Power BI 23 | Login-PowerBIServiceAccount -Credential $credential 24 | 25 | # Store the Auth token 26 | $auth = (Get-PowerBIAccessToken).Authorization 27 | 28 | Write-Host 'Building Rest API header with authorization token' 29 | $authHeader = @{ 30 | 'Content-Type'='application/json' 31 | 'Authorization'='Bearer ' + $auth 32 | } 33 | 34 | $TopN = 50 35 | $headers = @{ 36 | "Authorization" = $auth; 37 | "X-PowerBI-User-Admin" = $true 38 | } 39 | 40 | $FileName = "$folderFullPath\PowerBI-RefreshHistory.csv" 41 | if (Test-Path $FileName) { 42 | Remove-Item $FileName 43 | } 44 | 45 | $workspaces = Get-PowerBIWorkspace 46 | 47 | foreach($workspaces in $workspaces){ 48 | 49 | Write-Host "> Workspace: $($workspaces.Name)" 50 | 51 | $datasets = Get-PowerBIDataset -WorkspaceId $workspaces.Id 52 | 53 | $refreshes = @() 54 | 55 | foreach($dataset in $datasets){ 56 | 57 | if($dataset.IsRefreshable -eq "True") { 58 | 59 | Write-Host ">> Dataset: $($dataset.name)" 60 | 61 | $uri = "https://api.powerbi.com/v1.0/myorg/groups/$($workspaces.Id)/datasets/$($dataset.id)/refreshes/?`$top=$($TopN)" 62 | 63 | $refresh = Invoke-RestMethod -Uri $uri -Headers $headers -Method GET 64 | $refresh.value | Add-Member -NotePropertyName "DatasetID" -NotePropertyValue $dataset.id 65 | $refresh.value | Add-Member -NotePropertyName "DatasetName" -NotePropertyValue $dataset.name 66 | $refresh.value | Add-Member -NotePropertyName "WorkspaceID" -NotePropertyValue $workspaces.Id 67 | $refreshes += $refresh 68 | } 69 | } 70 | 71 | $refreshes.value | ForEach-Object { 72 | New-Object PSObject -Property @{ 73 | id = $_.id; 74 | refreshType = $_.refreshType; 75 | startTime = $_.startTime; 76 | endTime = $_.endTime; 77 | serviceExceptionJson = $_.serviceExceptionJson; 78 | status = $_.status; 79 | DatasetID = $_.DatasetID; 80 | DatasetName = $_.DatasetName; 81 | WorkspaceID = $_.WorkspaceID; 82 | } 83 | } | Export-Csv -Path $FileName -NoTypeInformation -Append 84 | } 85 | -------------------------------------------------------------------------------- /Power BI/PBIRS_ModelSize.sql: -------------------------------------------------------------------------------- 1 | -- Romain Casteres 2 | -- PBIRS Model Size 3 | 4 | SELECT 5 | c.ItemID, 6 | c.[Path], 7 | c.[Name] AS ReportName, 8 | ISNULL(cp.[Name], 'Root') AS ParentItem, 9 | CASE c.[Type] 10 | WHEN 1 THEN 'Folder' 11 | WHEN 2 THEN 'Report' 12 | WHEN 3 THEN 'Resources' 13 | WHEN 4 THEN 'Linked Report' 14 | WHEN 5 THEN 'Data Source' 15 | WHEN 6 THEN 'Report Model' 16 | WHEN 7 THEN 'Report Part' 17 | WHEN 8 THEN 'Shared dataset' 18 | WHEN 11 THEN 'KPI Card' 19 | WHEN 13 THEN 'PowerBI' 20 | ELSE CAST(c.[Type] AS VARCHAR(10)) 21 | END AS ItemType, 22 | c.Property, 23 | c.[Description], 24 | c.[Hidden], 25 | cu.UserName AS CreatedBy, 26 | c.CreationDate, 27 | mu.UserName AS ModifiedBy, 28 | c.ModifiedDate, 29 | ISNULL(CAST(c.ContentSize AS FLOAT) / CAST((1024 * 1024) AS FLOAT), 0) AS ContentSizeMb 30 | FROM dbo.[Catalog] c 31 | LEFT OUTER JOIN dbo.[Catalog] cp ON c.ParentID = cp.ItemID 32 | LEFT OUTER JOIN dbo.Users cu ON c.CreatedByID = cu.UserID 33 | LEFT OUTER JOIN dbo.Users mu ON c.ModifiedByID = mu.UserID 34 | WHERE LEFT(c.[Path], 14) <> '/Users Folders'; -------------------------------------------------------------------------------- /Power BI/Query PBI Dataset in Scale-Out.ps1: -------------------------------------------------------------------------------- 1 | [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.AnalysisServices.AdomdClient") 2 | 3 | $PowerBILogin = "###" 4 | $PowerBIPassword = "###" 5 | $Query = "Evaluate Query1" 6 | 7 | $PowerBIEndpoint = "powerbi://api.powerbi.com/v1.0/myorg/RCA_ScaleOut?readonly;initial catalog=ScaleOut_Test" 8 | $Connection = New-Object Microsoft.AnalysisServices.AdomdClient.AdomdConnection 9 | $Results = New-Object System.Data.DataTable 10 | $Connection.ConnectionString = "Datasource="+ $PowerBIEndpoint +";UID="+ $PowerBILogin +";PWD="+ $PowerBIPassword 11 | $Connection.Open() 12 | $Adapter = New-Object Microsoft.AnalysisServices.AdomdClient.AdomdDataAdapter $Query ,$Connection 13 | $Adapter.Fill($Results) 14 | $Results 15 | $Connection.Dispose() 16 | $Connection.Close() 17 | 18 | $PowerBIEndpoint = "powerbi://api.powerbi.com/v1.0/myorg/RCA_ScaleOut?readwrite;initial catalog=ScaleOut_Test" 19 | $Connection = New-Object Microsoft.AnalysisServices.AdomdClient.AdomdConnection 20 | $Results = New-Object System.Data.DataTable 21 | $Connection.ConnectionString = "Datasource="+ $PowerBIEndpoint +";UID="+ $PowerBILogin +";PWD="+ $PowerBIPassword 22 | $Connection.Open() 23 | $Adapter = New-Object Microsoft.AnalysisServices.AdomdClient.AdomdDataAdapter $Query ,$Connection 24 | $Adapter.Fill($Results) 25 | $Results 26 | $Connection.Dispose() 27 | $Connection.Close() 28 | -------------------------------------------------------------------------------- /Power BI/README.md: -------------------------------------------------------------------------------- 1 | Power BI Scripts -------------------------------------------------------------------------------- /Power BI/Update-AdminUserWorkspaces.ps1: -------------------------------------------------------------------------------- 1 | # Romain Casteres - https://www.PulsWeb.fr 2 | # Following script is adding users as admin of all workspaces [Administrator rights required] 3 | # "A person with a Power BI Pro license can be a member of a maximum 1,000 workspaces" Source : https://docs.microsoft.com/en-us/power-bi/collaborate-share/service-new-workspaces#limitations-and-considerations 4 | 5 | $UserMail = "###@###" 6 | 7 | $folder = "out" 8 | $folderFullPath = "$PSScriptRoot\$folder" 9 | If(!(test-path $folderFullPath)){ 10 | New-Item -ItemType Directory -Force -Path $folderFullPath 11 | } 12 | $FileName = "$folderFullPath\UpdatedWorkspaces.csv" 13 | if (Test-Path $FileName) { 14 | Remove-Item $FileName 15 | } 16 | 17 | # Installing PbiAdminModules if not present 18 | if (Get-Module -ListAvailable -Name "MicrosoftPowerBIMgmt") { 19 | Write-Host "MicrosoftPowerBIMgmt Module exists" 20 | #Update-Module MicrosoftPowerBIMgmt 21 | } else { 22 | Write-Host "MicrosoftPowerBIMgmt Module does not exist - Installing it..." 23 | Install-PbiAdminModules 24 | } 25 | Import-Module MicrosoftPowerBIMgmt 26 | 27 | Connect-PowerBIServiceAccount 28 | 29 | # Get the list of workspaces as a Power BI User and as Admin User 30 | $myWorkspaces = Get-PowerBIWorkspace 31 | $tentantWorkspaces = Get-PowerBIWorkspace -Scope Organization -All 32 | Write-Host “The current user has –” $myWorkspaces.Count “– workspaces. There are –” $tentantWorkspaces.Count “– workspaces in this Power BI tenant.” 33 | 34 | # Get the list of all workspaces and add Uset as Admin 35 | $Groups = Get-PowerBIWorkspace -Scope Organization -All # -First 5 36 | $Groups = $Groups | SELECT Id, Name, Type, State, Users | WHERE State -NE 'Deleted' 37 | #FILTER ON PERSONAL WORKSPACE 38 | $GroupWorkspaces = $Groups | WHERE Type -eq 'Workspace' 39 | $GroupWorkspaces | ForEach-Object { 40 | if($_.Users.UserPrincipalName -contains $UserMail) { 41 | Write-Host $UserMail "is already administrator of the" $_.Id "Workspace" 42 | } else { 43 | Write-Host "Adding" $UserMail "as administrator of the" $_.Id "Workspace" 44 | Add-PowerBIWorkspaceUser -Scope Organization -Id $_.Id -UserEmailAddress $UserMail -AccessRight Admin -WarningAction Ignore 45 | New-Object PSObject -Property @{ 46 | Id = $_.Id; 47 | Name = $_.Name; 48 | } 49 | } 50 | } | Export-CSV $FileName -NoTypeInformation -Encoding UTF8 -Force 51 | 52 | # Get the list of workspaces as a Power BI User and as Admin User 53 | $myWorkspaces = Get-PowerBIWorkspace 54 | $tentantWorkspaces = Get-PowerBIWorkspace -Scope Organization -All 55 | Write-Host “The current user has –” $myWorkspaces.Count “– workspaces. There are –” $tentantWorkspaces.Count “– workspaces in this Power BI tenant.” 56 | 57 | Disconnect-PowerBIServiceAccount -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Romain Casteres 2 | 3 | Cloud Solution Architect @ Microsoft | Unlocking Customer Data Value 4 | 5 | Blogger at https://www.pulsweb.fr/ 6 | -------------------------------------------------------------------------------- /SQL/README.md: -------------------------------------------------------------------------------- 1 | SQL Scripts --------------------------------------------------------------------------------