C Sharp Scripting logo

C Sharp Scripting

CommunityPopular
data-goblin
c-sharp-scripting

Writing and executing C# scripts and macros against Power BI semantic models using Tabular Editor 2/3. Automatically invoke when the user mentions "C# script", "Tabular Editor script", "TOM scripting", "MacroActions.json", "XMLA", or asks to "automate model changes", "bulk update measures", "create calculation groups", "write a macro", "format DAX expressions", "manage model metadata".

Overview

Publisherdata-goblin
Repositorypower-bi-agentic-development
Skill namec-sharp-scripting
Stars
1K
Forks
149
Bundled files
206
LicenseGPL-3.0
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • 206 bundled files

    Scripts, templates, and references the model can read while it works. Files are read-only and never executed.

  • Open source

    Published by data-goblin on GitHub. Read the source before you install it.

Installation

Install the C Sharp Scripting AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
    https://github.com/data-goblin/power-bi-agentic-development/tree/main/plugins/tabular-editor/skills/c-sharp-scripting
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/data-goblin/power-bi-agentic-development.git /tmp/power-bi-agentic-development
mkdir -p .claude/skills
cp -r /tmp/power-bi-agentic-development/plugins/tabular-editor/skills/c-sharp-scripting .claude/skills/c-sharp-scripting
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable C Sharp Scripting in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads C Sharp Scripting on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so C Sharp Scripting is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

C# Scripting for Tabular Editor

Expert guidance for writing and executing C# scripts to manipulate Power BI semantic model metadata using Tabular Editor 2/3 CLI or the Tabular Editor IDE.

When to Use This Skill

Activate automatically when tasks involve:

  • Writing C# scripts for Tabular Editor
  • Bulk operations on model objects (measures, columns, tables)
  • Creating or modifying calculation groups
  • Managing model security (roles, RLS, OLS)
  • Formatting DAX expressions
  • Automating repetitive model changes
  • Querying model metadata via TOM API
  • Building interactive scripts with user input dialogs

