Collectors

Run PowerShell on a Collector

Run vetted PowerShell scripts on a Windows collector from a workflow — place the .ps1 on the collector, register it, then call it from the built-in "Run PowerShell on Collector" workflow or the collector.powershell step, with the exit code and output captured back in the run.

Some of the work a network team automates has no API behind it — it is a PowerShell script somebody wrote years ago, the one that walks an F5 HA pair and enables AutoSync, or sweeps a BlueCat zone, or pulls a report off a Windows box that only answers to WinRM. Versus runs those scripts on the collector that already sits inside your network, and lets a workflow drive them. The script never travels through Versus: an administrator places it on the collector by hand, you register it the way you register a firmware image, and from then on a workflow only chooses which registered script runs and with what arguments. The collector runs it locally, on its own host, and reports the exit code and output back into the run.

That boundary is the whole point, so it is worth stating plainly before anything else: the cloud cannot send a script body to a collector. It can only name one that an on-prem admin already put there. Everything below follows from that.

Three pieces fit together:

PieceWhereWho
The .ps1 fileThe collector's scripts directoryAn on-prem administrator, by hand
The registrationSystem → Collector ScriptsA Versus admin (Network-Admin)
The runA workflow — the built-in tool, or the collector.powershell stepAnyone who can run the workflow

Put the script on the collector

Every collector watches a local scripts directory. By default that is scripts under the collector's state directory — on a Windows collector that is usually C:\var\lib\versus-agent\scripts. If you keep your scripts somewhere else, point the collector at it with the VERSUS_SCRIPTS_DIR environment variable and restart the agent.

Drop your .ps1 files in that directory. Only files ending in .ps1 are considered; anything else is ignored. Within about a minute the collector reports what it finds — the file name, its size, and a SHA-256 of its contents — and those files appear on the Collector Scripts page, ready to register. Nothing runs yet; reporting a file only makes it available to register.

Because the admin who placed the file is trusted, the collector runs it with -NoProfile -NonInteractive -ExecutionPolicy Bypass -File — an unsigned local script runs without a prompt. Keep the directory itself locked down the way you would any directory of scripts that run with the collector's privileges: what lands there is what Versus will run.


Register it

Open System → Collector Scripts. Under Scripts reported by collectors you will see each .ps1 every collector has reported, with its collector and size. A file you have already registered is marked; a new one has a Register button.

Registering is where you give the script the context a workflow needs:

  • Display name — what the script is called in the run dialog and the step. Defaults to the file name without its extension.
  • Description — a line on what it does, shown beside the name.
  • Interpreter — Auto prefers PowerShell 7+ (pwsh) and falls back to Windows PowerShell, or you can pin one.
  • Default timeout — how long the collector waits before it gives up and kills the run. A run can shorten it, never lengthen it past the ceiling of one hour.
  • Parameters — declare the arguments the script takes, one per row: the name (it must match the script's own parameter), a label for the run form, whether it is a string or a switch, and whether it is required. Declaring parameters is what lets the run dialog show a tidy form instead of a free-text box — but it is optional; a script that takes no arguments needs none.
  • Pass arguments positionally — leave this off and arguments are passed by name (-DeviceListPath C:\f5\devices.txt), which is how most scripts expect them. Turn it on only for a script that reads $args positionally.

Once registered, the script shows in the lower table with a state badge. In sync means the file on disk still matches what you registered. Changed on disk means the admin replaced the file since — the script will still run, but you are told the content drifted so nothing changes under you silently. Missing means the collector is no longer reporting that file at all. You can Disable a script to take it out of circulation without unregistering it, and Unregister removes it from Versus — it never touches the file on the collector.


Run it

There are two ways to run a registered script, and they share the same engine.

The built-in workflow

Run PowerShell on Collector is a ready-made workflow — find it in the workflow list and click Run. It asks for three things: the registered script, its arguments, and a timeout. Pick the script from the dropdown (it shows the drift badge, so you know the collector is still reporting it), fill in the arguments, and run. This is the quickest way to run a script ad-hoc, and it is a complete, auditable run like any other — it appears in the run history with its log, its output, and who started it.

You can also run a script straight from the Collector Scripts page with the Run button on its row, which opens a small dialog, runs it, and streams the result back in place — handy for a quick check without leaving the page.

The collector.powershell step

To make a script one step of a larger workflow — run it after a change, or only when a decision branch is taken — drop the Run PowerShell on Collector step (collector.powershell) onto the canvas. It has four settings:

  • Registered Script — which script to run. You can also feed this from a run input as {{script_id}}.
  • Arguments — a JSON object of {parameter: value} mapped to the script's declared parameters, or one Name=value per line.
  • Timeout (seconds) — defaults to the script's own default.
  • Fail the step on a non-zero exit code — on by default. Leave it on and the workflow stops if the script exits non-zero; turn it off for a script whose non-zero exit is informational, and read the exit code downstream instead.

The step hands the next steps three outputs: exit_code, stdout, and stderr — so a later step can branch on the result or fold the output into an email or a ticket.


How arguments reach the script

Arguments are never pasted into a command line and handed to a shell — that is how injection happens. Versus builds them as a list of discrete values and passes them straight to PowerShell after -File.

What you supply is matched against the parameters you declared:

  • A string parameter with a value becomes -Name value. An empty one is dropped.
  • A switch parameter becomes a bare -Name when it is on, and is left out entirely when it is off.
  • A parameter you did not declare is ignored, so a run cannot slip an unexpected flag past the script.

For a script you registered as positional, the values are passed in the order the parameters are declared, with no -Name in front. A run is capped at a sensible number and length of arguments, so a malformed input cannot balloon into an enormous command.


What you get back

When the collector finishes, the run shows what happened:

  • Exit code — the script's own exit code. Zero is success; anything else is a failure, unless you turned off fail on non-zero.
  • stdout and stderr — captured separately and shown in the run. Each stream is held to about a megabyte; a script that prints more than that is truncated with a note, so a runaway script cannot flood the run.
  • A timeout — if the script runs longer than its timeout the collector kills it and the step fails cleanly, rather than hanging the workflow.

If the collector cannot run the script at all — the file is gone, there is no PowerShell interpreter on the host, or the collector is offline — the step fails with a plain message saying why, which is different from the script running and exiting non-zero. You can tell "it never ran" from "it ran and failed" at a glance.


A few things worth knowing

  • The collector has to be online. A run queues until the collector claims it on its next check-in; if the collector is offline the step says it is waiting, and eventually times out. Nothing is lost — register once, run whenever.
  • Registering never runs anything. Reporting, registering and running are three separate acts. A file sitting in the directory is inert until a workflow asks for it.
  • Live execution needs a current collector. Running scripts is a capability of the collector agent; a collector has to be on a build that supports it. An older agent simply never reports a scripts directory, and the page stays empty for that collector until it is updated.

That is running PowerShell on a collector — an admin places the script, you register it with the arguments it expects, and a workflow runs it on the box inside your network and brings back the exit code and the output, with the script body never leaving the collector.