Last active
February 6, 2024 20:41
-
-
Save grintor/fdf4d16e724d752c0003889d1580c7c2 to your computer and use it in GitHub Desktop.
A script for migrating to NinjaOne RMM from other RMMs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# deploy_ninja.ps1: A script for migrating to NinjaOne RMM from other RMMs | |
# | |
# This script will silently download and install NinjaOne and place the endpoint into the provided organization/location | |
# If the location does not exist within the organization in NinjaOne, this script will create it. | |
# If the organization does not exist in NinjaOne, this script will create it. | |
# If an installer for the provided organization/location has not yet been built in NinjaOne, this script will build it. | |
# | |
# USAGE | |
# ------- | |
# powershell.exe -file auto_ninja.ps1 "organization name" "location name" | |
# | |
# NOTE | |
# ------ | |
# Environment variables for "ninjaone_access_token" or "ninjaone_client_id" and "ninjaone_client_secret" must be set before running the script. | |
# | |
# OBTAINING THE CLIENT ID AND CLIENT SECRET | |
# ------------------------------------------- | |
# Go to Administration > Apps > API > Client App IDs and click the Add button on the right. | |
# Select "API Services (machine-to-machine)". | |
# Select "Monitoring" and "Management" Scopes | |
# Select "Client Credentials" Allowed Grant Type | |
# | |
# LICENSE | |
# --------- | |
# This program is free software: you can redistribute it and/or modify | |
# it under the terms of the GNU General Public License as published by | |
# the Free Software Foundation, version 3. | |
# | |
# This program is distributed in the hope that it will be useful, but | |
# WITHOUT ANY WARRANTY; without even the implied warranty of | |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
# General Public License for more details. | |
# | |
# You should have received a copy of the GNU General Public License | |
# along with this program. If not, see <http://www.gnu.org/licenses/>. | |
# | |
# Copyright (c) 2024 Tier2 Technologies (www.tier2.tech) | |
# Author: Chris Wheeler <[email protected]> | |
$faux_user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36' | |
function Sane-WebRequest { | |
param ( | |
$method, | |
$url, | |
$headers, | |
$body | |
) | |
try { | |
$ProgressPreference = 'SilentlyContinue' | |
$response = Invoke-WebRequest -UseBasicParsing -Uri $url -Method $method -Headers $headers -Body $body | |
return @{ | |
'status' = $response.StatusCode; | |
'headers' = $response.Headers; | |
'body' = $response.Content | |
} | |
} | |
catch { | |
try { | |
$reader = New-Object System.IO.StreamReader($_.Exception.Response.GetResponseStream()) | |
$reader.BaseStream.Position = 0 | |
$reader.DiscardBufferedData() | |
return @{ | |
'status' = $_.Exception.Response.StatusCode.Value__; | |
'headers' = $_.Exception.Response.Headers; | |
'body' = $reader.ReadToEnd() | |
} | |
} catch { | |
return @{ | |
'status' = 99999; | |
'headers' = ''; | |
'body' = $($error[1]) | |
} | |
} | |
} | |
} | |
function Ninja-Request { | |
param ( | |
$method, | |
$path, | |
$body | |
) | |
$response = Sane-WebRequest -method $method -url "https://app.ninjarmm.com/v2/$path" -headers @{ | |
'Authorization' = "Bearer $env:ninjaone_access_token"; | |
'Content-Type' = 'application/json'; | |
'Accept' = 'application/json' | |
} -body ($body | ConvertTo-Json -Depth 100) | |
try {$response.result = ($response.body | ConvertFrom-Json)} catch {} | |
return $response | |
} | |
function Ninja-auth { | |
param ( | |
$client_id, | |
$client_secret | |
) | |
$response = Sane-WebRequest -method 'post' -url 'https://app.ninjarmm.com/ws/oauth/token' -ContentType 'application/x-www-form-urlencoded' -body @{ | |
'grant_type' = 'client_credentials'; | |
'client_id' = $client_id; | |
'client_secret' = $client_secret; | |
'scope' = 'monitoring management'; | |
} | |
try {$response.result = ($response.body | ConvertFrom-Json)} catch {} | |
return $response | |
} | |
if ((Get-Service -Name 'NinjaRMMAgent' -ea 0) -ne $null){ | |
$host.SetShouldExit(129) | |
return "NinjaOne is already installed." | |
} | |
$target_organization = $args[0] | |
if ($target_organization -eq $null){ | |
$host.SetShouldExit(127) | |
return "Argument 1 (organization name) is required." | |
} | |
$target_location = $args[1] | |
if ($target_location -eq $null){ | |
$host.SetShouldExit(128) | |
return "Argument 2 (location name) is required." | |
} | |
if ($env:ninjaone_access_token -eq $null) { | |
if ($env:ninjaone_client_id -eq $null -or $env:ninjaone_client_secret -eq $null){ | |
$host.SetShouldExit(126) | |
return "Environment variables for ninjaone_access_token or ninjaone_client_id and ninjaone_client_secret must be populated." | |
} | |
$response = Ninja-auth $env:ninjaone_client_id $env:ninjaone_client_secret | |
if ($response.status -ge 201){ | |
$host.SetShouldExit(125) | |
return "Could not authenticate. Error $($response.status): $($response.body)" | |
} | |
$env:ninjaone_access_token = $response.result.access_token | |
} | |
$response = Ninja-Request 'get' 'organizations' | |
if ($response.status -ge 201){ | |
$host.SetShouldExit(120) | |
return "Could not obtain organizations. Error $($response.status): $($response.body)" | |
} | |
foreach ($organization in $response.result){ | |
if ($organization.name -eq $target_organization){ | |
$organization_id = $organization.id | |
} | |
} | |
if ($organization_id -eq $null) { | |
Write-Host "Organization ""$target_organization"" does not exist. Creating." | |
$response = Ninja-Request 'post' 'organizations' @{ | |
'name' = $target_organization; | |
'locations' = @( | |
@{ 'name' = $target_location } | |
) | |
} | |
if ($response.status -ge 201){ | |
$host.SetShouldExit(121) | |
return "Could not create organization ""$target_organization"". Error $($response.status): $($response.body)" | |
} | |
$organization_id = $response.result.id | |
} | |
Write-Host "Organization ID for ""$target_organization"" is ""$organization_id""" | |
$response = Ninja-Request 'get' "organization/$organization_id" | |
if ($response.status -ge 201){ | |
$host.SetShouldExit(122) | |
return "Could not obtain organization details for organization ID ""$organization_id"", Error $($response.status): $($response.body)" | |
} | |
foreach ($location in $response.result.locations){ | |
if ($location.name -eq $target_location){ | |
$location_id = $location.id | |
} | |
} | |
if ($location_id -eq $null) { | |
Write-Host "Location ""$target_location"" does not exist. Creating." | |
$response = Ninja-Request 'post' "organization/$organization_id/locations" @{ | |
'name' = $target_location; | |
} | |
if ($response.status -ge 201){ | |
$host.SetShouldExit(130) | |
return "Could not create location ""$target_location"". Error $($response.status): $($response.body)" | |
} | |
$location_id = $response.result.id | |
} | |
Write-Host "Location ID for ""$target_location"" is ""$location_id""" | |
Write-Host "Getting installer URL..." | |
$response = Ninja-Request 'get' "organization/$organization_id/location/$location_id/installer/WINDOWS_MSI" | |
if ($response.status -ge 201){ | |
$host.SetShouldExit(123) | |
return "Could not obtain an installer. Error $($response.status): $($response.body)" | |
} | |
$installer_url = $response.result.url | |
Write-Host "the installer for ""$target_organization/$target_location"" is at ""$installer_url""" | |
Write-Host "Downloading the installer..." | |
$ProgressPreference = 'SilentlyContinue' | |
Invoke-WebRequest -UseBasicParsing -Uri $installer_url -headers @{'User-Agent' = $faux_user_agent} -OutFile "$env:temp\ninjaone_installer.msi" | |
if (-Not (New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)){ | |
$host.SetShouldExit(124) | |
return "Not admin. Can't run the installer." | |
} | |
Write-Host "Running the installer..." | |
Start-Process 'msiexec.exe' -ArgumentList "/i $env:temp\ninjaone_installer.msi /qn /norestart" -Wait | |
Write-Host "Done." | |
Remove-Item "$env:temp\ninjaone_installer.msi" -ea 0 | |
$host.SetShouldExit(0) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment