Skip to content

Manage entity ribbon buttons

crm ribbon reads and edits an entity's command-bar (ribbon) buttons.

Export the current ribbon

Export a single entity's composed ribbon, or the application-wide ribbon (commands not bound to any specific table):

crm ribbon export cwx_ticket            # one table's ribbon — readable XML to stdout
crm ribbon export cwx_ticket --output ribbon.xml
crm ribbon export --application         # application-wide ribbon to stdout
crm ribbon export --application --output app_ribbon.xml

Pass ENTITY for one table's ribbon, or --application / -a for the app-wide ribbon. Passing both, or neither, is an error. Read-only.

With --solution, export emits the entity's editable RibbonDiffXml fragment from that solution — the importable working-copy file for the offline flow below — instead of the composed read-only ribbon:

crm ribbon export cwx_ticket --solution MySolution --output ribbon_diff.xml

--solution requires ENTITY and cannot be combined with --application.

Compose edits offline (working-copy flow)

The per-verb write commands each run a full solution export → import → publish round-trip, and — unlike forms/views — an unpublished RibbonDiffXml is not carried by the solution export (see the warning under Add a JavaScript button). To compose several edits with a single publish, edit a local working-copy file instead:

# 1. Export the entity's editable RibbonDiffXml fragment to a file
crm ribbon export cwx_ticket --solution MySolution --output ribbon_diff.xml

# 2. Apply N edits to the local file — --diff-file makes ZERO backend calls
crm ribbon add-button cwx_ticket --diff-file ribbon_diff.xml \
    --label Validate --location form \
    --webresource cwx_/scripts/x.js --function ns.fn --param PrimaryControl
crm ribbon set-label cwx_ticket --diff-file ribbon_diff.xml \
    --button-id cwx_ticket.form.Validate.CustomAction --label "Validate Ticket"
crm ribbon set-rules cwx_ticket --diff-file ribbon_diff.xml \
    --command-id cwx_ticket.form.Validate.Command \
    --enable-rule Mscrm.SelectionCountExactlyOne

# 3. Import + publish the finished file once
crm ribbon apply cwx_ticket --solution MySolution --from ribbon_diff.xml

--diff-file is available on add-button, add-custom-rule, set-label, set-rules, and remove. In this mode the verb parses the file, applies the same edit, and writes it back — no backend calls — so the edits compose locally and the live pre-validations (web-resource existence, --lcid provisioned-language check) are deferred to apply's import. --diff-file is mutually exclusive with --solution and --publish (passing either together is a usage error).

ribbon apply full-replaces the entity's live RibbonDiffXml with the file verbatim (desired-state: a button you removed offline does not reappear from live state) and publishes once by default; pass --no-publish to stage the import. hide-button has no --diff-file mode — it needs the live composed ribbon to validate its target and derive the command, so it stays live-only.

List custom buttons

crm ribbon list cwx_ticket --solution MySolution

Add a JavaScript button

crm ribbon add-button cwx_ticket --solution MySolution \
    --label Validate --location form \
    --webresource cwx_/scripts/x.js --function ns.fn --param PrimaryControl

--location is form, homegrid, or subgrid. Override the target group with --group <id>. The web resource must already exist in the org/solution. The edit stages by default (no publish); pass --publish to publish it immediately.

Optionally give the button an icon at creation with --modern-image, --image16, and/or --image32 (any subset) — see Set a button's icon below for the slot rules. Omitting all three creates an icon-less button exactly as before.

Publish before editing a staged button

Unlike forms and views, an unpublished RibbonDiffXml is not carried by the solution export that set-label, set-rules, and add-custom-rule read to find their target. A button added without --publish is therefore invisible to those verbs (they fail with … not found / available: []). Add the button with --publish, or run crm solution publish-all before the follow-up edit — or compose the whole set offline with the working-copy flow, which needs no inter-edit publish at all.

Remove a button

crm ribbon remove cwx_ticket --solution MySolution \
    --button-id cwx_ticket.form.Validate.CustomAction --yes

Like add-button, this stages by default; pass --publish to publish the removal immediately (or run crm solution publish-all once your edits are done).

