Script to deploy ImmyBot agent from NinjaRMM

Since there’s not yet a NinjaRMM integration, we wanted to be able to deploy the ImmyBot agent from inside NinjaRMM. Here’s the script we used in case it’s helpful to someone.

Prerequisites:
Generate a PowerShell ImmyBot install string from inside immyBot for a particular tenant. Extract the “ID=XXX” and “KEY=XXX” strings from the middle of the PowerShell blob (it’s part of the arguments to the “msiexec” command) so you end up with a string that looks like this:
ID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX KEY=YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY

In NinjaRMM, make sure the Documentation App is enabled, and a Documentation form named “Deployments” is created as a single page type with document template named “Deployments” and a Custom Field of type text on this template where the custom field is named “immyBotIDAndKey” and the “Scripts” permission is set to Read Only. (None of this should be Mandatory.)

View the main page of an Organization in Ninja (click Dashboard->Organization Name for example), then on the Documentation tab, click Apps & Services. From the Deployments section on the left, edit the Deployments template on the right and paste the ID and KEY above (there should be a space between the two) and Save/Close.

Create a new script under Administration->Library->Scripting of type PowerShell for Windows, All bit-types, and give it a name (I use Deploy-ImmyBot). Use the following script as the body, then save. Run on any tenant where you’ve completed the above setup (if it doesn’t find an ID and KEY of the proper length/format, it will error in the Activity Log).

Here’s the script (replace the URL and YOURSUBDOMAIN values near the top with the ones from any of your ImmyBot PowerShell install blobs, they only needs to be set once to the real download location and your ImmyBot subdomain):

# ImmyBot Deployment via PowerShell script using tenant ID and KEY from Documentation Deployment/Deployment/immyBotIDAndKey field

# Replace this URL with the URL from the ImmyBot PowerShell code for your deployment:
$url = 'YOURDOWNLOADURL'
# Replace YOURSUBDOMAIN with your ImmyBot subdomain:
$ADDR = 'https://YOURSUBDOMAIN.immy.bot/plugins/api/v1/1'

#Service Name
$ServiceName = "ImmyBot Agent"
If ( Get-Service $ServiceName -ErrorAction SilentlyContinue ) {
  Write-Host "The service" $ServiceName "is Already Installed...Bye." 
  exit 0
}

# Make sure this Documentation form, template, and field exist, are script readable, and have the corresponding tenant ID/KEY saved!
$IDandKey = Ninja-Property-Docs-Get 'Deployments' 'Deployments' immyBotIDAndKey

#write-host "ImmyBot ID and Key from Documentation Field: $IDandKey"
$regex = "ID=([a-zA-Z00-9]{8}-[a-zA-Z00-9]{4}-[a-zA-Z00-9]{4}-[a-zA-Z00-9]{4}-[a-zA-Z00-9]{12})\s.*\s*KEY=(\S{44})"
$IDandKey -match $regex | Out-Null
($ID, $KEY) = ($matches[1], $matches[2])

if ($ID -NotMatch "^[a-zA-Z00-9]{8}-[a-zA-Z00-9]{4}-[a-zA-Z00-9]{4}-[a-zA-Z00-9]{4}-[a-zA-Z00-9]{12}$") {
  write-host "The ID field is either not defined or is in an invalid format, set valid immyBotIDAndKey in documentation"
  write-host "Format should be: ID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX KEY=YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"
  write-host "The discovered value is" $ID
  exit 1
} elseif ($KEY -NotMatch "^\S{44}$") {
  write-host "The KEY field is either not defined or is in an invalid format, set valid immyBotIDAndKey in documentation"
  write-host "Format should be: ID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX KEY=YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"
  write-host "The discovered value is" $KEY
  exit 1
} else {
  #write-host "Installing with ID=" $ID
  $IDmasked = $ID.SubString(0,10) + "****-****-" + $ID.SubString(24,12)
  write-host "Installing with ID: " $IDmasked

  #write-host "Installing with KEY=" $KEY
  $KEYmasked = $KEY.SubString(0,10) + "*************************" + $KEY.SubString(35,9)
  write-host "Installing with KEY:" $KEYmasked

  write-host "(identifiers partially masked for log)"
}

# The following code is the ImmyBot PowerShell deployment separated into lines for readability and with the ID and KEY variables swapped into the arguments:
$InstallerFile = [io.path]::ChangeExtension([io.path]::GetTempFileName(), ".msi")
(New-Object System.Net.WebClient).DownloadFile($url, $InstallerFile)
$InstallerLogFile = [io.path]::ChangeExtension([io.path]::GetTempFileName(), ".log")
$Arguments = " /c msiexec /i `"$InstallerFile`" /qn /norestart /l*v `"$InstallerLogFile`" REBOOT=REALLYSUPPRESS ID=$ID ADDR=$ADDR KEY=$KEY"
Write-Host "InstallerLogFile: $InstallerLogFile"
$Process = Start-Process -Wait cmd -ArgumentList $Arguments -PassThru
if ($Process.ExitCode -ne 0) {
    Get-Content $InstallerLogFile -ErrorAction SilentlyContinue | Select-Object -Last 200
}
Write-Host "Exit Code: $($Process.ExitCode)"
Write-Host "ComputerName: $($env:ComputerName)"

# Return the exit code from the installation as the script exit code:
exit $($Process.ExitCode)
1 Like

we are just switching to NinjaRMM after a lifetime of Labtech/Automate…we basically were about at the point of ‘how to script this out’…made alot of our work on this easy, TYVM dszp

Awesome, glad to hear it was helpful!

I’m sure that script above likely still works, but my latest version which has been tweaked a bit since, is on GitHub at NinjaOne-Scripts/ImmyBot/Deploy-ImmyBot.ps1 at main · dszp/NinjaOne-Scripts · GitHub and has better built-in docs at the top as well.

TY, checking those out right now

any way for me to reach out for a direct discussion about a couple of the scripts you have? especially the screenconnect one, I want to make sure I am understanding what needs to be done

Sure, I’m regularly in the NinjaOne Discord (discord dot gg slash ninjaone is the invite) and my DMs are open (username “david szp” without the space–just trying to avoid spam scrapers here), plus there’s a thread in their #script-share about most of the scripts in my GitHub repository, as most of them started there before I moved them to GitHub. Also a lot of folks there that help with PowerShell scripting in the #scripting-general-chat and others, even if I’m not available or able to figure something out, and sometimes they have better versions of stuff than me, or updates :slight_smile: