NinjaOne API Scripts
NinjaOne API Examples

Set Policy on Individual Device

This script updates the assigned policy on a specific NinjaOne device

PowerShell
# --------------------------------------------------
# Author: Gavin Stone (NinjaOne)
# Attribution: Luke Whitelock (NinjaOne) for his work on the Authentication Functions
# Date: 2026-03-10
# Description: Update the assigned policy on a specific device by its device ID. Only the policyId field should be changed — no other device properties should be modified.

# Version: 1.0
# --------------------------------------------------

# User editable variables:
$NinjaOneInstance = 'eu.ninjarmm.com' # Please replace with the region instance you login to (app.ninjarmm.com, us2.ninjarmm.com, eu.ninjarmm.com, ca.ninjarmm.com, oc.ninjarmm.com)
$NinjaOneClientId = ''
$NinjaOneClientSecret = ''

# The NinjaOne device ID to update
$DeviceId = 1

# The policy ID to assign to the device (set to $null to revert to the organisation-level policy)
$NewPolicyId = 42

# Functions for Authentication
function Get-NinjaOneToken {
    [CmdletBinding()]
    param()

    if ($Script:NinjaOneInstance -and $Script:NinjaOneClientID -and $Script:NinjaOneClientSecret ) {
        if ($Script:NinjaTokenExpiry -and (Get-Date) -lt $Script:NinjaTokenExpiry) {
            return $Script:NinjaToken
        }
        else {

            if ($Script:NinjaOneRefreshToken) {
                $Body = @{
                    'grant_type'    = 'refresh_token'
                    'client_id'     = $Script:NinjaOneClientID
                    'client_secret' = $Script:NinjaOneClientSecret
                    'refresh_token' = $Script:NinjaOneRefreshToken
                }
            }
            else {

                $body = @{
                    grant_type    = 'client_credentials'
                    client_id     = $Script:NinjaOneClientID
                    client_secret = $Script:NinjaOneClientSecret
                    scope         = 'monitoring management'
                }
            }

            $token = Invoke-RestMethod -Uri "https://$($Script:NinjaOneInstance -replace '/ws','')/ws/oauth/token" -Method Post -Body $body -ContentType 'application/x-www-form-urlencoded' -UseBasicParsing

            $Script:NinjaTokenExpiry = (Get-Date).AddSeconds($Token.expires_in)
            $Script:NinjaToken = $token

            Write-Host 'Fetched New Token'
            return $token
        }
    }
    else {
        Throw 'Please run Connect-NinjaOne first'
    }

}

function Connect-NinjaOne {
    [CmdletBinding()]
    param (
        [Parameter(mandatory = $true)]
        $NinjaOneInstance,
        [Parameter(mandatory = $true)]
        $NinjaOneClientID,
        [Parameter(mandatory = $true)]
        $NinjaOneClientSecret,
        $NinjaOneRefreshToken
    )

    $Script:NinjaOneInstance = $NinjaOneInstance
    $Script:NinjaOneClientID = $NinjaOneClientID
    $Script:NinjaOneClientSecret = $NinjaOneClientSecret
    $Script:NinjaOneRefreshToken = $NinjaOneRefreshToken


    try {
        $Null = Get-NinjaOneToken -ea Stop
    }
    catch {
        Throw "Failed to Connect to NinjaOne: $_"
    }

}

function Invoke-NinjaOneRequest {
    param(
        $Method,
        $Body,
        $InputObject,
        $Path,
        $QueryParams,
        [Switch]$Paginate,
        [Switch]$AsArray
    )

    $Token = Get-NinjaOneToken

    if ($InputObject) {
        if ($AsArray) {
            $Body = $InputObject | ConvertTo-Json -depth 100
            if (($InputObject | Measure-Object).count -eq 1 ) {
                $Body = '[' + $Body + ']'
            }
        }
        else {
            $Body = $InputObject | ConvertTo-Json -depth 100
        }
    }

    try {
        if ($Method -in @('GET', 'DELETE')) {
            if ($Paginate) {

                $After = 0
                $PageSize = 1000
                $NinjaResult = do {
                    $Result = Invoke-WebRequest -uri "https://$($Script:NinjaOneInstance)/api/v2/$($Path)?pageSize=$PageSize&after=$After$(if ($QueryParams){"&$QueryParams"})" -Method $Method -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json' -UseBasicParsing
                    $Result
                    $ResultCount = ($Result.id | Measure-Object -Maximum)
                    $After = $ResultCount.maximum

                } while ($ResultCount.count -eq $PageSize)
            }
            else {
                $NinjaResult = Invoke-WebRequest -uri "https://$($Script:NinjaOneInstance)/api/v2/$($Path)$(if ($QueryParams){"?$QueryParams"})" -Method $Method -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json; charset=utf-8' -UseBasicParsing
            }

        }
        elseif ($Method -in @('PATCH', 'PUT', 'POST')) {
            $NinjaResult = Invoke-WebRequest -uri "https://$($Script:NinjaOneInstance)/api/v2/$($Path)$(if ($QueryParams){"?$QueryParams"})" -Method $Method -Headers @{Authorization = "Bearer $($token.access_token)" } -Body $Body -ContentType 'application/json; charset=utf-8' -UseBasicParsing
        }
        else {
            Throw 'Unknown Method'
        }
    }
    catch {
        Throw "Error Occured: $_"
    }

    try {
        return $NinjaResult.content | ConvertFrom-Json -ea stop
    }
    catch {
        return $NinjaResult.content
    }

}