Set a button's label and tooltips

Use set-label to change the display text of a custom command-bar button — its LabelText, ToolTipTitle, and ToolTipDescription — without touching the button's Command, TemplateAlias, Sequence, or Id. Pass at least one of --label, --tooltip-title, or --tooltip-description.

# Set label and tooltip inline (text is XML-escaped automatically)
crm ribbon set-label cwx_ticket \
    --solution MySolution \
    --button-id cwx_ticket.form.Validate.CustomAction \
    --label "Validate Ticket" \
    --tooltip-title "Validate" \
    --tooltip-description "Runs the validation rules for this ticket."

# Preview the change without importing
crm --dry-run ribbon set-label cwx_ticket \
    --solution MySolution \
    --button-id cwx_ticket.form.Validate.CustomAction \
    --label "Validate Ticket"

# Localize for a specific language (e.g. Arabic, LCID 1025)
crm ribbon set-label cwx_ticket \
    --solution MySolution \
    --button-id cwx_ticket.form.Validate.CustomAction \
    --label "التحقق من التذكرة" \
    --lcid 1025

--button-id is the CustomAction Id as reported by crm ribbon list. Like every other mutating ribbon verb, set-label requires --solution — there is no profile default and no opt-out; pass --solution Default for a deliberate Default-Solution-only write.

Localization with --lcid. When --lcid <LCID> is given, the button attribute is set to a $LocLabels:<id> directive and the actual text lands in a <LocLabel>/<Titles>/<Title languagecode=LCID> row inside the RibbonDiffXml. The LCID is validated against the org's provisioned languages and the command errors if the language is not provisioned. Re-running for a second LCID adds a sibling <Title> row rather than overwriting the first. The $LocLabels directive id is case-sensitive — it is derived automatically from the button Id and attribute name; do not hand-edit the directive.

Only custom buttons. set-label locates the button by its CustomAction Id. Out-of-box buttons have no CustomAction entry and will not be found; use hide-button to suppress OOB buttons instead.

Set a button's icon

Give a custom command-bar button an icon — at creation via add-button, or on an existing button via set-icon. Both take the same three flags (any subset), and each points at a web resource that must already exist:

Flag Button attribute Web-resource type
--modern-image ModernImage SVG (Unified Interface icon)
--image16 Image16by16 raster: PNG / JPG / GIF / ICO (classic 16×16)
--image32 Image32by32 raster: PNG / JPG / GIF / ICO (classic 32×32)
# Set the modern (SVG) icon on an existing custom button
crm ribbon set-icon cwx_ticket --solution MySolution \
    --button-id cwx_ticket.form.Validate.CustomAction \
    --modern-image cwx_/icons/validate.svg

# Set classic + modern icons at once
crm ribbon set-icon cwx_ticket --solution MySolution \
    --button-id cwx_ticket.form.Validate.CustomAction \
    --modern-image cwx_/icons/validate.svg \
    --image16 cwx_/icons/validate16.png \
    --image32 cwx_/icons/validate32.png

# Create a button with its icon in one step
crm ribbon add-button cwx_ticket --solution MySolution \
    --label Validate --location form \
    --webresource cwx_/scripts/x.js --function ns.fn --param PrimaryControl \
    --modern-image cwx_/icons/validate.svg

You pass the plain web-resource name; the CLI writes it as a $webresource:<name> directive, which adds a solution dependency so the icon web resource can't be deleted while a button still references it. Each reference is validated up front — it must exist and match its slot type (--modern-image → SVG; --image16/--image32 → raster) — so a typo or wrong-type reference fails before the slow solution round-trip.

set-icon writes only the icon attributes; the button's Command, LabelText, TemplateAlias, Sequence, and Id are protected. Pass at least one icon flag (zero is a usage error). Like the other mutating verbs it stages by default; pass --publish to publish immediately. Only custom buttons can be re-iconed — set-icon locates the button by its CustomAction Id (as reported by crm ribbon list).

Hide an out-of-box button

Use hide-button to suppress an OOB command-bar button you cannot delete. Two methods are available; choose based on reversibility:

