Translate Script Components
A Script Component holds C# or Visual Basic that runs for every row of a data flow. No tool translates arbitrary .NET code reliably, so by default the importer does not try: the component becomes a placeholder, and its code is kept next to the pipeline for porting. Optionally, a language model translates C# Script Components into a User Defined Java Class while the import runs. Treat that translation as a first draft for the person who ports the script, not as a conversion.
What the importer keeps
For every Script Component, next to the pipeline:
<pipeline> - <component>.cs.txt(or.vb.txt): the code files the author wrote (main.csand any they added, not the files Visual Studio generates), after a header that lists the columns and variables;<pipeline> - <component>.script.json: the same as data: the language, the inputs and outputs with their columns (SSIS type, length, read-only or read-write), whether an output is synchronous, the variables, and the code files.
The placeholder keeps the component's name and hops, and the report lists it as MANUAL, with the
names of these files. Script Tasks, in the control flow, are kept the same way, as
<workflow> - <task>.cs.txt, and are never translated.
Port a script by hand
- Find it in the report's Needs review table, and open its
.cs.txtnext to the pipeline. - Decide whether it needs code at all. Much script code does what a Hop transform does: string handling (String operations, Calculator), date formatting (Select values), lookups (Stream lookup, Database lookup), counters (Add sequence). A transform is easier to maintain than code.
- If it does need code, write it in a User Defined Java Class in place of the placeholder,
reading and writing the columns listed in the header. Mind where .NET and Java differ: .NET's
Math.Roundrounds half to even,decimalis notdouble, andTryParse,Trim,Split, date formats and regular expression options all behave differently in Java. - Re-run the comparison from Validate a migration for that package.
Get a first draft from a language model
Only the import needs the model. A translated script is ordinary Java in an ordinary Hop transform: running the converted pipelines needs no model, no Ollama and no network.
Set up an endpoint
The import needs an endpoint that speaks the OpenAI chat completions API and serves the model you name. The simplest is Ollama on the machine that runs the import:
| macOS | Windows | Linux | |
|---|---|---|---|
| Install | the app from ollama.com, or brew install ollama | the installer from ollama.com (uses NVIDIA and AMD GPUs) | curl -fsSL https://ollama.com/install.sh | sh |
| Get the model | ollama pull <model> | ollama pull <model> | ollama pull <model> |
| Endpoint | http://localhost:11434/v1 | http://localhost:11434/v1 | http://localhost:11434/v1 |
A coding model of about 30B parameters needs about 20 GB of memory for the model alone: a machine
with 32 GB or more, or a GPU with 24 GB. Pick a model tag your hardware runs: some quantisations
(such as nvfp4) are meant for particular hardware; a q4_K_M tag runs everywhere.
LM Studio, vLLM or a hosted service work too: give their endpoint, and the API key in the
SSIS_TRANSLATION_API_KEY environment variable (export SSIS_TRANSLATION_API_KEY=... in bash,
$env:SSIS_TRANSLATION_API_KEY = "..." in PowerShell). The key is never stored in the options.
Run the import with translation
java -jar importer-ssis.jar --translate-scripts http://localhost:11434/v1 \
--translation-model <model> --translation-reasoning none <input-dir> <output-dir>
On Windows, the same on one line, or with ^ (cmd) or ` (PowerShell) at the line ends. In
Hop GUI, the import dialog has the same three fields. The import checks the endpoint first, and
stops with what to install or pull when it does not answer or does not have the model.
--translation-reasoning (none, low, medium, high) is for models that reason before they
answer, such as Qwen 3 in Ollama: without it they can spend their whole answer on reasoning and
return nothing. Leave it out for models that do not reason; some hosted ones reject it.
What is sent where
The C# of each Script Component, with the names and types of its columns and variables, goes to the endpoint you give, together with the importer's instructions and, on a retry, the reason the previous answer was rejected. No data is sent: the translation happens during the import, not when the pipeline runs. With a local model, nothing leaves the machine. With a hosted service, it goes to that service: check that your scripts may be sent there before you use one.
How a translation is checked
The importer rejects code that does not follow the class's rules (columns by name, one row at a
time), compiles it, and checks that it keeps .NET's semantics where .NET and Java differ (rounding
to even, TryParse, Trim, Split, formats, case-insensitive patterns), for which it gives the
model helpers. On a problem the model gets the message and tries again, up to three attempts.
- A script that never compiles stays a placeholder, reported as MANUAL with the reason.
- A script that compiles becomes a User Defined Java Class, reported as PARTIAL, "Machine-translated script", with the model's name, the number of attempts and any doubts left (for example a case-insensitive regular expression without its flag). The transform's description says it was machine-translated.
Not translated at all: Visual Basic, scripts that create rows of their own (asynchronous outputs), use connections or write variables, and Script Tasks.
How good the drafts are
We measure translations by running SSIS on Linux with the original C# and Hop with the translation, on the same data, and comparing the rows. The latest measurement, on six scripts written after the translator's helpers were last extended and never used to tune them:
| Model | Same rows as SSIS, per run |
|---|---|
| Qwen 3.5 35B, coding variant, reasoning off (local, Ollama) | 4 of 6, 4 of 6 |
| Codestral (Mistral, hosted) | 2 of 5, 5 of 6 |
| Mistral Large (Mistral, hosted) | 4 of 5, 2 of 6 |
(The first run had one test that SSIS itself could not compile; it is left out of that run.) The same model on the same scripts can score very differently from one run to the next, so these numbers do not rank the models: a local model does about as well as the hosted ones. What they do say is that a good share of translations compute what SSIS computes, and a good share do not, also among those that compile and pass every check.
Review every translated script against the original, next to the pipeline, and validate the package before relying on it.