Migrating scripts from Datto RMM
Datto RMM components are ordinary PowerShell, bash or batch with an environment-variable wrapper, so the bodies port with a handful of edits. What trips people up is that the Breeze side of each Datto feature lives on a different page: parameters and variables under Scripts, write-back under Custom fields, bulk loading under Script bundles. This page is the map between the two, with one component worked end to end.
For the rest of the migration — tenancy tree, UDF values, agent deployment, decommission — see Datto RMM → Breeze.
Concept map
Section titled “Concept map”| Datto RMM | Breeze |
|---|---|
| Component | Script |
| Component input variable (prompted when the job is created) | Script parameter with source Asked at run time. Read it as {{name}} in the body, or as the environment variable BREEZE_PARAM_<NAME>. |
Site / account variable ($env:VarName) |
Variable under Settings → Variables, referenced as {{var.key}}. An organization’s value overrides the partner-wide one with the same key. |
| Secret site variable | Secret variable, bound through a parameter with source From a secret variable (environment variable). Delivered only as BREEZE_VAR_<NAME>, never substituted into the body. |
Read a UDF ($env:UDF_7) |
Parameter with source From a device custom field, bound to the field key. |
Write a UDF (<-Start Result->key=value<-End Result->, or the HKLM:\SOFTWARE\CentraStage Custom1…Custom300 registry values) |
Print ::breeze:custom-fields:: {"key":"value"} to stdout. The field must have Allow scripts to write this field on. See Writing custom fields from a script. |
| Component exit-code alerting | exitCodeSeverityMapping on the script: 0 never alerts, map 1…n to low, medium, high or critical. |
| Monitor → response component | Automation with trigger Event → alert.triggered and action Run script. See the caution below. |
| ComStore component | Check the Breeze system script library first. |
| Bulk component export | Import bundle from loose .ps1 / .sh / .py / .bat / .cmd files (200 per bundle), or a Breeze .json bundle. |
Worked example: one component, before and after
Section titled “Worked example: one component, before and after”A component called Set maintenance window tag. In Datto it reads a prompted input variable WindowLabel, a site variable SiteTz, and UDF 7 (last_maintenance), then writes the next window into UDF 8 and exits 0 or 1.
# Datto injects every component and site variable as an environment variable.$label = $env:WindowLabel # component input variable, prompted at job creation$tz = $env:SiteTz # site variable$last = $env:UDF_7 # read UDF 7 (last maintenance)
if (-not $label) { Write-Host 'WindowLabel is required'; exit 1 }
$next = ([datetime]$last).AddDays(30).ToString('yyyy-MM-dd')Write-Host "Next window for $tz is $next ($label)"
# Write UDF 8 through the Datto result marker.Write-Host "<-Start Result->UDF_8=$next<-End Result->"exit 0# {{window_label}} is a parameter (source: Asked at run time) — substituted before the run.# {{var.site_tz}} is a Variable from Settings → Variables — resolved per device's organization.# last_maintenance is a parameter (source: From a device custom field) — read from the environment.$label = '{{window_label}}'$tz = '{{var.site_tz}}'$last = $env:BREEZE_PARAM_LAST_MAINTENANCE
if (-not $label) { Write-Output 'window_label is required'; exit 1 }
$next = ([datetime]$last).AddDays(30).ToString('yyyy-MM-dd')Write-Output "Next window for $tz is $next ($label)"
# Write the next_maintenance custom field through the Breeze marker.Write-Output "::breeze:custom-fields:: $(@{ next_maintenance = $next } | ConvertTo-Json -Compress)"exit 0The edits, in order:
-
In the script editor, add a parameter
window_labelwith source Asked at run time. Replace$env:WindowLabelwith'{{window_label}}'. -
Under Settings → Variables, create
site_tzwith Applies to: All organizations and a default, then override it per organization where the timezone differs. Replace$env:SiteTzwith'{{var.site_tz}}'. -
Add a parameter
last_maintenancewith source From a device custom field, bound to thelast_maintenancefield. Replace$env:UDF_7with$env:BREEZE_PARAM_LAST_MAINTENANCE. -
Replace the
<-Start Result->line with the::breeze:custom-fields::marker. The value after the marker is one JSON object keyed by field key. -
Keep the exit codes. Set
exitCodeSeverityMappingto{"1": "low"}if a missing label should raise a low-severity alert instead of the defaultmedium.
The next_maintenance field definition needs Allow scripts to write this field turned on, or the write is rejected as not_script_writable in the run’s custom-field summary. Field keys that look secret-shaped (token, password, …) break the marker’s JSON through output sanitization; see the caution on that page.
Secrets
Section titled “Secrets”Datto site variables are plaintext to the component. Breeze never pastes a secret into a script body: {{var.key}} pointing at a secret variable is rejected when the script is saved.
-
Create the variable under Settings → Variables with Secret ticked. The value is write-once.
-
In the script, add a parameter with source From a secret variable (environment variable) and bind it to that key. Name it in lowercase with underscores.
-
Read it as
$env:BREEZE_VAR_<NAME>(PowerShell) or$BREEZE_VAR_<NAME>(bash), where<NAME>is the parameter name in uppercase.
Secret parameters require system-context execution and an agent at v0.106.0 or later; a script that binds one is refused on older agents rather than run with the variable unset. The exact secret value is redacted from stored output. Full rules: Secret variables in scripts.
Loading the library in bulk
Section titled “Loading the library in bulk”-
Export each component body from Datto as a file. Name the file after the component and give it the extension for its language (
.ps1,.sh,.py,.bat,.cmd). The importer infers language and OS from the extension and the script name from the filename. -
Go to Scripts → Import bundle and drop the loose files. A bundle holds at most 200 scripts, so a 1,326-component library is seven batches.
-
Review the preview. Each script shows as New or Name conflict; for conflicts choose skip, import under a new name, or add as a new version of the existing script.
-
Set availability to All organizations so one copy serves every customer.
-
Open each imported script and add its parameters, variables and
exitCodeSeverityMapping. Loose-file import carries only the body; a Breeze.jsonbundle carries the metadata too, so once one instance is configured you can export it and import into another.
The same flow is available as POST /api/v1/scripts/bundle/preview and POST /api/v1/scripts/bundle/import; the migration toolkit has a ready-to-run script.
Alert-driven components
Section titled “Alert-driven components”A Datto monitor that fires a response component becomes an automation: trigger Event → alert.triggered, filtered to the alert type, with action Run script. The monitor itself is rebuilt on the Breeze side; see Monitors and alerting.
What does not carry over
Section titled “What does not carry over”- Component categories. Bundles carry a category and tags by name and create them on import. Datto’s category tree is flatter than most Breeze libraries end up, so review them after the first batch.
- Datto-only environment variables (
$env:CS_PROFILE_UID,$env:CS_DOMAIN,$env:CS_*). There is no equivalent. For hostname, OS or similar, add a parameter with source From a device property. - The result-marker convention.
<-Start Result->lines are plain output in Breeze. Replace them with the custom-fields marker. - Monitors. Components ported; monitors are re-authored as Breeze monitors and alert rules.
- ComStore entitlements. Check the system script library for the equivalent.
- Job schedules. Bundles never carry schedules or automations. Recreate them as Breeze schedules once the scripts are in.