Method Reversibility Gate
display-rule (default) Reversible — delete the override to restore none
hide-action One-way trapdoor — removable only by a new solution version confirm prompt (--yes to skip)

--target-id is the OOB button (control) Id as shown by crm ribbon export ENTITY. The command validates it against the live composed ribbon — a typo errors immediately instead of silently doing nothing after a slow solution import round-trip.

# Reversible: override the OOB command with two always-false DisplayRules
crm ribbon hide-button account --solution MySolution \
    --target-id Mscrm.Form.account.Save

# Irreversible: write a HideCustomAction (gated behind --yes)
crm ribbon hide-button account --solution MySolution \
    --target-id Mscrm.Form.account.Save \
    --method hide-action --yes

--method display-rule overrides the button's command with the platform's own Mscrm.HideOnModern and Mscrm.ShowOnlyOnModern DisplayRules (both always false). The original command definition is unchanged; remove the override to undo.

--method hide-action writes a HideCustomAction element. This is irreversible without shipping a new solution version, so the command asks for confirmation first; pass --yes to skip the prompt (required for --json / non-interactive runs).

Neither method touches the button's classid, Command, or TemplateAlias. Both emit a warning that overriding or hiding an OOB command is on unsupported ground and may change across platform updates.

Set enable/display rules

Replace the enable or display rule references on an existing custom CommandDefinition with an exact, ordered set. At least one --enable-rule or --display-rule is required; a category with no flags is left untouched.

# Show the command only when exactly one row is selected (platform rule)
crm ribbon set-rules cwx_ticket --solution MySolution \
    --command-id cwx_ticket.form.Validate.Command \
    --enable-rule Mscrm.SelectionCountExactlyOne

# Combine a platform rule with a custom one; stages by default (no publish)
# (pass --publish to publish this edit immediately instead)
crm ribbon set-rules cwx_ticket --solution MySolution \
    --command-id cwx_ticket.form.Validate.Command \
    --enable-rule Mscrm.SelectionCountExactlyOne \
    --enable-rule cwx_ticket.form.Validate.myCustomRule.EnableRule

# Suppress the button on modern UI only (display rule)
crm ribbon set-rules cwx_ticket --solution MySolution \
    --command-id cwx_ticket.form.Validate.Command \
    --display-rule Mscrm.HideOnModern

Platform (Mscrm.*) rule ids are validated against a curated allow-list — the server silently ignores an unknown Mscrm.* id, so passing one that isn't recognised is rejected with a clear error. Allowed platform enable rules: Mscrm.SelectionCountExactlyOne, Mscrm.ShowOnGrid, Mscrm.ShowOnQuickAction, Mscrm.ShowOnGridAndQuickAction. Allowed platform display rules: Mscrm.HideOnModern, Mscrm.ShowOnlyOnModern. Custom (non-Mscrm.) ids pass through. The CommandDefinition Id is never touched.

Use ribbon list to find command ids; the command warns when --command-id matches an out-of-the-box (Mscrm.*) command (editing OOB commands is unsupported and may break on upgrade).

Add a custom (JavaScript) rule

Define a custom EnableRule that calls a JavaScript function in a web resource, and attach it to a command in one step. The web resource must already exist (see crm webresource create). The generated rule id is {command_id}.{slug(function)}.EnableRule.

# Create a custom enable rule that calls cwx_.ns.canValidate() and wire it
crm ribbon add-custom-rule cwx_ticket --solution MySolution \
    --command-id cwx_ticket.form.Validate.Command \
    --webresource cwx_/scripts/ribbon.js \
    --function ns.canValidate

# Dry-run: preview without writing
crm --dry-run ribbon add-custom-rule cwx_ticket --solution MySolution \
    --command-id cwx_ticket.form.Validate.Command \
    --webresource cwx_/scripts/ribbon.js \
    --function ns.canValidate

The command prints the generated rule_id in data.rule_id — capture it to pass to ribbon set-rules --enable-rule in a subsequent step, or chain them in sequence since add-custom-rule also references the rule on the command automatically. The CommandDefinition Id is never touched.