Skip to main content

NinjaOne

This is a how-to for RMM mass-deploy on NinjaOne.

One policy scheduled script covers your whole fleet, client devices and your own. Fill in three values at the top of the script and deploy it; nothing else changes from client to client. Use a scheduled script, not NinjaOne's application-install UI.

Every method still needs a verified installer and the right deployment scope.

How the script knows which SparkLogs organization a device belongs to

When NinjaOne runs a Windows automation script, it injects the device's NinjaOne organization identity as environment variables for that script process only. They are not persistent machine environment variables. If you run the same PowerShell outside NinjaOne automation, they are empty.

NinjaOne variableUse in SparkLogs
NINJA_ORGANIZATION_IDRMMCLIENTID (numeric org ID on this NinjaOne instance)
NINJA_ORGANIZATION_NAMECLIENTNAME (display label only, not a link key)

NinjaOne's model is organization → location → device. NinjaOne organizations are a flat list of clients plus your own internal org. Using NINJA_ORGANIZATION_ID maps one NinjaOne organization (every location under it) to one SparkLogs organization (for most MSPs, a client).

Device groups and saved searches are targeting only; they never change NINJA_ORGANIZATION_ID.

Template values you fill in

If you followed the workspace setup wizard as an MSP, you have exactly two top-level SparkLogs organizations, Clients and Internal IT, each with its own registration token. The script picks the token from the device's NinjaOne organization, so it works as-is once you swap in three values:

ValueWhere to get it
Clients registration tokenSparkLogs deploy wizard, token minted on Clients
Internal IT registration tokenSparkLogs deploy wizard, token minted on Internal IT
NinjaOne org ID of your internal orgNinjaOne Administration → Organizations, hover your own org's row, ellipsis, Copy Org ID

The branch is a pattern you can extend: add more org IDs and tokens if you later want a separate SparkLogs parent for a group of clients.

The script

PowerShell, Windows, 64-bit, Run as System. It detects the SparkLogsAgent service so reruns are no-ops, refuses to run outside NinjaOne automation, verifies the download by SHA-256, and treats exit 0, 3010, and 1641 as success.

The URL and hash are the current published Windows x64 EXE (1.9.6). If your workspace release ring is not this build, take the URL and hash from the deploy wizard instead. This is a starting point to adapt, not a supported partner package.

$ErrorActionPreference = 'Stop'

# ============================================================
# FILL IN THESE THREE VALUES BEFORE YOU SAVE THE SCRIPT
# ============================================================
$ClientsToken = '<<< PASTE CLIENTS REGISTRATION TOKEN >>>'
$InternalItToken = '<<< PASTE INTERNAL IT REGISTRATION TOKEN >>>'
$InternalNinjaOrgId = '<<< PASTE NINJAONE ORG ID OF YOUR INTERNAL ORG >>>'
# ============================================================

if (Get-Service 'SparkLogsAgent' -ErrorAction SilentlyContinue) { exit 0 }

$RmmClientId = [string]$env:NINJA_ORGANIZATION_ID
$ClientName = [string]$env:NINJA_ORGANIZATION_NAME
if ([string]::IsNullOrWhiteSpace($RmmClientId)) {
throw 'NINJA_ORGANIZATION_ID is empty. Run this script from NinjaOne automation, not Task Scheduler.'
}

if ($RmmClientId -eq $InternalNinjaOrgId) {
$token = $InternalItToken
} else {
$token = $ClientsToken
}

$url = 'https://cdn.sparklogs.app/agent/data/1.9.6/windows_x86_64/sha256_43dffe5b77221bd6a87689b7f960938cb39cc67b8e45d4551226c9a0d2d7fe99/SparkLogsAgentSetup-x64-1.9.6.exe'
$sha = '43dffe5b77221bd6a87689b7f960938cb39cc67b8e45d4551226c9a0d2d7fe99'
$exe = Join-Path $env:TEMP 'SparkLogsAgentSetup.exe'

Invoke-WebRequest $url -OutFile $exe -UseBasicParsing
if ((Get-FileHash $exe -Algorithm SHA256).Hash -ne $sha) { throw 'SHA-256 mismatch' }