# Connect to NinjaOne API
try {
    Connect-NinjaOne -NinjaOneInstance $NinjaOneInstance -NinjaOneClientID $NinjaOneClientId -NinjaOneClientSecret $NinjaOneClientSecret
}
catch {
    Write-Output "Failed to connect to NinjaOne API: $_"
    exit 1
}

# ─── Script Logic ─────────────────────────────────────────────────────────────

# Validate inputs
if (-not $DeviceId) {
    Write-Host "Error: Please set the `$DeviceId variable to the target device's ID."
    exit 1
}

if (-not $NewPolicyId -and $NewPolicyId -ne 0) {
    Write-Host "Error: Please set the `$NewPolicyId variable to the policy ID to assign (or `$null to revert to the organisation policy)."
    exit 1
}

# Fetch the device first to confirm it exists and show current state
Write-Host "Fetching device $DeviceId..."
try {
    $Device = Invoke-NinjaOneRequest -Method GET -Path "device/$DeviceId"
} catch {
    Write-Host "Error: Could not find device with ID $DeviceId. Please check the ID and try again."
    exit 1
}

Write-Host "Device:         $($Device.systemName) (ID: $($Device.id))"
Write-Host "Current Policy: $(if ($Device.policyId) { $Device.policyId } else { '(organisation default)' })"
Write-Host "New Policy:     $(if ($NewPolicyId) { $NewPolicyId } else { '(revert to organisation default)' })"

if ($Device.policyId -eq $NewPolicyId) {
    Write-Host "`nDevice is already assigned to policy $NewPolicyId. No changes made."
    exit 0
}

# Build the update body — only include policyId to avoid changing anything else
$UpdateBody = @{
    policyId = $NewPolicyId
}

Write-Host "`nUpdating policy..."
try {
    Invoke-NinjaOneRequest -Method PATCH -Path "device/$DeviceId" -InputObject $UpdateBody
    Write-Host "Successfully updated device '$($Device.systemName)' (ID: $DeviceId) to policy ID $NewPolicyId."
} catch {
    Write-Host "Error: Failed to update device policy: $_"
    exit 1
}

Set-DevicePolicy

Overview

This script updates the assigned policy on a specific NinjaOne device. It sends only the policyId field in the PATCH request, ensuring no other device properties are modified.

Attribution

  • Author: Gavin Stone (NinjaOne)

Requirements / Prerequisites

  • NinjaOne API Credentials:
    • NinjaOneClientId
    • NinjaOneClientSecret
  • NinjaOne Instance URL: e.g., eu.ninjarmm.com
  • Policy ID to change too: You can find this by loading a policy, and it's the number that appears at the top, IE for editor/policy/106 it would be 106

How It Works

  1. Authentication: The script authenticates with the NinjaOne API using OAuth2 Client Credentials, obtaining an access token via Connect-NinjaOne.
  2. Fetch Device: Retrieves the target device via device/{id} to confirm it exists and display its current policy assignment.
  3. Compare Policies: Checks whether the device is already assigned to the requested policy and exits early if no change is needed.
  4. Update Policy: Sends a PATCH request to device/{id} with only { policyId: <value> } in the body, ensuring no other device properties are touched.
  5. Confirm Result: Displays a success message with the device name and new policy ID.

Usage

  1. Set Variables:

    • Open Set-DevicePolicy.ps1 in an editor (e.g., VS Code, PowerShell ISE).

    • Fill in your NinjaOne credentials and any script-specific variables at the top:

      $NinjaOneInstance     = "eu.ninjarmm.com"
      $NinjaOneClientId     = "your_client_id"
      $NinjaOneClientSecret = "your_client_secret"
      $DeviceId = 1
      $NewPolicyId = 42 # You can find this by loading a policy, and it's the number that appears at the top
  2. Run the Script:

    .\Set-DevicePolicy.ps1

Expected Output

Fetching device 142... Device: DESK-001 (ID: 142) Current Policy: 15 New Policy: 42 Updating policy... Successfully updated device 'DESK-001' (ID: 142) to policy ID 42.

Troubleshooting

  • Issue: Authentication fails with an error message.

    • Solution: Verify that $NinjaOneClientId and $NinjaOneClientSecret are correct and that the API client has the required scopes (monitoring, management).
  • Issue: The script cannot connect to the NinjaOne API.

    • Solution: Ensure that $NinjaOneInstance is correct (e.g., eu.ninjarmm.com, app.ninjarmm.com, oc.ninjarmm.com) and accessible from your network.
  • Issue: Error: Could not find device with ID.

    • Solution: Verify the device ID exists in your NinjaOne instance. You can find device IDs in the NinjaOne dashboard or by querying the /v2/devices endpoint.
  • Issue: 403 Forbidden when updating the device.

    • Solution: Ensure your API client credentials have the 'management' scope and write permissions for the target device's organisation.

Notes

  • Ensure that your NinjaOne API credentials are kept secure and not shared.
  • The PATCH request sends only policyId — no other device fields (displayName, location, userData, etc.) are included, so they remain unchanged.
  • To update multiple devices, you can wrap the script in a loop or modify it to accept an array of device IDs.