Critical

  • Every statement must end with ; (semicolon required by C#)
  • Use double quotes " for strings and escape with \ when needed
  • Use forward slashes / in DisplayFolder paths (auto-converted to \)
  • Always add Info() statements for debugging - script stops at error point
  • Test scripts on non-production models first
  • Changes are undoable with Ctrl+Z in the Tabular Editor UI

C# Version Support

EnvironmentC# VersionNotes
Tabular Editor 2Default compilerOlder C# syntax
Tabular Editor 3RoslynSupports up to C# 12 with VS2022
TE2 with RoslynConfigurableSet in File > Preferences > General

To use newer C# features in TE2, configure Roslyn compiler path in preferences.

Default Imports and Assemblies

Auto-Imported Namespaces

Scripts automatically have these using statements applied:

csharp
using System;
using System.Linq;
using System.Collections.Generic;
using Newtonsoft.Json;
using TabularEditor.TOMWrapper;
using TabularEditor.TOMWrapper.Utils;
using TabularEditor.UI;

Pre-Loaded Assemblies

These .NET assemblies are loaded by default:

  • System.Dll
  • System.Core.Dll
  • System.Data.Dll
  • System.Windows.Forms.Dll (for UI dialogs)
  • Microsoft.Csharp.Dll
  • Newtonsoft.Json.Dll
  • TomWrapper.Dll
  • TabularEditor.Exe
  • Microsoft.AnalysisServices.Tabular.Dll

Adding External Assemblies

csharp
// Assembly references must be at the very top of the file:
#r "System.IO.Compression"
#r "System.Drawing"

// Using statements come after assembly references:
using System.IO.Compression;
using System.Drawing;

Prerequisites

For Tabular Editor CLI

RequirementDescription
Tabular Editor 2 CLIDownload from GitHub releases
XMLA Read/WriteEnabled on Fabric capacity or Power BI Premium
Azure Service PrincipalFor XMLA connections (see authentication.md)

Environment Variables (for XMLA)

AZURE_CLIENT_ID=<app-id>
AZURE_TENANT_ID=<tenant-id>
AZURE_CLIENT_SECRET=<secret>

Execution Methods

1. Tabular Editor CLI

bash
# Inline script
TabularEditor.exe "WorkspaceName/ModelName" -S "Info(Model.Database.Name);"

# Script file
TabularEditor.exe "WorkspaceName/ModelName" -S "script.csx"

2. Connection Types

TypeFormatExample
XMLAworkspace/model"Sales WS/Sales Model"
Local BIMpath/to/model.bim"./model.bim"
Local TMDLpath/to/definition/"./MyModel.SemanticModel/definition/"
PBI Desktoplocalhost:PORT"localhost:52123"

Core Objects

The Model Object

Access any object in the loaded Tabular Model:

csharp
Model                           // Root model object
Model.Tables                    // All tables
Model.Tables["Sales"]           // Specific table
Model.AllMeasures               // All measures across all tables
Model.AllColumns                // All columns across all tables
Model.Relationships             // All relationships
Model.Roles                     // All security roles
Model.CalculationGroups         // All calculation groups
Model.Perspectives              // All perspectives
Model.Cultures                  // All translations/cultures
Model.Expressions               // All M expressions (shared queries)
Model.DataSources               // All data sources

The Selected Object

Access objects currently selected in the TOM Explorer (IDE only):

csharp
// Plural form - collections (safe even when empty)
Selected.Tables                 // Selected tables
Selected.Measures               // Selected measures
Selected.Columns                // Selected columns
Selected.Hierarchies            // Selected hierarchies

// Singular form - single object (error if not exactly one selected)
Selected.Table                  // The single selected table
Selected.Measure                // The single selected measure
Selected.Column                 // The single selected column

// Set properties on multiple objects at once
Selected.Measures.DisplayFolder = "Test";
Selected.Columns.IsHidden = true;

// Bulk rename with pattern
Selected.Measures.Rename("Amount", "Value");

When a Display Folder is selected, all child items are included in the selection.

LINQ Fundamentals

LINQ is essential for filtering and transforming TOM collections. See references/linq-reference.md for the full method table, lambda syntax, and examples.

Key methods: Where(), First(), FirstOrDefault(), Any(), All(), Count(), Select(), OrderBy(), ForEach(), ToList().

csharp
// Common pattern: filter, chain, act
Model.AllMeasures
    .Where(m => m.Name.Contains("Revenue"))
    .Where(m => string.IsNullOrEmpty(m.FormatString))
    .ForEach(m => m.FormatString = "$#,0");

Helper Methods

See references/helper-methods.md for the complete reference including Output() variations, file operations, property export/import, interactive selection dialogs, DAX formatting/execution, and macro invocation.

MethodPurpose
Info(message)Display info popup (CLI: writes to console)
Warning(message)Display warning popup
Error(message)Display error popup and stop script
Output(object)Display detailed object inspector dialog
SaveFile(path, content) / ReadFile(path)File I/O
ExportProperties() / ImportProperties()TSV export/import
SelectMeasure() / SelectTable()Interactive selection (IDE only)
FormatDax() / CallDaxFormatter()DAX formatting
EvaluateDax() / ExecuteDax()DAX execution (connected)

WinForms UI Patterns

For interactive dialogs (input forms, dropdowns, multi-select), see references/winforms-dialogs.md. Key setup: #r "System.Drawing", ScriptHelper.WaitFormVisible = false;

Quick Reference

Core Patterns

Add a Measure:

csharp
var m = Model.Tables["Sales"].AddMeasure("Total Revenue", "SUM(Sales[Amount])");
m.FormatString = "$#,0";
m.DisplayFolder = "Key Metrics";
m.Description = "Total sales revenue";
Info("Added: " + m.Name);

Iterate Tables/Columns:

csharp
foreach(var t in Model.Tables) {
    foreach(var c in t.Columns.Where(c => c.Name.EndsWith("Key"))) {
        c.IsHidden = true;
    }
}
Info("Hidden key columns");

Conditional Operations:

csharp
foreach(var m in Model.AllMeasures) {
    if(m.Name.Contains("Revenue")) m.FormatString = "$#,0";
    if(m.Name.Contains("Rate")) m.FormatString = "0.00%";
}

Create Calculation Group:

csharp
var cg = Model.AddCalculationGroup("Time Intelligence");
cg.Precedence = 10;

var ytd = cg.AddCalculationItem("YTD", "CALCULATE(SELECTEDMEASURE(), DATESYTD('Date'[Date]))");
var prior = cg.AddCalculationItem("Prior Year");
prior.Expression = @"
CALCULATE(
    SELECTEDMEASURE(),
    DATEADD('Date'[Date], -1, YEAR)
)
";
Info("Created calculation group");

TOM API Quick Reference

ObjectAccessCommon Properties
ModelModel.Tables, .AllMeasures, .Relationships
TableModel.Tables["Name"].Measures, .Columns, .Partitions, .IsHidden
MeasureTable.Measures["Name"].Expression, .FormatString, .DisplayFolder, .Description
ColumnTable.Columns["Name"].DataType, .FormatString, .IsHidden, .SummarizeBy
RelationshipModel.Relationships.FromTable, .ToTable, .IsActive, .CrossFilteringBehavior
RoleModel.Roles["Name"].Members, .TablePermissions
HierarchyTable.Hierarchies.Levels, .DisplayFolder, .IsHidden
PartitionTable.Partitions.Expression, .SourceType, .DataSource
PerspectiveModel.PerspectivesObjects have .InPerspective["Name"]
CultureModel.CulturesObjects have .TranslatedNames["culture"]

Object Type Reference

Detailed documentation for each object type in object-types/:

  • tables.md - Table CRUD, properties, partitions
  • columns.md - Column types, properties, sorting
  • measures.md - Measure creation, formatting, organization
  • relationships.md - Relationship management
  • calculation-groups.md - Calculation groups and items
  • roles.md - Roles, RLS, OLS configuration
  • hierarchies.md - Hierarchy and level management
  • partitions.md - Partition types and configuration
  • perspectives.md - Perspective membership
  • translations.md - Culture and translation management
  • annotations.md - Custom metadata annotations

Example Scripts

180 working .csx scripts organized by category in examples/. Before writing a script from scratch, check if a relevant example already exists -- read the example, adapt it to the task, and modify as needed.

CategoryScriptsDescription
bulk-operations/8Model initialization, batch updates, clean names, sync folders, validate
calculation-groups/2Time intelligence, currency conversion
columns/20Data types, hiding, sorting, encoding hints, cardinality, properties
cultures/4Add/delete cultures, list, modify translations
display-folders/8Organize by type, clear, rename, add/remove folders
evaluate-dax/5Execute DAX, scalar queries, table queries, column sizes, optimize
format-dax/8Format measures, calculated columns/tables, KPIs, detail rows
format-strings/6Apply by name/pattern, custom formats, dynamic format strings
functions/4Add/delete/list/modify shared M functions
hierarchies/4Add/delete/list/modify hierarchies
kpis/4Add/delete/list/modify KPIs
measures/18Full CRUD, time intelligence, bulk create, move, hide/unhide
model/10Properties, compatibility level, dependencies, refresh, export stats
partitions/6Refresh, find-replace M, incremental refresh, hybrid tables
perspectives/4Add/delete/list/modify perspectives
relationships/5Create, naming conventions, RI violations, integrity, properties
roles/7Add/delete roles, members, RLS, OLS configuration
shared-expressions/6Named expressions, range parameters, M functions
svg-measures/15Bar charts, bullet charts, dumbbells, lollipops, waterfall, jitter
tables/36All table types (import, DirectQuery, Direct Lake, calculated, field parameter, date), refresh policies, RLS/OLS, properties

Common Workflows

See references/common-workflows.md for complete workflow scripts: bulk format measures, create time intelligence measures, configure RLS, audit hidden objects. Also check examples/ for 180 working .csx scripts before writing from scratch.

Debugging & Troubleshooting

Script Doesn't Complete

Add Info() checkpoints to find where script fails:

csharp
Info("Step 1: Starting");
var table = Model.Tables["Sales"];
Info("Step 2: Got table");
var measure = table.AddMeasure("Test", "1");
Info("Step 3: Added measure");  // If this doesn't appear, AddMeasure failed

Object Not Found

Check existence before accessing:

csharp
if(Model.Tables.Contains("Sales")) {
    var table = Model.Tables["Sales"];
    // ...
} else {
    Error("Table 'Sales' not found");
}

// Or use FirstOrDefault
var table = Model.Tables.FirstOrDefault(t => t.Name == "Sales");
if(table == null) {
    Error("Table not found");
}

Changes Not Appearing

  • XMLA operations may take 2-5 seconds to sync
  • Refresh Power BI Desktop connection after changes
  • Check for silent errors (add Info() after each operation)

TE2/TE3 Compatibility

Use preprocessor directives for version-specific code:

csharp
#if TE3
    // TE3-specific code (version 3.10.0+)
    Info("Running in Tabular Editor 3");
#else
    // TE2 fallback
    Info("Running in Tabular Editor 2");
#endif

Check version at runtime:

csharp
var majorVersion = Selected.GetType().Assembly.GetName().Version.Major;
if(majorVersion >= 3) {
    // TE3 code
}

Best Practices

  1. Add Info() statements - Track script execution and catch errors early
  2. Check object existence - Use .Contains() or .Any() before accessing
  3. Use bulk operations - Single script with loops is faster than multiple scripts
  4. Test on dev models - Never test new scripts on production
  5. Use @"..." for DAX - Multi-line strings for DAX expressions
  6. Format with FormatDax() - After creating measures/columns
  7. Set DisplayFolder with / - Forward slashes auto-convert to backslashes
  8. Hide the wait spinner - ScriptHelper.WaitFormVisible = false; for UI dialogs

Additional Resources

Reference Files

  • object-types/ - Detailed API docs per object type
  • examples/ - 180 working .csx scripts across 20 categories; always check here before writing from scratch

Fetching Docs

To retrieve current TOM API reference docs, use microsoft_docs_search + microsoft_docs_fetch (MCP) if available, otherwise mslearn search + mslearn fetch (CLI). Search based on the user's request and run multiple searches as needed to ensure sufficient context before proceeding.

External References

Bundled files

The model reads these on demand while the skill is loaded. They are exposed as readable files and are never executed.

and 140 more files.

Frequently asked questions

What does the C Sharp Scripting AI skill do?

Writing and executing C# scripts and macros against Power BI semantic models using Tabular Editor 2/3. Automatically invoke when the user mentions "C# script", "Tabular Editor script", "TOM scripting", "MacroActions.json", "XMLA", or asks to "automate model changes", "bulk update measures", "create calculation groups", "write a macro", "format DAX expressions", "manage model metadata".

Why use C Sharp Scripting on TypingMind?

Because you install it once and use it with any model. C Sharp Scripting is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install C Sharp Scripting in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/data-goblin/power-bi-agentic-development/tree/main/plugins/tabular-editor/skills/c-sharp-scripting. TypingMind reads its SKILL.md and bundles its files and installs it as a skill you can enable per chat.

Which AI models can use C Sharp Scripting?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with C Sharp Scripting?

As many as you like. As long as a model supports skills, you can use C Sharp Scripting with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the C Sharp Scripting AI skill free?

Yes. It is published on GitHub by data-goblin under the GPL-3.0 license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