$installArgs = @(
'/qn', '/norestart',
'EULA=ACCEPT',
"REGISTRATION_TOKEN=$token",
"RMMCLIENTID=$RmmClientId",
"CLIENTNAME=`"$ClientName`""
)
$p = Start-Process $exe -Wait -PassThru -ArgumentList $installArgs
if ($p.ExitCode -notin 0, 3010, 1641) {
throw "Install failed with exit code $($p.ExitCode)"
}

Property names are RMMCLIENTID, CLIENTNAME, and PSACLIENTID (not CLIENT_NAME). Start-Process -Wait -PassThru is what makes PowerShell wait for the installer; see Troubleshooting. The MSI form uses the same properties on msiexec /i ... if you prefer MSI; see Download and verify.

Add it in NinjaOne

  1. Administration → Library → Automation → Add → New Script. Language PowerShell, architecture 64-bit, operating system Windows, run as System.
  2. Paste the script, fill in the template values at the top, and save it.
  3. Add the script to a policy (or a scheduled task) that targets a dynamic all-Windows device group, so new machines onboard without a new task.
  4. Schedule it hourly on day one to catch offline boxes, then daily once almost every run reports the agent is already installed. That daily run is your ongoing onboarding.

You do not need to exclude your internal NinjaOne organization from the target group; the script sends internal devices to the Internal IT token on its own. Internal devices appear under Internal IT in a sub-organization named for your NinjaOne org, so it stays clear which machines are yours.

Pilot before the fleet sweep

  1. Run it on one machine in your internal NinjaOne organization.
  2. Run it on one machine belonging to one small real client.
  3. In SparkLogs, confirm each agent landed under the parent you intended, with that client's name.

If a client box landed under Internal IT, its NinjaOne org ID matched $InternalNinjaOrgId, or the tokens are swapped.

  1. Fix the script values so later installs land correctly.
  2. Move the test box with Change ownership on Configure > Agents; reinstalling it with the corrected token does not move it. See Moving devices and organizations.
  3. Delete the misplaced SparkLogs organization if one was created, then sweep.

Linking to SparkLogs organizations you already created

SparkLogs auto-creates a direct child of the token's organization for each new RMMCLIENTID. If you already created client organizations in SparkLogs, set each one's RMM client ID to the NinjaOne org ID the script will send, so installs link instead of creating a duplicate. SparkLogs links on RMMCLIENTID and/or PSACLIENTID, not on a SparkLogs organization UUID by itself.

NINJA_ORGANIZATION_ID is local to this NinjaOne instance, and a tenant migration or merge can change it. If you already have SparkLogs organizations keyed to old IDs, update those organizations' RMM client IDs before you resume installs; see Changing RMM or PSA platforms.

Optional: a PSA ID or a shared ID

Use this when you already keep a PSA company ID on the NinjaOne organization, or when several NinjaOne organizations must land in one SparkLogs organization.

  1. Create or reuse a NinjaOne organization custom field (Text) and enable automation/script read on it. Type the field name yourself if the UI copies a label; names are immutable.
  2. Read it with Ninja-Property-Get and prefer it when non-empty. Pass a PSA value as PSACLIENTID, or use a shared value as RMMCLIENTID when several NinjaOne organizations map to one SparkLogs organization.
$PsaClientId = $null
if (Get-Command Ninja-Property-Get -ErrorAction SilentlyContinue) {
$PsaClientId = Ninja-Property-Get psaClientId 2>$null
}
if (-not [string]::IsNullOrWhiteSpace($PsaClientId)) {
$installArgs += "PSACLIENTID=$PsaClientId"
}

Fill the field before you expect those installs to match an existing SparkLogs organization. If the PSA ID lives on a Documentation template rather than a NinjaOne organization custom field, use Ninja-Property-Docs-Get-Single instead. The field still needs script read permission.

One NinjaOne organization that should become several SparkLogs organizations needs a different key entirely, for example a custom field you maintain, or NINJA_LOCATION_ID if you truly want one SparkLogs organization per location. Location-as-key is uncommon; only do it on purpose.

After a rename or a move in NinjaOne

NinjaOne documents that if an injected variable does not show the new value, reboot the device and rerun. That refresh only affects the next script run, and the values the script sends decide the SparkLogs organization for a device's first enrollment only.

  • Renaming a NinjaOne organization updates CLIENTNAME on a new install. It does not rename or move an agent that is already enrolled.
  • Moving a device to a different NinjaOne organization does not move it in SparkLogs. Move it with Change ownership on Configure > Agents; see Moving devices and organizations.
  • Reinstalling with a different client's token does not move a device. The endpoint returns to the device record and the SparkLogs organization it already has, whichever registration token the deployment package carries.
  • Once you move a device with Change ownership, it stays there through every later reinstall, reimage, and nightly restore, even while the script keeps sending the old client's values.

Uninstall and identity

  • NinjaOne's native Uninstall Program leaves SparkLogs enrollment state on disk. The next install continues the same enrollment.
  • Uninstalling with PURGE_STATE=1 clears that local state, and the endpoint still returns to its existing device record and SparkLogs organization on the next install. See Uninstall and reinstall.
  • To change which SparkLogs organization owns a device, use Change ownership. To stop collecting from a machine for good, delete it on Configure > Agents; that holds through wipes and reinstalls until you undelete it. See Moving devices and organizations.
  • A SparkLogs organization you deleted still matches while it is in its archive window, and an install that resolves to it fails rather than creating a duplicate. Undelete it, or confirm it has cleared, before you reuse the name.